Added a NULL check that was needed.
[blender.git] / source / blender / src / language.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is written by Rob Haarsma (phase)
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL/BL DUAL LICENSE BLOCK *****
28  */
29
30
31 #include <string.h>
32 #include <stdlib.h>
33
34 #include "DNA_listBase.h"
35 #include "DNA_userdef_types.h"
36 #include "DNA_vec_types.h"
37
38 #include "BKE_global.h"         /* G */
39 #include "BKE_utildefines.h"
40
41 #include "BLI_blenlib.h"
42 #include "BLI_linklist.h"       /* linknode */
43
44 #include "BIF_gl.h"
45 #include "BIF_language.h"
46 #include "BIF_space.h"          /* allqueue() */
47 #include "BIF_toolbox.h"        /* error() */
48 #include "datatoc.h"            /* std font */
49
50 #include "MEM_guardedalloc.h"   /* vprintf, etc ??? */
51
52 #include "mydevice.h"           /* REDRAWALL */
53
54 #include "BMF_Api.h"
55
56 #ifdef WITH_ICONV
57 #include "iconv.h"
58
59 void string_to_utf8(char *original, char *utf_8, char *code)
60 {
61         size_t inbytesleft=strlen(original);
62         size_t outbytesleft=512;
63         size_t rv=0;
64         iconv_t cd;
65         
66         cd=iconv_open("UTF-8", code);
67
68         if (cd == (iconv_t)(-1)) {
69                 printf("iconv_open Error");
70                 *utf_8='\0';
71                 return ;
72         }
73         rv=iconv(cd, &original, &inbytesleft, &utf_8, &outbytesleft);
74         if (rv == (size_t) -1) {
75                 printf("iconv Error\n");
76                 return ;
77         }
78         *utf_8 = '\0';
79         iconv_close(cd);
80 }
81 #endif // WITH_ICONV
82
83 #ifdef INTERNATIONAL
84 #include "FTF_Api.h"
85
86 static struct LANGMenuEntry *langmenu= 0;
87 static int tot_lang = 0;
88
89 #endif // INTERNATIONAL
90
91 void BIF_RasterPos(float x, float y)
92 {
93 #ifdef INTERNATIONAL
94         FTF_SetPosition(x, y);
95 #endif // INTERNATIONAL
96 }
97
98 void BIF_SetScale(float aspect)
99 {
100 #ifdef INTERNATIONAL
101         FTF_SetScale(aspect);
102 #endif // INTERNATIONAL
103 }
104
105 void refresh_interface_font(void)
106 {
107 #ifdef INTERNATIONAL
108         if(U.transopts & USER_DOTRANSLATE)
109                 start_interface_font();
110         else
111                 G.ui_international = FALSE;
112 #else // INTERNATIONAL
113         G.ui_international = FALSE;
114 #endif
115 }
116
117 int BIF_DrawString(BMF_Font* font, char *str, int translate)
118 {
119
120 #ifdef INTERNATIONAL
121         if(G.ui_international == TRUE) {
122                 if(translate)
123                 {
124 #ifdef WITH_ICONV
125                         if(translate & CONVERT_TO_UTF8) {
126                                 char utf_8[512];
127
128                                 struct LANGMenuEntry *lme;
129                                 lme = find_language(U.language);
130
131                                 if (lme !=NULL) {
132                                         if (!strcmp(lme->code, "ja_JP"))
133                                                 string_to_utf8(str, utf_8, "Shift_JIS");        /* Japanese */
134                                         else if (!strcmp(lme->code, "zh_CN"))
135                                                 string_to_utf8(str, utf_8, "GB2312");           /* Chinese */
136                                 }
137         
138                                 return FTF_DrawString(utf_8, FTF_INPUT_UTF8);
139                         }
140                         else
141 #endif // WITH_ICONV
142                                 return FTF_DrawString(str, FTF_USE_GETTEXT | FTF_INPUT_UTF8);
143                 }
144                 else
145                         return FTF_DrawString(str, FTF_NO_TRANSCONV | FTF_INPUT_UTF8);
146         } else {
147                 return BMF_DrawString(font, str);
148         }
149 #else // INTERNATIONAL
150         return BMF_DrawString(font, str);
151 #endif
152
153 }
154
155
156 float BIF_GetStringWidth(BMF_Font* font, char *str, int translate)
157 {
158         float rt;
159
160 #ifdef INTERNATIONAL
161         if(G.ui_international == TRUE)
162                 if(translate && (U.transopts & USER_TR_BUTTONS))
163                         rt= FTF_GetStringWidth(str, FTF_USE_GETTEXT | FTF_INPUT_UTF8);
164                 else
165                         rt= FTF_GetStringWidth(str, FTF_NO_TRANSCONV | FTF_INPUT_UTF8);
166         else
167                 rt= BMF_GetStringWidth(font, str);
168 #else
169         rt= BMF_GetStringWidth(font, str);
170 #endif
171
172         return rt;
173 }
174
175 void BIF_GetBoundingBox(struct BMF_Font* font, char* str, int translate, rctf *bbox){
176         float dummy;
177 #ifdef INTERNATIONAL
178         if(G.ui_international == TRUE)
179                 if(translate && (U.transopts & USER_TR_BUTTONS))
180                         FTF_GetBoundingBox(str, &bbox->xmin, &bbox->ymin, &dummy, &bbox->xmax, &bbox->ymax, &dummy, FTF_USE_GETTEXT | FTF_INPUT_UTF8);
181                 else
182                         FTF_GetBoundingBox(str, &bbox->xmin, &bbox->ymin, &dummy, &bbox->xmax, &bbox->ymax, &dummy, FTF_NO_TRANSCONV | FTF_INPUT_UTF8);
183         else
184                 BMF_GetStringBoundingBox(font, str, &bbox->xmin, &bbox->ymin, &bbox->xmax, &bbox->ymax);
185 #else
186         BMF_GetStringBoundingBox(font, str, &bbox->xmin, &bbox->ymin, &bbox->xmax, &bbox->ymax);
187 #endif
188 }
189
190
191 #ifdef INTERNATIONAL
192
193 char *fontsize_pup(void)
194 {
195         static char string[1024];
196         char formatstring[1024];
197
198         strcpy(formatstring, "Choose Font Size: %%t|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d");
199
200         sprintf(string, formatstring,
201                         "Font Size:   8",               8,
202                         "Font Size:   9",               9,
203                         "Font Size:  10",               10,
204                         "Font Size:  11",               11,
205                         "Font Size:  12",               12,
206                         "Font Size:  13",               13,
207                         "Font Size:  14",               14,
208                         "Font Size:  15",               15,
209                         "Font Size:  16",               16
210                );
211
212         return (string);
213 }
214
215
216 char *language_pup(void)
217 {
218         struct LANGMenuEntry *lme = langmenu;
219         static char string[1024];
220         static char tmp[1024];
221
222         if(tot_lang == 0)
223                 sprintf(string, "Choose Language: %%t|Language:  English %%x0");
224         else {
225                 sprintf(string, "Choose Language: %%t");
226                 while(lme) {
227                         sprintf(tmp, "|Language:  %s %%x%d", lme->language, lme->id);
228                         strcat(string, tmp);
229                         lme= lme->next;
230                 }
231         }
232
233         return string;
234 }
235
236
237 struct LANGMenuEntry *find_language(short langid)
238 {
239         struct LANGMenuEntry *lme = langmenu;
240
241         while(lme) {
242                 if(lme->id == langid)
243                         return lme;
244
245                 lme=lme->next;
246         }
247         return NULL;
248 }
249
250
251 void lang_setlanguage(void) 
252 {
253         struct LANGMenuEntry *lme;
254
255         lme = find_language(U.language);
256         if(lme) FTF_SetLanguage(lme->code);
257         else FTF_SetLanguage("en_US");
258 }
259
260 /* called from fileselector */
261 void set_interface_font(char *str) 
262 {
263
264         /* this test needed because fileselect callback can happen after disable AA fonts */
265         if(U.transopts & USER_DOTRANSLATE) {
266                 if(FTF_SetFont((unsigned char*)str, 0, U.fontsize)) {
267                         lang_setlanguage();
268                         
269                         if(strlen(str) < FILE_MAXDIR) strcpy(U.fontname, str);
270                         G.ui_international = TRUE;
271                 } 
272                 else {
273                         U.fontname[0]= 0;
274                         FTF_SetFont((unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size, U.fontsize);
275                         G.ui_international = TRUE;      // this case will switch to standard font
276                         okee("Invalid font selection - reverting to built-in font.");
277                 }
278                 allqueue(REDRAWALL, 0);
279         }
280 }
281
282
283 void start_interface_font(void) 
284 {
285         int result = 0;
286
287         if(U.transopts & USER_USETEXTUREFONT)
288                 FTF_SetMode(FTF_TEXTUREFONT);
289         else
290                 FTF_SetMode(FTF_PIXMAPFONT);
291         
292         if(U.fontsize && U.fontname[0] ) { // we have saved user settings + fontpath
293                 
294                 // try loading font from U.fontname = full path to font in usersettings
295                 result = FTF_SetFont((unsigned char*)U.fontname, 0, U.fontsize);
296         }
297         else if(U.fontsize) {   // user settings, default
298                 result = FTF_SetFont((unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size, U.fontsize);
299         }
300         
301         if(result==0) {         // use default
302                 U.language= 0;
303                 U.fontsize= 11;
304                 U.encoding= 0;
305                 U.fontname[0]= 0;
306                 result = FTF_SetFont((unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size, U.fontsize);
307         }
308
309         if(result) {
310                 
311                 lang_setlanguage();
312
313                 G.ui_international = TRUE;
314         } 
315         else {
316                 printf("no font found for international support\n");
317                 G.ui_international = FALSE;
318                 U.transopts &= ~USER_DOTRANSLATE;
319                 U.fontsize = 0;
320         }
321
322         allqueue(REDRAWALL, 0);
323 }
324
325
326 static char *first_dpointchar(char *string) 
327 {
328         char *dpointchar;
329         
330         dpointchar= strchr(string, ':');        
331
332         return dpointchar;
333 }
334
335
336 static void splitlangline(char *line, struct LANGMenuEntry *lme)
337 {
338         char *dpointchar= first_dpointchar(line);
339
340         if (dpointchar) {
341                 lme->code= BLI_strdup(dpointchar+1);
342                 *(dpointchar)=0;
343                 lme->language= BLI_strdup(line);
344         } else {
345                 error("Invalid language file");
346         }
347 }
348
349
350 static void puplang_insert_entry(char *line)
351 {
352         struct LANGMenuEntry *lme, *prev;
353         int sorted = 0;
354
355         prev= NULL;
356         lme= langmenu;
357
358         for (; lme; prev= lme, lme= lme->next) {
359                 if (lme->line) {
360                         if (BLI_streq(line, lme->line)) {
361                                 return;
362                         } else if (sorted && strcmp(line, lme->line)<0) {
363                                 break;
364                         }
365                 }
366         }
367         
368         lme= MEM_mallocN(sizeof(*lme), "lme");
369         lme->line = BLI_strdup(line);
370         splitlangline(line, lme);
371         lme->id = tot_lang;
372         tot_lang++;
373
374         if (prev) {
375                 lme->next= prev->next;
376                 prev->next= lme;
377         } else {
378                 lme->next= langmenu;
379                 langmenu= lme;
380         }
381 }
382
383
384 int read_languagefile(void) 
385 {
386         char name[FILE_MAXDIR+FILE_MAXFILE];
387         LinkNode *l, *lines;
388         
389         /* .Blanguages, http://www.blender3d.org/cms/Installation_Policy.352.0.html*/
390 #if defined (__APPLE__) || (WIN32)
391         BLI_make_file_string("/", name, BLI_gethome(), ".Blanguages");
392 #else
393         BLI_make_file_string("/", name, BLI_gethome(), ".blender/.Blanguages");
394 #endif
395
396         lines= BLI_read_file_as_lines(name);
397
398         if(lines == NULL) {
399                 /* If not found in home, try current dir 
400                  * (Resources folder of app bundle on OS X) */
401 #if defined (__APPLE__)
402                 char *bundlePath = BLI_getbundle();
403                 strcpy(name, bundlePath);
404                 strcat(name, "/Contents/Resources/.Blanguages");
405 #else
406                 /* Check the CWD. Takes care of the case where users
407                  * unpack blender tarball; cd blender-dir; ./blender */
408                 strcpy(name, ".blender/.Blanguages");
409 #endif
410                 lines= BLI_read_file_as_lines(name);
411
412                 if(lines == NULL) {
413                         /* If not found in .blender, try current dir */
414                         strcpy(name, ".Blanguages");
415                         lines= BLI_read_file_as_lines(name);
416                         if(lines == NULL) {
417                                 if(G.f & G_DEBUG) printf("File .Blanguages not found\n");
418                                 return 0;
419                         }
420                 }
421         }
422
423         for (l= lines; l; l= l->next) {
424                 char *line= l->link;
425                         
426                 if (!BLI_streq(line, "")) {
427                         puplang_insert_entry(line);
428                 }
429         }
430
431         BLI_free_file_lines(lines);
432
433         return 1;
434 }
435
436
437 void free_languagemenu(void)
438 {
439         struct LANGMenuEntry *lme= langmenu;
440
441         while (lme) {
442                 struct LANGMenuEntry *n= lme->next;
443
444                 if (lme->line) MEM_freeN(lme->line);
445                 if (lme->language) MEM_freeN(lme->language);
446                 if (lme->code) MEM_freeN(lme->code);
447                 MEM_freeN(lme);
448
449                 lme= n;
450         }
451 }
452
453 #endif /* INTERNATIONAL */