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