2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19 * All rights reserved.
21 * Contributor(s): Blender Foundation
23 * ***** END GPL LICENSE BLOCK *****
26 /** \file blender/editors/curve/editfont.c
42 #include "MEM_guardedalloc.h"
44 #include "BLI_blenlib.h"
46 #include "BLI_utildefines.h"
48 #include "DNA_curve_types.h"
49 #include "DNA_object_types.h"
50 #include "DNA_vfont_types.h"
51 #include "DNA_scene_types.h"
52 #include "DNA_text_types.h"
54 #include "BKE_context.h"
55 #include "BKE_curve.h"
56 #include "BKE_depsgraph.h"
58 #include "BKE_library.h"
59 #include "BKE_object.h"
60 #include "BKE_report.h"
62 #include "RNA_access.h"
63 #include "RNA_define.h"
69 #include "ED_object.h"
70 #include "ED_screen.h"
73 #include "UI_interface.h"
75 #include "curve_intern.h"
79 /************************* utilities ******************************/
81 static char findaccent(char char1, unsigned int code)
86 if(code=='`') new= 224;
87 else if(code==39) new= 225;
88 else if(code=='^') new= 226;
89 else if(code=='~') new= 227;
90 else if(code=='"') new= 228;
91 else if(code=='o') new= 229;
92 else if(code=='e') new= 230;
93 else if(code=='-') new= 170;
96 if(code==',') new= 231;
97 if(code=='|') new= 162;
100 if(code=='`') new= 232;
101 else if(code==39) new= 233;
102 else if(code=='^') new= 234;
103 else if(code=='"') new= 235;
105 else if(char1=='i') {
106 if(code=='`') new= 236;
107 else if(code==39) new= 237;
108 else if(code=='^') new= 238;
109 else if(code=='"') new= 239;
111 else if(char1=='n') {
112 if(code=='~') new= 241;
114 else if(char1=='o') {
115 if(code=='`') new= 242;
116 else if(code==39) new= 243;
117 else if(code=='^') new= 244;
118 else if(code=='~') new= 245;
119 else if(code=='"') new= 246;
120 else if(code=='/') new= 248;
121 else if(code=='-') new= 186;
122 else if(code=='e') new= 143;
124 else if(char1=='s') {
125 if(code=='s') new= 167;
127 else if(char1=='u') {
128 if(code=='`') new= 249;
129 else if(code==39) new= 250;
130 else if(code=='^') new= 251;
131 else if(code=='"') new= 252;
133 else if(char1=='y') {
134 if(code==39) new= 253;
135 else if(code=='"') new= 255;
137 else if(char1=='A') {
138 if(code=='`') new= 192;
139 else if(code==39) new= 193;
140 else if(code=='^') new= 194;
141 else if(code=='~') new= 195;
142 else if(code=='"') new= 196;
143 else if(code=='o') new= 197;
144 else if(code=='e') new= 198;
146 else if(char1=='C') {
147 if(code==',') new= 199;
149 else if(char1=='E') {
150 if(code=='`') new= 200;
151 else if(code==39) new= 201;
152 else if(code=='^') new= 202;
153 else if(code=='"') new= 203;
155 else if(char1=='I') {
156 if(code=='`') new= 204;
157 else if(code==39) new= 205;
158 else if(code=='^') new= 206;
159 else if(code=='"') new= 207;
161 else if(char1=='N') {
162 if(code=='~') new= 209;
164 else if(char1=='O') {
165 if(code=='`') new= 210;
166 else if(code==39) new= 211;
167 else if(code=='^') new= 212;
168 else if(code=='~') new= 213;
169 else if(code=='"') new= 214;
170 else if(code=='/') new= 216;
171 else if(code=='e') new= 141;
173 else if(char1=='U') {
174 if(code=='`') new= 217;
175 else if(code==39) new= 218;
176 else if(code=='^') new= 219;
177 else if(code=='"') new= 220;
179 else if(char1=='Y') {
180 if(code==39) new= 221;
182 else if(char1=='1') {
183 if(code=='4') new= 188;
184 if(code=='2') new= 189;
186 else if(char1=='3') {
187 if(code=='4') new= 190;
189 else if(char1==':') {
190 if(code=='-') new= 247;
192 else if(char1=='-') {
193 if(code==':') new= 247;
194 if(code=='|') new= 135;
195 if(code=='+') new= 177;
197 else if(char1=='|') {
198 if(code=='-') new= 135;
199 if(code=='=') new= 136;
201 else if(char1=='=') {
202 if(code=='|') new= 136;
204 else if(char1=='+') {
205 if(code=='-') new= 177;
213 static void update_string(Curve *cu)
215 EditFont *ef= cu->editfont;
218 // Free the old curve string
221 // Calculate the actual string length in UTF-8 variable characters
222 len = BLI_wstrlen_utf8(ef->textbuf);
224 // Alloc memory for UTF-8 variable char length string
225 cu->str = MEM_callocN(len + sizeof(wchar_t), "str");
227 // Copy the wchar to UTF-8
228 BLI_strncpy_wchar_as_utf8(cu->str, ef->textbuf, len + 1);
231 static int insert_into_textbuf(Object *obedit, uintptr_t c)
233 Curve *cu= obedit->data;
235 if(cu->len<MAXTEXT-1) {
236 EditFont *ef= cu->editfont;
239 for(x= cu->len; x>cu->pos; x--) ef->textbuf[x]= ef->textbuf[x-1];
240 for(x= cu->len; x>cu->pos; x--) ef->textbufinfo[x]= ef->textbufinfo[x-1];
241 ef->textbuf[cu->pos]= c;
242 ef->textbufinfo[cu->pos] = cu->curinfo;
243 ef->textbufinfo[cu->pos].kern = 0;
244 ef->textbufinfo[cu->pos].mat_nr = obedit->actcol;
248 ef->textbuf[cu->len]='\0';
258 static void text_update_edited(bContext *C, Scene *scene, Object *obedit, int recalc, int mode)
260 struct Main *bmain= CTX_data_main(C);
261 Curve *cu= obedit->data;
262 EditFont *ef= cu->editfont;
263 cu->curinfo = ef->textbufinfo[cu->pos?cu->pos-1:0];
265 if(obedit->totcol > 0) {
266 obedit->actcol= ef->textbufinfo[cu->pos?cu->pos-1:0].mat_nr;
268 /* since this array is calloc'd, it can be 0 even though we try ensure
269 * (mat_nr > 0) almost everywhere */
270 if (obedit->actcol < 1) {
278 BKE_text_to_curve(bmain, scene, obedit, mode);
281 DAG_id_tag_update(obedit->data, 0);
282 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
285 /********************** insert lorem operator *********************/
287 static int insert_lorem_exec(bContext *C, wmOperator *UNUSED(op))
289 Object *obedit= CTX_data_edit_object(C);
292 static const char *lastlorem;
299 i= rand()/(RAND_MAX/6)+4;
301 for(p2=p; *p2 && i; p2++) {
302 insert_into_textbuf(obedit, *p2);
309 if(strlen(lastlorem)<5)
310 lastlorem = ED_lorem;
312 insert_into_textbuf(obedit, '\n');
313 insert_into_textbuf(obedit, '\n');
315 DAG_id_tag_update(obedit->data, 0);
316 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
318 return OPERATOR_FINISHED;
321 void FONT_OT_insert_lorem(wmOperatorType *ot)
324 ot->name= "Insert Lorem";
325 ot->description= "Insert placeholder text";
326 ot->idname= "FONT_OT_insert_lorem";
329 ot->exec= insert_lorem_exec;
330 ot->poll= ED_operator_editfont;
333 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
336 /******************* paste file operator ********************/
338 /* note this handles both ascii and utf8 unicode, previously
339 * there were 3 functions that did effectively the same thing. */
341 static int paste_file(bContext *C, ReportList *reports, const char *filename)
343 Scene *scene= CTX_data_scene(C);
344 Object *obedit= CTX_data_edit_object(C);
345 Curve *cu= obedit->data;
346 EditFont *ef= cu->editfont;
351 fp= fopen(filename, "r");
355 BKE_reportf(reports, RPT_ERROR, "Failed to open file %s", filename);
356 return OPERATOR_CANCELLED;
359 fseek(fp, 0L, SEEK_END);
361 fseek(fp, 0L, SEEK_SET);
363 strp= MEM_callocN(filelen+4, "tempstr");
365 // fread() instead of read(), because windows read() converts text
366 // to DOS \r\n linebreaks, causing double linebreaks in the 3d text
367 filelen = fread(strp, 1, filelen, fp);
371 if(cu->len+filelen<MAXTEXT) {
373 wchar_t *mem = MEM_callocN((sizeof(wchar_t)*filelen)+(4*sizeof(wchar_t)), "temporary");
374 tmplen = BLI_strncpy_wchar_from_utf8(mem, strp, filelen + 1);
375 wcscat(ef->textbuf, mem);
382 text_update_edited(C, scene, obedit, 1, FO_EDIT);
384 return OPERATOR_FINISHED;
387 static int paste_file_exec(bContext *C, wmOperator *op)
392 path= RNA_string_get_alloc(op->ptr, "filepath", NULL, 0);
393 retval= paste_file(C, op->reports, path);
399 static int paste_file_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
401 if(RNA_property_is_set(op->ptr, "filepath"))
402 return paste_file_exec(C, op);
404 WM_event_add_fileselect(C, op);
406 return OPERATOR_RUNNING_MODAL;
409 void FONT_OT_file_paste(wmOperatorType *ot)
412 ot->name= "Paste File";
413 ot->description= "Paste contents from file";
414 ot->idname= "FONT_OT_file_paste";
417 ot->exec= paste_file_exec;
418 ot->invoke= paste_file_invoke;
419 ot->poll= ED_operator_editfont;
422 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
425 WM_operator_properties_filesel(ot, FOLDERFILE|TEXTFILE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH);
428 /******************* text to object operator ********************/
430 static void txt_add_object(bContext *C, TextLine *firstline, int totline, float offset[3])
432 Scene *scene= CTX_data_scene(C);
436 struct TextLine *tmp;
438 float rot[3] = {0.f, 0.f, 0.f};
440 obedit= add_object(scene, OB_FONT);
444 ED_object_base_init_transform(C, base, NULL, rot); /* seems to assume view align ? TODO - look into this, could be an operator option */
445 where_is_object(scene, obedit);
447 obedit->loc[0] += offset[0];
448 obedit->loc[1] += offset[1];
449 obedit->loc[2] += offset[2];
452 cu->vfont= get_builtin_font();
455 for(tmp=firstline, a=0; cu->len<MAXTEXT && a<totline; tmp=tmp->next, a++)
456 nchars += strlen(tmp->line) + 1;
458 if(cu->str) MEM_freeN(cu->str);
459 if(cu->strinfo) MEM_freeN(cu->strinfo);
461 cu->str= MEM_callocN(nchars+4, "str");
462 cu->strinfo= MEM_callocN((nchars+4)*sizeof(CharInfo), "strinfo");
468 for(tmp=firstline, a=0; cu->len<MAXTEXT && a<totline; tmp=tmp->next, a++) {
469 strcat(cu->str, tmp->line);
470 cu->len+= strlen(tmp->line);
473 strcat(cu->str, "\n");
480 WM_event_add_notifier(C, NC_OBJECT|NA_ADDED, obedit);
483 void ED_text_to_object(bContext *C, Text *text, int split_lines)
485 RegionView3D *rv3d= CTX_wm_region_view3d(C);
490 if(!text || !text->lines.first) return;
493 for(line=text->lines.first; line; line=line->next) {
494 /* skip lines with no text, but still make space for them */
495 if(line->line[0] == '\0') {
500 /* do the translation */
502 offset[1] = -linenum;
506 mul_mat3_m4_v3(rv3d->viewinv, offset);
508 txt_add_object(C, line, 1, offset);
518 txt_add_object(C, text->lines.first, BLI_countlist(&text->lines), offset);
522 /********************** utilities ***************************/
524 static short next_word(Curve *cu)
527 for(s=cu->pos; (cu->str[s]) && (cu->str[s]!=' ') && (cu->str[s]!='\n') &&
528 (cu->str[s]!=1) && (cu->str[s]!='\r'); s++);
529 if(cu->str[s]) return(s+1); else return(s);
532 static short prev_word(Curve *cu)
536 if(cu->pos==0) return(0);
537 for(s=cu->pos-2; (cu->str[s]) && (cu->str[s]!=' ') && (cu->str[s]!='\n') &&
538 (cu->str[s]!=1) && (cu->str[s]!='\r'); s--);
539 if(cu->str[s]) return(s+1); else return(s);
542 static int kill_selection(Object *obedit, int ins) /* 1 == new character */
544 Curve *cu= obedit->data;
545 EditFont *ef= cu->editfont;
546 int selend, selstart, direction;
550 direction = BKE_font_getselection(obedit, &selstart, &selend);
554 if(cu->pos >= selstart) cu->pos = selstart+offset;
555 if((direction == -1) && ins) {
559 getfrom = selend+offset;
560 if(ins==0) getfrom++;
561 size = (cu->len * sizeof(wchar_t)) - (selstart * sizeof(wchar_t)) + (offset*sizeof(wchar_t));
562 memmove(ef->textbuf+selstart, ef->textbuf+getfrom, size);
563 memmove(ef->textbufinfo+selstart, ef->textbufinfo+getfrom, ((cu->len-selstart)+offset)*sizeof(CharInfo));
564 cu->len -= (selend-selstart)+offset;
565 cu->selstart = cu->selend = 0;
571 /******************* set style operator ********************/
573 static EnumPropertyItem style_items[]= {
574 {CU_CHINFO_BOLD, "BOLD", 0, "Bold", ""},
575 {CU_CHINFO_ITALIC, "ITALIC", 0, "Italic", ""},
576 {CU_CHINFO_UNDERLINE, "UNDERLINE", 0, "Underline", ""},
577 {CU_CHINFO_SMALLCAPS, "SMALL_CAPS", 0, "Small Caps", ""},
578 {0, NULL, 0, NULL, NULL}};
580 static int set_style(bContext *C, const int style, const int clear)
582 Object *obedit= CTX_data_edit_object(C);
583 Curve *cu= obedit->data;
584 EditFont *ef= cu->editfont;
585 int i, selstart, selend;
587 if(!BKE_font_getselection(obedit, &selstart, &selend))
588 return OPERATOR_CANCELLED;
590 for(i=selstart; i<=selend; i++) {
592 ef->textbufinfo[i].flag &= ~style;
594 ef->textbufinfo[i].flag |= style;
597 DAG_id_tag_update(obedit->data, 0);
598 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
600 return OPERATOR_FINISHED;
603 static int set_style_exec(bContext *C, wmOperator *op)
605 const int style= RNA_enum_get(op->ptr, "style");
606 const int clear= RNA_boolean_get(op->ptr, "clear");
608 return set_style(C, style, clear);
611 void FONT_OT_style_set(wmOperatorType *ot)
614 ot->name= "Set Style";
615 ot->description= "Set font style";
616 ot->idname= "FONT_OT_style_set";
619 ot->exec= set_style_exec;
620 ot->poll= ED_operator_editfont;
623 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
626 RNA_def_enum(ot->srna, "style", style_items, CU_CHINFO_BOLD, "Style", "Style to set selection to");
627 RNA_def_boolean(ot->srna, "clear", 0, "Clear", "Clear style rather than setting it");
630 /******************* toggle style operator ********************/
632 static int toggle_style_exec(bContext *C, wmOperator *op)
634 Object *obedit= CTX_data_edit_object(C);
635 Curve *cu= obedit->data;
636 int style, clear, selstart, selend;
638 if(!BKE_font_getselection(obedit, &selstart, &selend))
639 return OPERATOR_CANCELLED;
641 style= RNA_enum_get(op->ptr, "style");
643 cu->curinfo.flag ^= style;
644 clear= (cu->curinfo.flag & style) == 0;
646 return set_style(C, style, clear);
649 void FONT_OT_style_toggle(wmOperatorType *ot)
652 ot->name= "Toggle Style";
653 ot->description= "Toggle font style";
654 ot->idname= "FONT_OT_style_toggle";
657 ot->exec= toggle_style_exec;
658 ot->poll= ED_operator_editfont;
661 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
664 RNA_def_enum(ot->srna, "style", style_items, CU_CHINFO_BOLD, "Style", "Style to set selection to");
667 /******************* copy text operator ********************/
669 static void copy_selection(Object *obedit)
671 int selstart, selend;
673 if(BKE_font_getselection(obedit, &selstart, &selend)) {
674 Curve *cu= obedit->data;
675 EditFont *ef= cu->editfont;
677 memcpy(ef->copybuf, ef->textbuf+selstart, ((selend-selstart)+1)*sizeof(wchar_t));
678 ef->copybuf[(selend-selstart)+1]=0;
679 memcpy(ef->copybufinfo, ef->textbufinfo+selstart, ((selend-selstart)+1)*sizeof(CharInfo));
683 static int copy_text_exec(bContext *C, wmOperator *UNUSED(op))
685 Object *obedit= CTX_data_edit_object(C);
687 copy_selection(obedit);
689 return OPERATOR_FINISHED;
692 void FONT_OT_text_copy(wmOperatorType *ot)
695 ot->name= "Copy Text";
696 ot->description= "Copy selected text to clipboard";
697 ot->idname= "FONT_OT_text_copy";
700 ot->exec= copy_text_exec;
701 ot->poll= ED_operator_editfont;
704 /******************* cut text operator ********************/
706 static int cut_text_exec(bContext *C, wmOperator *UNUSED(op))
708 Scene *scene= CTX_data_scene(C);
709 Object *obedit= CTX_data_edit_object(C);
710 int selstart, selend;
712 if(!BKE_font_getselection(obedit, &selstart, &selend))
713 return OPERATOR_CANCELLED;
715 copy_selection(obedit);
716 kill_selection(obedit, 0);
718 text_update_edited(C, scene, obedit, 1, FO_EDIT);
720 return OPERATOR_FINISHED;
723 void FONT_OT_text_cut(wmOperatorType *ot)
726 ot->name= "Cut Text";
727 ot->description= "Cut selected text to clipboard";
728 ot->idname= "FONT_OT_text_cut";
731 ot->exec= cut_text_exec;
732 ot->poll= ED_operator_editfont;
735 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
738 /******************* paste text operator ********************/
740 static int paste_selection(Object *obedit, ReportList *reports)
742 Curve *cu= obedit->data;
743 EditFont *ef= cu->editfont;
744 int len= wcslen(ef->copybuf);
746 // Verify that the copy buffer => [copy buffer len] + cu->len < MAXTEXT
747 if(cu->len + len <= MAXTEXT) {
749 int size = (cu->len * sizeof(wchar_t)) - (cu->pos*sizeof(wchar_t)) + sizeof(wchar_t);
750 memmove(ef->textbuf+cu->pos+len, ef->textbuf+cu->pos, size);
751 memcpy(ef->textbuf+cu->pos, ef->copybuf, len * sizeof(wchar_t));
753 memmove(ef->textbufinfo+cu->pos+len, ef->textbufinfo+cu->pos, (cu->len-cu->pos+1)*sizeof(CharInfo));
754 memcpy(ef->textbufinfo+cu->pos, ef->copybufinfo, len*sizeof(CharInfo));
763 BKE_report(reports, RPT_WARNING, "Text too long");
768 static int paste_text_exec(bContext *C, wmOperator *op)
770 Scene *scene= CTX_data_scene(C);
771 Object *obedit= CTX_data_edit_object(C);
773 if(!paste_selection(obedit, op->reports))
774 return OPERATOR_CANCELLED;
776 text_update_edited(C, scene, obedit, 1, FO_EDIT);
778 return OPERATOR_FINISHED;
781 void FONT_OT_text_paste(wmOperatorType *ot)
784 ot->name= "Paste Text";
785 ot->description= "Paste text from clipboard";
786 ot->idname= "FONT_OT_text_paste";
789 ot->exec= paste_text_exec;
790 ot->poll= ED_operator_editfont;
793 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
796 /************************ move operator ************************/
798 static EnumPropertyItem move_type_items[]= {
799 {LINE_BEGIN, "LINE_BEGIN", 0, "Line Begin", ""},
800 {LINE_END, "LINE_END", 0, "Line End", ""},
801 {PREV_CHAR, "PREVIOUS_CHARACTER", 0, "Previous Character", ""},
802 {NEXT_CHAR, "NEXT_CHARACTER", 0, "Next Character", ""},
803 {PREV_WORD, "PREVIOUS_WORD", 0, "Previous Word", ""},
804 {NEXT_WORD, "NEXT_WORD", 0, "Next Word", ""},
805 {PREV_LINE, "PREVIOUS_LINE", 0, "Previous Line", ""},
806 {NEXT_LINE, "NEXT_LINE", 0, "Next Line", ""},
807 {PREV_PAGE, "PREVIOUS_PAGE", 0, "Previous Page", ""},
808 {NEXT_PAGE, "NEXT_PAGE", 0, "Next Page", ""},
809 {0, NULL, 0, NULL, NULL}};
811 static int move_cursor(bContext *C, int type, int select)
813 Scene *scene= CTX_data_scene(C);
814 Object *obedit= CTX_data_edit_object(C);
815 Curve *cu= obedit->data;
816 EditFont *ef= cu->editfont;
821 if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
823 if(ef->textbuf[cu->pos-1]=='\n') break;
824 if(ef->textbufinfo[cu->pos-1].flag & CU_CHINFO_WRAP) break;
831 if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
832 while(cu->pos<cu->len) {
833 if(ef->textbuf[cu->pos]==0) break;
834 if(ef->textbuf[cu->pos]=='\n') break;
835 if(ef->textbufinfo[cu->pos].flag & CU_CHINFO_WRAP ) break;
842 if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
843 cu->pos= prev_word(cu);
848 if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
849 cu->pos= next_word(cu);
854 if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
860 if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
867 if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
872 if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
873 cursmove= FO_CURSDOWN;
877 if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
882 if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
883 cursmove=FO_PAGEDOWN;
888 return OPERATOR_CANCELLED;
892 struct Main *bmain= CTX_data_main(C);
893 cu->selstart = cu->selend = 0;
895 BKE_text_to_curve(bmain, scene, obedit, FO_SELCHANGE);
899 if(cu->pos>cu->len) cu->pos= cu->len;
900 else if(cu->pos>=MAXTEXT) cu->pos= MAXTEXT;
901 else if(cu->pos<0) cu->pos= 0;
903 text_update_edited(C, scene, obedit, select, cursmove);
906 cu->selend = cu->pos;
908 return OPERATOR_FINISHED;
911 static int move_exec(bContext *C, wmOperator *op)
913 int type= RNA_enum_get(op->ptr, "type");
915 return move_cursor(C, type, 0);
918 void FONT_OT_move(wmOperatorType *ot)
921 ot->name= "Move Cursor";
922 ot->description= "Move cursor to position type";
923 ot->idname= "FONT_OT_move";
927 ot->poll= ED_operator_editfont;
930 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
933 RNA_def_enum(ot->srna, "type", move_type_items, LINE_BEGIN, "Type", "Where to move cursor to");
936 /******************* move select operator ********************/
938 static int move_select_exec(bContext *C, wmOperator *op)
940 int type= RNA_enum_get(op->ptr, "type");
942 return move_cursor(C, type, 1);
945 void FONT_OT_move_select(wmOperatorType *ot)
948 ot->name= "Move Select";
949 ot->description= "Make selection from current cursor position to new cursor position type";
950 ot->idname= "FONT_OT_move_select";
953 ot->exec= move_select_exec;
954 ot->poll= ED_operator_editfont;
957 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
960 RNA_def_enum(ot->srna, "type", move_type_items, LINE_BEGIN, "Type", "Where to move cursor to, to make a selection");
963 /************************* change spacing **********************/
965 static int change_spacing_exec(bContext *C, wmOperator *op)
967 Scene *scene= CTX_data_scene(C);
968 Object *obedit= CTX_data_edit_object(C);
969 Curve *cu= obedit->data;
970 EditFont *ef= cu->editfont;
971 int kern, delta= RNA_int_get(op->ptr, "delta");
973 kern = ef->textbufinfo[cu->pos-1].kern;
975 CLAMP(kern, -20, 20);
977 if(ef->textbufinfo[cu->pos-1].kern == kern)
978 return OPERATOR_CANCELLED;
980 ef->textbufinfo[cu->pos-1].kern = kern;
982 text_update_edited(C, scene, obedit, 1, FO_EDIT);
984 return OPERATOR_FINISHED;
987 void FONT_OT_change_spacing(wmOperatorType *ot)
990 ot->name= "Change Spacing";
991 ot->description= "Change font spacing";
992 ot->idname= "FONT_OT_change_spacing";
995 ot->exec= change_spacing_exec;
996 ot->poll= ED_operator_editfont;
999 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1002 RNA_def_int(ot->srna, "delta", 1, -20, 20, "Delta", "Amount to decrease or increase character spacing with", -20, 20);
1005 /************************* change character **********************/
1007 static int change_character_exec(bContext *C, wmOperator *op)
1009 Scene *scene= CTX_data_scene(C);
1010 Object *obedit= CTX_data_edit_object(C);
1011 Curve *cu= obedit->data;
1012 EditFont *ef= cu->editfont;
1013 int character, delta= RNA_int_get(op->ptr, "delta");
1016 return OPERATOR_CANCELLED;
1018 character= ef->textbuf[cu->pos - 1];
1020 CLAMP(character, 0, 255);
1022 if(character == ef->textbuf[cu->pos - 1])
1023 return OPERATOR_CANCELLED;
1025 ef->textbuf[cu->pos - 1]= character;
1027 text_update_edited(C, scene, obedit, 1, FO_EDIT);
1029 return OPERATOR_FINISHED;
1032 void FONT_OT_change_character(wmOperatorType *ot)
1035 ot->name= "Change Character";
1036 ot->description= "Change font character code";
1037 ot->idname= "FONT_OT_change_character";
1040 ot->exec= change_character_exec;
1041 ot->poll= ED_operator_editfont;
1044 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1047 RNA_def_int(ot->srna, "delta", 1, -255, 255, "Delta", "Number to increase or decrease character code with", -255, 255);
1050 /******************* line break operator ********************/
1052 static int line_break_exec(bContext *C, wmOperator *op)
1054 Scene *scene= CTX_data_scene(C);
1055 Object *obedit= CTX_data_edit_object(C);
1056 Curve *cu= obedit->data;
1057 EditFont *ef= cu->editfont;
1058 const int ctrl= RNA_boolean_get(op->ptr, "ctrl");
1061 insert_into_textbuf(obedit, 1);
1062 if(ef->textbuf[cu->pos]!='\n')
1063 insert_into_textbuf(obedit, '\n');
1066 insert_into_textbuf(obedit, '\n');
1068 cu->selstart = cu->selend = 0;
1070 text_update_edited(C, scene, obedit, 1, FO_EDIT);
1072 return OPERATOR_FINISHED;
1075 void FONT_OT_line_break(wmOperatorType *ot)
1078 ot->name= "Line Break";
1079 ot->description= "Insert line break at cursor position";
1080 ot->idname= "FONT_OT_line_break";
1083 ot->exec= line_break_exec;
1084 ot->poll= ED_operator_editfont;
1087 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1090 RNA_def_boolean(ot->srna, "ctrl", 0, "Ctrl", ""); // XXX what is this?
1093 /******************* delete operator **********************/
1095 static EnumPropertyItem delete_type_items[]= {
1096 {DEL_ALL, "ALL", 0, "All", ""},
1097 {DEL_NEXT_CHAR, "NEXT_CHARACTER", 0, "Next Character", ""},
1098 {DEL_PREV_CHAR, "PREVIOUS_CHARACTER", 0, "Previous Character", ""},
1099 {DEL_SELECTION, "SELECTION", 0, "Selection", ""},
1100 {DEL_NEXT_SEL, "NEXT_OR_SELECTION", 0, "Next or Selection", ""},
1101 {DEL_PREV_SEL, "PREVIOUS_OR_SELECTION", 0, "Previous or Selection", ""},
1102 {0, NULL, 0, NULL, NULL}};
1104 static int delete_exec(bContext *C, wmOperator *op)
1106 Scene *scene= CTX_data_scene(C);
1107 Object *obedit= CTX_data_edit_object(C);
1108 Curve *cu= obedit->data;
1109 EditFont *ef= cu->editfont;
1110 int x, selstart, selend, type= RNA_enum_get(op->ptr, "type");
1113 return OPERATOR_CANCELLED;
1115 if(BKE_font_getselection(obedit, &selstart, &selend)) {
1116 if(type == DEL_NEXT_SEL) type= DEL_SELECTION;
1117 else if(type == DEL_PREV_SEL) type= DEL_SELECTION;
1120 if(type == DEL_NEXT_SEL) type= DEL_NEXT_CHAR;
1121 else if(type == DEL_PREV_SEL) type= DEL_PREV_CHAR;
1126 cu->len = cu->pos = 0;
1130 if(!kill_selection(obedit, 0))
1131 return OPERATOR_CANCELLED;
1135 return OPERATOR_CANCELLED;
1137 for(x=cu->pos;x<=cu->len;x++)
1138 ef->textbuf[x-1]= ef->textbuf[x];
1139 for(x=cu->pos;x<=cu->len;x++)
1140 ef->textbufinfo[x-1]= ef->textbufinfo[x];
1143 ef->textbuf[--cu->len]='\0';
1146 if(cu->pos>=cu->len)
1147 return OPERATOR_CANCELLED;
1149 for(x=cu->pos;x<cu->len;x++)
1150 ef->textbuf[x]= ef->textbuf[x+1];
1151 for(x=cu->pos;x<cu->len;x++)
1152 ef->textbufinfo[x]= ef->textbufinfo[x+1];
1154 ef->textbuf[--cu->len]='\0';
1157 return OPERATOR_CANCELLED;
1160 text_update_edited(C, scene, obedit, 1, FO_EDIT);
1162 return OPERATOR_FINISHED;
1165 void FONT_OT_delete(wmOperatorType *ot)
1169 ot->description= "Delete text by cursor position";
1170 ot->idname= "FONT_OT_delete";
1173 ot->exec= delete_exec;
1174 ot->poll= ED_operator_editfont;
1177 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1180 RNA_def_enum(ot->srna, "type", delete_type_items, DEL_ALL, "Type", "Which part of the text to delete");
1183 /*********************** insert text operator *************************/
1185 static int insert_text_exec(bContext *C, wmOperator *op)
1187 Scene *scene= CTX_data_scene(C);
1188 Object *obedit= CTX_data_edit_object(C);
1189 char *inserted_utf8;
1190 wchar_t *inserted_text;
1193 if(!RNA_property_is_set(op->ptr, "text"))
1194 return OPERATOR_CANCELLED;
1196 inserted_utf8= RNA_string_get_alloc(op->ptr, "text", NULL, 0);
1197 len= BLI_strlen_utf8(inserted_utf8);
1199 inserted_text= MEM_callocN(sizeof(wchar_t)*(len+1), "FONT_insert_text");
1200 BLI_strncpy_wchar_from_utf8(inserted_text, inserted_utf8, len+1);
1202 for(a=0; a<len; a++)
1203 insert_into_textbuf(obedit, inserted_text[a]);
1205 MEM_freeN(inserted_text);
1206 MEM_freeN(inserted_utf8);
1208 kill_selection(obedit, 1);
1209 text_update_edited(C, scene, obedit, 1, FO_EDIT);
1211 return OPERATOR_FINISHED;
1214 static int insert_text_invoke(bContext *C, wmOperator *op, wmEvent *evt)
1216 Scene *scene= CTX_data_scene(C);
1217 Object *obedit= CTX_data_edit_object(C);
1218 Curve *cu= obedit->data;
1219 EditFont *ef= cu->editfont;
1220 static int accentcode= 0;
1221 uintptr_t ascii = evt->ascii;
1222 int alt= evt->alt, shift= evt->shift, ctrl= evt->ctrl;
1223 int event= evt->type, val= evt->val;
1224 wchar_t inserted_text[2]= {0};
1226 if(RNA_property_is_set(op->ptr, "text"))
1227 return insert_text_exec(C, op);
1229 if(RNA_property_is_set(op->ptr, "accent")) {
1230 if(cu->len!=0 && cu->pos>0)
1232 return OPERATOR_FINISHED;
1235 /* tab should exit editmode, but we allow it to be typed using modifier keys */
1237 if((alt||ctrl||shift) == 0)
1238 return OPERATOR_PASS_THROUGH;
1242 else if(event==BACKSPACEKEY)
1245 if(val && (ascii || evt->utf8_buf[0])) {
1246 /* handle case like TAB (== 9) */
1247 if( (ascii > 31 && ascii < 254 && ascii != 127) ||
1254 if (evt->utf8_buf[0]) {
1255 BLI_strncpy_wchar_from_utf8(inserted_text, evt->utf8_buf, 1);
1256 ascii= inserted_text[0];
1257 insert_into_textbuf(obedit, ascii);
1260 else if(accentcode) {
1262 inserted_text[0]= findaccent(ef->textbuf[cu->pos-1], ascii);
1263 ef->textbuf[cu->pos-1]= inserted_text[0];
1267 else if(cu->len<MAXTEXT-1) {
1269 /* might become obsolete, apple has default values for this, other OS's too? */
1270 if(ascii=='t') ascii= 137;
1271 else if(ascii=='c') ascii= 169;
1272 else if(ascii=='f') ascii= 164;
1273 else if(ascii=='g') ascii= 176;
1274 else if(ascii=='l') ascii= 163;
1275 else if(ascii=='r') ascii= 174;
1276 else if(ascii=='s') ascii= 223;
1277 else if(ascii=='y') ascii= 165;
1278 else if(ascii=='.') ascii= 138;
1279 else if(ascii=='1') ascii= 185;
1280 else if(ascii=='2') ascii= 178;
1281 else if(ascii=='3') ascii= 179;
1282 else if(ascii=='%') ascii= 139;
1283 else if(ascii=='?') ascii= 191;
1284 else if(ascii=='!') ascii= 161;
1285 else if(ascii=='x') ascii= 215;
1286 else if(ascii=='>') ascii= 187;
1287 else if(ascii=='<') ascii= 171;
1290 inserted_text[0]= ascii;
1291 insert_into_textbuf(obedit, ascii);
1294 kill_selection(obedit, 1);
1295 text_update_edited(C, scene, obedit, 1, FO_EDIT);
1298 inserted_text[0]= ascii;
1299 insert_into_textbuf(obedit, ascii);
1300 text_update_edited(C, scene, obedit, 1, FO_EDIT);
1303 else if(val && event == BACKSPACEKEY) {
1304 if(alt && cu->len!=0 && cu->pos>0)
1307 return OPERATOR_PASS_THROUGH;
1310 return OPERATOR_PASS_THROUGH;
1312 if(inserted_text[0]) {
1313 /* store as utf8 in RNA string */
1314 char inserted_utf8[8] = {0};
1316 BLI_strncpy_wchar_as_utf8(inserted_utf8, inserted_text, sizeof(inserted_utf8));
1317 RNA_string_set(op->ptr, "text", inserted_utf8);
1320 /* reset property? */
1323 return OPERATOR_FINISHED;
1326 void FONT_OT_text_insert(wmOperatorType *ot)
1329 ot->name= "Insert Text";
1330 ot->description= "Insert text at cursor position";
1331 ot->idname= "FONT_OT_text_insert";
1334 ot->exec= insert_text_exec;
1335 ot->invoke= insert_text_invoke;
1336 ot->poll= ED_operator_editfont;
1339 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1342 RNA_def_string(ot->srna, "text", "", 0, "Text", "Text to insert at the cursor position");
1343 RNA_def_boolean(ot->srna, "accent", 0, "Accent mode", "Next typed character will strike through previous, for special character input");
1347 /*********************** textbox add operator *************************/
1348 static int textbox_add_exec(bContext *C, wmOperator *UNUSED(op))
1350 Object *obedit= CTX_data_active_object(C);
1351 Curve *cu= obedit->data;
1354 if (cu->totbox < 256) {
1355 for (i = cu->totbox; i>cu->actbox; i--) cu->tb[i]= cu->tb[i-1];
1356 cu->tb[cu->actbox]= cu->tb[cu->actbox-1];
1361 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1362 return OPERATOR_FINISHED;
1365 void FONT_OT_textbox_add(wmOperatorType *ot)
1368 ot->name= "Add Textbox";
1369 ot->description= "Add a new text box";
1370 ot->idname= "FONT_OT_textbox_add";
1373 ot->exec= textbox_add_exec;
1374 ot->poll= ED_operator_object_active_editable_font;
1377 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1384 /*********************** textbox remove operator *************************/
1388 static int textbox_remove_exec(bContext *C, wmOperator *op)
1390 Object *obedit= CTX_data_active_object(C);
1391 Curve *cu= obedit->data;
1393 int index = RNA_int_get(op->ptr, "index");
1396 if (cu->totbox > 1) {
1397 for (i = index; i < cu->totbox; i++) cu->tb[i]= cu->tb[i+1];
1399 if (cu->actbox >= index)
1403 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1405 return OPERATOR_FINISHED;
1408 void FONT_OT_textbox_remove(wmOperatorType *ot)
1411 ot->name= "Remove Textbox";
1412 ot->description= "Remove the textbox";
1413 ot->idname= "FONT_OT_textbox_remove";
1416 ot->exec= textbox_remove_exec;
1417 ot->poll= ED_operator_object_active_editable_font;
1420 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1422 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "The current text box", 0, INT_MAX);
1427 /***************** editmode enter/exit ********************/
1429 void make_editText(Object *obedit)
1431 Curve *cu= obedit->data;
1432 EditFont *ef= cu->editfont;
1435 ef= cu->editfont= MEM_callocN(sizeof(EditFont), "editfont");
1437 ef->textbuf= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "texteditbuf");
1438 ef->textbufinfo= MEM_callocN((MAXTEXT+4)*sizeof(CharInfo), "texteditbufinfo");
1439 ef->copybuf= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "texteditcopybuf");
1440 ef->copybufinfo= MEM_callocN((MAXTEXT+4)*sizeof(CharInfo), "texteditcopybufinfo");
1441 ef->oldstr= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "oldstrbuf");
1442 ef->oldstrinfo= MEM_callocN((MAXTEXT+4)*sizeof(CharInfo), "oldstrbuf");
1445 // Convert the original text to wchar_t
1446 BLI_strncpy_wchar_from_utf8(ef->textbuf, cu->str, MAXTEXT+4); /* length is bogus */
1447 wcscpy(ef->oldstr, ef->textbuf);
1449 cu->len= wcslen(ef->textbuf);
1451 memcpy(ef->textbufinfo, cu->strinfo, (cu->len)*sizeof(CharInfo));
1452 memcpy(ef->oldstrinfo, cu->strinfo, (cu->len)*sizeof(CharInfo));
1454 if(cu->pos>cu->len) cu->pos= cu->len;
1457 cu->curinfo = ef->textbufinfo[cu->pos-1];
1459 cu->curinfo = ef->textbufinfo[0];
1465 void load_editText(Object *obedit)
1467 Curve *cu= obedit->data;
1468 EditFont *ef= cu->editfont;
1470 MEM_freeN(ef->oldstr);
1472 MEM_freeN(ef->oldstrinfo);
1473 ef->oldstrinfo= NULL;
1478 MEM_freeN(cu->strinfo);
1479 cu->strinfo= MEM_callocN((cu->len+4)*sizeof(CharInfo), "texteditinfo");
1480 memcpy(cu->strinfo, ef->textbufinfo, (cu->len)*sizeof(CharInfo));
1482 cu->len= strlen(cu->str);
1484 /* this memory system is weak... */
1487 MEM_freeN(cu->selboxes);
1492 void free_editText(Object *obedit)
1494 BKE_free_editfont((Curve *)obedit->data);
1497 /********************** set case operator *********************/
1499 static EnumPropertyItem case_items[]= {
1500 {CASE_LOWER, "LOWER", 0, "Lower", ""},
1501 {CASE_UPPER, "UPPER", 0, "Upper", ""},
1502 {0, NULL, 0, NULL, NULL}};
1504 static int set_case(bContext *C, int ccase)
1506 Scene *scene= CTX_data_scene(C);
1507 Object *obedit= CTX_data_edit_object(C);
1508 Curve *cu= obedit->data;
1509 EditFont *ef= cu->editfont;
1513 len= wcslen(ef->textbuf);
1516 if(*str>='a' && *str<='z')
1522 if(ccase == CASE_LOWER) {
1523 len= wcslen(ef->textbuf);
1526 if(*str>='A' && *str<='Z') {
1534 text_update_edited(C, scene, obedit, 1, FO_EDIT);
1536 return OPERATOR_FINISHED;
1539 static int set_case_exec(bContext *C, wmOperator *op)
1541 return set_case(C, RNA_enum_get(op->ptr, "case"));
1544 void FONT_OT_case_set(wmOperatorType *ot)
1547 ot->name= "Set Case";
1548 ot->description= "Set font case";
1549 ot->idname= "FONT_OT_case_set";
1552 ot->exec= set_case_exec;
1553 ot->poll= ED_operator_editfont;
1556 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1559 RNA_def_enum(ot->srna, "case", case_items, CASE_LOWER, "Case", "Lower or upper case");
1562 /********************** toggle case operator *********************/
1564 static int toggle_case_exec(bContext *C, wmOperator *UNUSED(op))
1566 Object *obedit= CTX_data_edit_object(C);
1567 Curve *cu= obedit->data;
1568 EditFont *ef= cu->editfont;
1570 int len, ccase= CASE_UPPER;
1572 len= wcslen(ef->textbuf);
1575 if(*str>='a' && *str<='z') {
1584 return set_case(C, ccase);
1587 void FONT_OT_case_toggle(wmOperatorType *ot)
1590 ot->name= "Toggle Case";
1591 ot->description= "Toggle font case";
1592 ot->idname= "FONT_OT_case_toggle";
1595 ot->exec= toggle_case_exec;
1596 ot->poll= ED_operator_editfont;
1599 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1602 /* **************** Open Font ************** */
1604 static void font_ui_template_init(bContext *C, wmOperator *op)
1606 PropertyPointerRNA *pprop;
1608 op->customdata= pprop= MEM_callocN(sizeof(PropertyPointerRNA), "OpenPropertyPointerRNA");
1609 uiIDContextProperty(C, &pprop->ptr, &pprop->prop);
1612 static int font_open_cancel(bContext *UNUSED(C), wmOperator *op)
1614 MEM_freeN(op->customdata);
1615 op->customdata= NULL;
1616 return OPERATOR_CANCELLED;
1619 static int font_open_exec(bContext *C, wmOperator *op)
1621 struct Main *bmain= CTX_data_main(C);
1623 PropertyPointerRNA *pprop;
1625 char filepath[FILE_MAX];
1626 RNA_string_get(op->ptr, "filepath", filepath);
1628 font= load_vfont(bmain, filepath);
1631 if(op->customdata) MEM_freeN(op->customdata);
1632 return OPERATOR_CANCELLED;
1636 font_ui_template_init(C, op);
1639 pprop= op->customdata;
1642 /* when creating new ID blocks, use is already 1, but RNA
1643 * pointer se also increases user, so this compensates it */
1646 RNA_id_pointer_create(&font->id, &idptr);
1647 RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr);
1648 RNA_property_update(C, &pprop->ptr, pprop->prop);
1651 MEM_freeN(op->customdata);
1653 return OPERATOR_FINISHED;
1656 static int open_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1662 PropertyPointerRNA *pprop;
1664 font_ui_template_init(C, op);
1667 pprop= op->customdata;
1670 idptr= RNA_property_pointer_get((PointerRNA *)pprop, pprop->prop);
1671 font= idptr.id.data;
1674 path = (font && strcmp(font->name, FO_BUILTIN_NAME) != 0)? font->name: U.fontdir;
1676 if(RNA_property_is_set(op->ptr, "filepath"))
1677 return font_open_exec(C, op);
1679 RNA_string_set(op->ptr, "filepath", path);
1680 WM_event_add_fileselect(C, op);
1682 return OPERATOR_RUNNING_MODAL;
1685 void FONT_OT_open(wmOperatorType *ot)
1688 ot->name= "Open Font";
1689 ot->idname= "FONT_OT_open";
1692 ot->exec= font_open_exec;
1693 ot->invoke= open_invoke;
1694 ot->cancel= font_open_cancel;
1697 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1700 WM_operator_properties_filesel(ot, FOLDERFILE|FTFONTFILE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH|WM_FILESEL_RELPATH);
1703 /******************* delete operator *********************/
1705 static int font_unlink_exec(bContext *C, wmOperator *op)
1707 VFont *builtin_font;
1710 PropertyPointerRNA pprop;
1712 uiIDContextProperty(C, &pprop.ptr, &pprop.prop);
1714 if(pprop.prop==NULL) {
1715 BKE_report(op->reports, RPT_ERROR, "Incorrect context for running font unlink");
1716 return OPERATOR_CANCELLED;
1719 builtin_font = get_builtin_font();
1721 RNA_id_pointer_create(&builtin_font->id, &idptr);
1722 RNA_property_pointer_set(&pprop.ptr, pprop.prop, idptr);
1723 RNA_property_update(C, &pprop.ptr, pprop.prop);
1725 return OPERATOR_FINISHED;
1728 void FONT_OT_unlink(wmOperatorType *ot)
1732 ot->idname= "FONT_OT_unlink";
1733 ot->description= "Unlink active font data block";
1736 ot->exec= font_unlink_exec;
1740 /* **************** undo for font object ************** */
1742 static void undoFont_to_editFont(void *strv, void *ecu)
1744 Curve *cu= (Curve *)ecu;
1745 EditFont *ef= cu->editfont;
1748 cu->pos= *((short *)str);
1749 cu->len= *((short *)(str+2));
1751 memcpy(ef->textbuf, str+4, (cu->len+1)*sizeof(wchar_t));
1752 memcpy(ef->textbufinfo, str+4 + (cu->len+1)*sizeof(wchar_t), cu->len*sizeof(CharInfo));
1754 cu->selstart = cu->selend = 0;
1759 static void *editFont_to_undoFont(void *ecu)
1761 Curve *cu= (Curve *)ecu;
1762 EditFont *ef= cu->editfont;
1765 // The undo buffer includes [MAXTEXT+6]=actual string and [MAXTEXT+4]*sizeof(CharInfo)=charinfo
1766 str= MEM_callocN((MAXTEXT+6)*sizeof(wchar_t) + (MAXTEXT+4)*sizeof(CharInfo), "string undo");
1768 // Copy the string and string information
1769 memcpy(str+4, ef->textbuf, (cu->len+1)*sizeof(wchar_t));
1770 memcpy(str+4 + (cu->len+1)*sizeof(wchar_t), ef->textbufinfo, cu->len*sizeof(CharInfo));
1772 *((short *)str)= cu->pos;
1773 *((short *)(str+2))= cu->len;
1778 static void free_undoFont(void *strv)
1783 static void *get_undoFont(bContext *C)
1785 Object *obedit= CTX_data_edit_object(C);
1786 if(obedit && obedit->type==OB_FONT) {
1787 return obedit->data;
1792 /* and this is all the undo system needs to know */
1793 void undo_push_font(bContext *C, const char *name)
1795 undo_editmode_push(C, name, get_undoFont, free_undoFont, undoFont_to_editFont, editFont_to_undoFont, NULL);