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