=== Custom Transform Orientation ===
[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 <stdlib.h>
34 #include <string.h>
35 #include <fcntl.h>
36 #include <wchar.h>
37
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #ifndef WIN32 
43 #include <unistd.h>
44 #else
45 #include <io.h>
46 #endif
47
48 #include "MTC_matrixops.h"
49
50 #include "MEM_guardedalloc.h"
51
52 #include "BLI_blenlib.h"
53 #include "BLI_arithb.h"
54
55 #include "DNA_curve_types.h"
56 #include "DNA_object_types.h"
57 #include "DNA_vfont_types.h"
58 #include "DNA_scene_types.h"
59 #include "DNA_text_types.h"
60 #include "DNA_view3d_types.h"
61 #include "DNA_userdef_types.h"
62
63 #include "BKE_depsgraph.h"
64 #include "BKE_font.h"
65 #include "BKE_object.h"
66 #include "BKE_global.h"
67 #include "BKE_main.h"
68 #include "BKE_utildefines.h"
69
70 #include "BIF_editfont.h"
71 #include "BIF_editmode_undo.h"
72 #include "BIF_toolbox.h"
73 #include "BIF_space.h"
74 #include "BIF_mywindow.h"
75
76 #include "BDR_editobject.h"
77
78 #include "mydevice.h"
79
80 #include "blendef.h"
81
82 #define MAXTEXT 32766
83
84 /* -- prototypes --------*/
85 VFont *get_builtin_font(void);
86
87 int textediting=0;
88
89 extern struct SelBox *selboxes;         /* from blenkernel/font.c */
90
91 static char findaccent(char char1, unsigned int code)
92 {
93         char new= 0;
94         
95         if(char1=='a') {
96                 if(code=='`') new= 224;
97                 else if(code==39) new= 225;
98                 else if(code=='^') new= 226;
99                 else if(code=='~') new= 227;
100                 else if(code=='"') new= 228;
101                 else if(code=='o') new= 229;
102                 else if(code=='e') new= 230;
103                 else if(code=='-') new= 170;
104         }
105         else if(char1=='c') {
106                 if(code==',') new= 231;
107                 if(code=='|') new= 162;
108         }
109         else if(char1=='e') {
110                 if(code=='`') new= 232;
111                 else if(code==39) new= 233;
112                 else if(code=='^') new= 234;
113                 else if(code=='"') new= 235;
114         }
115         else if(char1=='i') {
116                 if(code=='`') new= 236;
117                 else if(code==39) new= 237;
118                 else if(code=='^') new= 238;
119                 else if(code=='"') new= 239;
120         }
121         else if(char1=='n') {
122                 if(code=='~') new= 241;
123         }
124         else if(char1=='o') {
125                 if(code=='`') new= 242;
126                 else if(code==39) new= 243;
127                 else if(code=='^') new= 244;
128                 else if(code=='~') new= 245;
129                 else if(code=='"') new= 246;
130                 else if(code=='/') new= 248;
131                 else if(code=='-') new= 186;
132                 else if(code=='e') new= 143;
133         }
134         else if(char1=='s') {
135                 if(code=='s') new= 167;
136         }
137         else if(char1=='u') {
138                 if(code=='`') new= 249;
139                 else if(code==39) new= 250;
140                 else if(code=='^') new= 251;
141                 else if(code=='"') new= 252;
142         }
143         else if(char1=='y') {
144                 if(code==39) new= 253;
145                 else if(code=='"') new= 255;
146         }
147         else if(char1=='A') {
148                 if(code=='`') new= 192;
149                 else if(code==39) new= 193;
150                 else if(code=='^') new= 194;
151                 else if(code=='~') new= 195;
152                 else if(code=='"') new= 196;
153                 else if(code=='o') new= 197;
154                 else if(code=='e') new= 198;
155         }
156         else if(char1=='C') {
157                 if(code==',') new= 199;
158         }
159         else if(char1=='E') {
160                 if(code=='`') new= 200;
161                 else if(code==39) new= 201;
162                 else if(code=='^') new= 202;
163                 else if(code=='"') new= 203;
164         }
165         else if(char1=='I') {
166                 if(code=='`') new= 204;
167                 else if(code==39) new= 205;
168                 else if(code=='^') new= 206;
169                 else if(code=='"') new= 207;
170         }
171         else if(char1=='N') {
172                 if(code=='~') new= 209;
173         }
174         else if(char1=='O') {
175                 if(code=='`') new= 210;
176                 else if(code==39) new= 211;
177                 else if(code=='^') new= 212;
178                 else if(code=='~') new= 213;
179                 else if(code=='"') new= 214;
180                 else if(code=='/') new= 216;
181                 else if(code=='e') new= 141;
182         }
183         else if(char1=='U') {
184                 if(code=='`') new= 217;
185                 else if(code==39) new= 218;
186                 else if(code=='^') new= 219;
187                 else if(code=='"') new= 220;
188         }
189         else if(char1=='Y') {
190                 if(code==39) new= 221;
191         }
192         else if(char1=='1') {
193                 if(code=='4') new= 188;
194                 if(code=='2') new= 189;
195         }
196         else if(char1=='3') {
197                 if(code=='4') new= 190;
198         }
199         else if(char1==':') {
200                 if(code=='-') new= 247;
201         }
202         else if(char1=='-') {
203                 if(code==':') new= 247;
204                 if(code=='|') new= 135;
205                 if(code=='+') new= 177;
206         }
207         else if(char1=='|') {
208                 if(code=='-') new= 135;
209                 if(code=='=') new= 136;
210         }
211         else if(char1=='=') {
212                 if(code=='|') new= 136;
213         }
214         else if(char1=='+') {
215                 if(code=='-') new= 177;
216         }
217         
218         if(new) return new;
219         else return char1;
220 }
221
222 wchar_t *copybuf=NULL;
223 wchar_t *copybufinfo=NULL;
224
225 static wchar_t *textbuf=NULL;
226 static CharInfo *textbufinfo=NULL;
227 static wchar_t *oldstr=NULL;
228 static CharInfo *oldstrinfo=NULL;
229
230 void update_string(Curve *cu)
231 {
232         int len;
233
234         // Free the old curve string    
235         MEM_freeN(cu->str);
236
237         // Calculate the actual string length in UTF-8 variable characters
238         len = wcsleninu8(textbuf);
239
240         // Alloc memory for UTF-8 variable char length string
241         cu->str = MEM_callocN(len + sizeof(wchar_t), "str");
242
243         // Copy the wchar to UTF-8
244         wcs2utf8s(cu->str, textbuf);
245 }
246
247 static int insert_into_textbuf(Curve *cu, unsigned long c)
248 {
249         if (cu->len<MAXTEXT-1) {
250                 int x;
251
252                 for(x= cu->len; x>cu->pos; x--) textbuf[x]= textbuf[x-1];
253                 for(x= cu->len; x>cu->pos; x--) textbufinfo[x]= textbufinfo[x-1];               
254                 textbuf[cu->pos]= c;
255                 textbufinfo[cu->pos] = cu->curinfo;
256                 textbufinfo[cu->pos].kern = 0;
257                 if (G.obedit->actcol>0)
258                         textbufinfo[cu->pos].mat_nr = G.obedit->actcol;
259                 else
260                         textbufinfo[cu->pos].mat_nr = 0;
261                                         
262                 cu->pos++;
263                 cu->len++;
264                 textbuf[cu->len]='\0';
265
266                 update_string(cu);
267
268                 return 1;
269         } else {
270                 return 0;
271         }
272 }
273
274 void add_lorem(void)
275 {
276         char *p, *p2;
277         int i;
278         Curve *cu=G.obedit->data;
279         static char* lastlorem;
280         
281         if (lastlorem)
282                 p= lastlorem;
283         else
284                 p= BIF_lorem;
285         
286         i= rand()/(RAND_MAX/6)+4;       
287                 
288         for (p2=p; *p2 && i; p2++) {
289                 insert_into_textbuf(cu, *p2);
290                 if (*p2=='.') i--;
291         }
292         lastlorem = p2+1;
293         if (strlen(lastlorem)<5) lastlorem = BIF_lorem;
294         
295         insert_into_textbuf(cu, '\n');
296         insert_into_textbuf(cu, '\n');  
297         DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
298         allqueue(REDRAWVIEW3D, 0);      
299 }
300
301 void load_3dtext_fs(char *file) 
302 {
303         FILE *fp;
304         int filelen;
305         char *strp;
306         Curve *cu=G.obedit->data;
307
308         fp= fopen(file, "r");
309         if (!fp) return;
310
311         fseek(fp, 0L, SEEK_END);
312         filelen = ftell(fp);
313         fseek(fp, 0L, SEEK_SET);        
314
315         strp = MEM_callocN(filelen+4, "tempstr");       
316
317         filelen = fread(strp, 1, filelen, fp);
318         fclose(fp);
319         strp[filelen]= 0;
320         
321         if(cu->len+filelen<MAXTEXT)
322         {
323                 int tmplen;
324                 wchar_t *mem = MEM_callocN((sizeof(wchar_t)*filelen)+(4*sizeof(wchar_t)), "temporary");
325                 tmplen = utf8towchar_(mem, strp);
326                 wcscat(textbuf, mem);
327                 MEM_freeN(mem);
328                 cu->len += tmplen;
329                 cu->pos= cu->len;
330         }
331         MEM_freeN(strp);
332
333         update_string(cu);
334
335         DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
336         allqueue(REDRAWVIEW3D, 0);      
337 }
338
339 VFont *get_builtin_font(void)
340 {
341         VFont *vf;
342         
343         for (vf= G.main->vfont.first; vf; vf= vf->id.next)
344                 if (BLI_streq(vf->name, "<builtin>"))
345                         return vf;
346         
347         return load_vfont("<builtin>");
348 }
349
350
351 void txt_export_to_object(struct Text *text)
352 {
353         ID *id;
354         Curve *cu;
355         struct TextLine *tmp;
356         int nchars = 0;
357 //      char sdir[FILE_MAXDIR];
358 //      char sfile[FILE_MAXFILE];
359
360         if(!text) return;
361
362         id = (ID *)text;
363
364         if (G.obedit && G.obedit->type==OB_FONT) return;
365         check_editmode(OB_FONT);
366         
367         add_object(OB_FONT);
368
369         base_init_from_view3d(BASACT, G.vd);
370         G.obedit= BASACT->object;
371         where_is_object(G.obedit);
372
373         cu= G.obedit->data;
374
375 /*      
376 //              renames object, careful with long filenames.
377
378         if (text->name) {
379         //ID *find_id(char *type, char *name)   
380                 BLI_split_dirfile(text->name, sdir, sfile);
381 //              rename_id((ID *)G.obedit, sfile);
382                 rename_id((ID *)cu, sfile);
383                 id->us++;
384         }
385 */      
386         cu->vfont= get_builtin_font();
387         cu->vfont->id.us++;
388
389         tmp= text->lines.first;
390         while(cu->len<MAXTEXT && tmp) {
391                 nchars += strlen(tmp->line) + 1;
392                 tmp = tmp->next;
393         }
394
395         if(cu->str) MEM_freeN(cu->str);
396         if(cu->strinfo) MEM_freeN(cu->strinfo); 
397
398         cu->str= MEM_mallocN(nchars+4, "str");
399         cu->strinfo= MEM_callocN((nchars+4)*sizeof(CharInfo), "strinfo");
400         cu->totbox= cu->actbox= 1;
401         cu->tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "textbox");
402         cu->tb[0].w = cu->tb[0].h = 0.0;
403         
404         tmp= text->lines.first;
405         strcpy(cu->str, tmp->line);
406         cu->len= strlen(tmp->line);
407         cu->pos= cu->len;
408
409         tmp= tmp->next;
410
411         while(cu->len<MAXTEXT && tmp) {
412                 strcat(cu->str, "\n");
413                 strcat(cu->str, tmp->line);
414                 cu->len+= strlen(tmp->line) + 1;
415                 cu->pos= cu->len;
416                 tmp= tmp->next;
417         }
418
419         make_editText();
420         exit_editmode(EM_FREEDATA|EM_WAITCURSOR);
421
422         allqueue(REDRAWVIEW3D, 0);
423 }
424
425
426 void txt_export_to_objects(struct Text *text)
427 {
428         ID *id;
429         Curve *cu;
430         struct TextLine *curline;
431         int nchars;
432         int linenum = 0;
433         float offset[3] = {0.0,0.0,0.0};
434
435         if(!text) return;
436
437         id = (ID *)text;
438
439         if (G.obedit && G.obedit->type==OB_FONT) return;
440         check_editmode(OB_FONT);
441
442         curline = text->lines.first;
443         while(curline){ 
444                 /*skip lines with no text, but still make space for them*/
445                 if(curline->line[0] == '\0'){
446                         linenum++;
447                         curline = curline->next;
448                         continue;
449                 }
450                         
451                 nchars = 0;     
452                 add_object(OB_FONT);
453         
454                 base_init_from_view3d(BASACT, G.vd);
455                 G.obedit= BASACT->object;
456                 where_is_object(G.obedit);      
457                 
458                 /* Do the translation */
459                 offset[0] = 0;
460                 offset[1] = -linenum;
461                 offset[2] = 0;
462         
463                 Mat4Mul3Vecfl(G.vd->viewinv,offset);
464                 
465                 G.obedit->loc[0] += offset[0];
466                 G.obedit->loc[1] += offset[1];
467                 G.obedit->loc[2] += offset[2];
468                 /* End Translation */
469                                         
470                 cu= G.obedit->data;
471                 
472                 cu->vfont= get_builtin_font();
473                 cu->vfont->id.us++;
474         
475                 nchars = strlen(curline->line) + 1;
476         
477                 if(cu->str) MEM_freeN(cu->str);
478                 if(cu->strinfo) MEM_freeN(cu->strinfo);         
479         
480                 cu->str= MEM_mallocN(nchars+4, "str");
481                 cu->strinfo= MEM_callocN((nchars+4)*sizeof(CharInfo), "strinfo");
482                 cu->totbox= cu->actbox= 1;
483                 cu->tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "textbox");
484                 cu->tb[0].w = cu->tb[0].h = 0.0;
485                 
486                 strcpy(cu->str, curline->line);
487                 cu->len= strlen(curline->line);
488                 cu->pos= cu->len;
489
490                 make_editText();
491                 exit_editmode(EM_FREEDATA|EM_WAITCURSOR);
492
493                 linenum++;
494                 curline = curline->next;
495         }
496         BIF_undo_push("Add Text as Objects");
497         allqueue(REDRAWVIEW3D, 0);
498 }
499
500 static short next_word(Curve *cu)
501 {
502         short s;
503         for (s=cu->pos; (cu->str[s]) && (cu->str[s]!=' ') && (cu->str[s]!='\n') &&
504                         (cu->str[s]!=1) && (cu->str[s]!='\r'); s++);
505         if (cu->str[s]) return(s+1); else return(s);
506 }
507
508 static short prev_word(Curve *cu)
509 {
510         short s;
511         
512         if (cu->pos==0) return(0);
513         for (s=cu->pos-2; (cu->str[s]) && (cu->str[s]!=' ') && (cu->str[s]!='\n') &&
514                         (cu->str[s]!=1) && (cu->str[s]!='\r'); s--);
515         if (cu->str[s]) return(s+1); else return(s);
516 }
517
518
519
520 static int killselection(int ins)       /* 1 == new character */
521 {
522         int selend, selstart, direction;
523         Curve *cu= G.obedit->data;
524         int offset = 0;
525         int getfrom;
526
527         direction = getselection(&selstart, &selend);
528         if (direction) {
529                 int size;
530                 if (ins) offset = 1;
531                 if (cu->pos >= selstart) cu->pos = selstart+offset;
532                 if ((direction == -1) && ins) {
533                         selstart++;
534                         selend++;
535                 }
536                 getfrom = selend+offset;
537                 if (ins==0) getfrom++;
538                 size = (cu->len * sizeof(wchar_t)) - (selstart * sizeof(wchar_t)) + (offset*sizeof(wchar_t));
539                 memmove(textbuf+selstart, textbuf+getfrom, size);
540                 memmove(textbufinfo+selstart, textbufinfo+getfrom, ((cu->len-selstart)+offset)*sizeof(CharInfo));
541                 cu->len -= (selend-selstart)+offset;
542                 cu->selstart = cu->selend = 0;
543         }
544         return(direction);
545 }
546
547 static void copyselection(void)
548 {
549         int selstart, selend;
550         
551         if (getselection(&selstart, &selend)) {
552                 memcpy(copybuf, textbuf+selstart, ((selend-selstart)+1)*sizeof(wchar_t));
553                 copybuf[(selend-selstart)+1]=0;
554                 memcpy(copybufinfo, textbufinfo+selstart, ((selend-selstart)+1)*sizeof(CharInfo));      
555         }
556 }
557
558 static void pasteselection(void)
559 {
560         Curve *cu= G.obedit->data;
561
562         int len= wcslen(copybuf);
563
564         // Verify that the copy buffer => [copy buffer len] + cu->len < MAXTEXT
565         if(cu->len + len <= MAXTEXT)
566         {
567                 if (len) {      
568                         int size = (cu->len * sizeof(wchar_t)) - (cu->pos*sizeof(wchar_t)) + sizeof(wchar_t);
569                         memmove(textbuf+cu->pos+len, textbuf+cu->pos, size);
570                         memcpy(textbuf+cu->pos, copybuf, len * sizeof(wchar_t));
571                 
572                         memmove(textbufinfo+cu->pos+len, textbufinfo+cu->pos, (cu->len-cu->pos+1)*sizeof(CharInfo));
573                         memcpy(textbufinfo+cu->pos, copybufinfo, len*sizeof(CharInfo)); 
574                 
575                         cu->len += len;
576                         cu->pos += len;
577                 }
578         }
579         else
580         {
581                 error("Text too long");
582         }
583 }
584
585 int style_to_sel(int style, int toggle) 
586 {
587         int selstart, selend;
588         int i;
589         Curve *cu;
590         
591         if (G.obedit && (G.obedit->type == OB_FONT)) {
592                 cu= G.obedit->data;
593                 
594                 if (getselection(&selstart, &selend)) {
595                         for (i=selstart; i<=selend; i++) {
596                                 if (toggle==0) {
597                                         textbufinfo[i].flag &= ~style;
598                                 } else {
599                                         textbufinfo[i].flag |= style;
600                                 }
601                         }
602                         return 1;
603                 }
604         }
605         return 0;
606 }
607
608 int mat_to_sel(void) {
609         int selstart, selend;
610         int i;
611         Curve *cu;
612         
613         if (G.obedit && (G.obedit->type == OB_FONT)) {
614                 cu= G.obedit->data;
615                 
616                 if (getselection(&selstart, &selend)) {
617                         for (i=selstart; i<=selend; i++) {
618                                 textbufinfo[i].mat_nr = G.obedit->actcol;
619                         }
620                         return 1;
621                 }
622         }
623         return 0;
624 }
625
626 void do_textedit(unsigned short event, short val, unsigned long _ascii)
627 {
628         Curve *cu;
629         static int accentcode= 0;
630         int x, doit=0, cursmove=0;
631         unsigned long ascii = _ascii;
632         short kern;
633
634         cu= G.obedit->data;
635
636         if(ascii) {
637         
638                 /* handle case like TAB (TAB==9) */
639                 if( (ascii > 31 && ascii < 254 && ascii != 127) || (ascii==13) || (ascii==10) || (ascii==8)) {
640         
641                         if(accentcode) {
642                                 if(cu->pos>0) textbuf[cu->pos-1]= findaccent(textbuf[cu->pos-1], ascii);
643                                 accentcode= 0;
644                         }
645                         else if(cu->len<MAXTEXT-1) {
646                                 if(G.qual & LR_ALTKEY ) {
647                                 
648                                         /* might become obsolete, apple has default values for this, other OS's too? */
649                                 
650                                         if(ascii=='t') ascii= 137;
651                                         else if(ascii=='c') ascii= 169;
652                                         else if(ascii=='f') ascii= 164;
653                                         else if(ascii=='g') ascii= 176;
654                                         else if(ascii=='l') ascii= 163;
655                                         else if(ascii=='r') ascii= 174;
656                                         else if(ascii=='s') ascii= 223;
657                                         else if(ascii=='v') ascii= 1001;
658                                         else if(ascii=='y') ascii= 165;
659                                         else if(ascii=='.') ascii= 138;
660                                         else if(ascii=='1') ascii= 185;
661                                         else if(ascii=='2') ascii= 178;
662                                         else if(ascii=='3') ascii= 179;
663                                         else if(ascii=='%') ascii= 139;
664                                         else if(ascii=='?') ascii= 191;
665                                         else if(ascii=='!') ascii= 161;
666                                         else if(ascii=='x') ascii= 215;
667                                         else if(ascii=='>') ascii= 187;
668                                         else if(ascii=='<') ascii= 171;
669                                 }
670                                 if(ascii==1001) {
671                                         int file, filelen;
672                                         char *strp;
673                                         
674 /* this should be solved by clipboard support */
675 #ifdef __WIN32_DISABLED 
676                                         file= open("C:\\windows\\temp\\cutbuf", O_BINARY|O_RDONLY);
677 #else
678                                         file= open("/tmp/.cutbuffer", O_BINARY|O_RDONLY);
679 #endif
680                                         if(file>0) {
681                                         
682                                                 filelen = BLI_filesize(file);
683                                         
684                                                 strp= MEM_mallocN(filelen+4, "tempstr");
685                                                 read(file, strp, filelen);
686                                                 close(file);
687                                                 strp[filelen]= 0;
688
689                                                 if(cu->len+filelen<MAXTEXT) {
690                                                         int tmplen;
691                                                         wchar_t *mem = MEM_callocN((sizeof(wchar_t)*filelen)+(4*sizeof(wchar_t)), "temporary");
692                                                         tmplen = utf8towchar_(mem, strp);
693                                                         wcscat(textbuf, mem);
694                                                         MEM_freeN(mem);
695                                                         cu->len += tmplen;
696                                                         cu->pos= cu->len;
697                                                 }
698                                                 MEM_freeN(strp);
699                                         }
700                                 }
701                                 else {
702                                         insert_into_textbuf(cu, ascii);
703                                 }
704                         }
705                         
706                         killselection(1);
707                         
708                         doit= 1;
709                 }
710                 else
711                 {
712                         insert_into_textbuf(cu, ascii);
713                         doit = 1;
714                 }
715         }
716         else if(val) {
717                 cursmove= 0;
718                 
719                 switch(event) {
720                 case ENDKEY:
721                         if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;         
722                         while(cu->pos<cu->len) {
723                                 if( textbuf[cu->pos]==0) break;
724                                 if( textbuf[cu->pos]=='\n') break;
725                                 if( textbufinfo[cu->pos].flag & CU_WRAP ) break;
726                                 cu->pos++;
727                         }
728                         cursmove=FO_CURS;
729                         break;
730
731                 case HOMEKEY:
732                         if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
733                         while(cu->pos>0) {
734                                 if( textbuf[cu->pos-1]=='\n') break;
735                                 if( textbufinfo[cu->pos-1].flag & CU_WRAP ) break;                              
736                                 cu->pos--;
737                         }               
738                         cursmove=FO_CURS;
739                         break;
740                         
741                 case RETKEY:
742                         if(G.qual & LR_CTRLKEY) {
743                                 insert_into_textbuf(cu, 1);
744                                 if (textbuf[cu->pos]!='\n') insert_into_textbuf(cu, '\n');                              
745                         }
746                         else {
747                                 insert_into_textbuf(cu, '\n');
748                         }
749                         cu->selstart = cu->selend = 0;
750                         doit= 1;
751                         break;
752
753                 case RIGHTARROWKEY:     
754                         if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
755                         if (G.qual & LR_CTRLKEY) {
756                                 cu->pos= next_word(cu);
757                                 cursmove= FO_CURS;                              
758                         } 
759                         else if (G.qual & LR_ALTKEY) {
760                                 kern = textbufinfo[cu->pos-1].kern;
761                                 kern += 1;
762                                 if (kern>20) kern = 20;
763                                 textbufinfo[cu->pos-1].kern = kern;
764                                 doit = 1;
765                         }
766                         else {
767                                 cu->pos++;
768                                 cursmove= FO_CURS;                              
769                         }
770
771                         break;
772                         
773                 case LEFTARROWKEY:
774                         if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
775                         if (G.qual & LR_CTRLKEY) {
776                                 cu->pos= prev_word(cu);
777                                 cursmove= FO_CURS;
778                         } 
779                         else if (G.qual & LR_ALTKEY) {
780                                 kern = textbufinfo[cu->pos-1].kern;
781                                 kern -= 1;
782                                 if (kern<-20) kern = -20;
783                                 textbufinfo[cu->pos-1].kern = kern;
784                                 doit = 1;
785                         }
786                         else {
787                                 cu->pos--;
788                                 cursmove=FO_CURS;
789                         }
790                         break;
791
792                 case UPARROWKEY:
793                         if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
794                         if(G.qual & LR_ALTKEY) {
795                                 if (cu->pos && textbuf[cu->pos - 1] < 255) {
796                                         textbuf[cu->pos - 1]++;
797                                         doit= 1;
798                                 }
799                         }
800                         else cursmove=FO_CURSUP;
801                         break;
802                         
803                 case PAGEUPKEY:
804                         if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
805                         cursmove=FO_PAGEUP;
806                         break;
807                         
808                 case DOWNARROWKEY:
809                         if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
810                         if(G.qual & LR_ALTKEY) {
811                                 if (cu->pos && textbuf[cu->pos - 1] > 1) {
812                                         textbuf[cu->pos - 1]--;
813                                         doit= 1;
814                                 }
815                         }
816                         else cursmove= FO_CURSDOWN;
817                         break;
818
819                 case PAGEDOWNKEY:
820                         if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
821                         cursmove=FO_PAGEDOWN;
822                         break;
823                         
824                 case BACKSPACEKEY:
825                         if(cu->len!=0) {
826                                 if(G.qual & LR_ALTKEY) {
827                                         if(cu->pos>0) accentcode= 1;
828                                 }
829                                 else if (G.qual & LR_CTRLKEY) {
830                                         cu->len = cu->pos = 0;
831                                         textbuf[0]= 0;
832                                         doit= 1;
833                                 }
834                                 else {
835                                         if (killselection(0)==0) {
836                                                 if (cu->pos>0) {
837                                                         for(x=cu->pos;x<=cu->len;x++) textbuf[x-1]= textbuf[x];
838                                                         for(x=cu->pos;x<=cu->len;x++) textbufinfo[x-1]= textbufinfo[x];                                 
839                                                         cu->pos--;
840                                                         textbuf[--cu->len]='\0';
841                                                         doit=1;
842                                                 }
843                                         } else doit=1;
844                                 }
845                         }
846                         break;
847
848                 case DELKEY:
849                         if(cu->len!=0) {
850                                 if (killselection(0)==0) {
851                                         if(cu->pos<cu->len) {                                   
852                                                 for(x=cu->pos;x<cu->len;x++) textbuf[x]= textbuf[x+1];
853                                                 for(x=cu->pos;x<cu->len;x++) textbufinfo[x]= textbufinfo[x+1];                                  
854                                                 textbuf[--cu->len]='\0';
855                                                 doit=1;
856                                         }
857                                 } else doit=1;
858                         }
859                         break;
860                 
861                 case IKEY:
862                         if (G.qual & LR_CTRLKEY) {
863                                 cu->curinfo.flag ^= CU_ITALIC;
864                                 if (style_to_sel(CU_ITALIC, cu->curinfo.flag & CU_ITALIC)) doit= 1;                             
865                                 allqueue(REDRAWBUTSEDIT, 0);
866                         }
867                         break;
868
869                 case BKEY:
870                         if (G.qual & LR_CTRLKEY) {
871                                 cu->curinfo.flag ^= CU_BOLD;
872                                 if (style_to_sel(CU_BOLD, cu->curinfo.flag & CU_BOLD)) doit= 1;
873                                 allqueue(REDRAWBUTSEDIT, 0);
874                         }
875                         break;                  
876                         
877                 case UKEY:
878                         if (G.qual & LR_CTRLKEY) {
879                                 cu->curinfo.flag ^= CU_UNDERLINE;
880                                 if (style_to_sel(CU_UNDERLINE, cu->curinfo.flag & CU_UNDERLINE)) doit= 1;
881                                 allqueue(REDRAWBUTSEDIT, 0);
882                         }
883                         break;
884                         
885                 case XKEY:
886                         if (G.qual & LR_CTRLKEY) {
887                                 copyselection();
888                                 killselection(0);
889                                 doit= 1;
890                         }
891                         break;
892                         
893                 case CKEY:
894                         if (G.qual & LR_CTRLKEY) {
895                                 copyselection();
896                         }
897                         break;                          
898                         
899                 case VKEY:
900                         if (G.qual & LR_CTRLKEY) {
901                                 pasteselection();
902                                 doit= 1;
903                         }
904                         break;
905                 
906                 }
907                         
908                 if(cursmove) {
909                         if ((G.qual & LR_SHIFTKEY)==0) {
910                                 if (cu->selstart) {
911                                         cu->selstart = cu->selend = 0;
912                                         update_string(cu);
913                                         text_to_curve(G.obedit, FO_SELCHANGE);
914                                         allqueue(REDRAWVIEW3D, 0);
915                                 }
916                         }
917                         if(cu->pos>cu->len) cu->pos= cu->len;
918                         else if(cu->pos>=MAXTEXT) cu->pos= MAXTEXT;
919                         else if(cu->pos<0) cu->pos= 0;
920                 }
921         }
922         if(doit || cursmove) {
923         
924                 if (cu->pos) {
925                         cu->curinfo = textbufinfo[cu->pos-1];
926                 } else cu->curinfo = textbufinfo[0];
927                 
928                 if (G.obedit->totcol>0) {
929                         G.obedit->actcol = textbufinfo[cu->pos-1].mat_nr;
930                 }
931                 allqueue(REDRAWBUTSEDIT, 0);
932                 update_string(cu);
933                 text_to_curve(G.obedit, cursmove);
934                 if (cursmove && (G.qual & LR_SHIFTKEY)) {
935                         cu->selend = cu->pos;
936                         DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
937                 }
938                 if(cursmove==0) {
939                         DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
940                 }                       
941
942                 BIF_undo_push("Textedit");
943                 allqueue(REDRAWVIEW3D, 0);
944         }
945 }
946
947 void paste_unicodeText(char *filename)
948 {
949         Curve *cu= G.obedit->data;
950         int filelen, doit= 0;
951         char *strp;
952         FILE *fp = NULL;
953
954         fp= fopen(filename, "r");
955
956         if(fp) {
957
958                 fseek( fp, 0L, SEEK_END );
959                 filelen = ftell( fp );
960                 fseek( fp, 0L, SEEK_SET );
961                         
962                 strp= MEM_mallocN(filelen+4, "tempstr");
963                 //fread() instead of read(),
964                 //because windows read() converts text to DOS \r\n linebreaks
965                 //causing double linebreaks in the 3d text
966                 filelen = fread(strp, 1, filelen, fp);
967                 fclose(fp);
968                 strp[filelen]= 0;
969
970
971                 if(cu->len+filelen<MAXTEXT) 
972                 {
973                         int tmplen;
974                         wchar_t *mem = MEM_callocN((sizeof(wchar_t)*filelen)+(4*sizeof(wchar_t)), "temporary");
975                         tmplen = utf8towchar_(mem, strp);
976 //                      mem =utf8s2wc(strp);
977                         wcscat(textbuf, mem);
978                         MEM_freeN(mem);
979                         cu->len += tmplen;
980                         cu->pos= cu->len;
981                 }
982                 MEM_freeN(strp);
983                 doit = 1;
984         }
985         if(doit) {
986                 update_string(cu);
987                 text_to_curve(G.obedit, 0);
988                 DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
989                 allqueue(REDRAWVIEW3D, 0);
990                 BIF_undo_push("Paste text");
991         }
992 }
993
994 void paste_editText(void)
995 {
996         Curve *cu= G.obedit->data;
997         int filelen, doit= 0;
998         char *strp;
999         FILE *fp = NULL;
1000
1001 #ifdef WIN32
1002         fp= fopen("C:\\windows\\temp\\cutbuf.txt", "r");
1003
1004 //      The following is more likely to work on all Win32 installations.
1005 //      suggested by Douglas Toltzman. Needs windows include files...
1006 /*
1007         char tempFileName[MAX_PATH];
1008         DWORD pathlen;
1009         static const char cutbufname[]="cutbuf.txt";
1010
1011         if ((pathlen=GetTempPath(sizeof(tempFileName),tempFileName)) > 0 &&
1012                 pathlen + sizeof(cutbufname) <= sizeof(tempFileName))
1013         {
1014                 strcat(tempFileName,cutbufname);
1015                 file= open(tempFileName, O_BINARY|O_RDONLY);
1016         }
1017 */
1018 #else
1019         fp= fopen("/tmp/.cutbuffer", "r");
1020 #endif
1021
1022         if(fp) {
1023                 
1024                 fseek(fp, 0L, SEEK_END);                
1025                 filelen = ftell( fp );
1026                 fseek(fp, 0L, SEEK_SET);
1027                                 
1028                 strp= MEM_mallocN(filelen+4, "tempstr");
1029                 // fread() instead of read(),
1030                 // because windows read() converts text to DOS \r\n linebreaks
1031                 // causing double linebreaks in the 3d text
1032                 filelen = fread(strp, 1, filelen, fp);
1033                 fclose(fp);
1034                 strp[filelen]= 0;
1035                 
1036                 if(cu->len+filelen<MAXTEXT) {
1037                         int tmplen;
1038                         wchar_t *mem = MEM_callocN((sizeof(wchar_t) * filelen) + (4 * sizeof(wchar_t)), "temporary");
1039                         tmplen = utf8towchar_(mem, strp);
1040                         wcscat(textbuf, mem);
1041                         MEM_freeN(mem);
1042                         cu->len += tmplen;
1043                         cu->pos= cu->len;
1044                 }
1045                 MEM_freeN(strp);
1046                 doit = 1;
1047         }
1048         if(doit) {
1049                 update_string(cu);
1050                 text_to_curve(G.obedit, 0);
1051                 DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
1052                 allqueue(REDRAWVIEW3D, 0);
1053                 BIF_undo_push("Paste text");
1054         }
1055 }
1056
1057
1058 void make_editText(void)
1059 {
1060         Curve *cu;
1061         cu= G.obedit->data;
1062         
1063         if(textbuf==NULL) textbuf= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "texteditbuf");
1064         if(textbufinfo==NULL) textbufinfo= MEM_callocN((MAXTEXT+4)*sizeof(CharInfo), "texteditbufinfo");
1065         if(copybuf==NULL) copybuf= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "texteditcopybuf");
1066         if(copybufinfo==NULL) copybufinfo= MEM_callocN((MAXTEXT+4)*sizeof(CharInfo), "texteditcopybufinfo");    
1067         if(oldstr==NULL) oldstr= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "oldstrbuf");
1068         
1069         // Convert the original text to wchar_t
1070         utf8towchar_(textbuf, cu->str);
1071         wcscpy(oldstr, textbuf);
1072                 
1073         cu->len= wcslen(textbuf);
1074         
1075         memcpy(textbufinfo, cu->strinfo, (cu->len)*sizeof(CharInfo));
1076         
1077         oldstrinfo= cu->strinfo;
1078         cu->strinfo= textbufinfo;
1079
1080         if(cu->pos>cu->len) cu->pos= cu->len;
1081
1082         if (cu->pos) {
1083                 cu->curinfo = textbufinfo[cu->pos-1];
1084         } else cu->curinfo = textbufinfo[0];
1085         
1086         // Convert to UTF-8
1087         update_string(cu);
1088         
1089         DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
1090         
1091         textediting= 1;
1092         BIF_undo_push("Original");
1093 }
1094
1095
1096 void load_editText(void)
1097 {
1098         Curve *cu;
1099         
1100         cu= G.obedit->data;
1101
1102         MEM_freeN(oldstr);
1103         oldstr= NULL;
1104         MEM_freeN(oldstrinfo);
1105         oldstrinfo= NULL;
1106         
1107         update_string(cu);
1108         
1109         cu->strinfo= MEM_callocN((cu->len+4)*sizeof(CharInfo), "texteditinfo");
1110         memcpy(cu->strinfo, textbufinfo, (cu->len)*sizeof(CharInfo));
1111
1112         cu->len= strlen(cu->str);
1113         
1114         /* this memory system is weak... */
1115         MEM_freeN(textbuf);
1116         MEM_freeN(textbufinfo);
1117         textbuf= NULL;
1118         textbufinfo= NULL;
1119         
1120         if (selboxes) {
1121                 MEM_freeN(selboxes);
1122                 selboxes= NULL;
1123         }
1124         
1125         textediting= 0;
1126         
1127         DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
1128
1129 }
1130
1131
1132 void remake_editText(void)
1133 {
1134         Curve *cu;
1135                 
1136         if(okee("Reload original text")==0) return;
1137         
1138         // Copy the oldstr to textbuf temporary global variable
1139         wcscpy(textbuf, oldstr);
1140
1141         // Set the object length and position   
1142         cu= G.obedit->data;
1143         cu->len= wcslen(textbuf);
1144         if(cu->pos>cu->len) cu->pos= cu->len;
1145
1146         update_string(cu);
1147         
1148         DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);     
1149         allqueue(REDRAWVIEW3D, 0);
1150         
1151         BIF_undo_push("Reload");
1152 }
1153
1154
1155 void free_editText(void)
1156 {
1157         if(oldstr) MEM_freeN(oldstr);
1158         if(oldstrinfo) MEM_freeN(oldstrinfo);
1159         if(textbuf) MEM_freeN(textbuf);
1160         textbuf = oldstr = NULL;
1161         textbufinfo = oldstrinfo = NULL;
1162         textediting= 0;
1163 }
1164
1165
1166 void add_primitiveFont(int dummy_argument)
1167 {
1168         Curve *cu;
1169
1170         if (G.obedit && G.obedit->type==OB_FONT) return;
1171         check_editmode(OB_FONT);
1172         
1173         add_object_draw(OB_FONT);
1174         base_init_from_view3d(BASACT, G.vd);
1175         
1176         where_is_object(BASACT->object);
1177         
1178         cu= BASACT->object->data;
1179         
1180         cu->vfont= cu->vfontb= cu->vfonti= cu->vfontbi= get_builtin_font();
1181         cu->vfont->id.us+=4;
1182         cu->str= MEM_mallocN(12, "str");
1183         strcpy(cu->str, "Text");
1184         cu->pos= 4;
1185         cu->strinfo= MEM_callocN(12*sizeof(CharInfo), "strinfo");
1186         cu->totbox= cu->actbox= 1;
1187         cu->tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "textbox");
1188         cu->tb[0].w = cu->tb[0].h = 0.0;
1189         
1190         if (U.flag & USER_ADD_EDITMODE) 
1191                 enter_editmode(EM_WAITCURSOR);
1192
1193         allqueue(REDRAWALL, 0);
1194 }
1195
1196 void to_upper(void)
1197 {
1198         Curve *cu;
1199         int len, ok;
1200         wchar_t *str;
1201         
1202         if(G.obedit==0) {
1203                 return;
1204         }
1205         
1206         ok= 0;
1207         cu= G.obedit->data;
1208         
1209         len= wcslen(textbuf);
1210         str= textbuf;
1211         while(len) {
1212                 if( *str>=97 && *str<=122) {
1213                         ok= 1;
1214                         *str-= 32;
1215                 }
1216                 len--;
1217                 str++;
1218         }
1219         
1220         if(ok==0) {
1221                 len= wcslen(textbuf);
1222                 str= textbuf;
1223                 while(len) {
1224                         if( *str>=65 && *str<=90) {
1225                                 *str+= 32;
1226                         }
1227                         len--;
1228                         str++;
1229                 }
1230         }
1231         DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
1232         allqueue(REDRAWVIEW3D, 0);
1233         BIF_undo_push("To upper");
1234
1235         update_string(cu);
1236 }
1237
1238
1239 /* **************** undo for font object ************** */
1240
1241 static void undoFont_to_editFont(void *strv)
1242 {
1243         Curve *cu= G.obedit->data;
1244         char *str= strv;
1245
1246         cu->pos= *((short *)str);
1247         cu->len= *((short *)(str+2));
1248
1249         memcpy(textbuf, str+4, (cu->len+1)*sizeof(wchar_t));
1250         memcpy(textbufinfo, str+4 + (cu->len+1)*sizeof(wchar_t), cu->len*sizeof(CharInfo));
1251         
1252         cu->selstart = cu->selend = 0;
1253         DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
1254         
1255         update_string(cu);
1256         
1257         allqueue(REDRAWVIEW3D, 0);
1258 }
1259
1260 static void *editFont_to_undoFont(void)
1261 {
1262         Curve *cu= G.obedit->data;
1263         char *str;
1264         
1265         // The undo buffer includes [MAXTEXT+6]=actual string and [MAXTEXT+4]*sizeof(CharInfo)=charinfo
1266         str= MEM_callocN((MAXTEXT+6)*sizeof(wchar_t) + (MAXTEXT+4)*sizeof(CharInfo), "string undo");
1267
1268         // Copy the string and string information
1269         memcpy(str+4, textbuf, (cu->len+1)*sizeof(wchar_t));
1270         memcpy(str+4 + (cu->len+1)*sizeof(wchar_t), textbufinfo, cu->len*sizeof(CharInfo));
1271
1272         *((short *)str)= cu->pos;
1273         *((short *)(str+2))= cu->len;   
1274         
1275         return str;
1276 }
1277
1278 static void free_undoFont(void *strv)
1279 {
1280         MEM_freeN(strv);
1281 }
1282
1283 /* and this is all the undo system needs to know */
1284 void undo_push_font(char *name)
1285 {
1286         undo_editmode_push(name, free_undoFont, undoFont_to_editFont, editFont_to_undoFont);
1287 }
1288
1289
1290
1291 /***/