Blender V2.61 - r43446

interface_style.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version. 
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2009 Blender Foundation.
00019  * All rights reserved.
00020  * 
00021  * Contributor(s): Blender Foundation
00022  *
00023  * ***** END GPL LICENSE BLOCK *****
00024  */
00025 
00031 #include <limits.h>
00032 #include <math.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 
00036 #include "MEM_guardedalloc.h"
00037 
00038 #include "DNA_screen_types.h"
00039 #include "DNA_userdef_types.h"
00040 
00041 #include "BLI_math.h"
00042 #include "BLI_listbase.h"
00043 #include "BLI_rect.h"
00044 #include "BLI_string.h"
00045 #include "BLI_utildefines.h"
00046 
00047 #include "BKE_global.h"
00048 
00049 
00050 #include "BLF_api.h"
00051 #include "BLF_translation.h"
00052 
00053 #include "UI_interface.h"
00054 
00055 #include "ED_datafiles.h"
00056 
00057 #include "interface_intern.h"
00058 
00059 
00060 /* style + theme + layout-engine = UI */
00061 
00062 /* 
00063  This is a complete set of layout rules, the 'state' of the Layout 
00064  Engine. Multiple styles are possible, defined via C or Python. Styles 
00065  get a name, and will typically get activated per region type, like 
00066  "Header", or "Listview" or "Toolbar". Properties of Style definitions 
00067  are:
00068  
00069  - default collumn properties, internal spacing, aligning, min/max width
00070  - button alignment rules (for groups)
00071  - label placement rules
00072  - internal labeling or external labeling default
00073  - default minimum widths for buttons/labels (in amount of characters)
00074  - font types, styles and relative sizes for Panel titles, labels, etc.
00075 
00076 */
00077 
00078 
00079 /* ********************************************** */
00080 
00081 static uiStyle *ui_style_new(ListBase *styles, const char *name, short uifont_id)
00082 {
00083     uiStyle *style= MEM_callocN(sizeof(uiStyle), "new style");
00084     
00085     BLI_addtail(styles, style);
00086     BLI_strncpy(style->name, name, MAX_STYLE_NAME);
00087     
00088     style->panelzoom= 1.0; /* unused */
00089 
00090     style->paneltitle.uifont_id= uifont_id;
00091     style->paneltitle.points= 12;
00092     style->paneltitle.kerning= 1;
00093     style->paneltitle.shadow= 1;
00094     style->paneltitle.shadx= 0;
00095     style->paneltitle.shady= -1;
00096     style->paneltitle.shadowalpha= 0.15f;
00097     style->paneltitle.shadowcolor= 1.0f;
00098     
00099     style->grouplabel.uifont_id= uifont_id;
00100     style->grouplabel.points= 12;
00101     style->grouplabel.kerning= 1;
00102     style->grouplabel.shadow= 3;
00103     style->grouplabel.shadx= 0;
00104     style->grouplabel.shady= -1;
00105     style->grouplabel.shadowalpha= 0.25f;
00106     
00107     style->widgetlabel.uifont_id= uifont_id;
00108     style->widgetlabel.points= 11;
00109     style->widgetlabel.kerning= 1;
00110     style->widgetlabel.shadow= 3;
00111     style->widgetlabel.shadx= 0;
00112     style->widgetlabel.shady= -1;
00113     style->widgetlabel.shadowalpha= 0.15f;
00114     style->widgetlabel.shadowcolor= 1.0f;
00115     
00116     style->widget.uifont_id= uifont_id;
00117     style->widget.points= 11;
00118     style->widget.kerning= 1;
00119     style->widget.shadowalpha= 0.25f;
00120 
00121     style->columnspace= 8;
00122     style->templatespace= 5;
00123     style->boxspace= 5;
00124     style->buttonspacex= 8;
00125     style->buttonspacey= 2;
00126     style->panelspace= 8;
00127     style->panelouter= 4;
00128     
00129     return style;
00130 }
00131 
00132 static uiFont *uifont_to_blfont(int id)
00133 {
00134     uiFont *font= U.uifonts.first;
00135     
00136     for(; font; font= font->next) {
00137         if(font->uifont_id==id) {
00138             return font;
00139         }
00140     }
00141     return U.uifonts.first;
00142 }
00143 
00144 /* *************** draw ************************ */
00145 
00146 
00147 void uiStyleFontDrawExt(uiFontStyle *fs, rcti *rect, const char *str,
00148     float *r_xofs, float *r_yofs)
00149 {
00150     float height;
00151     int xofs=0, yofs;
00152     
00153     uiStyleFontSet(fs);
00154 
00155     height= BLF_ascender(fs->uifont_id);
00156     yofs= ceil( 0.5f*(rect->ymax - rect->ymin - height));
00157 
00158     if(fs->align==UI_STYLE_TEXT_CENTER) {
00159         xofs= floor( 0.5f*(rect->xmax - rect->xmin - BLF_width(fs->uifont_id, str)));
00160         /* don't center text if it chops off the start of the text, 2 gives some margin */
00161         if(xofs < 2) {
00162             xofs= 2;
00163         }
00164     }
00165     else if(fs->align==UI_STYLE_TEXT_RIGHT) {
00166         xofs= rect->xmax - rect->xmin - BLF_width(fs->uifont_id, str) - 1;
00167     }
00168     
00169     /* clip is very strict, so we give it some space */
00170     BLF_clipping(fs->uifont_id, rect->xmin-1, rect->ymin-4, rect->xmax+1, rect->ymax+4);
00171     BLF_enable(fs->uifont_id, BLF_CLIPPING);
00172     BLF_position(fs->uifont_id, rect->xmin+xofs, rect->ymin+yofs, 0.0f);
00173 
00174     if (fs->shadow) {
00175         BLF_enable(fs->uifont_id, BLF_SHADOW);
00176         BLF_shadow(fs->uifont_id, fs->shadow, fs->shadowcolor, fs->shadowcolor, fs->shadowcolor, fs->shadowalpha);
00177         BLF_shadow_offset(fs->uifont_id, fs->shadx, fs->shady);
00178     }
00179 
00180     if (fs->kerning == 1)
00181         BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT);
00182 
00183     BLF_draw(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
00184     BLF_disable(fs->uifont_id, BLF_CLIPPING);
00185     if (fs->shadow)
00186         BLF_disable(fs->uifont_id, BLF_SHADOW);
00187     if (fs->kerning == 1)
00188         BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT);
00189 
00190     *r_xofs= xofs;
00191     *r_yofs= yofs;
00192 }
00193 
00194 void uiStyleFontDraw(uiFontStyle *fs, rcti *rect, const char *str)
00195 {
00196     float xofs, yofs;
00197     uiStyleFontDrawExt(fs, rect, str,
00198         &xofs, &yofs);
00199 }
00200 
00201 /* drawn same as above, but at 90 degree angle */
00202 void uiStyleFontDrawRotated(uiFontStyle *fs, rcti *rect, const char *str)
00203 {
00204     float height;
00205     int xofs, yofs;
00206     float angle;
00207     rcti txtrect;
00208 
00209     uiStyleFontSet(fs);
00210 
00211     height= BLF_ascender(fs->uifont_id);
00212     /* becomes x-offset when rotated */
00213     xofs= ceil( 0.5f*(rect->ymax - rect->ymin - height));
00214 
00215     /* ignore UI_STYLE, always aligned to top */
00216 
00217     /* rotate counter-clockwise for now (assumes left-to-right language)*/
00218     xofs+= height;
00219     yofs= BLF_width(fs->uifont_id, str) + 5;
00220     angle= 90.0f;
00221 
00222     /* translate rect to vertical */
00223     txtrect.xmin= rect->xmin - (rect->ymax - rect->ymin);
00224     txtrect.ymin= rect->ymin - (rect->xmax - rect->xmin);
00225     txtrect.xmax= rect->xmin;
00226     txtrect.ymax= rect->ymin;
00227 
00228     /* clip is very strict, so we give it some space */
00229     /* clipping is done without rotation, so make rect big enough to contain both positions */
00230     BLF_clipping(fs->uifont_id, txtrect.xmin-1, txtrect.ymin-yofs-xofs-4, rect->xmax+1, rect->ymax+4);
00231     BLF_enable(fs->uifont_id, BLF_CLIPPING);
00232     BLF_position(fs->uifont_id, txtrect.xmin+xofs, txtrect.ymax-yofs, 0.0f);
00233 
00234     BLF_enable(fs->uifont_id, BLF_ROTATION);
00235     BLF_rotation(fs->uifont_id, angle);
00236 
00237     if (fs->shadow) {
00238         BLF_enable(fs->uifont_id, BLF_SHADOW);
00239         BLF_shadow(fs->uifont_id, fs->shadow, fs->shadowcolor, fs->shadowcolor, fs->shadowcolor, fs->shadowalpha);
00240         BLF_shadow_offset(fs->uifont_id, fs->shadx, fs->shady);
00241     }
00242 
00243     if (fs->kerning == 1)
00244         BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT);
00245 
00246     BLF_draw(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
00247     BLF_disable(fs->uifont_id, BLF_ROTATION);
00248     BLF_disable(fs->uifont_id, BLF_CLIPPING);
00249     if (fs->shadow)
00250         BLF_disable(fs->uifont_id, BLF_SHADOW);
00251     if (fs->kerning == 1)
00252         BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT);
00253 }
00254 
00255 /* ************** helpers ************************ */
00256 /* XXX: read a style configure */
00257 uiStyle* UI_GetStyle(void)
00258 {
00259     uiStyle *style = NULL;
00260     /* offset is two struct uiStyle pointers */
00261     /* style = BLI_findstring( &U.uistyles, "Unifont Style", sizeof(style)*2 ) */;
00262     return (style != NULL) ? style : U.uistyles.first;
00263 }
00264 
00265 /* temporarily, does widget font */
00266 int UI_GetStringWidth(const char *str)
00267 {
00268     uiStyle *style= UI_GetStyle();
00269     uiFontStyle *fstyle= &style->widget;
00270     int width;
00271     
00272     if (fstyle->kerning==1) /* for BLF_width */
00273         BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
00274     
00275     uiStyleFontSet(fstyle);
00276     width= BLF_width(fstyle->uifont_id, str);   
00277     
00278     if (fstyle->kerning==1)
00279         BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
00280     
00281     return width;
00282 }
00283 
00284 /* temporarily, does widget font */
00285 void UI_DrawString(float x, float y, const char *str)
00286 {
00287     uiStyle *style= UI_GetStyle();
00288     
00289     if (style->widget.kerning == 1)
00290         BLF_enable(style->widget.uifont_id, BLF_KERNING_DEFAULT);
00291 
00292     uiStyleFontSet(&style->widget);
00293     BLF_position(style->widget.uifont_id, x, y, 0.0f);
00294     BLF_draw(style->widget.uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
00295 
00296     if (style->widget.kerning == 1)
00297         BLF_disable(style->widget.uifont_id, BLF_KERNING_DEFAULT);
00298 }
00299 
00300 /* ************** init exit ************************ */
00301 
00302 /* called on each startup.blend read */
00303 /* reading without uifont will create one */
00304 void uiStyleInit(void)
00305 {
00306     uiFont *font= U.uifonts.first;
00307     uiStyle *style= U.uistyles.first;
00308     
00309     /* recover from uninitialized dpi */
00310     if(U.dpi == 0)
00311         U.dpi= 72;
00312     CLAMP(U.dpi, 48, 128);
00313     
00314     /* default builtin */
00315     if(font==NULL) {
00316         font= MEM_callocN(sizeof(uiFont), "ui font");
00317         BLI_addtail(&U.uifonts, font);
00318         
00319         BLI_strncpy(font->filename, "default", sizeof(font->filename));
00320         font->uifont_id= UIFONT_DEFAULT;
00321     }
00322     
00323     for(font= U.uifonts.first; font; font= font->next) {
00324         
00325         if(font->uifont_id==UIFONT_DEFAULT) {
00326 #ifdef WITH_INTERNATIONAL
00327             int font_size= datatoc_bfont_ttf_size;
00328             unsigned char *font_ttf= (unsigned char*)datatoc_bfont_ttf;
00329             static int last_font_size = 0;
00330 
00331             /* use unicode font for translation */
00332             if(U.transopts & USER_DOTRANSLATE) {
00333                 font_ttf= BLF_get_unifont(&font_size);
00334 
00335                 if(!font_ttf) {
00336                     /* fall back if not found */
00337                     font_size= datatoc_bfont_ttf_size;
00338                     font_ttf= (unsigned char*)datatoc_bfont_ttf;
00339                 }
00340             }
00341 
00342             /* relload only if needed */
00343             if(last_font_size != font_size) {
00344                 BLF_unload("default");
00345                 last_font_size = font_size;
00346             }
00347 
00348             font->blf_id= BLF_load_mem("default", font_ttf, font_size);
00349 #else
00350             font->blf_id= BLF_load_mem("default", (unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size);
00351 #endif
00352         }       
00353         else {
00354             font->blf_id= BLF_load(font->filename);
00355             if(font->blf_id == -1)
00356                 font->blf_id= BLF_load_mem("default", (unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size);
00357         }
00358 
00359         if (font->blf_id == -1) {
00360             if (G.f & G_DEBUG)
00361                 printf("%s: error, no fonts available\n", __func__);
00362         }
00363         else {
00364             /* ? just for speed to initialize?
00365              * Yes, this build the glyph cache and create
00366              * the texture.
00367              */
00368             BLF_size(font->blf_id, 11, U.dpi);
00369             BLF_size(font->blf_id, 12, U.dpi);
00370             BLF_size(font->blf_id, 14, U.dpi);
00371         }
00372     }
00373     
00374     if(style==NULL) {
00375         ui_style_new(&U.uistyles, "Default Style", UIFONT_DEFAULT );
00376     }
00377     
00378     // XXX, this should be moved into a style, but for now best only load the monospaced font once.
00379     if (blf_mono_font == -1)
00380         blf_mono_font= BLF_load_mem_unique("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
00381 
00382     BLF_size(blf_mono_font, 12, 72);
00383     
00384     /* second for rendering else we get threading problems */
00385     if (blf_mono_font_render == -1)
00386         blf_mono_font_render= BLF_load_mem_unique("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
00387 
00388     BLF_size(blf_mono_font_render, 12, 72);
00389 }
00390 
00391 void uiStyleFontSet(uiFontStyle *fs)
00392 {
00393     uiFont *font= uifont_to_blfont(fs->uifont_id);
00394     
00395     BLF_size(font->blf_id, fs->points, U.dpi);
00396 }
00397