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