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