99cf13d46f826d500f3efc6210f4dcc2b7217484
[blender.git] / source / blender / src / editfont.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 Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <string.h>
34 #include <fcntl.h>
35
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #ifndef WIN32 
41 #include <unistd.h>
42 #else
43 #include <io.h>
44 #endif
45
46 #include "MTC_matrixops.h"
47
48 #include "MEM_guardedalloc.h"
49
50 #include "BLI_blenlib.h"
51 #include "BLI_arithb.h"
52
53 #include "DNA_curve_types.h"
54 #include "DNA_object_types.h"
55 #include "DNA_vfont_types.h"
56 #include "DNA_scene_types.h"
57 #include "DNA_text_types.h"
58 #include "DNA_view3d_types.h"
59
60 #include "BKE_displist.h"
61 #include "BKE_font.h"
62 #include "BKE_object.h"
63 #include "BKE_global.h"
64 #include "BKE_main.h"
65 #include "BKE_utildefines.h"
66
67 #include "BIF_editfont.h"
68 #include "BIF_editmode_undo.h"
69 #include "BIF_toolbox.h"
70 #include "BIF_space.h"
71 #include "BIF_mywindow.h"
72
73 #include "BDR_editobject.h"
74
75 #include "mydevice.h"
76
77 #include "blendef.h"
78
79 #define MAXTEXT 1000
80
81 int textediting=0;
82
83 static char findaccent(char char1, char code)
84 {
85         char new= 0;
86         
87         if(char1=='a') {
88                 if(code=='`') new= 224;
89                 else if(code==39) new= 225;
90                 else if(code=='^') new= 226;
91                 else if(code=='~') new= 227;
92                 else if(code=='"') new= 228;
93                 else if(code=='o') new= 229;
94                 else if(code=='e') new= 230;
95                 else if(code=='-') new= 170;
96         }
97         else if(char1=='c') {
98                 if(code==',') new= 231;
99                 if(code=='|') new= 162;
100         }
101         else if(char1=='e') {
102                 if(code=='`') new= 232;
103                 else if(code==39) new= 233;
104                 else if(code=='^') new= 234;
105                 else if(code=='"') new= 235;
106         }
107         else if(char1=='i') {
108                 if(code=='`') new= 236;
109                 else if(code==39) new= 237;
110                 else if(code=='^') new= 238;
111                 else if(code=='"') new= 239;
112         }
113         else if(char1=='n') {
114                 if(code=='~') new= 241;
115         }
116         else if(char1=='o') {
117                 if(code=='`') new= 242;
118                 else if(code==39) new= 243;
119                 else if(code=='^') new= 244;
120                 else if(code=='~') new= 245;
121                 else if(code=='"') new= 246;
122                 else if(code=='/') new= 248;
123                 else if(code=='-') new= 186;
124                 else if(code=='e') new= 143;
125         }
126         else if(char1=='s') {
127                 if(code=='s') new= 167;
128         }
129         else if(char1=='u') {
130                 if(code=='`') new= 249;
131                 else if(code==39) new= 250;
132                 else if(code=='^') new= 251;
133                 else if(code=='"') new= 252;
134         }
135         else if(char1=='y') {
136                 if(code==39) new= 253;
137                 else if(code=='"') new= 255;
138         }
139         else if(char1=='A') {
140                 if(code=='`') new= 192;
141                 else if(code==39) new= 193;
142                 else if(code=='^') new= 194;
143                 else if(code=='~') new= 195;
144                 else if(code=='"') new= 196;
145                 else if(code=='o') new= 197;
146                 else if(code=='e') new= 198;
147         }
148         else if(char1=='C') {
149                 if(code==',') new= 199;
150         }
151         else if(char1=='E') {
152                 if(code=='`') new= 200;
153                 else if(code==39) new= 201;
154                 else if(code=='^') new= 202;
155                 else if(code=='"') new= 203;
156         }
157         else if(char1=='I') {
158                 if(code=='`') new= 204;
159                 else if(code==39) new= 205;
160                 else if(code=='^') new= 206;
161                 else if(code=='"') new= 207;
162         }
163         else if(char1=='N') {
164                 if(code=='~') new= 209;
165         }
166         else if(char1=='O') {
167                 if(code=='`') new= 210;
168                 else if(code==39) new= 211;
169                 else if(code=='^') new= 212;
170                 else if(code=='~') new= 213;
171                 else if(code=='"') new= 214;
172                 else if(code=='/') new= 216;
173                 else if(code=='e') new= 141;
174         }
175         else if(char1=='U') {
176                 if(code=='`') new= 217;
177                 else if(code==39) new= 218;
178                 else if(code=='^') new= 219;
179                 else if(code=='"') new= 220;
180         }
181         else if(char1=='Y') {
182                 if(code==39) new= 221;
183         }
184         else if(char1=='1') {
185                 if(code=='4') new= 188;
186                 if(code=='2') new= 189;
187         }
188         else if(char1=='3') {
189                 if(code=='4') new= 190;
190         }
191         else if(char1==':') {
192                 if(code=='-') new= 247;
193         }
194         else if(char1=='-') {
195                 if(code==':') new= 247;
196                 if(code=='|') new= 135;
197                 if(code=='+') new= 177;
198         }
199         else if(char1=='|') {
200                 if(code=='-') new= 135;
201                 if(code=='=') new= 136;
202         }
203         else if(char1=='=') {
204                 if(code=='|') new= 136;
205         }
206         else if(char1=='+') {
207                 if(code=='-') new= 177;
208         }
209         
210         if(new) return new;
211         else return char1;
212 }
213
214
215 static char *textbuf=NULL;
216 static char *oldstr=NULL;
217
218 static int insert_into_textbuf(Curve *cu, char c)
219 {
220         if (cu->len<MAXTEXT-1) {
221                 int x;
222
223                 for(x= cu->len; x>cu->pos; x--) textbuf[x]= textbuf[x-1];
224                 textbuf[cu->pos]= c;
225                                         
226                 cu->pos++;
227                 cu->len++;
228                 textbuf[cu->len]='\0';
229
230                 return 1;
231         } else {
232                 return 0;
233         }
234 }
235
236
237 static VFont *get_builtin_font(void)
238 {
239         VFont *vf;
240         
241         for (vf= G.main->vfont.first; vf; vf= vf->id.next)
242                 if (BLI_streq(vf->name, "<builtin>"))
243                         return vf;
244         
245         return load_vfont("<builtin>");
246 }
247
248
249 void txt_export_to_object(struct Text *text)
250 {
251         ID *id;
252         Curve *cu;
253         struct TextLine *tmp;
254         int nchars = 0;
255 //      char sdir[FILE_MAXDIR];
256 //      char sfile[FILE_MAXFILE];
257
258         if(!text) return;
259
260         id = (ID *)text;
261
262         if (G.obedit && G.obedit->type==OB_FONT) return;
263         check_editmode(OB_FONT);
264         
265         add_object(OB_FONT);
266
267         base_init_from_view3d(BASACT, G.vd);
268         G.obedit= BASACT->object;
269         where_is_object(G.obedit);
270
271         cu= G.obedit->data;
272
273 /*      
274 //              renames object, careful with long filenames.
275
276         if (text->name) {
277         //ID *find_id(char *type, char *name)   
278                 BLI_split_dirfile(text->name, sdir, sfile);
279 //              rename_id((ID *)G.obedit, sfile);
280                 rename_id((ID *)cu, sfile);
281                 id->us++;
282         }
283 */      
284         cu->vfont= get_builtin_font();
285         cu->vfont->id.us++;
286
287         tmp= text->lines.first;
288         while(cu->len<MAXTEXT && tmp) {
289                 nchars += strlen(tmp->line) + 1;
290                 tmp = tmp->next;
291         }
292
293         if(cu->str) MEM_freeN(cu->str);
294
295         cu->str= MEM_mallocN(nchars+4, "str");
296         
297         tmp= text->lines.first;
298         strcpy(cu->str, tmp->line);
299         cu->len= strlen(tmp->line);
300         cu->pos= cu->len;
301
302         tmp= tmp->next;
303
304         while(cu->len<MAXTEXT && tmp) {
305                 strcat(cu->str, "\n");
306                 strcat(cu->str, tmp->line);
307                 cu->len+= strlen(tmp->line) + 1;
308                 cu->pos= cu->len;
309                 tmp= tmp->next;
310         }
311
312         make_editText();
313         exit_editmode(1);
314
315         allqueue(REDRAWVIEW3D, 0);
316 }
317
318
319 void txt_export_to_objects(struct Text *text)
320 {
321         ID *id;
322         Curve *cu;
323         struct TextLine *curline;
324         int nchars;
325         int linenum = 0;
326         float offset[3] = {0.0,0.0,0.0};
327
328         if(!text) return;
329
330         id = (ID *)text;
331
332         if (G.obedit && G.obedit->type==OB_FONT) return;
333         check_editmode(OB_FONT);
334
335         curline = text->lines.first;
336         while(curline){ 
337                 /*skip lines with no text, but still make space for them*/
338                 if(curline->line[0] == '\0'){
339                         linenum++;
340                         curline = curline->next;
341                         continue;
342                 }
343                         
344                 nchars = 0;     
345                 add_object(OB_FONT);
346         
347                 base_init_from_view3d(BASACT, G.vd);
348                 G.obedit= BASACT->object;
349                 where_is_object(G.obedit);      
350                 
351                 /* Do the translation */
352                 offset[0] = 0;
353                 offset[1] = -linenum;
354                 offset[2] = 0;
355         
356                 Mat4Mul3Vecfl(G.vd->viewinv,offset);
357                 
358                 G.obedit->loc[0] += offset[0];
359                 G.obedit->loc[1] += offset[1];
360                 G.obedit->loc[2] += offset[2];
361                 /* End Translation */
362                                         
363                 cu= G.obedit->data;
364                 
365                 cu->vfont= get_builtin_font();
366                 cu->vfont->id.us++;
367         
368                 nchars = strlen(curline->line) + 1;
369         
370                 if(cu->str) MEM_freeN(cu->str);
371         
372                 cu->str= MEM_mallocN(nchars+4, "str");
373                 
374                 strcpy(cu->str, curline->line);
375                 cu->len= strlen(curline->line);
376                 cu->pos= cu->len;
377
378                 make_editText();
379                 exit_editmode(1);
380
381                 linenum++;
382                 curline = curline->next;
383         }
384         BIF_undo_push("Add Text as Objects");
385         allqueue(REDRAWVIEW3D, 0);
386 }
387
388
389 void do_textedit(unsigned short event, short val, char _ascii)
390 {
391         Curve *cu;
392         static int accentcode= 0;
393         int x, doit=0, cursmove=0;
394         int ascii = _ascii;
395
396         cu= G.obedit->data;
397
398         if(ascii) {
399         
400                 /* handle case like TAB (TAB==9) */
401                 if( (ascii > 31 && ascii < 254 && ascii != 127) || (ascii==13) || (ascii==10) || (ascii==8)) {
402         
403                         if(accentcode) {
404                                 if(cu->pos>0) textbuf[cu->pos-1]= findaccent(textbuf[cu->pos-1], ascii);
405                                 accentcode= 0;
406                         }
407                         else if(cu->len<MAXTEXT-1) {
408                                 if(G.qual & LR_ALTKEY ) {
409                                 
410                                         /* might become obsolete, apple has default values for this, other OS's too? */
411                                 
412                                         if(ascii=='t') ascii= 137;
413                                         else if(ascii=='c') ascii= 169;
414                                         else if(ascii=='f') ascii= 164;
415                                         else if(ascii=='g') ascii= 176;
416                                         else if(ascii=='l') ascii= 163;
417                                         else if(ascii=='r') ascii= 174;
418                                         else if(ascii=='s') ascii= 223;
419                                         else if(ascii=='v') ascii= 1001;
420                                         else if(ascii=='y') ascii= 165;
421                                         else if(ascii=='.') ascii= 138;
422                                         else if(ascii=='1') ascii= 185;
423                                         else if(ascii=='2') ascii= 178;
424                                         else if(ascii=='3') ascii= 179;
425                                         else if(ascii=='%') ascii= 139;
426                                         else if(ascii=='?') ascii= 191;
427                                         else if(ascii=='!') ascii= 161;
428                                         else if(ascii=='x') ascii= 215;
429                                         else if(ascii=='>') ascii= 187;
430                                         else if(ascii=='<') ascii= 171;
431                                 }
432                                 
433                                 if(ascii==1001) {
434                                         int file, filelen;
435                                         char *strp;
436                                         
437 /* this should be solved by clipboard support */
438 #ifdef __WIN32_DISABLED 
439                                         file= open("C:\\windows\\temp\\cutbuf", O_BINARY|O_RDONLY);
440 #else
441                                         file= open("/tmp/.cutbuffer", O_BINARY|O_RDONLY);
442 #endif
443                                         if(file>0) {
444                                         
445                                                 filelen = BLI_filesize(file);
446                                         
447                                                 strp= MEM_mallocN(filelen+4, "tempstr");
448                                                 read(file, strp, filelen);
449                                                 close(file);
450                                                 strp[filelen]= 0;
451                                                 if(cu->len+filelen<MAXTEXT) {
452                                                         strcat( textbuf, strp);
453                                                         cu->len= strlen(textbuf);
454                                                         cu->pos= cu->len;
455                                                 }
456                                                 MEM_freeN(strp);
457                                         }
458                                 }
459                                 else {
460                                         insert_into_textbuf(cu, ascii);
461                                 }
462                         }
463                         
464                         doit= 1;
465                 }
466         }
467         else if(val) {
468                 cursmove= 0;
469                 
470                 switch(event) {
471                 case RETKEY:
472                         insert_into_textbuf(cu, '\n');
473                         doit= 1;
474                         break;
475
476                 case RIGHTARROWKEY:     
477                         if(G.qual & LR_SHIFTKEY) {
478                                 while(cu->pos<cu->len) {
479                                         if( textbuf[cu->pos]==0) break;
480                                         if( textbuf[cu->pos]=='\n') break;
481                                         cu->pos++;
482                                 }
483                         }
484                         else {
485                                 cu->pos++;
486                         }
487                         cursmove= FO_CURS;
488                         break;
489                         
490                 case LEFTARROWKEY:
491                         
492                         if(G.qual & LR_SHIFTKEY) {
493                                 while(cu->pos>0) {
494                                         if( textbuf[cu->pos-1]=='\n') break;
495                                         cu->pos--;
496                                 }
497                         }
498                         else {
499                                 cu->pos--;
500                         }
501                         cursmove=FO_CURS;
502                         break;
503
504                 case UPARROWKEY:
505                         if(G.qual & LR_SHIFTKEY) {
506                                 cu->pos= 0;
507                                 cursmove= FO_CURS;
508                         }
509                         else if(G.qual & LR_ALTKEY) {
510                                 if (cu->pos && textbuf[cu->pos - 1] < 255) {
511                                         textbuf[cu->pos - 1]++;
512                                         doit= 1;
513                                 }
514                         }
515                         else cursmove=FO_CURSUP;
516                         break;
517                         
518                 case DOWNARROWKEY:
519                         if(G.qual & LR_SHIFTKEY) {
520                                 cu->pos= cu->len;
521                                 cursmove= FO_CURS;
522                         }
523                         else if(G.qual & LR_ALTKEY) {
524                                 if (cu->pos && textbuf[cu->pos - 1] > 1) {
525                                         textbuf[cu->pos - 1]--;
526                                         doit= 1;
527                                 }
528                         }
529                         else cursmove= FO_CURSDOWN;
530                         break;
531                         
532                 case BACKSPACEKEY:
533                         if(cu->len!=0) {
534                                 if(G.qual & LR_ALTKEY) {
535                                         if(cu->pos>0) accentcode= 1;
536                                 }
537                                 else if(G.qual & LR_SHIFTKEY) {
538                                         cu->pos= 0;
539                                         textbuf[0]= 0;
540                                         cu->len= 0;
541                                 }
542                                 else if(cu->pos>0) {
543                                         for(x=cu->pos;x<=cu->len;x++) textbuf[x-1]= textbuf[x];
544                                         cu->pos--;
545                                         textbuf[--cu->len]='\0';
546                                 }
547                         }
548                         doit= 1;
549                         break;
550
551                 case DELKEY:
552                         if(cu->len!=0) {
553                                 if(cu->pos<cu->len) {
554                                         for(x=cu->pos;x<cu->len;x++) textbuf[x]= textbuf[x+1];
555                                         textbuf[--cu->len]='\0';
556                                 }
557                         }
558                         doit= 1;
559                         break;
560                 }
561                         
562                 if(cursmove) {
563                         if(cu->pos>cu->len) cu->pos= cu->len;
564                         else if(cu->pos>=MAXTEXT) cu->pos= MAXTEXT;
565                         else if(cu->pos<0) cu->pos= 0;
566                 }
567         }
568         if(doit || cursmove) {
569                 text_to_curve(G.obedit, cursmove);
570                 if(cursmove==0) makeDispList(G.obedit);
571                 BIF_undo_push("Textedit");
572                 allqueue(REDRAWVIEW3D, 0);
573         }
574 }
575
576
577 void paste_editText(void)
578 {
579         Curve *cu;
580         int file, filelen, doit= 0;
581         char *strp;
582
583
584 #ifdef WIN32
585         file= open("C:\\windows\\temp\\cutbuf.txt", O_BINARY|O_RDONLY);
586
587 //      The following is more likely to work on all Win32 installations.
588 //      suggested by Douglas Toltzman. Needs windows include files...
589 /*
590         char tempFileName[MAX_PATH];
591         DWORD pathlen;
592         static const char cutbufname[]="cutbuf.txt";
593
594         if ((pathlen=GetTempPath(sizeof(tempFileName),tempFileName)) > 0 &&
595                 pathlen + sizeof(cutbufname) <= sizeof(tempFileName))
596         {
597                 strcat(tempFileName,cutbufname);
598                 file= open(tempFileName, O_BINARY|O_RDONLY);
599         }
600 */
601 #else
602         file= open("/tmp/.cutbuffer", O_BINARY|O_RDONLY);
603 #endif
604
605         if(file>0) {
606                 cu= G.obedit->data;
607                 filelen = BLI_filesize(file);
608                                 
609                 strp= MEM_mallocN(filelen+4, "tempstr");
610                 read(file, strp, filelen);
611                 close(file);
612                 strp[filelen]= 0;
613                 if(cu->len+filelen<MAXTEXT) {
614                         strcat( textbuf, strp);
615                         cu->len= strlen(textbuf);
616                         cu->pos= cu->len;
617                 }
618                 MEM_freeN(strp);
619                 doit = 1;
620         }
621         if(doit) {
622                 text_to_curve(G.obedit, 0);
623                 makeDispList(G.obedit);
624                 allqueue(REDRAWVIEW3D, 0);
625                 BIF_undo_push("Paste text");
626         }
627 }
628
629
630 void make_editText(void)
631 {
632         Curve *cu;
633
634         cu= G.obedit->data;
635         if(textbuf==NULL) textbuf= MEM_mallocN(MAXTEXT+4, "texteditbuf");
636         BLI_strncpy(textbuf, cu->str, MAXTEXT);
637         oldstr= cu->str;
638         cu->str= textbuf;
639
640         cu->len= strlen(textbuf);
641         if(cu->pos>cu->len) cu->pos= cu->len;
642         
643         text_to_curve(G.obedit, 0);
644         makeDispList(G.obedit);
645         
646         textediting= 1;
647         BIF_undo_push("Original");
648 }
649
650
651 void load_editText(void)
652 {
653         Curve *cu;
654         
655         cu= G.obedit->data;
656
657         MEM_freeN(oldstr);
658         oldstr= NULL;
659         
660         cu->str= MEM_mallocN(cu->len+4, "tekstedit");
661         strcpy(cu->str, textbuf);
662         
663         /* this memory system is weak... */
664         MEM_freeN(textbuf);
665         textbuf= NULL;
666         
667         cu->len= strlen(cu->str);
668         textediting= 0;
669 }
670
671
672 void remake_editText(void)
673 {
674         Curve *cu;
675                 
676         if(okee("Reload original text")==0) return;
677         
678         BLI_strncpy(textbuf, oldstr, MAXTEXT);
679         cu= G.obedit->data;
680         cu->len= strlen(textbuf);
681         if(cu->pos>cu->len) cu->pos= cu->len;
682         
683         text_to_curve(G.obedit, 0);
684         makeDispList(G.obedit);
685         
686         allqueue(REDRAWVIEW3D, 0);
687         BIF_undo_push("Reload");
688 }
689
690
691 void free_editText(void)
692 {
693         if(oldstr) MEM_freeN(oldstr);
694         textbuf= oldstr= NULL;
695         textediting= 0;
696 }
697
698
699 void add_primitiveFont(int dummy_argument)
700 {
701         Curve *cu;
702
703         if (G.obedit && G.obedit->type==OB_FONT) return;
704         check_editmode(OB_FONT);
705         
706         add_object_draw(OB_FONT);
707         base_init_from_view3d(BASACT, G.vd);
708         G.obedit= BASACT->object;
709         where_is_object(G.obedit);
710         
711         cu= G.obedit->data;
712         
713         cu->vfont= get_builtin_font();
714         cu->vfont->id.us++;
715         cu->str= MEM_mallocN(12, "str");
716         strcpy(cu->str, "Text");
717         cu->pos= 4;
718         
719         make_editText();
720
721         allqueue(REDRAWALL, 0);
722 }
723
724 void to_upper(void)
725 {
726         Curve *cu;
727         int len, ok;
728         char *str;
729         
730         if(G.obedit==0) {
731                 return;
732         }
733         
734         ok= 0;
735         cu= G.obedit->data;
736         
737         len= strlen(cu->str);
738         str= cu->str;
739         while(len) {
740                 if( *str>=97 && *str<=122) {
741                         ok= 1;
742                         *str-= 32;
743                 }
744                 len--;
745                 str++;
746         }
747         
748         if(ok==0) {
749                 len= strlen(cu->str);
750                 str= cu->str;
751                 while(len) {
752                         if( *str>=65 && *str<=90) {
753                                 *str+= 32;
754                         }
755                         len--;
756                         str++;
757                 }
758         }
759         text_to_curve(G.obedit, 0);
760         makeDispList(G.obedit);
761
762         allqueue(REDRAWVIEW3D, 0);
763         BIF_undo_push("To upper");
764 }
765
766
767 /* **************** undo for font object ************** */
768
769 static void undoFont_to_editFont(void *strv)
770 {
771         Curve *cu= G.obedit->data;
772         char *str= strv;
773         
774         strncpy(textbuf, str+2, MAXTEXT);
775         cu->pos= *((short *)str);
776         cu->len= strlen(textbuf);
777         text_to_curve(G.obedit, 0);
778         makeDispList(G.obedit);
779         
780         allqueue(REDRAWVIEW3D, 0);
781 }
782
783 static void *editFont_to_undoFont(void)
784 {
785         Curve *cu= G.obedit->data;
786         char *str;
787         
788         str= MEM_callocN(MAXTEXT+4, "string undo");
789         
790         strncpy(str+2, textbuf, MAXTEXT);
791         *((short *)str)= cu->pos;
792         
793         return str;
794 }
795
796 static void free_undoFont(void *strv)
797 {
798         MEM_freeN(strv);
799 }
800
801 /* and this is all the undo system needs to know */
802 void undo_push_font(char *name)
803 {
804         undo_editmode_push(name, free_undoFont, undoFont_to_editFont, editFont_to_undoFont);
805 }
806
807
808
809 /***/