Merging trunk up to r39145.
[blender-staging.git] / source / blender / editors / interface / interface_style.c
1 /*
2 * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2009 Blender Foundation.
19  * All rights reserved.
20  * 
21  * Contributor(s): Blender Foundation
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/interface/interface_style.c
27  *  \ingroup edinterface
28  */
29
30
31 #include <limits.h>
32 #include <math.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "DNA_screen_types.h"
39 #include "DNA_userdef_types.h"
40
41 #include "BLI_math.h"
42 #include "BLI_listbase.h"
43 #include "BLI_rect.h"
44 #include "BLI_string.h"
45
46 #include "BKE_global.h"
47
48
49 #include "BLF_api.h"
50
51 #include "UI_interface.h"
52
53 #include "ED_datafiles.h"
54
55 #include "interface_intern.h"
56
57
58 /* style + theme + layout-engine = UI */
59
60 /* 
61  This is a complete set of layout rules, the 'state' of the Layout 
62  Engine. Multiple styles are possible, defined via C or Python. Styles 
63  get a name, and will typically get activated per region type, like 
64  "Header", or "Listview" or "Toolbar". Properties of Style definitions 
65  are:
66  
67  - default collumn properties, internal spacing, aligning, min/max width
68  - button alignment rules (for groups)
69  - label placement rules
70  - internal labeling or external labeling default
71  - default minimum widths for buttons/labels (in amount of characters)
72  - font types, styles and relative sizes for Panel titles, labels, etc.
73
74 */
75
76
77 /* ********************************************** */
78
79 static uiStyle *ui_style_new(ListBase *styles, const char *name)
80 {
81         uiStyle *style= MEM_callocN(sizeof(uiStyle), "new style");
82         
83         BLI_addtail(styles, style);
84         BLI_strncpy(style->name, name, MAX_STYLE_NAME);
85         
86         style->panelzoom= 1.0; /* unused */
87
88         style->paneltitle.uifont_id= UIFONT_DEFAULT;
89         style->paneltitle.points= 12;
90         style->paneltitle.kerning= 1;
91         style->paneltitle.shadow= 1;
92         style->paneltitle.shadx= 0;
93         style->paneltitle.shady= -1;
94         style->paneltitle.shadowalpha= 0.15f;
95         style->paneltitle.shadowcolor= 1.0f;
96         
97         style->grouplabel.uifont_id= UIFONT_DEFAULT;
98         style->grouplabel.points= 12;
99         style->grouplabel.kerning= 1;
100         style->grouplabel.shadow= 3;
101         style->grouplabel.shadx= 0;
102         style->grouplabel.shady= -1;
103         style->grouplabel.shadowalpha= 0.25f;
104         
105         style->widgetlabel.uifont_id= UIFONT_DEFAULT;
106         style->widgetlabel.points= 11;
107         style->widgetlabel.kerning= 1;
108         style->widgetlabel.shadow= 3;
109         style->widgetlabel.shadx= 0;
110         style->widgetlabel.shady= -1;
111         style->widgetlabel.shadowalpha= 0.15f;
112         style->widgetlabel.shadowcolor= 1.0f;
113         
114         style->widget.uifont_id= UIFONT_DEFAULT;
115         style->widget.points= 11;
116         style->widget.kerning= 1;
117         style->widget.shadowalpha= 0.25f;
118
119         style->columnspace= 8;
120         style->templatespace= 5;
121         style->boxspace= 5;
122         style->buttonspacex= 8;
123         style->buttonspacey= 2;
124         style->panelspace= 8;
125         style->panelouter= 4;
126         
127         return style;
128 }
129
130 static uiFont *uifont_to_blfont(int id)
131 {
132         uiFont *font= U.uifonts.first;
133         
134         for(; font; font= font->next) {
135                 if(font->uifont_id==id) {
136                         return font;
137                 }
138         }
139         return U.uifonts.first;
140 }
141
142 /* *************** draw ************************ */
143
144
145 void uiStyleFontDrawExt(uiFontStyle *fs, rcti *rect, const char *str,
146         float *r_xofs, float *r_yofs)
147 {
148         float height;
149         int xofs=0, yofs;
150         
151         uiStyleFontSet(fs);
152
153         height= BLF_ascender(fs->uifont_id);
154         yofs= ceil( 0.5f*(rect->ymax - rect->ymin - height));
155
156         if(fs->align==UI_STYLE_TEXT_CENTER) {
157                 xofs= floor( 0.5f*(rect->xmax - rect->xmin - BLF_width(fs->uifont_id, str)));
158                 /* don't center text if it chops off the start of the text, 2 gives some margin */
159                 if(xofs < 2) {
160                         xofs= 2;
161                 }
162         }
163         else if(fs->align==UI_STYLE_TEXT_RIGHT) {
164                 xofs= rect->xmax - rect->xmin - BLF_width(fs->uifont_id, str) - 1;
165         }
166         
167         /* clip is very strict, so we give it some space */
168         BLF_clipping(fs->uifont_id, rect->xmin-1, rect->ymin-4, rect->xmax+1, rect->ymax+4);
169         BLF_enable(fs->uifont_id, BLF_CLIPPING);
170         BLF_position(fs->uifont_id, rect->xmin+xofs, rect->ymin+yofs, 0.0f);
171
172         if (fs->shadow) {
173                 BLF_enable(fs->uifont_id, BLF_SHADOW);
174                 BLF_shadow(fs->uifont_id, fs->shadow, fs->shadowcolor, fs->shadowcolor, fs->shadowcolor, fs->shadowalpha);
175                 BLF_shadow_offset(fs->uifont_id, fs->shadx, fs->shady);
176         }
177
178         if (fs->kerning == 1)
179                 BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT);
180
181         BLF_draw(fs->uifont_id, str, 65535); /* XXX, use real length */
182         BLF_disable(fs->uifont_id, BLF_CLIPPING);
183         if (fs->shadow)
184                 BLF_disable(fs->uifont_id, BLF_SHADOW);
185         if (fs->kerning == 1)
186                 BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT);
187
188         *r_xofs= xofs;
189         *r_yofs= yofs;
190 }
191
192 void uiStyleFontDraw(uiFontStyle *fs, rcti *rect, const char *str)
193 {
194         float xofs, yofs;
195         uiStyleFontDrawExt(fs, rect, str,
196                 &xofs, &yofs);
197 }
198
199 /* drawn same as above, but at 90 degree angle */
200 void uiStyleFontDrawRotated(uiFontStyle *fs, rcti *rect, const char *str)
201 {
202         float height;
203         int xofs, yofs;
204         float angle;
205         rcti txtrect;
206
207         uiStyleFontSet(fs);
208
209         height= BLF_ascender(fs->uifont_id);
210         /* becomes x-offset when rotated */
211         xofs= ceil( 0.5f*(rect->ymax - rect->ymin - height));
212
213         /* ignore UI_STYLE, always aligned to top */
214
215         /* rotate counter-clockwise for now (assumes left-to-right language)*/
216         xofs+= height;
217         yofs= BLF_width(fs->uifont_id, str) + 5;
218         angle= 90.0f;
219
220         /* translate rect to vertical */
221         txtrect.xmin= rect->xmin - (rect->ymax - rect->ymin);
222         txtrect.ymin= rect->ymin - (rect->xmax - rect->xmin);
223         txtrect.xmax= rect->xmin;
224         txtrect.ymax= rect->ymin;
225
226         /* clip is very strict, so we give it some space */
227         /* clipping is done without rotation, so make rect big enough to contain both positions */
228         BLF_clipping(fs->uifont_id, txtrect.xmin-1, txtrect.ymin-yofs-xofs-4, rect->xmax+1, rect->ymax+4);
229         BLF_enable(fs->uifont_id, BLF_CLIPPING);
230         BLF_position(fs->uifont_id, txtrect.xmin+xofs, txtrect.ymax-yofs, 0.0f);
231
232         BLF_enable(fs->uifont_id, BLF_ROTATION);
233         BLF_rotation(fs->uifont_id, angle);
234
235         if (fs->shadow) {
236                 BLF_enable(fs->uifont_id, BLF_SHADOW);
237                 BLF_shadow(fs->uifont_id, fs->shadow, fs->shadowcolor, fs->shadowcolor, fs->shadowcolor, fs->shadowalpha);
238                 BLF_shadow_offset(fs->uifont_id, fs->shadx, fs->shady);
239         }
240
241         if (fs->kerning == 1)
242                 BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT);
243
244         BLF_draw(fs->uifont_id, str, 65535); /* XXX, use real length */
245         BLF_disable(fs->uifont_id, BLF_ROTATION);
246         BLF_disable(fs->uifont_id, BLF_CLIPPING);
247         if (fs->shadow)
248                 BLF_disable(fs->uifont_id, BLF_SHADOW);
249         if (fs->kerning == 1)
250                 BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT);
251 }
252
253 /* ************** helpers ************************ */
254
255 /* temporarily, does widget font */
256 int UI_GetStringWidth(const char *str)
257 {
258         uiStyle *style= U.uistyles.first;
259         uiFontStyle *fstyle= &style->widget;
260         int width;
261         
262         if (fstyle->kerning==1) /* for BLF_width */
263                 BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
264         
265         uiStyleFontSet(fstyle);
266         width= BLF_width(fstyle->uifont_id, str);       
267         
268         if (fstyle->kerning==1)
269                 BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
270         
271         return width;
272 }
273
274 /* temporarily, does widget font */
275 void UI_DrawString(float x, float y, const char *str)
276 {
277         uiStyle *style= U.uistyles.first;
278         
279         if (style->widget.kerning == 1)
280                 BLF_enable(style->widget.uifont_id, BLF_KERNING_DEFAULT);
281
282         uiStyleFontSet(&style->widget);
283         BLF_position(style->widget.uifont_id, x, y, 0.0f);
284         BLF_draw(style->widget.uifont_id, str, 65535); /* XXX, use real length */
285
286         if (style->widget.kerning == 1)
287                 BLF_disable(style->widget.uifont_id, BLF_KERNING_DEFAULT);
288 }
289
290 /* ************** init exit ************************ */
291
292 /* called on each startup.blend read */
293 /* reading without uifont will create one */
294 void uiStyleInit(void)
295 {
296         uiFont *font= U.uifonts.first;
297         uiStyle *style= U.uistyles.first;
298         int defaultFontId = -1;
299         
300         /* recover from uninitialized dpi */
301         if(U.dpi == 0)
302                 U.dpi= 72;
303         CLAMP(U.dpi, 48, 128);
304         
305         /* default builtin */
306         if(font==NULL) {
307                 font= MEM_callocN(sizeof(uiFont), "ui font");
308                 BLI_addtail(&U.uifonts, font);
309                 
310                 strcpy(font->filename, "default");
311                 font->uifont_id= UIFONT_DEFAULT;
312         }
313         
314         for(font= U.uifonts.first; font; font= font->next) {
315                 
316                 if(font->uifont_id==UIFONT_DEFAULT) {
317                         font->blf_id= BLF_load_mem("default", (unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size);
318                         defaultFontId = font->blf_id;
319                 }               
320                 else {
321                         font->blf_id= BLF_load(font->filename);
322                         if(font->blf_id == -1)
323                                 font->blf_id= BLF_load_mem("default", (unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size);
324                 }
325
326                 if (font->blf_id == -1) {
327                         if (G.f & G_DEBUG)
328                                 printf("uiStyleInit error, no fonts available\n");
329                 }
330                 else {
331                         /* ? just for speed to initialize?
332                          * Yes, this build the glyph cache and create
333                          * the texture.
334                          */
335                         BLF_size(font->blf_id, 11, U.dpi);
336                         BLF_size(font->blf_id, 12, U.dpi);
337                         BLF_size(font->blf_id, 14, U.dpi);
338                 }
339         }
340         
341         if(style==NULL) {
342                 ui_style_new(&U.uistyles, "Default Style");
343         }
344         
345         // XXX, this should be moved into a style, but for now best only load the monospaced font once.
346         if (blf_mono_font == -1)
347                 blf_mono_font= BLF_load_mem_unique("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
348
349         BLF_size(blf_mono_font, 12, 72);
350         
351         /* second for rendering else we get threading problems */
352         if (blf_mono_font_render == -1)
353                 blf_mono_font_render= BLF_load_mem_unique("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
354
355         BLF_size(blf_mono_font_render, 12, 72);
356         
357         /* also another copy of default for rendering else we get threading problems */
358         if (defaultFontId != -1) {
359                 if (blf_default_font_render == -1)
360                         blf_default_font_render= BLF_load_mem_unique("default", (unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size);
361                         
362                 BLF_size(blf_default_font_render, 12, 72);
363         }
364 }
365
366 void uiStyleFontSet(uiFontStyle *fs)
367 {
368         uiFont *font= uifont_to_blfont(fs->uifont_id);
369         
370         BLF_size(font->blf_id, fs->points, U.dpi);
371 }
372