2.5: Text edit mode operators back. Took me a while getting
[blender-staging.git] / source / blender / editors / curve / editfont.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <wchar.h>
32
33 #ifndef WIN32 
34 #include <unistd.h>
35 #else
36 #include <io.h>
37 #endif
38
39 #include "MEM_guardedalloc.h"
40
41 #include "BLI_blenlib.h"
42 #include "BLI_arithb.h"
43
44 #include "DNA_curve_types.h"
45 #include "DNA_object_types.h"
46 #include "DNA_vfont_types.h"
47 #include "DNA_scene_types.h"
48 #include "DNA_text_types.h"
49 #include "DNA_view3d_types.h"
50 #include "DNA_userdef_types.h"
51
52 #include "BKE_context.h"
53 #include "BKE_curve.h"
54 #include "BKE_depsgraph.h"
55 #include "BKE_font.h"
56 #include "BKE_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, unsigned long 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_paste_file(wmOperatorType *ot)
405 {
406         /* identifiers */
407         ot->name= "Paste File";
408         ot->idname= "FONT_OT_paste_file";
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_paste_buffer(wmOperatorType *ot)
453 {
454         /* identifiers */
455         ot->name= "Paste Buffer";
456         ot->idname= "FONT_OT_paste_buffer";
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 /******************* XXX text to object operator ********************/
467
468 static void txt_export_to_object(Scene *scene, Object *obedit, Text *text)
469 {
470         ID *id;
471         Curve *cu;
472         struct TextLine *tmp;
473         int nchars = 0;
474 //      char sdir[FILE_MAXDIR];
475 //      char sfile[FILE_MAXFILE];
476
477         if(!text || !text->lines.first) return;
478
479         id = (ID *)text;
480
481         if(obedit && obedit->type==OB_FONT) return;
482 // XXX  check_editmode(OB_FONT);
483         
484         add_object(scene, OB_FONT);
485
486         ED_object_base_init_from_view(NULL, BASACT); // XXX
487         obedit= BASACT->object;
488         where_is_object(scene, obedit);
489
490         cu= obedit->data;
491
492 /*      
493 //              renames object, careful with long filenames.
494
495         if(text->name) {
496         //ID *find_id(char *type, char *name)   
497                 BLI_split_dirfile(text->name, sdir, sfile);
498 //              rename_id((ID *)obedit, sfile);
499                 rename_id((ID *)cu, sfile);
500                 id->us++;
501         }
502 */      
503         cu->vfont= get_builtin_font();
504         cu->vfont->id.us++;
505
506         tmp= text->lines.first;
507         while(cu->len<MAXTEXT && tmp) {
508                 nchars += strlen(tmp->line) + 1;
509                 tmp = tmp->next;
510         }
511
512         if(cu->str) MEM_freeN(cu->str);
513         if(cu->strinfo) MEM_freeN(cu->strinfo); 
514
515         cu->str= MEM_mallocN(nchars+4, "str");
516         cu->strinfo= MEM_callocN((nchars+4)*sizeof(CharInfo), "strinfo");
517         cu->totbox= cu->actbox= 1;
518         cu->tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "textbox");
519         cu->tb[0].w = cu->tb[0].h = 0.0;
520         
521         tmp= text->lines.first;
522         strcpy(cu->str, tmp->line);
523         cu->len= strlen(tmp->line);
524         cu->pos= cu->len;
525
526         tmp= tmp->next;
527
528         while(cu->len<MAXTEXT && tmp) {
529                 strcat(cu->str, "\n");
530                 strcat(cu->str, tmp->line);
531                 cu->len+= strlen(tmp->line) + 1;
532                 cu->pos= cu->len;
533                 tmp= tmp->next;
534         }
535
536         make_editText(obedit);
537         ED_object_exit_editmode(NULL, EM_FREEDATA|EM_WAITCURSOR); // XXX
538 }
539
540 static void txt_export_to_objects(Scene *scene, Object *obedit, Text *text)
541 {
542         RegionView3D *rv3d= NULL; // XXX
543         ID *id;
544         Curve *cu;
545         struct TextLine *curline;
546         int nchars;
547         int linenum = 0;
548         float offset[3] = {0.0,0.0,0.0};
549
550         if(!text || !text->lines.first) return;
551
552         id = (ID *)text;
553
554         if(obedit && obedit->type==OB_FONT) return;
555 // XXX  check_editmode(OB_FONT);
556
557         curline = text->lines.first;
558         while(curline){ 
559                 /*skip lines with no text, but still make space for them*/
560                 if(curline->line[0] == '\0'){
561                         linenum++;
562                         curline = curline->next;
563                         continue;
564                 }
565                         
566                 nchars = 0;     
567                 add_object(scene, OB_FONT);
568         
569                 ED_object_base_init_from_view(NULL, BASACT); // XXX
570                 obedit= BASACT->object;
571                 where_is_object(scene, obedit); 
572                 
573                 /* Do the translation */
574                 offset[0] = 0;
575                 offset[1] = -linenum;
576                 offset[2] = 0;
577         
578                 Mat4Mul3Vecfl(rv3d->viewinv, offset);
579                 
580                 obedit->loc[0] += offset[0];
581                 obedit->loc[1] += offset[1];
582                 obedit->loc[2] += offset[2];
583                 /* End Translation */
584                                         
585                 cu= obedit->data;
586                 
587                 cu->vfont= get_builtin_font();
588                 cu->vfont->id.us++;
589         
590                 nchars = strlen(curline->line) + 1;
591         
592                 if(cu->str) MEM_freeN(cu->str);
593                 if(cu->strinfo) MEM_freeN(cu->strinfo);         
594         
595                 cu->str= MEM_mallocN(nchars+4, "str");
596                 cu->strinfo= MEM_callocN((nchars+4)*sizeof(CharInfo), "strinfo");
597                 cu->totbox= cu->actbox= 1;
598                 cu->tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "textbox");
599                 cu->tb[0].w = cu->tb[0].h = 0.0;
600                 
601                 strcpy(cu->str, curline->line);
602                 cu->len= strlen(curline->line);
603                 cu->pos= cu->len;
604
605                 make_editText(obedit);
606                 ED_object_exit_editmode(NULL, EM_FREEDATA|EM_WAITCURSOR); // XXX
607
608                 linenum++;
609                 curline = curline->next;
610         }
611 }
612
613 static int text_to_object_exec(bContext *C, wmOperator *op)
614 {
615         Scene *scene= CTX_data_scene(C);
616         Object *obedit= CTX_data_edit_object(C);
617         Text *text= NULL; /// XXX retrieve this ..
618
619         if(RNA_boolean_get(op->ptr, "split_lines"))
620                 txt_export_to_objects(scene, obedit, text);
621         else
622                 txt_export_to_object(scene, obedit, text);
623
624         return OPERATOR_FINISHED;
625 }
626
627 void FONT_OT_text_to_object(wmOperatorType *ot)
628 {
629         /* identifiers */
630         ot->name= "Text to Object";
631         ot->idname= "FONT_OT_text_to_object";
632         
633         /* api callbacks */
634         ot->exec= text_to_object_exec;
635         ot->poll= ED_operator_editfont; // XXX not correct
636         
637         /* flags */
638         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
639
640         /* properties */
641         RNA_def_boolean(ot->srna, "split_lines", 0, "Split Lines", "Create one object per line in the text.");
642 }
643
644 /********************** utilities ***************************/
645
646 static short next_word(Curve *cu)
647 {
648         short s;
649         for(s=cu->pos; (cu->str[s]) && (cu->str[s]!=' ') && (cu->str[s]!='\n') &&
650                         (cu->str[s]!=1) && (cu->str[s]!='\r'); s++);
651         if(cu->str[s]) return(s+1); else return(s);
652 }
653
654 static short prev_word(Curve *cu)
655 {
656         short s;
657         
658         if(cu->pos==0) return(0);
659         for(s=cu->pos-2; (cu->str[s]) && (cu->str[s]!=' ') && (cu->str[s]!='\n') &&
660                         (cu->str[s]!=1) && (cu->str[s]!='\r'); s--);
661         if(cu->str[s]) return(s+1); else return(s);
662 }
663
664 static int kill_selection(Object *obedit, int ins)      /* 1 == new character */
665 {
666         Curve *cu= obedit->data;
667         EditFont *ef= cu->editfont;
668         int selend, selstart, direction;
669         int offset = 0;
670         int getfrom;
671
672         direction = BKE_font_getselection(obedit, &selstart, &selend);
673         if(direction) {
674                 int size;
675                 if(ins) offset = 1;
676                 if(cu->pos >= selstart) cu->pos = selstart+offset;
677                 if((direction == -1) && ins) {
678                         selstart++;
679                         selend++;
680                 }
681                 getfrom = selend+offset;
682                 if(ins==0) getfrom++;
683                 size = (cu->len * sizeof(wchar_t)) - (selstart * sizeof(wchar_t)) + (offset*sizeof(wchar_t));
684                 memmove(ef->textbuf+selstart, ef->textbuf+getfrom, size);
685                 memmove(ef->textbufinfo+selstart, ef->textbufinfo+getfrom, ((cu->len-selstart)+offset)*sizeof(CharInfo));
686                 cu->len -= (selend-selstart)+offset;
687                 cu->selstart = cu->selend = 0;
688         }
689
690         return(direction);
691 }
692
693 /******************* set style operator ********************/
694
695 static EnumPropertyItem style_items[]= {
696         {CU_BOLD, "BOLD", "Bold", ""},
697         {CU_ITALIC, "ITALIC", "Italic", ""},
698         {CU_UNDERLINE, "UNDERLINE", "Underline", ""},
699         {0, NULL, NULL, NULL}};
700
701 static int set_style(bContext *C, int style, int clear)
702 {
703         Scene *scene= CTX_data_scene(C);
704         Object *obedit= CTX_data_edit_object(C);
705         Curve *cu= obedit->data;
706         EditFont *ef= cu->editfont;
707         int i, selstart, selend;
708
709         if(!BKE_font_getselection(obedit, &selstart, &selend))
710                 return OPERATOR_CANCELLED;
711
712         for(i=selstart; i<=selend; i++) {
713                 if(clear)
714                         ef->textbufinfo[i].flag &= ~style;
715                 else
716                         ef->textbufinfo[i].flag |= style;
717         }
718
719         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
720         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
721
722         return OPERATOR_FINISHED;
723 }
724
725 static int set_style_exec(bContext *C, wmOperator *op)
726 {
727         int style, clear;
728
729         style= RNA_enum_get(op->ptr, "style");
730         clear= RNA_enum_get(op->ptr, "clear");
731
732         return set_style(C, style, clear);
733 }
734
735 void FONT_OT_set_style(wmOperatorType *ot)
736 {
737         /* identifiers */
738         ot->name= "Set Style";
739         ot->idname= "FONT_OT_set_style";
740         
741         /* api callbacks */
742         ot->exec= set_style_exec;
743         ot->poll= ED_operator_editfont;
744         
745         /* flags */
746         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
747
748         /* properties */
749         RNA_def_enum(ot->srna, "style", style_items, CU_BOLD, "Style", "Style to set selection to.");
750         RNA_def_boolean(ot->srna, "clear", 0, "Clear", "Clear style rather than setting it.");
751 }
752
753 /******************* toggle style operator ********************/
754
755 static int toggle_style_exec(bContext *C, wmOperator *op)
756 {
757         Object *obedit= CTX_data_edit_object(C);
758         Curve *cu= obedit->data;
759         int style, clear, selstart, selend;
760
761         if(!BKE_font_getselection(obedit, &selstart, &selend))
762                 return OPERATOR_CANCELLED;
763         
764         style= RNA_enum_get(op->ptr, "style");
765
766         cu->curinfo.flag ^= style;
767         clear= (cu->curinfo.flag & style) == 0;
768
769         return set_style(C, style, clear);
770 }
771
772 void FONT_OT_toggle_style(wmOperatorType *ot)
773 {
774         /* identifiers */
775         ot->name= "Toggle Style";
776         ot->idname= "FONT_OT_toggle_style";
777         
778         /* api callbacks */
779         ot->exec= toggle_style_exec;
780         ot->poll= ED_operator_editfont;
781         
782         /* flags */
783         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
784
785         /* properties */
786         RNA_def_enum(ot->srna, "style", style_items, CU_BOLD, "Style", "Style to set selection to.");
787 }
788
789 /******************* set material operator ********************/
790
791 static int set_material_exec(bContext *C, wmOperator *op)
792 {
793         Scene *scene= CTX_data_scene(C);
794         Object *obedit= CTX_data_edit_object(C);
795         Curve *cu= obedit->data;
796         EditFont *ef= cu->editfont;
797         int i, mat_nr, selstart, selend;
798
799         if(!BKE_font_getselection(obedit, &selstart, &selend))
800                 return OPERATOR_CANCELLED;
801
802         if(RNA_property_is_set(op->ptr, "index"))
803                 mat_nr= RNA_int_get(op->ptr, "index");
804         else
805                 mat_nr= obedit->actcol;
806
807         for(i=selstart; i<=selend; i++)
808                 ef->textbufinfo[i].mat_nr = mat_nr;
809
810         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
811         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
812
813         return OPERATOR_FINISHED;
814 }
815
816 void FONT_OT_set_material(wmOperatorType *ot)
817 {
818         /* identifiers */
819         ot->name= "Set Material";
820         ot->idname= "FONT_OT_set_material";
821         
822         /* api callbacks */
823         ot->exec= set_material_exec;
824         ot->poll= ED_operator_editfont;
825         
826         /* flags */
827         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
828
829         /* properties */
830         RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Material Index", "Material slot index.", 0, INT_MAX);
831 }
832
833 /******************* copy text operator ********************/
834
835 static void copy_selection(Object *obedit)
836 {
837         int selstart, selend;
838         
839         if(BKE_font_getselection(obedit, &selstart, &selend)) {
840                 Curve *cu= obedit->data;
841                 EditFont *ef= cu->editfont;
842                 
843                 memcpy(ef->copybuf, ef->textbuf+selstart, ((selend-selstart)+1)*sizeof(wchar_t));
844                 ef->copybuf[(selend-selstart)+1]=0;
845                 memcpy(ef->copybufinfo, ef->textbufinfo+selstart, ((selend-selstart)+1)*sizeof(CharInfo));      
846         }
847 }
848
849 static int copy_text_exec(bContext *C, wmOperator *op)
850 {
851         Object *obedit= CTX_data_edit_object(C);
852
853         copy_selection(obedit);
854
855         return OPERATOR_FINISHED;
856 }
857
858 void FONT_OT_copy_text(wmOperatorType *ot)
859 {
860         /* identifiers */
861         ot->name= "Copy Text";
862         ot->idname= "FONT_OT_copy_text";
863         
864         /* api callbacks */
865         ot->exec= copy_text_exec;
866         ot->poll= ED_operator_editfont;
867 }
868
869 /******************* cut text operator ********************/
870
871 static int cut_text_exec(bContext *C, wmOperator *op)
872 {
873         Scene *scene= CTX_data_scene(C);
874         Object *obedit= CTX_data_edit_object(C);
875         int selstart, selend;
876
877         if(!BKE_font_getselection(obedit, &selstart, &selend))
878                 return OPERATOR_CANCELLED;
879
880         copy_selection(obedit);
881         kill_selection(obedit, 0);
882
883         text_update_edited(C, scene, obedit, 1, 0);
884
885         return OPERATOR_FINISHED;
886 }
887
888 void FONT_OT_cut_text(wmOperatorType *ot)
889 {
890         /* identifiers */
891         ot->name= "Cut Text";
892         ot->idname= "FONT_OT_cut_text";
893         
894         /* api callbacks */
895         ot->exec= cut_text_exec;
896         ot->poll= ED_operator_editfont;
897
898         /* flags */
899         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
900 }
901
902 /******************* paste text operator ********************/
903
904 static int paste_selection(Object *obedit, ReportList *reports)
905 {
906         Curve *cu= obedit->data;
907         EditFont *ef= cu->editfont;
908         int len= wcslen(ef->copybuf);
909
910         // Verify that the copy buffer => [copy buffer len] + cu->len < MAXTEXT
911         if(cu->len + len <= MAXTEXT) {
912                 if(len) {       
913                         int size = (cu->len * sizeof(wchar_t)) - (cu->pos*sizeof(wchar_t)) + sizeof(wchar_t);
914                         memmove(ef->textbuf+cu->pos+len, ef->textbuf+cu->pos, size);
915                         memcpy(ef->textbuf+cu->pos, ef->copybuf, len * sizeof(wchar_t));
916                 
917                         memmove(ef->textbufinfo+cu->pos+len, ef->textbufinfo+cu->pos, (cu->len-cu->pos+1)*sizeof(CharInfo));
918                         memcpy(ef->textbufinfo+cu->pos, ef->copybufinfo, len*sizeof(CharInfo)); 
919                 
920                         cu->len += len;
921                         cu->pos += len;
922
923                         return 1;
924                 }
925         }
926         else
927                 BKE_report(reports, RPT_WARNING, "Text too long.");
928         
929         return 0;
930 }
931
932 static int paste_text_exec(bContext *C, wmOperator *op)
933 {
934         Scene *scene= CTX_data_scene(C);
935         Object *obedit= CTX_data_edit_object(C);
936
937         if(!paste_selection(obedit, op->reports))
938                 return OPERATOR_CANCELLED;
939
940         text_update_edited(C, scene, obedit, 1, 0);
941
942         return OPERATOR_FINISHED;
943 }
944
945 void FONT_OT_paste_text(wmOperatorType *ot)
946 {
947         /* identifiers */
948         ot->name= "Paste Text";
949         ot->idname= "FONT_OT_paste_text";
950         
951         /* api callbacks */
952         ot->exec= paste_text_exec;
953         ot->poll= ED_operator_editfont;
954
955         /* flags */
956         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
957 }
958
959 /************************ move operator ************************/
960
961 static EnumPropertyItem move_type_items[]= {
962         {LINE_BEGIN, "LINE_BEGIN", "Line Begin", ""},
963         {LINE_END, "LINE_END", "Line End", ""},
964         {PREV_CHAR, "PREVIOUS_CHARACTER", "Previous Character", ""},
965         {NEXT_CHAR, "NEXT_CHARACTER", "Next Character", ""},
966         {PREV_WORD, "PREVIOUS_WORD", "Previous Word", ""},
967         {NEXT_WORD, "NEXT_WORD", "Next Word", ""},
968         {PREV_LINE, "PREVIOUS_LINE", "Previous Line", ""},
969         {NEXT_LINE, "NEXT_LINE", "Next Line", ""},
970         {PREV_PAGE, "PREVIOUS_PAGE", "Previous Page", ""},
971         {NEXT_PAGE, "NEXT_PAGE", "Next Page", ""},
972         {0, NULL, NULL, NULL}};
973
974 static int move_cursor(bContext *C, int type, int select)
975 {
976         Scene *scene= CTX_data_scene(C);
977         Object *obedit= CTX_data_edit_object(C);
978         Curve *cu= obedit->data;
979         EditFont *ef= cu->editfont;
980         int cursmove= 0;
981
982         switch(type) {
983                 case LINE_BEGIN:
984                         if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
985                         while(cu->pos>0) {
986                                 if(ef->textbuf[cu->pos-1]=='\n') break;
987                                 if(ef->textbufinfo[cu->pos-1].flag & CU_WRAP ) break;                           
988                                 cu->pos--;
989                         }               
990                         cursmove=FO_CURS;
991                         break;
992                         
993                 case LINE_END:
994                         if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;                
995                         while(cu->pos<cu->len) {
996                                 if(ef->textbuf[cu->pos]==0) break;
997                                 if(ef->textbuf[cu->pos]=='\n') break;
998                                 if(ef->textbufinfo[cu->pos].flag & CU_WRAP ) break;
999                                 cu->pos++;
1000                         }
1001                         cursmove=FO_CURS;
1002                         break;
1003
1004                 case PREV_WORD:
1005                         if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
1006                         cu->pos= prev_word(cu);
1007                         cursmove= FO_CURS;
1008                         break;
1009
1010                 case NEXT_WORD:
1011                         if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
1012                         cu->pos= next_word(cu);
1013                         cursmove= FO_CURS;                              
1014                         break;
1015
1016                 case PREV_CHAR:
1017                         if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
1018                         cu->pos--;
1019                         cursmove=FO_CURS;
1020                         break;
1021
1022                 case NEXT_CHAR: 
1023                         if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
1024                         cu->pos++;
1025                         cursmove= FO_CURS;                              
1026
1027                         break;
1028
1029                 case PREV_LINE:
1030                         if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
1031                         cursmove=FO_CURSUP;
1032                         break;
1033                         
1034                 case NEXT_LINE:
1035                         if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
1036                         cursmove= FO_CURSDOWN;
1037                         break;
1038
1039                 case PREV_PAGE:
1040                         if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
1041                         cursmove=FO_PAGEUP;
1042                         break;
1043
1044                 case NEXT_PAGE:
1045                         if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
1046                         cursmove=FO_PAGEDOWN;
1047                         break;
1048         }
1049                 
1050         if(!cursmove)
1051                 return OPERATOR_CANCELLED;
1052
1053         if(select == 0) {
1054                 if(cu->selstart) {
1055                         cu->selstart = cu->selend = 0;
1056                         update_string(cu);
1057                         BKE_text_to_curve(scene, obedit, FO_SELCHANGE);
1058                 }
1059         }
1060
1061         if(cu->pos>cu->len) cu->pos= cu->len;
1062         else if(cu->pos>=MAXTEXT) cu->pos= MAXTEXT;
1063         else if(cu->pos<0) cu->pos= 0;
1064
1065         text_update_edited(C, scene, obedit, select, cursmove);
1066
1067         if(select)
1068                 cu->selend = cu->pos;
1069
1070         return OPERATOR_FINISHED;
1071 }
1072
1073 static int move_exec(bContext *C, wmOperator *op)
1074 {
1075         int type= RNA_enum_get(op->ptr, "type");
1076
1077         return move_cursor(C, type, 0);
1078 }
1079
1080 void FONT_OT_move(wmOperatorType *ot)
1081 {
1082         /* identifiers */
1083         ot->name= "Move Cursor";
1084         ot->idname= "FONT_OT_move";
1085         
1086         /* api callbacks */
1087         ot->exec= move_exec;
1088         ot->poll= ED_operator_editfont;
1089
1090         /* flags */
1091         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1092
1093         /* properties */
1094         RNA_def_enum(ot->srna, "type", move_type_items, LINE_BEGIN, "Type", "Where to move cursor to.");
1095 }
1096
1097 /******************* move select operator ********************/
1098
1099 static int move_select_exec(bContext *C, wmOperator *op)
1100 {
1101         int type= RNA_enum_get(op->ptr, "type");
1102
1103         return move_cursor(C, type, 1);
1104 }
1105
1106 void FONT_OT_move_select(wmOperatorType *ot)
1107 {
1108         /* identifiers */
1109         ot->name= "Move Select";
1110         ot->idname= "FONT_OT_move_select";
1111         
1112         /* api callbacks */
1113         ot->exec= move_select_exec;
1114         ot->poll= ED_operator_editfont;
1115
1116         /* flags */
1117         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1118
1119         /* properties */
1120         RNA_def_enum(ot->srna, "type", move_type_items, LINE_BEGIN, "Type", "Where to move cursor to, to make a selection.");
1121 }
1122
1123 /************************* change spacing **********************/
1124
1125 static int change_spacing_exec(bContext *C, wmOperator *op)
1126 {
1127         Scene *scene= CTX_data_scene(C);
1128         Object *obedit= CTX_data_edit_object(C);
1129         Curve *cu= obedit->data;
1130         EditFont *ef= cu->editfont;
1131         int kern, delta= RNA_int_get(op->ptr, "delta");
1132
1133         kern = ef->textbufinfo[cu->pos-1].kern;
1134         kern += delta;
1135         CLAMP(kern, -20, 20);
1136
1137         if(ef->textbufinfo[cu->pos-1].kern == kern)
1138                 return OPERATOR_CANCELLED;
1139
1140         ef->textbufinfo[cu->pos-1].kern = kern;
1141
1142         text_update_edited(C, scene, obedit, 1, 0);
1143
1144         return OPERATOR_FINISHED;
1145 }
1146
1147 void FONT_OT_change_spacing(wmOperatorType *ot)
1148 {
1149         /* identifiers */
1150         ot->name= "Change Spacing";
1151         ot->idname= "FONT_OT_change_spacing";
1152         
1153         /* api callbacks */
1154         ot->exec= change_spacing_exec;
1155         ot->poll= ED_operator_editfont;
1156
1157         /* flags */
1158         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1159
1160         /* properties */
1161         RNA_def_int(ot->srna, "delta", 1, -20, 20, "Delta", "Amount to decrease or increasing character spacing with.", -20, 20);
1162 }
1163
1164 /************************* change character **********************/
1165
1166 static int change_character_exec(bContext *C, wmOperator *op)
1167 {
1168         Scene *scene= CTX_data_scene(C);
1169         Object *obedit= CTX_data_edit_object(C);
1170         Curve *cu= obedit->data;
1171         EditFont *ef= cu->editfont;
1172         int character, delta= RNA_int_get(op->ptr, "delta");
1173
1174         if(cu->pos <= 0)
1175                 return OPERATOR_CANCELLED;
1176
1177         character= ef->textbuf[cu->pos - 1];
1178         character += delta;
1179         CLAMP(character, 0, 255);
1180
1181         if(character == ef->textbuf[cu->pos - 1])
1182                 return OPERATOR_CANCELLED;
1183
1184         ef->textbuf[cu->pos - 1]= character;
1185
1186         text_update_edited(C, scene, obedit, 1, 0);
1187
1188         return OPERATOR_FINISHED;
1189 }
1190
1191 void FONT_OT_change_character(wmOperatorType *ot)
1192 {
1193         /* identifiers */
1194         ot->name= "Change Character";
1195         ot->idname= "FONT_OT_change_character";
1196         
1197         /* api callbacks */
1198         ot->exec= change_character_exec;
1199         ot->poll= ED_operator_editfont;
1200
1201         /* flags */
1202         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1203
1204         /* properties */
1205         RNA_def_int(ot->srna, "delta", 1, -255, 255, "Delta", "Number to increase or decrease character code with.", -255, 255);
1206 }
1207
1208 /******************* line break operator ********************/
1209
1210 static int line_break_exec(bContext *C, wmOperator *op)
1211 {
1212         Scene *scene= CTX_data_scene(C);
1213         Object *obedit= CTX_data_edit_object(C);
1214         Curve *cu= obedit->data;
1215         EditFont *ef= cu->editfont;
1216         int ctrl= RNA_enum_get(op->ptr, "ctrl");
1217
1218         if(ctrl) {
1219                 insert_into_textbuf(obedit, 1);
1220                 if(ef->textbuf[cu->pos]!='\n')
1221                         insert_into_textbuf(obedit, '\n');
1222         }
1223         else
1224                 insert_into_textbuf(obedit, '\n');
1225
1226         cu->selstart = cu->selend = 0;
1227
1228         text_update_edited(C, scene, obedit, 1, 0);
1229
1230         return OPERATOR_FINISHED;
1231 }
1232
1233 void FONT_OT_line_break(wmOperatorType *ot)
1234 {
1235         /* identifiers */
1236         ot->name= "Line Break";
1237         ot->idname= "FONT_OT_line_break";
1238         
1239         /* api callbacks */
1240         ot->exec= line_break_exec;
1241         ot->poll= ED_operator_editfont;
1242
1243         /* flags */
1244         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1245
1246         /* properties */
1247         RNA_def_boolean(ot->srna, "ctrl", 0, "Ctrl", ""); // XXX what is this?
1248 }
1249
1250 /******************* delete operator **********************/
1251
1252 static EnumPropertyItem delete_type_items[]= {
1253         {DEL_ALL, "ALL", "All", ""},
1254         {DEL_NEXT_CHAR, "NEXT_CHARACTER", "Next Character", ""},
1255         {DEL_PREV_CHAR, "PREVIOUS_CHARACTER", "Previous Character", ""},
1256         {DEL_SELECTION, "SELECTION", "Selection", ""},
1257         {DEL_NEXT_SEL, "NEXT_OR_SELECTION", "Next or Selection", ""},
1258         {DEL_PREV_SEL, "PREVIOUS_OR_SELECTION", "Previous or Selection", ""},
1259         {0, NULL, NULL, NULL}};
1260
1261 static int delete_exec(bContext *C, wmOperator *op)
1262 {
1263         Scene *scene= CTX_data_scene(C);
1264         Object *obedit= CTX_data_edit_object(C);
1265         Curve *cu= obedit->data;
1266         EditFont *ef= cu->editfont;
1267         int x, selstart, selend, type= RNA_enum_get(op->ptr, "type");
1268
1269         if(cu->len == 0)
1270                 return OPERATOR_CANCELLED;
1271
1272         if(BKE_font_getselection(obedit, &selstart, &selend)) {
1273                 if(type == DEL_NEXT_SEL) type= DEL_SELECTION;
1274                 else if(type == DEL_PREV_SEL) type= DEL_SELECTION;
1275         }
1276         else {
1277                 if(type == DEL_NEXT_SEL) type= DEL_NEXT_CHAR;
1278                 else if(type == DEL_PREV_SEL) type= DEL_PREV_CHAR;
1279         }
1280
1281         switch(type) {
1282                 case DEL_ALL:
1283                         cu->len = cu->pos = 0;
1284                         ef->textbuf[0]= 0;
1285                         break;
1286                 case DEL_SELECTION:
1287                         if(!kill_selection(obedit, 0))
1288                                 return OPERATOR_CANCELLED;
1289                         break;
1290                 case DEL_PREV_CHAR:
1291                         if(cu->pos<=0)
1292                                 return OPERATOR_CANCELLED;
1293
1294                         for(x=cu->pos;x<=cu->len;x++)
1295                                 ef->textbuf[x-1]= ef->textbuf[x];
1296                         for(x=cu->pos;x<=cu->len;x++)
1297                                 ef->textbufinfo[x-1]= ef->textbufinfo[x];                                       
1298
1299                         cu->pos--;
1300                         ef->textbuf[--cu->len]='\0';
1301                         break;
1302                 case DEL_NEXT_CHAR:
1303                         if(cu->pos>=cu->len)
1304                                 return OPERATOR_CANCELLED;
1305
1306                         for(x=cu->pos;x<cu->len;x++)
1307                                 ef->textbuf[x]= ef->textbuf[x+1];
1308                         for(x=cu->pos;x<cu->len;x++)
1309                                 ef->textbufinfo[x]= ef->textbufinfo[x+1];                                       
1310
1311                         ef->textbuf[--cu->len]='\0';
1312                         break;
1313                 default:
1314                         return OPERATOR_CANCELLED;
1315         }
1316
1317         text_update_edited(C, scene, obedit, 1, 0);
1318
1319         return OPERATOR_FINISHED;
1320 }
1321
1322 void FONT_OT_delete(wmOperatorType *ot)
1323 {
1324         /* identifiers */
1325         ot->name= "Delete";
1326         ot->idname= "FONT_OT_delete";
1327         
1328         /* api callbacks */
1329         ot->exec= delete_exec;
1330         ot->poll= ED_operator_editfont;
1331
1332         /* flags */
1333         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1334
1335         /* properties */
1336         RNA_def_enum(ot->srna, "type", delete_type_items, DEL_ALL, "Type", "Which part of the text to delete.");
1337 }
1338
1339 /*********************** insert text operator *************************/
1340
1341 static int insert_text_exec(bContext *C, wmOperator *op)
1342 {
1343         Scene *scene= CTX_data_scene(C);
1344         Object *obedit= CTX_data_edit_object(C);
1345         char *inserted_utf8;
1346         wchar_t *inserted_text, first;
1347         int len;
1348
1349         if(!RNA_property_is_set(op->ptr, "text"))
1350                 return OPERATOR_CANCELLED;
1351         
1352         inserted_utf8= RNA_string_get_alloc(op->ptr, "text", NULL, 0);
1353         len= strlen(inserted_utf8);
1354
1355         inserted_text= MEM_callocN(sizeof(wchar_t)*(len+1), "FONT_insert_text");
1356         utf8towchar(inserted_text, inserted_utf8);
1357         first= inserted_text[0];
1358
1359         MEM_freeN(inserted_text);
1360         MEM_freeN(inserted_utf8);
1361
1362         if(!first)
1363                 return OPERATOR_CANCELLED;
1364
1365         insert_into_textbuf(obedit, first);
1366         kill_selection(obedit, 1);
1367         text_update_edited(C, scene, obedit, 1, 0);
1368
1369         return OPERATOR_FINISHED;
1370 }
1371
1372 static int insert_text_invoke(bContext *C, wmOperator *op, wmEvent *evt)
1373 {
1374         Scene *scene= CTX_data_scene(C);
1375         Object *obedit= CTX_data_edit_object(C);
1376         Curve *cu= obedit->data;
1377         EditFont *ef= cu->editfont;
1378         static int accentcode= 0;
1379         unsigned long ascii = evt->ascii;
1380         int alt= evt->alt, shift= evt->shift, ctrl= evt->ctrl;
1381         int event= evt->type, val= evt->val;
1382         wchar_t inserted_text[2]= {0};
1383
1384         if(RNA_property_is_set(op->ptr, "text"))
1385                 return insert_text_exec(C, op);
1386         
1387         /* tab should exit editmode, but we allow it to be typed using modifier keys */
1388         if(event==TABKEY) {
1389                 if((alt||ctrl||shift) == 0)
1390                         return OPERATOR_PASS_THROUGH;
1391                 else
1392                         ascii= 9;
1393         }
1394         else if(event==BACKSPACEKEY)
1395                 ascii= 0;
1396
1397         if(val && ascii) {
1398                 /* handle case like TAB (== 9) */
1399                 if((ascii > 31 && ascii < 254 && ascii != 127) || (ascii==13) || (ascii==10) || (ascii==8)) {
1400                         if(accentcode) {
1401                                 if(cu->pos>0) {
1402                                         inserted_text[0]= findaccent(ef->textbuf[cu->pos-1], ascii);
1403                                         ef->textbuf[cu->pos-1]= inserted_text[0];
1404                                 }
1405                                 accentcode= 0;
1406                         }
1407                         else if(cu->len<MAXTEXT-1) {
1408                                 if(alt) {
1409                                         /* might become obsolete, apple has default values for this, other OS's too? */
1410                                         if(ascii=='t') ascii= 137;
1411                                         else if(ascii=='c') ascii= 169;
1412                                         else if(ascii=='f') ascii= 164;
1413                                         else if(ascii=='g') ascii= 176;
1414                                         else if(ascii=='l') ascii= 163;
1415                                         else if(ascii=='r') ascii= 174;
1416                                         else if(ascii=='s') ascii= 223;
1417                                         else if(ascii=='y') ascii= 165;
1418                                         else if(ascii=='.') ascii= 138;
1419                                         else if(ascii=='1') ascii= 185;
1420                                         else if(ascii=='2') ascii= 178;
1421                                         else if(ascii=='3') ascii= 179;
1422                                         else if(ascii=='%') ascii= 139;
1423                                         else if(ascii=='?') ascii= 191;
1424                                         else if(ascii=='!') ascii= 161;
1425                                         else if(ascii=='x') ascii= 215;
1426                                         else if(ascii=='>') ascii= 187;
1427                                         else if(ascii=='<') ascii= 171;
1428                                 }
1429
1430                                 inserted_text[0]= ascii;
1431                                 insert_into_textbuf(obedit, ascii);
1432                         }
1433                         
1434                         kill_selection(obedit, 1);
1435                         text_update_edited(C, scene, obedit, 1, 0);
1436                 }
1437                 else {
1438                         inserted_text[0]= ascii;
1439                         insert_into_textbuf(obedit, ascii);
1440                         text_update_edited(C, scene, obedit, 1, 0);
1441                 }
1442         }
1443         else if(val && event == BACKSPACEKEY) {
1444                 if(alt && cu->len!=0 && cu->pos>0)
1445                         accentcode= 1;
1446
1447                 return OPERATOR_PASS_THROUGH;
1448         }
1449         else
1450                 return OPERATOR_PASS_THROUGH;
1451
1452         if(inserted_text[0]) {
1453                 /* store as utf8 in RNA string */
1454                 char inserted_utf8[8] = {0};
1455
1456                 wcs2utf8s(inserted_utf8, inserted_text);
1457                 RNA_string_set(op->ptr, "text", inserted_utf8);
1458         }
1459
1460         return OPERATOR_FINISHED;
1461 }
1462
1463 void FONT_OT_insert_text(wmOperatorType *ot)
1464 {
1465         /* identifiers */
1466         ot->name= "Insert Text";
1467         ot->idname= "FONT_OT_insert_text";
1468         
1469         /* api callbacks */
1470         ot->exec= insert_text_exec;
1471         ot->invoke= insert_text_invoke;
1472         ot->poll= ED_operator_editfont;
1473         
1474         /* flags */
1475         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1476
1477         /* properties */
1478         RNA_def_string(ot->srna, "text", "", 0, "Text", "Text to insert at the cursor position.");
1479 }
1480
1481 /***************** editmode enter/exit ********************/
1482
1483 void make_editText(Object *obedit)
1484 {
1485         Curve *cu= obedit->data;
1486         EditFont *ef= cu->editfont;
1487         
1488         if(ef==NULL) {
1489                 ef= cu->editfont= MEM_callocN(sizeof(EditFont), "editfont");
1490         
1491                 ef->textbuf= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "texteditbuf");
1492                 ef->textbufinfo= MEM_callocN((MAXTEXT+4)*sizeof(CharInfo), "texteditbufinfo");
1493                 ef->copybuf= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "texteditcopybuf");
1494                 ef->copybufinfo= MEM_callocN((MAXTEXT+4)*sizeof(CharInfo), "texteditcopybufinfo");      
1495                 ef->oldstr= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "oldstrbuf");
1496                 ef->oldstrinfo= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "oldstrbuf");
1497         }
1498         
1499         // Convert the original text to wchar_t
1500         utf8towchar(ef->textbuf, cu->str);
1501         wcscpy(ef->oldstr, ef->textbuf);
1502                 
1503         cu->len= wcslen(ef->textbuf);
1504         
1505         memcpy(ef->textbufinfo, cu->strinfo, (cu->len)*sizeof(CharInfo));
1506         memcpy(ef->oldstrinfo, cu->strinfo, (cu->len)*sizeof(CharInfo));
1507
1508         if(cu->pos>cu->len) cu->pos= cu->len;
1509
1510         if(cu->pos)
1511                 cu->curinfo = ef->textbufinfo[cu->pos-1];
1512         else
1513                 cu->curinfo = ef->textbufinfo[0];
1514         
1515         // Convert to UTF-8
1516         update_string(cu);
1517 }
1518
1519 void load_editText(Object *obedit)
1520 {
1521         Curve *cu= obedit->data;
1522         EditFont *ef= cu->editfont;
1523         
1524         MEM_freeN(ef->oldstr);
1525         ef->oldstr= NULL;
1526         MEM_freeN(ef->oldstrinfo);
1527         ef->oldstrinfo= NULL;
1528         
1529         update_string(cu);
1530         
1531         if(cu->strinfo)
1532                 MEM_freeN(cu->strinfo);
1533         cu->strinfo= MEM_callocN((cu->len+4)*sizeof(CharInfo), "texteditinfo");
1534         memcpy(cu->strinfo, ef->textbufinfo, (cu->len)*sizeof(CharInfo));
1535
1536         cu->len= strlen(cu->str);
1537         
1538         /* this memory system is weak... */
1539         
1540         if(cu->selboxes) {
1541                 MEM_freeN(cu->selboxes);
1542                 cu->selboxes= NULL;
1543         }
1544 }
1545
1546 void free_editText(Object *obedit)
1547 {
1548         BKE_free_editfont((Curve *)obedit->data);
1549 }
1550
1551 /********************** set case operator *********************/
1552
1553 static EnumPropertyItem case_items[]= {
1554         {CASE_LOWER, "LOWER", "Lower", ""},
1555         {CASE_UPPER, "UPPER", "Upper", ""},
1556         {0, NULL, NULL, NULL}};
1557
1558 static int set_case(bContext *C, int ccase)
1559 {
1560         Scene *scene= CTX_data_scene(C);
1561         Object *obedit= CTX_data_edit_object(C);
1562         Curve *cu= obedit->data;
1563         EditFont *ef= cu->editfont;
1564         wchar_t *str;
1565         int len;
1566         
1567         len= wcslen(ef->textbuf);
1568         str= ef->textbuf;
1569         while(len) {
1570                 if(*str>='a' && *str<='z')
1571                         *str-= 32;
1572                 len--;
1573                 str++;
1574         }
1575         
1576         if(ccase == CASE_LOWER) {
1577                 len= wcslen(ef->textbuf);
1578                 str= ef->textbuf;
1579                 while(len) {
1580                         if(*str>='A' && *str<='Z') {
1581                                 *str+= 32;
1582                         }
1583                         len--;
1584                         str++;
1585                 }
1586         }
1587
1588         text_update_edited(C, scene, obedit, 1, 0);
1589
1590         return OPERATOR_FINISHED;
1591 }
1592
1593 static int set_case_exec(bContext *C, wmOperator *op)
1594 {
1595         return set_case(C, RNA_enum_get(op->ptr, "case"));
1596 }
1597
1598 void FONT_OT_set_case(wmOperatorType *ot)
1599 {
1600         /* identifiers */
1601         ot->name= "Set Case";
1602         ot->idname= "FONT_OT_set_case";
1603         
1604         /* api callbacks */
1605         ot->exec= set_case_exec;
1606         ot->poll= ED_operator_editfont;
1607
1608         /* flags */
1609         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1610
1611         /* properties */
1612         RNA_def_enum(ot->srna, "case", case_items, CASE_LOWER, "Case", "Lower or upper case.");
1613 }
1614
1615 /********************** toggle case operator *********************/
1616
1617 static int toggle_case_exec(bContext *C, wmOperator *op)
1618 {
1619         Object *obedit= CTX_data_edit_object(C);
1620         Curve *cu= obedit->data;
1621         EditFont *ef= cu->editfont;
1622         wchar_t *str;
1623         int len, ccase= CASE_UPPER;
1624         
1625         len= wcslen(ef->textbuf);
1626         str= ef->textbuf;
1627         while(len) {
1628                 if(*str>='a' && *str<='z') {
1629                         ccase= CASE_LOWER;
1630                         break;
1631                 }
1632
1633                 len--;
1634                 str++;
1635         }
1636         
1637         return set_case(C, ccase);
1638 }
1639
1640 void FONT_OT_toggle_case(wmOperatorType *ot)
1641 {
1642         /* identifiers */
1643         ot->name= "Toggle Case";
1644         ot->idname= "FONT_OT_toggle_case";
1645         
1646         /* api callbacks */
1647         ot->exec= toggle_case_exec;
1648         ot->poll= ED_operator_editfont;
1649
1650         /* flags */
1651         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1652 }
1653
1654 /* **************** undo for font object ************** */
1655
1656 static void undoFont_to_editFont(void *strv, void *ecu)
1657 {
1658         Curve *cu= (Curve *)ecu;
1659         EditFont *ef= cu->editfont;
1660         char *str= strv;
1661
1662         cu->pos= *((short *)str);
1663         cu->len= *((short *)(str+2));
1664
1665         memcpy(ef->textbuf, str+4, (cu->len+1)*sizeof(wchar_t));
1666         memcpy(ef->textbufinfo, str+4 + (cu->len+1)*sizeof(wchar_t), cu->len*sizeof(CharInfo));
1667         
1668         cu->selstart = cu->selend = 0;
1669         
1670         update_string(cu);
1671 }
1672
1673 static void *editFont_to_undoFont(void *ecu)
1674 {
1675         Curve *cu= (Curve *)ecu;
1676         EditFont *ef= cu->editfont;
1677         char *str;
1678         
1679         // The undo buffer includes [MAXTEXT+6]=actual string and [MAXTEXT+4]*sizeof(CharInfo)=charinfo
1680         str= MEM_callocN((MAXTEXT+6)*sizeof(wchar_t) + (MAXTEXT+4)*sizeof(CharInfo), "string undo");
1681
1682         // Copy the string and string information
1683         memcpy(str+4, ef->textbuf, (cu->len+1)*sizeof(wchar_t));
1684         memcpy(str+4 + (cu->len+1)*sizeof(wchar_t), ef->textbufinfo, cu->len*sizeof(CharInfo));
1685
1686         *((short *)str)= cu->pos;
1687         *((short *)(str+2))= cu->len;   
1688         
1689         return str;
1690 }
1691
1692 static void free_undoFont(void *strv)
1693 {
1694         MEM_freeN(strv);
1695 }
1696
1697 static void *get_undoFont(bContext *C)
1698 {
1699         Object *obedit= CTX_data_edit_object(C);
1700         if(obedit && obedit->type==OB_FONT) {
1701                 return obedit->data;
1702         }
1703         return NULL;
1704 }
1705
1706 /* and this is all the undo system needs to know */
1707 void undo_push_font(bContext *C, char *name)
1708 {
1709         undo_editmode_push(C, name, get_undoFont, free_undoFont, undoFont_to_editFont, editFont_to_undoFont, NULL);
1710 }
1711