Blender  V2.59
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 
00046 #include "BKE_global.h"
00047 
00048 
00049 #include "BLF_api.h"
00050 
00051 #include "UI_interface.h"
00052 
00053 #include "ED_datafiles.h"
00054 
00055 #include "interface_intern.h"
00056 
00057 
00058 /* style + theme + layout-engine = UI */
00059 
00060 /* 
00061  This is a complete set of layout rules, the 'state' of the Layout 
00062  Engine. Multiple styles are possible, defined via C or Python. Styles 
00063  get a name, and will typically get activated per region type, like 
00064  "Header", or "Listview" or "Toolbar". Properties of Style definitions 
00065  are:
00066  
00067  - default collumn properties, internal spacing, aligning, min/max width
00068  - button alignment rules (for groups)
00069  - label placement rules
00070  - internal labeling or external labeling default
00071  - default minimum widths for buttons/labels (in amount of characters)
00072  - font types, styles and relative sizes for Panel titles, labels, etc.
00073 
00074 */
00075 
00076 
00077 /* ********************************************** */
00078 
00079 static uiStyle *ui_style_new(ListBase *styles, const char *name)
00080 {
00081         uiStyle *style= MEM_callocN(sizeof(uiStyle), "new style");
00082         
00083         BLI_addtail(styles, style);
00084         BLI_strncpy(style->name, name, MAX_STYLE_NAME);
00085         
00086         style->panelzoom= 1.0; /* unused */
00087 
00088         style->paneltitle.uifont_id= UIFONT_DEFAULT;
00089         style->paneltitle.points= 12;
00090         style->paneltitle.kerning= 1;
00091         style->paneltitle.shadow= 1;
00092         style->paneltitle.shadx= 0;
00093         style->paneltitle.shady= -1;
00094         style->paneltitle.shadowalpha= 0.15f;
00095         style->paneltitle.shadowcolor= 1.0f;
00096         
00097         style->grouplabel.uifont_id= UIFONT_DEFAULT;
00098         style->grouplabel.points= 12;
00099         style->grouplabel.kerning= 1;
00100         style->grouplabel.shadow= 3;
00101         style->grouplabel.shadx= 0;
00102         style->grouplabel.shady= -1;
00103         style->grouplabel.shadowalpha= 0.25f;
00104         
00105         style->widgetlabel.uifont_id= UIFONT_DEFAULT;
00106         style->widgetlabel.points= 11;
00107         style->widgetlabel.kerning= 1;
00108         style->widgetlabel.shadow= 3;
00109         style->widgetlabel.shadx= 0;
00110         style->widgetlabel.shady= -1;
00111         style->widgetlabel.shadowalpha= 0.15f;
00112         style->widgetlabel.shadowcolor= 1.0f;
00113         
00114         style->widget.uifont_id= UIFONT_DEFAULT;
00115         style->widget.points= 11;
00116         style->widget.kerning= 1;
00117         style->widget.shadowalpha= 0.25f;
00118 
00119         style->columnspace= 8;
00120         style->templatespace= 5;
00121         style->boxspace= 5;
00122         style->buttonspacex= 8;
00123         style->buttonspacey= 2;
00124         style->panelspace= 8;
00125         style->panelouter= 4;
00126         
00127         return style;
00128 }
00129 
00130 static uiFont *uifont_to_blfont(int id)
00131 {
00132         uiFont *font= U.uifonts.first;
00133         
00134         for(; font; font= font->next) {
00135                 if(font->uifont_id==id) {
00136                         return font;
00137                 }
00138         }
00139         return U.uifonts.first;
00140 }
00141 
00142 /* *************** draw ************************ */
00143 
00144 
00145 void uiStyleFontDrawExt(uiFontStyle *fs, rcti *rect, const char *str,
00146         float *r_xofs, float *r_yofs)
00147 {
00148         float height;
00149         int xofs=0, yofs;
00150         
00151         uiStyleFontSet(fs);
00152 
00153         height= BLF_ascender(fs->uifont_id);
00154         yofs= ceil( 0.5f*(rect->ymax - rect->ymin - height));
00155 
00156         if(fs->align==UI_STYLE_TEXT_CENTER) {
00157                 xofs= floor( 0.5f*(rect->xmax - rect->xmin - BLF_width(fs->uifont_id, str)));
00158                 /* don't center text if it chops off the start of the text, 2 gives some margin */
00159                 if(xofs < 2) {
00160                         xofs= 2;
00161                 }
00162         }
00163         else if(fs->align==UI_STYLE_TEXT_RIGHT) {
00164                 xofs= rect->xmax - rect->xmin - BLF_width(fs->uifont_id, str) - 1;
00165         }
00166         
00167         /* clip is very strict, so we give it some space */
00168         BLF_clipping(fs->uifont_id, rect->xmin-1, rect->ymin-4, rect->xmax+1, rect->ymax+4);
00169         BLF_enable(fs->uifont_id, BLF_CLIPPING);
00170         BLF_position(fs->uifont_id, rect->xmin+xofs, rect->ymin+yofs, 0.0f);
00171 
00172         if (fs->shadow) {
00173                 BLF_enable(fs->uifont_id, BLF_SHADOW);
00174                 BLF_shadow(fs->uifont_id, fs->shadow, fs->shadowcolor, fs->shadowcolor, fs->shadowcolor, fs->shadowalpha);
00175                 BLF_shadow_offset(fs->uifont_id, fs->shadx, fs->shady);
00176         }
00177 
00178         if (fs->kerning == 1)
00179                 BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT);
00180 
00181         BLF_draw(fs->uifont_id, str, 65535); /* XXX, use real length */
00182         BLF_disable(fs->uifont_id, BLF_CLIPPING);
00183         if (fs->shadow)
00184                 BLF_disable(fs->uifont_id, BLF_SHADOW);
00185         if (fs->kerning == 1)
00186                 BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT);
00187 
00188         *r_xofs= xofs;
00189         *r_yofs= yofs;
00190 }
00191 
00192 void uiStyleFontDraw(uiFontStyle *fs, rcti *rect, const char *str)
00193 {
00194         float xofs, yofs;
00195         uiStyleFontDrawExt(fs, rect, str,
00196                 &xofs, &yofs);
00197 }
00198 
00199 /* drawn same as above, but at 90 degree angle */
00200 void uiStyleFontDrawRotated(uiFontStyle *fs, rcti *rect, const char *str)
00201 {
00202         float height;
00203         int xofs, yofs;
00204         float angle;
00205         rcti txtrect;
00206 
00207         uiStyleFontSet(fs);
00208 
00209         height= BLF_ascender(fs->uifont_id);
00210         /* becomes x-offset when rotated */
00211         xofs= ceil( 0.5f*(rect->ymax - rect->ymin - height));
00212 
00213         /* ignore UI_STYLE, always aligned to top */
00214 
00215         /* rotate counter-clockwise for now (assumes left-to-right language)*/
00216         xofs+= height;
00217         yofs= BLF_width(fs->uifont_id, str) + 5;
00218         angle= 90.0f;
00219 
00220         /* translate rect to vertical */
00221         txtrect.xmin= rect->xmin - (rect->ymax - rect->ymin);
00222         txtrect.ymin= rect->ymin - (rect->xmax - rect->xmin);
00223         txtrect.xmax= rect->xmin;
00224         txtrect.ymax= rect->ymin;
00225 
00226         /* clip is very strict, so we give it some space */
00227         /* clipping is done without rotation, so make rect big enough to contain both positions */
00228         BLF_clipping(fs->uifont_id, txtrect.xmin-1, txtrect.ymin-yofs-xofs-4, rect->xmax+1, rect->ymax+4);
00229         BLF_enable(fs->uifont_id, BLF_CLIPPING);
00230         BLF_position(fs->uifont_id, txtrect.xmin+xofs, txtrect.ymax-yofs, 0.0f);
00231 
00232         BLF_enable(fs->uifont_id, BLF_ROTATION);
00233         BLF_rotation(fs->uifont_id, angle);
00234 
00235         if (fs->shadow) {
00236                 BLF_enable(fs->uifont_id, BLF_SHADOW);
00237                 BLF_shadow(fs->uifont_id, fs->shadow, fs->shadowcolor, fs->shadowcolor, fs->shadowcolor, fs->shadowalpha);
00238                 BLF_shadow_offset(fs->uifont_id, fs->shadx, fs->shady);
00239         }
00240 
00241         if (fs->kerning == 1)
00242                 BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT);
00243 
00244         BLF_draw(fs->uifont_id, str, 65535); /* XXX, use real length */
00245         BLF_disable(fs->uifont_id, BLF_ROTATION);
00246         BLF_disable(fs->uifont_id, BLF_CLIPPING);
00247         if (fs->shadow)
00248                 BLF_disable(fs->uifont_id, BLF_SHADOW);
00249         if (fs->kerning == 1)
00250                 BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT);
00251 }
00252 
00253 /* ************** helpers ************************ */
00254 
00255 /* temporarily, does widget font */
00256 int UI_GetStringWidth(const char *str)
00257 {
00258         uiStyle *style= U.uistyles.first;
00259         uiFontStyle *fstyle= &style->widget;
00260         int width;
00261         
00262         if (fstyle->kerning==1) /* for BLF_width */
00263                 BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
00264         
00265         uiStyleFontSet(fstyle);
00266         width= BLF_width(fstyle->uifont_id, str);       
00267         
00268         if (fstyle->kerning==1)
00269                 BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
00270         
00271         return width;
00272 }
00273 
00274 /* temporarily, does widget font */
00275 void UI_DrawString(float x, float y, const char *str)
00276 {
00277         uiStyle *style= U.uistyles.first;
00278         
00279         if (style->widget.kerning == 1)
00280                 BLF_enable(style->widget.uifont_id, BLF_KERNING_DEFAULT);
00281 
00282         uiStyleFontSet(&style->widget);
00283         BLF_position(style->widget.uifont_id, x, y, 0.0f);
00284         BLF_draw(style->widget.uifont_id, str, 65535); /* XXX, use real length */
00285 
00286         if (style->widget.kerning == 1)
00287                 BLF_disable(style->widget.uifont_id, BLF_KERNING_DEFAULT);
00288 }
00289 
00290 /* ************** init exit ************************ */
00291 
00292 /* called on each startup.blend read */
00293 /* reading without uifont will create one */
00294 void uiStyleInit(void)
00295 {
00296         uiFont *font= U.uifonts.first;
00297         uiStyle *style= U.uistyles.first;
00298         
00299         /* recover from uninitialized dpi */
00300         if(U.dpi == 0)
00301                 U.dpi= 72;
00302         CLAMP(U.dpi, 48, 128);
00303         
00304         /* default builtin */
00305         if(font==NULL) {
00306                 font= MEM_callocN(sizeof(uiFont), "ui font");
00307                 BLI_addtail(&U.uifonts, font);
00308                 
00309                 strcpy(font->filename, "default");
00310                 font->uifont_id= UIFONT_DEFAULT;
00311         }
00312         
00313         for(font= U.uifonts.first; font; font= font->next) {
00314                 
00315                 if(font->uifont_id==UIFONT_DEFAULT) {
00316                         font->blf_id= BLF_load_mem("default", (unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size);
00317                 }               
00318                 else {
00319                         font->blf_id= BLF_load(font->filename);
00320                         if(font->blf_id == -1)
00321                                 font->blf_id= BLF_load_mem("default", (unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size);
00322                 }
00323 
00324                 if (font->blf_id == -1) {
00325                         if (G.f & G_DEBUG)
00326                                 printf("uiStyleInit error, no fonts available\n");
00327                 }
00328                 else {
00329                         /* ? just for speed to initialize?
00330                          * Yes, this build the glyph cache and create
00331                          * the texture.
00332                          */
00333                         BLF_size(font->blf_id, 11, U.dpi);
00334                         BLF_size(font->blf_id, 12, U.dpi);
00335                         BLF_size(font->blf_id, 14, U.dpi);
00336                 }
00337         }
00338         
00339         if(style==NULL) {
00340                 ui_style_new(&U.uistyles, "Default Style");
00341         }
00342         
00343         // XXX, this should be moved into a style, but for now best only load the monospaced font once.
00344         if (blf_mono_font == -1)
00345                 blf_mono_font= BLF_load_mem_unique("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
00346 
00347         BLF_size(blf_mono_font, 12, 72);
00348         
00349         /* second for rendering else we get threading problems */
00350         if (blf_mono_font_render == -1)
00351                 blf_mono_font_render= BLF_load_mem_unique("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
00352 
00353         BLF_size(blf_mono_font_render, 12, 72);
00354 }
00355 
00356 void uiStyleFontSet(uiFontStyle *fs)
00357 {
00358         uiFont *font= uifont_to_blfont(fs->uifont_id);
00359         
00360         BLF_size(font->blf_id, fs->points, U.dpi);
00361 }
00362