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