remove unused includes
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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_math.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
50 #include "BKE_context.h"
51 #include "BKE_curve.h"
52 #include "BKE_depsgraph.h"
53 #include "BKE_font.h"
54 #include "BKE_library.h"
55 #include "BKE_object.h"
56 #include "BKE_report.h"
57
58 #include "RNA_access.h"
59 #include "RNA_define.h"
60
61 #include "WM_api.h"
62 #include "WM_types.h"
63
64 #include "ED_object.h"
65 #include "ED_screen.h"
66 #include "ED_util.h"
67
68 #include "UI_interface.h"
69
70 #include "curve_intern.h"
71
72 #define MAXTEXT 32766
73
74 /************************* utilities ******************************/
75
76 static char findaccent(char char1, unsigned int code)
77 {
78         char new= 0;
79         
80         if(char1=='a') {
81                 if(code=='`') new= 224;
82                 else if(code==39) new= 225;
83                 else if(code=='^') new= 226;
84                 else if(code=='~') new= 227;
85                 else if(code=='"') new= 228;
86                 else if(code=='o') new= 229;
87                 else if(code=='e') new= 230;
88                 else if(code=='-') new= 170;
89         }
90         else if(char1=='c') {
91                 if(code==',') new= 231;
92                 if(code=='|') new= 162;
93         }
94         else if(char1=='e') {
95                 if(code=='`') new= 232;
96                 else if(code==39) new= 233;
97                 else if(code=='^') new= 234;
98                 else if(code=='"') new= 235;
99         }
100         else if(char1=='i') {
101                 if(code=='`') new= 236;
102                 else if(code==39) new= 237;
103                 else if(code=='^') new= 238;
104                 else if(code=='"') new= 239;
105         }
106         else if(char1=='n') {
107                 if(code=='~') new= 241;
108         }
109         else if(char1=='o') {
110                 if(code=='`') new= 242;
111                 else if(code==39) new= 243;
112                 else if(code=='^') new= 244;
113                 else if(code=='~') new= 245;
114                 else if(code=='"') new= 246;
115                 else if(code=='/') new= 248;
116                 else if(code=='-') new= 186;
117                 else if(code=='e') new= 143;
118         }
119         else if(char1=='s') {
120                 if(code=='s') new= 167;
121         }
122         else if(char1=='u') {
123                 if(code=='`') new= 249;
124                 else if(code==39) new= 250;
125                 else if(code=='^') new= 251;
126                 else if(code=='"') new= 252;
127         }
128         else if(char1=='y') {
129                 if(code==39) new= 253;
130                 else if(code=='"') new= 255;
131         }
132         else if(char1=='A') {
133                 if(code=='`') new= 192;
134                 else if(code==39) new= 193;
135                 else if(code=='^') new= 194;
136                 else if(code=='~') new= 195;
137                 else if(code=='"') new= 196;
138                 else if(code=='o') new= 197;
139                 else if(code=='e') new= 198;
140         }
141         else if(char1=='C') {
142                 if(code==',') new= 199;
143         }
144         else if(char1=='E') {
145                 if(code=='`') new= 200;
146                 else if(code==39) new= 201;
147                 else if(code=='^') new= 202;
148                 else if(code=='"') new= 203;
149         }
150         else if(char1=='I') {
151                 if(code=='`') new= 204;
152                 else if(code==39) new= 205;
153                 else if(code=='^') new= 206;
154                 else if(code=='"') new= 207;
155         }
156         else if(char1=='N') {
157                 if(code=='~') new= 209;
158         }
159         else if(char1=='O') {
160                 if(code=='`') new= 210;
161                 else if(code==39) new= 211;
162                 else if(code=='^') new= 212;
163                 else if(code=='~') new= 213;
164                 else if(code=='"') new= 214;
165                 else if(code=='/') new= 216;
166                 else if(code=='e') new= 141;
167         }
168         else if(char1=='U') {
169                 if(code=='`') new= 217;
170                 else if(code==39) new= 218;
171                 else if(code=='^') new= 219;
172                 else if(code=='"') new= 220;
173         }
174         else if(char1=='Y') {
175                 if(code==39) new= 221;
176         }
177         else if(char1=='1') {
178                 if(code=='4') new= 188;
179                 if(code=='2') new= 189;
180         }
181         else if(char1=='3') {
182                 if(code=='4') new= 190;
183         }
184         else if(char1==':') {
185                 if(code=='-') new= 247;
186         }
187         else if(char1=='-') {
188                 if(code==':') new= 247;
189                 if(code=='|') new= 135;
190                 if(code=='+') new= 177;
191         }
192         else if(char1=='|') {
193                 if(code=='-') new= 135;
194                 if(code=='=') new= 136;
195         }
196         else if(char1=='=') {
197                 if(code=='|') new= 136;
198         }
199         else if(char1=='+') {
200                 if(code=='-') new= 177;
201         }
202         
203         if(new) return new;
204         else return char1;
205 }
206
207
208 void update_string(Curve *cu)
209 {
210         EditFont *ef= cu->editfont;
211         int len;
212
213         // Free the old curve string    
214         MEM_freeN(cu->str);
215
216         // Calculate the actual string length in UTF-8 variable characters
217         len = wcsleninu8(ef->textbuf);
218
219         // Alloc memory for UTF-8 variable char length string
220         cu->str = MEM_callocN(len + sizeof(wchar_t), "str");
221
222         // Copy the wchar to UTF-8
223         wcs2utf8s(cu->str, ef->textbuf);
224 }
225
226 static int insert_into_textbuf(Object *obedit, uintptr_t c)
227 {
228         Curve *cu= obedit->data;
229         
230         if(cu->len<MAXTEXT-1) {
231                 EditFont *ef= cu->editfont;
232                 int x;
233
234                 for(x= cu->len; x>cu->pos; x--) ef->textbuf[x]= ef->textbuf[x-1];
235                 for(x= cu->len; x>cu->pos; x--) ef->textbufinfo[x]= ef->textbufinfo[x-1];               
236                 ef->textbuf[cu->pos]= c;
237                 ef->textbufinfo[cu->pos] = cu->curinfo;
238                 ef->textbufinfo[cu->pos].kern = 0;
239                 if(obedit->actcol>0)
240                         ef->textbufinfo[cu->pos].mat_nr = obedit->actcol;
241                 else
242                         ef->textbufinfo[cu->pos].mat_nr = 0;
243                                         
244                 cu->pos++;
245                 cu->len++;
246                 ef->textbuf[cu->len]='\0';
247
248                 update_string(cu);
249
250                 return 1;
251         }
252         else
253                 return 0;
254 }
255
256 static void text_update_edited(bContext *C, Scene *scene, Object *obedit, int recalc, int mode)
257 {
258         Curve *cu= obedit->data;
259         EditFont *ef= cu->editfont;
260
261         if(cu->pos)
262                 cu->curinfo = ef->textbufinfo[cu->pos-1];
263         else
264                 cu->curinfo = ef->textbufinfo[0];
265         
266         if(obedit->totcol>0)
267                 obedit->actcol= ef->textbufinfo[cu->pos-1].mat_nr;
268
269         update_string(cu);
270         BKE_text_to_curve(scene, obedit, mode);
271
272         if(recalc)
273                 DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
274         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
275 }
276
277 /********************** insert lorem operator *********************/
278
279 static int insert_lorem_exec(bContext *C, wmOperator *op)
280 {
281         Object *obedit= CTX_data_edit_object(C);
282         char *p, *p2;
283         int i;
284         static char *lastlorem;
285         
286         if(lastlorem)
287                 p= lastlorem;
288         else
289                 p= ED_lorem;
290         
291         i= rand()/(RAND_MAX/6)+4;       
292                 
293         for(p2=p; *p2 && i; p2++) {
294                 insert_into_textbuf(obedit, *p2);
295
296                 if(*p2=='.')
297                         i--;
298         }
299
300         lastlorem = p2+1;
301         if(strlen(lastlorem)<5)
302                 lastlorem = ED_lorem;
303         
304         insert_into_textbuf(obedit, '\n');
305         insert_into_textbuf(obedit, '\n');      
306
307         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
308         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
309
310         return OPERATOR_FINISHED;
311 }
312
313 void FONT_OT_insert_lorem(wmOperatorType *ot)
314 {
315         /* identifiers */
316         ot->name= "Insert Lorem";
317         ot->description= "Insert placeholder text";
318         ot->idname= "FONT_OT_insert_lorem";
319         
320         /* api callbacks */
321         ot->exec= insert_lorem_exec;
322         ot->poll= ED_operator_editfont;
323         
324         /* flags */
325         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
326 }
327
328 /******************* paste file operator ********************/
329
330 /* note this handles both ascii and utf8 unicode, previously
331  * there were 3 functions that did effectively the same thing. */
332
333 static int paste_file(bContext *C, ReportList *reports, char *filename)
334 {
335         Scene *scene= CTX_data_scene(C);
336         Object *obedit= CTX_data_edit_object(C);
337         Curve *cu= obedit->data;
338         EditFont *ef= cu->editfont;
339         FILE *fp;
340         int filelen;
341         char *strp;
342
343         fp= fopen(filename, "r");
344
345         if(!fp) {
346                 if(reports)
347                         BKE_reportf(reports, RPT_ERROR, "Failed to open file %s.", filename);
348                 return OPERATOR_CANCELLED;
349         }
350
351         fseek(fp, 0L, SEEK_END);
352         filelen = ftell(fp);
353         fseek(fp, 0L, SEEK_SET);
354
355         strp= MEM_callocN(filelen+4, "tempstr");
356
357         // fread() instead of read(), because windows read() converts text
358         // to DOS \r\n linebreaks, causing double linebreaks in the 3d text
359         filelen = fread(strp, 1, filelen, fp);
360         fclose(fp);
361         strp[filelen]= 0;
362
363         if(cu->len+filelen<MAXTEXT) {
364                 int tmplen;
365                 wchar_t *mem = MEM_callocN((sizeof(wchar_t)*filelen)+(4*sizeof(wchar_t)), "temporary");
366                 tmplen = utf8towchar(mem, strp);
367                 wcscat(ef->textbuf, mem);
368                 MEM_freeN(mem);
369                 cu->len += tmplen;
370                 cu->pos= cu->len;
371         }
372         MEM_freeN(strp);
373
374         text_update_edited(C, scene, obedit, 1, 0);
375
376         return OPERATOR_FINISHED;
377 }
378
379 static int paste_file_exec(bContext *C, wmOperator *op)
380 {
381         char *path;
382         int retval;
383         
384         path= RNA_string_get_alloc(op->ptr, "filepath", NULL, 0);
385         retval= paste_file(C, op->reports, path);
386         MEM_freeN(path);
387
388         return retval;
389 }
390
391 static int paste_file_invoke(bContext *C, wmOperator *op, wmEvent *event)
392 {
393         if(RNA_property_is_set(op->ptr, "filepath"))
394                 return paste_file_exec(C, op);
395
396         WM_event_add_fileselect(C, op); 
397
398         return OPERATOR_RUNNING_MODAL;
399 }
400
401 void FONT_OT_file_paste(wmOperatorType *ot)
402 {
403         /* identifiers */
404         ot->name= "Paste File";
405         ot->description= "Paste contents from file";
406         ot->idname= "FONT_OT_file_paste";
407         
408         /* api callbacks */
409         ot->exec= paste_file_exec;
410         ot->invoke= paste_file_invoke;
411         ot->poll= ED_operator_editfont;
412         
413         /* flags */
414         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
415
416         /* properties */
417         WM_operator_properties_filesel(ot, FOLDERFILE|TEXTFILE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH);
418 }
419
420 /******************* paste buffer operator ********************/
421
422 static int paste_buffer_exec(bContext *C, wmOperator *op)
423 {
424         char *filename;
425
426 #ifdef WIN32
427         filename= "C:\\windows\\temp\\cutbuf.txt";
428
429 //      The following is more likely to work on all Win32 installations.
430 //      suggested by Douglas Toltzman. Needs windows include files...
431 /*
432         char tempFileName[MAX_PATH];
433         DWORD pathlen;
434         static const char cutbufname[]="cutbuf.txt";
435
436         if((pathlen=GetTempPath(sizeof(tempFileName),tempFileName)) > 0 &&
437                 pathlen + sizeof(cutbufname) <= sizeof(tempFileName))
438         {
439                 strcat(tempFileName,cutbufname);
440                 filename= tempFilename;
441         }
442 */
443 #else
444         filename= "/tmp/.cutbuffer";
445 #endif
446
447         return paste_file(C, NULL, filename);
448 }
449
450 void FONT_OT_buffer_paste(wmOperatorType *ot)
451 {
452         /* identifiers */
453         ot->name= "Paste Buffer";
454         ot->description= "Paste text from OS buffer";
455         ot->idname= "FONT_OT_buffer_paste";
456         
457         /* api callbacks */
458         ot->exec= paste_buffer_exec;
459         ot->poll= ED_operator_editfont;
460         
461         /* flags */
462         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
463 }
464
465 /******************* text to object operator ********************/
466
467 static void txt_add_object(bContext *C, TextLine *firstline, int totline, float offset[3])
468 {
469         Scene *scene= CTX_data_scene(C);
470         Curve *cu;
471         Object *obedit;
472         Base *base;
473         struct TextLine *tmp;
474         int nchars = 0, a;
475         float rot[3] = {0.f, 0.f, 0.f};
476         
477         obedit= add_object(scene, OB_FONT);
478         base= scene->basact;
479
480         
481         ED_object_base_init_transform(C, base, NULL, rot); /* seems to assume view align ? TODO - look into this, could be an operator option */
482         where_is_object(scene, obedit);
483
484         obedit->loc[0] += offset[0];
485         obedit->loc[1] += offset[1];
486         obedit->loc[2] += offset[2];
487
488         cu= obedit->data;
489         cu->vfont= get_builtin_font();
490         cu->vfont->id.us++;
491
492         for(tmp=firstline, a=0; cu->len<MAXTEXT && a<totline; tmp=tmp->next, a++)
493                 nchars += strlen(tmp->line) + 1;
494
495         if(cu->str) MEM_freeN(cu->str);
496         if(cu->strinfo) MEM_freeN(cu->strinfo); 
497
498         cu->str= MEM_callocN(nchars+4, "str");
499         cu->strinfo= MEM_callocN((nchars+4)*sizeof(CharInfo), "strinfo");
500
501         cu->str[0]= '\0';
502         cu->len= 0;
503         cu->pos= 0;
504         
505         for(tmp=firstline, a=0; cu->len<MAXTEXT && a<totline; tmp=tmp->next, a++) {
506                 strcat(cu->str, tmp->line);
507                 cu->len+= strlen(tmp->line);
508
509                 if(tmp->next) {
510                         strcat(cu->str, "\n");
511                         cu->len++;
512                 }
513
514                 cu->pos= cu->len;
515         }
516
517         WM_event_add_notifier(C, NC_OBJECT|NA_ADDED, obedit);
518 }
519
520 void ED_text_to_object(bContext *C, Text *text, int split_lines)
521 {
522         RegionView3D *rv3d= CTX_wm_region_view3d(C);
523         TextLine *line;
524         float offset[3];
525         int linenum= 0;
526
527         if(!text || !text->lines.first) return;
528
529         if(split_lines) {
530                 for(line=text->lines.first; line; line=line->next) {
531                         /* skip lines with no text, but still make space for them */
532                         if(line->line[0] == '\0') {
533                                 linenum++;
534                                 continue;
535                         }
536         
537                         /* do the translation */
538                         offset[0] = 0;
539                         offset[1] = -linenum;
540                         offset[2] = 0;
541         
542                         if(rv3d)
543                                 mul_mat3_m4_v3(rv3d->viewinv, offset);
544
545                         txt_add_object(C, line, 1, offset);
546
547                         linenum++;
548                 }
549         }
550         else {
551                 offset[0]= 0.0f;
552                 offset[1]= 0.0f;
553                 offset[2]= 0.0f;
554
555                 txt_add_object(C, text->lines.first, BLI_countlist(&text->lines), offset);
556         }
557 }
558
559 /********************** utilities ***************************/
560
561 static short next_word(Curve *cu)
562 {
563         short s;
564         for(s=cu->pos; (cu->str[s]) && (cu->str[s]!=' ') && (cu->str[s]!='\n') &&
565                                         (cu->str[s]!=1) && (cu->str[s]!='\r'); s++);
566         if(cu->str[s]) return(s+1); else return(s);
567 }
568
569 static short prev_word(Curve *cu)
570 {
571         short s;
572         
573         if(cu->pos==0) return(0);
574         for(s=cu->pos-2; (cu->str[s]) && (cu->str[s]!=' ') && (cu->str[s]!='\n') &&
575                                         (cu->str[s]!=1) && (cu->str[s]!='\r'); s--);
576         if(cu->str[s]) return(s+1); else return(s);
577 }
578
579 static int kill_selection(Object *obedit, int ins)      /* 1 == new character */
580 {
581         Curve *cu= obedit->data;
582         EditFont *ef= cu->editfont;
583         int selend, selstart, direction;
584         int offset = 0;
585         int getfrom;
586
587         direction = BKE_font_getselection(obedit, &selstart, &selend);
588         if(direction) {
589                 int size;
590                 if(ins) offset = 1;
591                 if(cu->pos >= selstart) cu->pos = selstart+offset;
592                 if((direction == -1) && ins) {
593                         selstart++;
594                         selend++;
595                 }
596                 getfrom = selend+offset;
597                 if(ins==0) getfrom++;
598                 size = (cu->len * sizeof(wchar_t)) - (selstart * sizeof(wchar_t)) + (offset*sizeof(wchar_t));
599                 memmove(ef->textbuf+selstart, ef->textbuf+getfrom, size);
600                 memmove(ef->textbufinfo+selstart, ef->textbufinfo+getfrom, ((cu->len-selstart)+offset)*sizeof(CharInfo));
601                 cu->len -= (selend-selstart)+offset;
602                 cu->selstart = cu->selend = 0;
603         }
604
605         return(direction);
606 }
607
608 /******************* set style operator ********************/
609
610 static EnumPropertyItem style_items[]= {
611         {CU_CHINFO_BOLD, "BOLD", 0, "Bold", ""},
612         {CU_CHINFO_ITALIC, "ITALIC", 0, "Italic", ""},
613         {CU_CHINFO_UNDERLINE, "UNDERLINE", 0, "Underline", ""},
614         {CU_CHINFO_SMALLCAPS, "SMALL_CAPS", 0, "Small Caps", ""},
615         {0, NULL, 0, NULL, NULL}};
616
617 static int set_style(bContext *C, int style, int clear)
618 {
619         Object *obedit= CTX_data_edit_object(C);
620         Curve *cu= obedit->data;
621         EditFont *ef= cu->editfont;
622         int i, selstart, selend;
623
624         if(!BKE_font_getselection(obedit, &selstart, &selend))
625                 return OPERATOR_CANCELLED;
626
627         for(i=selstart; i<=selend; i++) {
628                 if(clear)
629                         ef->textbufinfo[i].flag &= ~style;
630                 else
631                         ef->textbufinfo[i].flag |= style;
632         }
633
634         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
635         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
636
637         return OPERATOR_FINISHED;
638 }
639
640 static int set_style_exec(bContext *C, wmOperator *op)
641 {
642         int style, clear;
643
644         style= RNA_enum_get(op->ptr, "style");
645         clear= RNA_enum_get(op->ptr, "clear");
646
647         return set_style(C, style, clear);
648 }
649
650 void FONT_OT_style_set(wmOperatorType *ot)
651 {
652         /* identifiers */
653         ot->name= "Set Style";
654         ot->description= "Set font style";
655         ot->idname= "FONT_OT_style_set";
656         
657         /* api callbacks */
658         ot->exec= set_style_exec;
659         ot->poll= ED_operator_editfont;
660         
661         /* flags */
662         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
663
664         /* properties */
665         RNA_def_enum(ot->srna, "style", style_items, CU_CHINFO_BOLD, "Style", "Style to set selection to.");
666         RNA_def_boolean(ot->srna, "clear", 0, "Clear", "Clear style rather than setting it.");
667 }
668
669 /******************* toggle style operator ********************/
670
671 static int toggle_style_exec(bContext *C, wmOperator *op)
672 {
673         Object *obedit= CTX_data_edit_object(C);
674         Curve *cu= obedit->data;
675         int style, clear, selstart, selend;
676
677         if(!BKE_font_getselection(obedit, &selstart, &selend))
678                 return OPERATOR_CANCELLED;
679         
680         style= RNA_enum_get(op->ptr, "style");
681
682         cu->curinfo.flag ^= style;
683         clear= (cu->curinfo.flag & style) == 0;
684
685         return set_style(C, style, clear);
686 }
687
688 void FONT_OT_style_toggle(wmOperatorType *ot)
689 {
690         /* identifiers */
691         ot->name= "Toggle Style";
692         ot->description= "Toggle font style";
693         ot->idname= "FONT_OT_style_toggle";
694         
695         /* api callbacks */
696         ot->exec= toggle_style_exec;
697         ot->poll= ED_operator_editfont;
698         
699         /* flags */
700         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
701
702         /* properties */
703         RNA_def_enum(ot->srna, "style", style_items, CU_CHINFO_BOLD, "Style", "Style to set selection to.");
704 }
705
706 /******************* copy text operator ********************/
707
708 static void copy_selection(Object *obedit)
709 {
710         int selstart, selend;
711         
712         if(BKE_font_getselection(obedit, &selstart, &selend)) {
713                 Curve *cu= obedit->data;
714                 EditFont *ef= cu->editfont;
715                 
716                 memcpy(ef->copybuf, ef->textbuf+selstart, ((selend-selstart)+1)*sizeof(wchar_t));
717                 ef->copybuf[(selend-selstart)+1]=0;
718                 memcpy(ef->copybufinfo, ef->textbufinfo+selstart, ((selend-selstart)+1)*sizeof(CharInfo));      
719         }
720 }
721
722 static int copy_text_exec(bContext *C, wmOperator *op)
723 {
724         Object *obedit= CTX_data_edit_object(C);
725
726         copy_selection(obedit);
727
728         return OPERATOR_FINISHED;
729 }
730
731 void FONT_OT_text_copy(wmOperatorType *ot)
732 {
733         /* identifiers */
734         ot->name= "Copy Text";
735         ot->description= "Copy selected text to clipboard";
736         ot->idname= "FONT_OT_text_copy";
737         
738         /* api callbacks */
739         ot->exec= copy_text_exec;
740         ot->poll= ED_operator_editfont;
741 }
742
743 /******************* cut text operator ********************/
744
745 static int cut_text_exec(bContext *C, wmOperator *op)
746 {
747         Scene *scene= CTX_data_scene(C);
748         Object *obedit= CTX_data_edit_object(C);
749         int selstart, selend;
750
751         if(!BKE_font_getselection(obedit, &selstart, &selend))
752                 return OPERATOR_CANCELLED;
753
754         copy_selection(obedit);
755         kill_selection(obedit, 0);
756
757         text_update_edited(C, scene, obedit, 1, 0);
758
759         return OPERATOR_FINISHED;
760 }
761
762 void FONT_OT_text_cut(wmOperatorType *ot)
763 {
764         /* identifiers */
765         ot->name= "Cut Text";
766         ot->description= "Cut selected text to clipboard";
767         ot->idname= "FONT_OT_text_cut";
768         
769         /* api callbacks */
770         ot->exec= cut_text_exec;
771         ot->poll= ED_operator_editfont;
772
773         /* flags */
774         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
775 }
776
777 /******************* paste text operator ********************/
778
779 static int paste_selection(Object *obedit, ReportList *reports)
780 {
781         Curve *cu= obedit->data;
782         EditFont *ef= cu->editfont;
783         int len= wcslen(ef->copybuf);
784
785         // Verify that the copy buffer => [copy buffer len] + cu->len < MAXTEXT
786         if(cu->len + len <= MAXTEXT) {
787                 if(len) {       
788                         int size = (cu->len * sizeof(wchar_t)) - (cu->pos*sizeof(wchar_t)) + sizeof(wchar_t);
789                         memmove(ef->textbuf+cu->pos+len, ef->textbuf+cu->pos, size);
790                         memcpy(ef->textbuf+cu->pos, ef->copybuf, len * sizeof(wchar_t));
791                 
792                         memmove(ef->textbufinfo+cu->pos+len, ef->textbufinfo+cu->pos, (cu->len-cu->pos+1)*sizeof(CharInfo));
793                         memcpy(ef->textbufinfo+cu->pos, ef->copybufinfo, len*sizeof(CharInfo)); 
794                 
795                         cu->len += len;
796                         cu->pos += len;
797
798                         return 1;
799                 }
800         }
801         else
802                 BKE_report(reports, RPT_WARNING, "Text too long.");
803         
804         return 0;
805 }
806
807 static int paste_text_exec(bContext *C, wmOperator *op)
808 {
809         Scene *scene= CTX_data_scene(C);
810         Object *obedit= CTX_data_edit_object(C);
811
812         if(!paste_selection(obedit, op->reports))
813                 return OPERATOR_CANCELLED;
814
815         text_update_edited(C, scene, obedit, 1, 0);
816
817         return OPERATOR_FINISHED;
818 }
819
820 void FONT_OT_text_paste(wmOperatorType *ot)
821 {
822         /* identifiers */
823         ot->name= "Paste Text";
824         ot->description= "Paste text from clipboard";
825         ot->idname= "FONT_OT_text_paste";
826         
827         /* api callbacks */
828         ot->exec= paste_text_exec;
829         ot->poll= ED_operator_editfont;
830
831         /* flags */
832         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
833 }
834
835 /************************ move operator ************************/
836
837 static EnumPropertyItem move_type_items[]= {
838         {LINE_BEGIN, "LINE_BEGIN", 0, "Line Begin", ""},
839         {LINE_END, "LINE_END", 0, "Line End", ""},
840         {PREV_CHAR, "PREVIOUS_CHARACTER", 0, "Previous Character", ""},
841         {NEXT_CHAR, "NEXT_CHARACTER", 0, "Next Character", ""},
842         {PREV_WORD, "PREVIOUS_WORD", 0, "Previous Word", ""},
843         {NEXT_WORD, "NEXT_WORD", 0, "Next Word", ""},
844         {PREV_LINE, "PREVIOUS_LINE", 0, "Previous Line", ""},
845         {NEXT_LINE, "NEXT_LINE", 0, "Next Line", ""},
846         {PREV_PAGE, "PREVIOUS_PAGE", 0, "Previous Page", ""},
847         {NEXT_PAGE, "NEXT_PAGE", 0, "Next Page", ""},
848         {0, NULL, 0, NULL, NULL}};
849
850 static int move_cursor(bContext *C, int type, int select)
851 {
852         Scene *scene= CTX_data_scene(C);
853         Object *obedit= CTX_data_edit_object(C);
854         Curve *cu= obedit->data;
855         EditFont *ef= cu->editfont;
856         int cursmove= 0;
857
858         switch(type) {
859                 case LINE_BEGIN:
860                         if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
861                         while(cu->pos>0) {
862                                 if(ef->textbuf[cu->pos-1]=='\n') break;
863                                 if(ef->textbufinfo[cu->pos-1].flag & CU_CHINFO_WRAP) break;                             
864                                 cu->pos--;
865                         }               
866                         cursmove=FO_CURS;
867                         break;
868                         
869                 case LINE_END:
870                         if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;                
871                         while(cu->pos<cu->len) {
872                                 if(ef->textbuf[cu->pos]==0) break;
873                                 if(ef->textbuf[cu->pos]=='\n') break;
874                                 if(ef->textbufinfo[cu->pos].flag & CU_CHINFO_WRAP ) break;
875                                 cu->pos++;
876                         }
877                         cursmove=FO_CURS;
878                         break;
879
880                 case PREV_WORD:
881                         if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
882                         cu->pos= prev_word(cu);
883                         cursmove= FO_CURS;
884                         break;
885
886                 case NEXT_WORD:
887                         if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
888                         cu->pos= next_word(cu);
889                         cursmove= FO_CURS;                              
890                         break;
891
892                 case PREV_CHAR:
893                         if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
894                         cu->pos--;
895                         cursmove=FO_CURS;
896                         break;
897
898                 case NEXT_CHAR: 
899                         if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
900                         cu->pos++;
901                         cursmove= FO_CURS;                              
902
903                         break;
904
905                 case PREV_LINE:
906                         if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
907                         cursmove=FO_CURSUP;
908                         break;
909                         
910                 case NEXT_LINE:
911                         if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
912                         cursmove= FO_CURSDOWN;
913                         break;
914
915                 case PREV_PAGE:
916                         if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
917                         cursmove=FO_PAGEUP;
918                         break;
919
920                 case NEXT_PAGE:
921                         if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
922                         cursmove=FO_PAGEDOWN;
923                         break;
924         }
925                 
926         if(!cursmove)
927                 return OPERATOR_CANCELLED;
928
929         if(select == 0) {
930                 if(cu->selstart) {
931                         cu->selstart = cu->selend = 0;
932                         update_string(cu);
933                         BKE_text_to_curve(scene, obedit, FO_SELCHANGE);
934                 }
935         }
936
937         if(cu->pos>cu->len) cu->pos= cu->len;
938         else if(cu->pos>=MAXTEXT) cu->pos= MAXTEXT;
939         else if(cu->pos<0) cu->pos= 0;
940
941         text_update_edited(C, scene, obedit, select, cursmove);
942
943         if(select)
944                 cu->selend = cu->pos;
945
946         return OPERATOR_FINISHED;
947 }
948
949 static int move_exec(bContext *C, wmOperator *op)
950 {
951         int type= RNA_enum_get(op->ptr, "type");
952
953         return move_cursor(C, type, 0);
954 }
955
956 void FONT_OT_move(wmOperatorType *ot)
957 {
958         /* identifiers */
959         ot->name= "Move Cursor";
960         ot->description= "Move cursor to position type";
961         ot->idname= "FONT_OT_move";
962         
963         /* api callbacks */
964         ot->exec= move_exec;
965         ot->poll= ED_operator_editfont;
966
967         /* flags */
968         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
969
970         /* properties */
971         RNA_def_enum(ot->srna, "type", move_type_items, LINE_BEGIN, "Type", "Where to move cursor to.");
972 }
973
974 /******************* move select operator ********************/
975
976 static int move_select_exec(bContext *C, wmOperator *op)
977 {
978         int type= RNA_enum_get(op->ptr, "type");
979
980         return move_cursor(C, type, 1);
981 }
982
983 void FONT_OT_move_select(wmOperatorType *ot)
984 {
985         /* identifiers */
986         ot->name= "Move Select";
987         ot->description= "Make selection from current cursor position to new cursor position type";
988         ot->idname= "FONT_OT_move_select";
989         
990         /* api callbacks */
991         ot->exec= move_select_exec;
992         ot->poll= ED_operator_editfont;
993
994         /* flags */
995         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
996
997         /* properties */
998         RNA_def_enum(ot->srna, "type", move_type_items, LINE_BEGIN, "Type", "Where to move cursor to, to make a selection.");
999 }
1000
1001 /************************* change spacing **********************/
1002
1003 static int change_spacing_exec(bContext *C, wmOperator *op)
1004 {
1005         Scene *scene= CTX_data_scene(C);
1006         Object *obedit= CTX_data_edit_object(C);
1007         Curve *cu= obedit->data;
1008         EditFont *ef= cu->editfont;
1009         int kern, delta= RNA_int_get(op->ptr, "delta");
1010
1011         kern = ef->textbufinfo[cu->pos-1].kern;
1012         kern += delta;
1013         CLAMP(kern, -20, 20);
1014
1015         if(ef->textbufinfo[cu->pos-1].kern == kern)
1016                 return OPERATOR_CANCELLED;
1017
1018         ef->textbufinfo[cu->pos-1].kern = kern;
1019
1020         text_update_edited(C, scene, obedit, 1, 0);
1021
1022         return OPERATOR_FINISHED;
1023 }
1024
1025 void FONT_OT_change_spacing(wmOperatorType *ot)
1026 {
1027         /* identifiers */
1028         ot->name= "Change Spacing";
1029         ot->description= "Change font spacing";
1030         ot->idname= "FONT_OT_change_spacing";
1031         
1032         /* api callbacks */
1033         ot->exec= change_spacing_exec;
1034         ot->poll= ED_operator_editfont;
1035
1036         /* flags */
1037         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1038
1039         /* properties */
1040         RNA_def_int(ot->srna, "delta", 1, -20, 20, "Delta", "Amount to decrease or increasing character spacing with.", -20, 20);
1041 }
1042
1043 /************************* change character **********************/
1044
1045 static int change_character_exec(bContext *C, wmOperator *op)
1046 {
1047         Scene *scene= CTX_data_scene(C);
1048         Object *obedit= CTX_data_edit_object(C);
1049         Curve *cu= obedit->data;
1050         EditFont *ef= cu->editfont;
1051         int character, delta= RNA_int_get(op->ptr, "delta");
1052
1053         if(cu->pos <= 0)
1054                 return OPERATOR_CANCELLED;
1055
1056         character= ef->textbuf[cu->pos - 1];
1057         character += delta;
1058         CLAMP(character, 0, 255);
1059
1060         if(character == ef->textbuf[cu->pos - 1])
1061                 return OPERATOR_CANCELLED;
1062
1063         ef->textbuf[cu->pos - 1]= character;
1064
1065         text_update_edited(C, scene, obedit, 1, 0);
1066
1067         return OPERATOR_FINISHED;
1068 }
1069
1070 void FONT_OT_change_character(wmOperatorType *ot)
1071 {
1072         /* identifiers */
1073         ot->name= "Change Character";
1074         ot->description= "Change font character code";
1075         ot->idname= "FONT_OT_change_character";
1076         
1077         /* api callbacks */
1078         ot->exec= change_character_exec;
1079         ot->poll= ED_operator_editfont;
1080
1081         /* flags */
1082         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1083
1084         /* properties */
1085         RNA_def_int(ot->srna, "delta", 1, -255, 255, "Delta", "Number to increase or decrease character code with.", -255, 255);
1086 }
1087
1088 /******************* line break operator ********************/
1089
1090 static int line_break_exec(bContext *C, wmOperator *op)
1091 {
1092         Scene *scene= CTX_data_scene(C);
1093         Object *obedit= CTX_data_edit_object(C);
1094         Curve *cu= obedit->data;
1095         EditFont *ef= cu->editfont;
1096         int ctrl= RNA_enum_get(op->ptr, "ctrl");
1097
1098         if(ctrl) {
1099                 insert_into_textbuf(obedit, 1);
1100                 if(ef->textbuf[cu->pos]!='\n')
1101                         insert_into_textbuf(obedit, '\n');
1102         }
1103         else
1104                 insert_into_textbuf(obedit, '\n');
1105
1106         cu->selstart = cu->selend = 0;
1107
1108         text_update_edited(C, scene, obedit, 1, 0);
1109
1110         return OPERATOR_FINISHED;
1111 }
1112
1113 void FONT_OT_line_break(wmOperatorType *ot)
1114 {
1115         /* identifiers */
1116         ot->name= "Line Break";
1117         ot->description= "Insert line break at cursor position";
1118         ot->idname= "FONT_OT_line_break";
1119         
1120         /* api callbacks */
1121         ot->exec= line_break_exec;
1122         ot->poll= ED_operator_editfont;
1123
1124         /* flags */
1125         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1126
1127         /* properties */
1128         RNA_def_boolean(ot->srna, "ctrl", 0, "Ctrl", ""); // XXX what is this?
1129 }
1130
1131 /******************* delete operator **********************/
1132
1133 static EnumPropertyItem delete_type_items[]= {
1134         {DEL_ALL, "ALL", 0, "All", ""},
1135         {DEL_NEXT_CHAR, "NEXT_CHARACTER", 0, "Next Character", ""},
1136         {DEL_PREV_CHAR, "PREVIOUS_CHARACTER", 0, "Previous Character", ""},
1137         {DEL_SELECTION, "SELECTION", 0, "Selection", ""},
1138         {DEL_NEXT_SEL, "NEXT_OR_SELECTION", 0, "Next or Selection", ""},
1139         {DEL_PREV_SEL, "PREVIOUS_OR_SELECTION", 0, "Previous or Selection", ""},
1140         {0, NULL, 0, NULL, NULL}};
1141
1142 static int delete_exec(bContext *C, wmOperator *op)
1143 {
1144         Scene *scene= CTX_data_scene(C);
1145         Object *obedit= CTX_data_edit_object(C);
1146         Curve *cu= obedit->data;
1147         EditFont *ef= cu->editfont;
1148         int x, selstart, selend, type= RNA_enum_get(op->ptr, "type");
1149
1150         if(cu->len == 0)
1151                 return OPERATOR_CANCELLED;
1152
1153         if(BKE_font_getselection(obedit, &selstart, &selend)) {
1154                 if(type == DEL_NEXT_SEL) type= DEL_SELECTION;
1155                 else if(type == DEL_PREV_SEL) type= DEL_SELECTION;
1156         }
1157         else {
1158                 if(type == DEL_NEXT_SEL) type= DEL_NEXT_CHAR;
1159                 else if(type == DEL_PREV_SEL) type= DEL_PREV_CHAR;
1160         }
1161
1162         switch(type) {
1163                 case DEL_ALL:
1164                         cu->len = cu->pos = 0;
1165                         ef->textbuf[0]= 0;
1166                         break;
1167                 case DEL_SELECTION:
1168                         if(!kill_selection(obedit, 0))
1169                                 return OPERATOR_CANCELLED;
1170                         break;
1171                 case DEL_PREV_CHAR:
1172                         if(cu->pos<=0)
1173                                 return OPERATOR_CANCELLED;
1174
1175                         for(x=cu->pos;x<=cu->len;x++)
1176                                 ef->textbuf[x-1]= ef->textbuf[x];
1177                         for(x=cu->pos;x<=cu->len;x++)
1178                                 ef->textbufinfo[x-1]= ef->textbufinfo[x];                                       
1179
1180                         cu->pos--;
1181                         ef->textbuf[--cu->len]='\0';
1182                         break;
1183                 case DEL_NEXT_CHAR:
1184                         if(cu->pos>=cu->len)
1185                                 return OPERATOR_CANCELLED;
1186
1187                         for(x=cu->pos;x<cu->len;x++)
1188                                 ef->textbuf[x]= ef->textbuf[x+1];
1189                         for(x=cu->pos;x<cu->len;x++)
1190                                 ef->textbufinfo[x]= ef->textbufinfo[x+1];                                       
1191
1192                         ef->textbuf[--cu->len]='\0';
1193                         break;
1194                 default:
1195                         return OPERATOR_CANCELLED;
1196         }
1197
1198         text_update_edited(C, scene, obedit, 1, 0);
1199
1200         return OPERATOR_FINISHED;
1201 }
1202
1203 void FONT_OT_delete(wmOperatorType *ot)
1204 {
1205         /* identifiers */
1206         ot->name= "Delete";
1207         ot->description= "Delete text by cursor position";
1208         ot->idname= "FONT_OT_delete";
1209         
1210         /* api callbacks */
1211         ot->exec= delete_exec;
1212         ot->poll= ED_operator_editfont;
1213
1214         /* flags */
1215         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1216
1217         /* properties */
1218         RNA_def_enum(ot->srna, "type", delete_type_items, DEL_ALL, "Type", "Which part of the text to delete.");
1219 }
1220
1221 /*********************** insert text operator *************************/
1222
1223 static int insert_text_exec(bContext *C, wmOperator *op)
1224 {
1225         Scene *scene= CTX_data_scene(C);
1226         Object *obedit= CTX_data_edit_object(C);
1227         char *inserted_utf8;
1228         wchar_t *inserted_text, first;
1229         int a, len;
1230
1231         if(!RNA_property_is_set(op->ptr, "text"))
1232                 return OPERATOR_CANCELLED;
1233         
1234         inserted_utf8= RNA_string_get_alloc(op->ptr, "text", NULL, 0);
1235         len= strlen(inserted_utf8);
1236
1237         inserted_text= MEM_callocN(sizeof(wchar_t)*(len+1), "FONT_insert_text");
1238         utf8towchar(inserted_text, inserted_utf8);
1239         first= inserted_text[0];
1240
1241         for(a=0; a<len; a++)
1242                 insert_into_textbuf(obedit, inserted_text[a]);
1243
1244         MEM_freeN(inserted_text);
1245         MEM_freeN(inserted_utf8);
1246
1247         kill_selection(obedit, 1);
1248         text_update_edited(C, scene, obedit, 1, 0);
1249
1250         return OPERATOR_FINISHED;
1251 }
1252
1253 static int insert_text_invoke(bContext *C, wmOperator *op, wmEvent *evt)
1254 {
1255         Scene *scene= CTX_data_scene(C);
1256         Object *obedit= CTX_data_edit_object(C);
1257         Curve *cu= obedit->data;
1258         EditFont *ef= cu->editfont;
1259         static int accentcode= 0;
1260         uintptr_t ascii = evt->ascii;
1261         int alt= evt->alt, shift= evt->shift, ctrl= evt->ctrl;
1262         int event= evt->type, val= evt->val;
1263         wchar_t inserted_text[2]= {0};
1264
1265         if(RNA_property_is_set(op->ptr, "text"))
1266                 return insert_text_exec(C, op);
1267         
1268         /* tab should exit editmode, but we allow it to be typed using modifier keys */
1269         if(event==TABKEY) {
1270                 if((alt||ctrl||shift) == 0)
1271                         return OPERATOR_PASS_THROUGH;
1272                 else
1273                         ascii= 9;
1274         }
1275         else if(event==BACKSPACEKEY)
1276                 ascii= 0;
1277
1278         if(val && ascii) {
1279                 /* handle case like TAB (== 9) */
1280                 if((ascii > 31 && ascii < 254 && ascii != 127) || (ascii==13) || (ascii==10) || (ascii==8)) {
1281                         if(accentcode) {
1282                                 if(cu->pos>0) {
1283                                         inserted_text[0]= findaccent(ef->textbuf[cu->pos-1], ascii);
1284                                         ef->textbuf[cu->pos-1]= inserted_text[0];
1285                                 }
1286                                 accentcode= 0;
1287                         }
1288                         else if(cu->len<MAXTEXT-1) {
1289                                 if(alt) {
1290                                         /* might become obsolete, apple has default values for this, other OS's too? */
1291                                         if(ascii=='t') ascii= 137;
1292                                         else if(ascii=='c') ascii= 169;
1293                                         else if(ascii=='f') ascii= 164;
1294                                         else if(ascii=='g') ascii= 176;
1295                                         else if(ascii=='l') ascii= 163;
1296                                         else if(ascii=='r') ascii= 174;
1297                                         else if(ascii=='s') ascii= 223;
1298                                         else if(ascii=='y') ascii= 165;
1299                                         else if(ascii=='.') ascii= 138;
1300                                         else if(ascii=='1') ascii= 185;
1301                                         else if(ascii=='2') ascii= 178;
1302                                         else if(ascii=='3') ascii= 179;
1303                                         else if(ascii=='%') ascii= 139;
1304                                         else if(ascii=='?') ascii= 191;
1305                                         else if(ascii=='!') ascii= 161;
1306                                         else if(ascii=='x') ascii= 215;
1307                                         else if(ascii=='>') ascii= 187;
1308                                         else if(ascii=='<') ascii= 171;
1309                                 }
1310
1311                                 inserted_text[0]= ascii;
1312                                 insert_into_textbuf(obedit, ascii);
1313                         }
1314                         
1315                         kill_selection(obedit, 1);
1316                         text_update_edited(C, scene, obedit, 1, 0);
1317                 }
1318                 else {
1319                         inserted_text[0]= ascii;
1320                         insert_into_textbuf(obedit, ascii);
1321                         text_update_edited(C, scene, obedit, 1, 0);
1322                 }
1323         }
1324         else if(val && event == BACKSPACEKEY) {
1325                 if(alt && cu->len!=0 && cu->pos>0)
1326                         accentcode= 1;
1327
1328                 return OPERATOR_PASS_THROUGH;
1329         }
1330         else
1331                 return OPERATOR_PASS_THROUGH;
1332
1333         if(inserted_text[0]) {
1334                 /* store as utf8 in RNA string */
1335                 char inserted_utf8[8] = {0};
1336
1337                 wcs2utf8s(inserted_utf8, inserted_text);
1338                 RNA_string_set(op->ptr, "text", inserted_utf8);
1339         }
1340
1341         return OPERATOR_FINISHED;
1342 }
1343
1344 void FONT_OT_text_insert(wmOperatorType *ot)
1345 {
1346         /* identifiers */
1347         ot->name= "Insert Text";
1348         ot->description= "Insert text at cursor position";
1349         ot->idname= "FONT_OT_text_insert";
1350         
1351         /* api callbacks */
1352         ot->exec= insert_text_exec;
1353         ot->invoke= insert_text_invoke;
1354         ot->poll= ED_operator_editfont;
1355         
1356         /* flags */
1357         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1358
1359         /* properties */
1360         RNA_def_string(ot->srna, "text", "", 0, "Text", "Text to insert at the cursor position.");
1361 }
1362
1363
1364 /*********************** textbox add operator *************************/
1365 static int textbox_poll(bContext *C)
1366 {
1367         Object *ob = CTX_data_active_object(C);
1368         
1369         if (!ED_operator_object_active_editable(C) ) return 0;
1370         if (ob->type != OB_FONT) return 0;
1371         
1372         return 1;
1373 }
1374
1375 static int textbox_add_exec(bContext *C, wmOperator *op)
1376 {
1377         Object *obedit= CTX_data_active_object(C);
1378         Curve *cu= obedit->data;
1379         int i;
1380         
1381         if (cu->totbox < 256) {
1382                 for (i = cu->totbox; i>cu->actbox; i--) cu->tb[i]= cu->tb[i-1];
1383                 cu->tb[cu->actbox]= cu->tb[cu->actbox-1];
1384                 cu->actbox++;
1385                 cu->totbox++;
1386         }
1387         
1388         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1389         return OPERATOR_FINISHED;
1390 }
1391
1392 void FONT_OT_textbox_add(wmOperatorType *ot)
1393 {
1394         /* identifiers */
1395         ot->name= "Add Textbox";
1396         ot->description= "Add a new text box";
1397         ot->idname= "FONT_OT_textbox_add";
1398         
1399         /* api callbacks */
1400         ot->exec= textbox_add_exec;
1401         ot->poll= textbox_poll;
1402         
1403         /* flags */
1404         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1405         
1406         
1407 }
1408
1409
1410
1411 /*********************** textbox remove operator *************************/
1412
1413
1414
1415 static int textbox_remove_exec(bContext *C, wmOperator *op)
1416 {
1417         Object *obedit= CTX_data_active_object(C);
1418         Curve *cu= obedit->data;
1419         int i;
1420         int index = RNA_int_get(op->ptr, "index");
1421         
1422         
1423         if (cu->totbox > 1) {
1424                 for (i = index; i < cu->totbox; i++) cu->tb[i]= cu->tb[i+1];
1425                 cu->totbox--;
1426                 if (cu->actbox >= index)
1427                         cu->actbox--;
1428         }
1429         
1430         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1431         
1432         return OPERATOR_FINISHED;
1433 }
1434
1435 void FONT_OT_textbox_remove(wmOperatorType *ot)
1436 {
1437         /* identifiers */
1438         ot->name= "Remove Textbox";
1439         ot->description= "Remove the textbox";
1440         ot->idname= "FONT_OT_textbox_remove";
1441         
1442         /* api callbacks */
1443         ot->exec= textbox_remove_exec;
1444         ot->poll= textbox_poll;
1445         
1446         /* flags */
1447         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1448         
1449         RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "The current text box.", 0, INT_MAX);
1450         
1451         
1452 }
1453
1454
1455
1456 /***************** editmode enter/exit ********************/
1457
1458 void make_editText(Object *obedit)
1459 {
1460         Curve *cu= obedit->data;
1461         EditFont *ef= cu->editfont;
1462         
1463         if(ef==NULL) {
1464                 ef= cu->editfont= MEM_callocN(sizeof(EditFont), "editfont");
1465         
1466                 ef->textbuf= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "texteditbuf");
1467                 ef->textbufinfo= MEM_callocN((MAXTEXT+4)*sizeof(CharInfo), "texteditbufinfo");
1468                 ef->copybuf= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "texteditcopybuf");
1469                 ef->copybufinfo= MEM_callocN((MAXTEXT+4)*sizeof(CharInfo), "texteditcopybufinfo");      
1470                 ef->oldstr= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "oldstrbuf");
1471                 ef->oldstrinfo= MEM_callocN((MAXTEXT+4)*sizeof(CharInfo), "oldstrbuf");
1472         }
1473         
1474         // Convert the original text to wchar_t
1475         utf8towchar(ef->textbuf, cu->str);
1476         wcscpy(ef->oldstr, ef->textbuf);
1477                 
1478         cu->len= wcslen(ef->textbuf);
1479         
1480         memcpy(ef->textbufinfo, cu->strinfo, (cu->len)*sizeof(CharInfo));
1481         memcpy(ef->oldstrinfo, cu->strinfo, (cu->len)*sizeof(CharInfo));
1482
1483         if(cu->pos>cu->len) cu->pos= cu->len;
1484
1485         if(cu->pos)
1486                 cu->curinfo = ef->textbufinfo[cu->pos-1];
1487         else
1488                 cu->curinfo = ef->textbufinfo[0];
1489         
1490         // Convert to UTF-8
1491         update_string(cu);
1492 }
1493
1494 void load_editText(Object *obedit)
1495 {
1496         Curve *cu= obedit->data;
1497         EditFont *ef= cu->editfont;
1498         
1499         MEM_freeN(ef->oldstr);
1500         ef->oldstr= NULL;
1501         MEM_freeN(ef->oldstrinfo);
1502         ef->oldstrinfo= NULL;
1503         
1504         update_string(cu);
1505         
1506         if(cu->strinfo)
1507                 MEM_freeN(cu->strinfo);
1508         cu->strinfo= MEM_callocN((cu->len+4)*sizeof(CharInfo), "texteditinfo");
1509         memcpy(cu->strinfo, ef->textbufinfo, (cu->len)*sizeof(CharInfo));
1510
1511         cu->len= strlen(cu->str);
1512         
1513         /* this memory system is weak... */
1514         
1515         if(cu->selboxes) {
1516                 MEM_freeN(cu->selboxes);
1517                 cu->selboxes= NULL;
1518         }
1519 }
1520
1521 void free_editText(Object *obedit)
1522 {
1523         BKE_free_editfont((Curve *)obedit->data);
1524 }
1525
1526 /********************** set case operator *********************/
1527
1528 static EnumPropertyItem case_items[]= {
1529         {CASE_LOWER, "LOWER", 0, "Lower", ""},
1530         {CASE_UPPER, "UPPER", 0, "Upper", ""},
1531         {0, NULL, 0, NULL, NULL}};
1532
1533 static int set_case(bContext *C, int ccase)
1534 {
1535         Scene *scene= CTX_data_scene(C);
1536         Object *obedit= CTX_data_edit_object(C);
1537         Curve *cu= obedit->data;
1538         EditFont *ef= cu->editfont;
1539         wchar_t *str;
1540         int len;
1541         
1542         len= wcslen(ef->textbuf);
1543         str= ef->textbuf;
1544         while(len) {
1545                 if(*str>='a' && *str<='z')
1546                         *str-= 32;
1547                 len--;
1548                 str++;
1549         }
1550         
1551         if(ccase == CASE_LOWER) {
1552                 len= wcslen(ef->textbuf);
1553                 str= ef->textbuf;
1554                 while(len) {
1555                         if(*str>='A' && *str<='Z') {
1556                                 *str+= 32;
1557                         }
1558                         len--;
1559                         str++;
1560                 }
1561         }
1562
1563         text_update_edited(C, scene, obedit, 1, 0);
1564
1565         return OPERATOR_FINISHED;
1566 }
1567
1568 static int set_case_exec(bContext *C, wmOperator *op)
1569 {
1570         return set_case(C, RNA_enum_get(op->ptr, "case"));
1571 }
1572
1573 void FONT_OT_case_set(wmOperatorType *ot)
1574 {
1575         /* identifiers */
1576         ot->name= "Set Case";
1577         ot->description= "Set font case";
1578         ot->idname= "FONT_OT_case_set";
1579         
1580         /* api callbacks */
1581         ot->exec= set_case_exec;
1582         ot->poll= ED_operator_editfont;
1583
1584         /* flags */
1585         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1586
1587         /* properties */
1588         RNA_def_enum(ot->srna, "case", case_items, CASE_LOWER, "Case", "Lower or upper case.");
1589 }
1590
1591 /********************** toggle case operator *********************/
1592
1593 static int toggle_case_exec(bContext *C, wmOperator *op)
1594 {
1595         Object *obedit= CTX_data_edit_object(C);
1596         Curve *cu= obedit->data;
1597         EditFont *ef= cu->editfont;
1598         wchar_t *str;
1599         int len, ccase= CASE_UPPER;
1600         
1601         len= wcslen(ef->textbuf);
1602         str= ef->textbuf;
1603         while(len) {
1604                 if(*str>='a' && *str<='z') {
1605                         ccase= CASE_LOWER;
1606                         break;
1607                 }
1608
1609                 len--;
1610                 str++;
1611         }
1612         
1613         return set_case(C, ccase);
1614 }
1615
1616 void FONT_OT_case_toggle(wmOperatorType *ot)
1617 {
1618         /* identifiers */
1619         ot->name= "Toggle Case";
1620         ot->description= "Toggle font case";
1621         ot->idname= "FONT_OT_case_toggle";
1622         
1623         /* api callbacks */
1624         ot->exec= toggle_case_exec;
1625         ot->poll= ED_operator_editfont;
1626
1627         /* flags */
1628         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1629 }
1630
1631 /* **************** Open Font ************** */
1632
1633 static void open_init(bContext *C, wmOperator *op)
1634 {
1635         PropertyPointerRNA *pprop;
1636         
1637         op->customdata= pprop= MEM_callocN(sizeof(PropertyPointerRNA), "OpenPropertyPointerRNA");
1638         uiIDContextProperty(C, &pprop->ptr, &pprop->prop);
1639 }
1640
1641 static int open_cancel(bContext *C, wmOperator *op)
1642 {
1643         MEM_freeN(op->customdata);
1644         op->customdata= NULL;
1645         return OPERATOR_CANCELLED;
1646 }
1647
1648 static int open_exec(bContext *C, wmOperator *op)
1649 {
1650         Object *ob = CTX_data_active_object(C);
1651         Curve *cu;
1652         VFont *font;
1653         PropertyPointerRNA *pprop;
1654         PointerRNA idptr;
1655         char str[FILE_MAX];
1656         
1657         RNA_string_get(op->ptr, "filepath", str);
1658
1659         font = load_vfont(str);
1660         
1661         if(!font) {
1662                 if(op->customdata) MEM_freeN(op->customdata);
1663                 return OPERATOR_CANCELLED;
1664         }
1665         
1666         if(!op->customdata)
1667                 open_init(C, op);
1668         
1669         /* hook into UI */
1670         pprop= op->customdata;
1671         
1672         if(pprop->prop) {
1673                 /* when creating new ID blocks, use is already 1, but RNA
1674                  * pointer se also increases user, so this compensates it */
1675                 font->id.us--;
1676                 
1677                 RNA_id_pointer_create(&font->id, &idptr);
1678                 RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr);
1679                 RNA_property_update(C, &pprop->ptr, pprop->prop);
1680         } else if(ob && ob->type == OB_FONT) {
1681                 cu = ob->data;
1682                 id_us_min(&cu->vfont->id);
1683                 cu->vfont = font;
1684         }
1685         
1686         DAG_id_flush_update(ob->data, OB_RECALC_DATA);
1687         WM_event_add_notifier(C, NC_GEOM|ND_DATA|NA_EDITED, ob->data);
1688         
1689         MEM_freeN(op->customdata);
1690         
1691         return OPERATOR_FINISHED;
1692 }
1693
1694 static int open_invoke(bContext *C, wmOperator *op, wmEvent *event)
1695 {
1696         Object *ob = CTX_data_active_object(C);
1697         Curve *cu;
1698         VFont *font=NULL;
1699         char *path;
1700         if (ob && ob->type == OB_FONT) {
1701                 cu = ob->data;
1702                 font = cu->vfont;
1703         }
1704         path = (font && font->name)? font->name: U.fontdir;
1705          
1706         if(RNA_property_is_set(op->ptr, "filepath"))
1707                 return open_exec(C, op);
1708         
1709         open_init(C, op);
1710         
1711         RNA_string_set(op->ptr, "filepath", path);
1712         WM_event_add_fileselect(C, op); 
1713
1714         return OPERATOR_RUNNING_MODAL;
1715 }
1716
1717 void FONT_OT_open(wmOperatorType *ot)
1718 {
1719         /* identifiers */
1720         ot->name= "Open";
1721         ot->idname= "FONT_OT_open";
1722         
1723         /* api callbacks */
1724         ot->exec= open_exec;
1725         ot->invoke= open_invoke;
1726         ot->cancel= open_cancel;
1727         
1728         /* flags */
1729         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1730         
1731         /* properties */
1732         WM_operator_properties_filesel(ot, FOLDERFILE|FTFONTFILE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH);
1733 }
1734
1735 /******************* delete operator *********************/
1736 static int font_unlink_poll(bContext *C)
1737 {
1738         Object *ob = CTX_data_active_object(C);
1739         Curve *cu;
1740         
1741         if (!ED_operator_object_active_editable(C) ) return 0;
1742         if (ob->type != OB_FONT) return 0;
1743         
1744         cu = ob->data;
1745         if (cu && strcmp(cu->vfont->name, "<builtin>")==0) return 0;
1746         return 1;
1747 }
1748
1749 static int font_unlink_exec(bContext *C, wmOperator *op)
1750 {
1751         Object *ob = CTX_data_active_object(C);
1752         Curve *cu;
1753         VFont *font, *builtin_font;
1754                 
1755         cu = ob->data;
1756         font = cu->vfont;
1757         
1758         if (!font) {
1759                 BKE_report(op->reports, RPT_ERROR, "No font datablock available to unlink.");
1760                 return OPERATOR_CANCELLED;
1761         }
1762         
1763         if (strcmp(font->name, "<builtin>")==0) {
1764                 BKE_report(op->reports, RPT_WARNING, "Can't unlink the default builtin font.");
1765                 return OPERATOR_FINISHED;
1766         }
1767
1768         /* revert back to builtin font */
1769         builtin_font = get_builtin_font();
1770
1771         cu->vfont = builtin_font;
1772         id_us_plus(&cu->vfont->id);
1773         id_us_min(&font->id);
1774         
1775         DAG_id_flush_update(ob->data, OB_RECALC_DATA);
1776         WM_event_add_notifier(C, NC_GEOM|ND_DATA|NA_EDITED, ob->data);
1777         
1778         return OPERATOR_FINISHED;
1779 }
1780
1781 void FONT_OT_unlink(wmOperatorType *ot)
1782 {
1783         /* identifiers */
1784         ot->name= "Unlink";
1785         ot->idname= "FONT_OT_unlink";
1786         ot->description= "Unlink active font data block";
1787         
1788         /* api callbacks */
1789         ot->exec= font_unlink_exec;
1790         ot->poll= font_unlink_poll;
1791 }
1792
1793
1794 /* **************** undo for font object ************** */
1795
1796 static void undoFont_to_editFont(void *strv, void *ecu)
1797 {
1798         Curve *cu= (Curve *)ecu;
1799         EditFont *ef= cu->editfont;
1800         char *str= strv;
1801
1802         cu->pos= *((short *)str);
1803         cu->len= *((short *)(str+2));
1804
1805         memcpy(ef->textbuf, str+4, (cu->len+1)*sizeof(wchar_t));
1806         memcpy(ef->textbufinfo, str+4 + (cu->len+1)*sizeof(wchar_t), cu->len*sizeof(CharInfo));
1807         
1808         cu->selstart = cu->selend = 0;
1809         
1810         update_string(cu);
1811 }
1812
1813 static void *editFont_to_undoFont(void *ecu)
1814 {
1815         Curve *cu= (Curve *)ecu;
1816         EditFont *ef= cu->editfont;
1817         char *str;
1818         
1819         // The undo buffer includes [MAXTEXT+6]=actual string and [MAXTEXT+4]*sizeof(CharInfo)=charinfo
1820         str= MEM_callocN((MAXTEXT+6)*sizeof(wchar_t) + (MAXTEXT+4)*sizeof(CharInfo), "string undo");
1821
1822         // Copy the string and string information
1823         memcpy(str+4, ef->textbuf, (cu->len+1)*sizeof(wchar_t));
1824         memcpy(str+4 + (cu->len+1)*sizeof(wchar_t), ef->textbufinfo, cu->len*sizeof(CharInfo));
1825
1826         *((short *)str)= cu->pos;
1827         *((short *)(str+2))= cu->len;   
1828         
1829         return str;
1830 }
1831
1832 static void free_undoFont(void *strv)
1833 {
1834         MEM_freeN(strv);
1835 }
1836
1837 static void *get_undoFont(bContext *C)
1838 {
1839         Object *obedit= CTX_data_edit_object(C);
1840         if(obedit && obedit->type==OB_FONT) {
1841                 return obedit->data;
1842         }
1843         return NULL;
1844 }
1845
1846 /* and this is all the undo system needs to know */
1847 void undo_push_font(bContext *C, char *name)
1848 {
1849         undo_editmode_push(C, name, get_undoFont, free_undoFont, undoFont_to_editFont, editFont_to_undoFont, NULL);
1850 }