Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00019 * All rights reserved. 00020 * 00021 * Contributor(s): Blender Foundation 00022 * 00023 * ***** END GPL LICENSE BLOCK ***** 00024 */ 00025 00031 #include <stdlib.h> 00032 #include <string.h> 00033 #include <fcntl.h> 00034 #include <wchar.h> 00035 00036 #ifndef WIN32 00037 #include <unistd.h> 00038 #else 00039 #include <io.h> 00040 #endif 00041 00042 #include "MEM_guardedalloc.h" 00043 00044 #include "BLI_blenlib.h" 00045 #include "BLI_math.h" 00046 #include "BLI_utildefines.h" 00047 00048 #include "DNA_curve_types.h" 00049 #include "DNA_object_types.h" 00050 #include "DNA_vfont_types.h" 00051 #include "DNA_scene_types.h" 00052 #include "DNA_text_types.h" 00053 00054 #include "BKE_context.h" 00055 #include "BKE_curve.h" 00056 #include "BKE_depsgraph.h" 00057 #include "BKE_font.h" 00058 #include "BKE_library.h" 00059 #include "BKE_object.h" 00060 #include "BKE_report.h" 00061 00062 #include "RNA_access.h" 00063 #include "RNA_define.h" 00064 00065 #include "WM_api.h" 00066 #include "WM_types.h" 00067 00068 #include "ED_curve.h" 00069 #include "ED_object.h" 00070 #include "ED_screen.h" 00071 #include "ED_util.h" 00072 00073 #include "UI_interface.h" 00074 00075 #include "curve_intern.h" 00076 00077 #define MAXTEXT 32766 00078 00079 /************************* utilities ******************************/ 00080 00081 static char findaccent(char char1, unsigned int code) 00082 { 00083 char new= 0; 00084 00085 if(char1=='a') { 00086 if(code=='`') new= 224; 00087 else if(code==39) new= 225; 00088 else if(code=='^') new= 226; 00089 else if(code=='~') new= 227; 00090 else if(code=='"') new= 228; 00091 else if(code=='o') new= 229; 00092 else if(code=='e') new= 230; 00093 else if(code=='-') new= 170; 00094 } 00095 else if(char1=='c') { 00096 if(code==',') new= 231; 00097 if(code=='|') new= 162; 00098 } 00099 else if(char1=='e') { 00100 if(code=='`') new= 232; 00101 else if(code==39) new= 233; 00102 else if(code=='^') new= 234; 00103 else if(code=='"') new= 235; 00104 } 00105 else if(char1=='i') { 00106 if(code=='`') new= 236; 00107 else if(code==39) new= 237; 00108 else if(code=='^') new= 238; 00109 else if(code=='"') new= 239; 00110 } 00111 else if(char1=='n') { 00112 if(code=='~') new= 241; 00113 } 00114 else if(char1=='o') { 00115 if(code=='`') new= 242; 00116 else if(code==39) new= 243; 00117 else if(code=='^') new= 244; 00118 else if(code=='~') new= 245; 00119 else if(code=='"') new= 246; 00120 else if(code=='/') new= 248; 00121 else if(code=='-') new= 186; 00122 else if(code=='e') new= 143; 00123 } 00124 else if(char1=='s') { 00125 if(code=='s') new= 167; 00126 } 00127 else if(char1=='u') { 00128 if(code=='`') new= 249; 00129 else if(code==39) new= 250; 00130 else if(code=='^') new= 251; 00131 else if(code=='"') new= 252; 00132 } 00133 else if(char1=='y') { 00134 if(code==39) new= 253; 00135 else if(code=='"') new= 255; 00136 } 00137 else if(char1=='A') { 00138 if(code=='`') new= 192; 00139 else if(code==39) new= 193; 00140 else if(code=='^') new= 194; 00141 else if(code=='~') new= 195; 00142 else if(code=='"') new= 196; 00143 else if(code=='o') new= 197; 00144 else if(code=='e') new= 198; 00145 } 00146 else if(char1=='C') { 00147 if(code==',') new= 199; 00148 } 00149 else if(char1=='E') { 00150 if(code=='`') new= 200; 00151 else if(code==39) new= 201; 00152 else if(code=='^') new= 202; 00153 else if(code=='"') new= 203; 00154 } 00155 else if(char1=='I') { 00156 if(code=='`') new= 204; 00157 else if(code==39) new= 205; 00158 else if(code=='^') new= 206; 00159 else if(code=='"') new= 207; 00160 } 00161 else if(char1=='N') { 00162 if(code=='~') new= 209; 00163 } 00164 else if(char1=='O') { 00165 if(code=='`') new= 210; 00166 else if(code==39) new= 211; 00167 else if(code=='^') new= 212; 00168 else if(code=='~') new= 213; 00169 else if(code=='"') new= 214; 00170 else if(code=='/') new= 216; 00171 else if(code=='e') new= 141; 00172 } 00173 else if(char1=='U') { 00174 if(code=='`') new= 217; 00175 else if(code==39) new= 218; 00176 else if(code=='^') new= 219; 00177 else if(code=='"') new= 220; 00178 } 00179 else if(char1=='Y') { 00180 if(code==39) new= 221; 00181 } 00182 else if(char1=='1') { 00183 if(code=='4') new= 188; 00184 if(code=='2') new= 189; 00185 } 00186 else if(char1=='3') { 00187 if(code=='4') new= 190; 00188 } 00189 else if(char1==':') { 00190 if(code=='-') new= 247; 00191 } 00192 else if(char1=='-') { 00193 if(code==':') new= 247; 00194 if(code=='|') new= 135; 00195 if(code=='+') new= 177; 00196 } 00197 else if(char1=='|') { 00198 if(code=='-') new= 135; 00199 if(code=='=') new= 136; 00200 } 00201 else if(char1=='=') { 00202 if(code=='|') new= 136; 00203 } 00204 else if(char1=='+') { 00205 if(code=='-') new= 177; 00206 } 00207 00208 if(new) return new; 00209 else return char1; 00210 } 00211 00212 00213 static void update_string(Curve *cu) 00214 { 00215 EditFont *ef= cu->editfont; 00216 int len; 00217 00218 // Free the old curve string 00219 MEM_freeN(cu->str); 00220 00221 // Calculate the actual string length in UTF-8 variable characters 00222 len = BLI_wstrlen_utf8(ef->textbuf); 00223 00224 // Alloc memory for UTF-8 variable char length string 00225 cu->str = MEM_callocN(len + sizeof(wchar_t), "str"); 00226 00227 // Copy the wchar to UTF-8 00228 BLI_strncpy_wchar_as_utf8(cu->str, ef->textbuf, len + 1); 00229 } 00230 00231 static int insert_into_textbuf(Object *obedit, uintptr_t c) 00232 { 00233 Curve *cu= obedit->data; 00234 00235 if(cu->len<MAXTEXT-1) { 00236 EditFont *ef= cu->editfont; 00237 int x; 00238 00239 for(x= cu->len; x>cu->pos; x--) ef->textbuf[x]= ef->textbuf[x-1]; 00240 for(x= cu->len; x>cu->pos; x--) ef->textbufinfo[x]= ef->textbufinfo[x-1]; 00241 ef->textbuf[cu->pos]= c; 00242 ef->textbufinfo[cu->pos] = cu->curinfo; 00243 ef->textbufinfo[cu->pos].kern = 0; 00244 ef->textbufinfo[cu->pos].mat_nr = obedit->actcol; 00245 00246 cu->pos++; 00247 cu->len++; 00248 ef->textbuf[cu->len]='\0'; 00249 00250 update_string(cu); 00251 00252 return 1; 00253 } 00254 else 00255 return 0; 00256 } 00257 00258 static void text_update_edited(bContext *C, Scene *scene, Object *obedit, int recalc, int mode) 00259 { 00260 struct Main *bmain= CTX_data_main(C); 00261 Curve *cu= obedit->data; 00262 EditFont *ef= cu->editfont; 00263 cu->curinfo = ef->textbufinfo[cu->pos?cu->pos-1:0]; 00264 00265 if(obedit->totcol > 0) { 00266 obedit->actcol= ef->textbufinfo[cu->pos?cu->pos-1:0].mat_nr; 00267 00268 /* since this array is calloc'd, it can be 0 even though we try ensure 00269 * (mat_nr > 0) almost everywhere */ 00270 if (obedit->actcol < 1) { 00271 obedit->actcol= 1; 00272 } 00273 } 00274 00275 if(mode == FO_EDIT) 00276 update_string(cu); 00277 00278 BKE_text_to_curve(bmain, scene, obedit, mode); 00279 00280 if(recalc) 00281 DAG_id_tag_update(obedit->data, 0); 00282 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 00283 } 00284 00285 /********************** insert lorem operator *********************/ 00286 00287 static int insert_lorem_exec(bContext *C, wmOperator *UNUSED(op)) 00288 { 00289 Object *obedit= CTX_data_edit_object(C); 00290 const char *p, *p2; 00291 int i; 00292 static const char *lastlorem; 00293 00294 if(lastlorem) 00295 p= lastlorem; 00296 else 00297 p= ED_lorem; 00298 00299 i= rand()/(RAND_MAX/6)+4; 00300 00301 for(p2=p; *p2 && i; p2++) { 00302 insert_into_textbuf(obedit, *p2); 00303 00304 if(*p2=='.') 00305 i--; 00306 } 00307 00308 lastlorem = p2+1; 00309 if(strlen(lastlorem)<5) 00310 lastlorem = ED_lorem; 00311 00312 insert_into_textbuf(obedit, '\n'); 00313 insert_into_textbuf(obedit, '\n'); 00314 00315 DAG_id_tag_update(obedit->data, 0); 00316 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 00317 00318 return OPERATOR_FINISHED; 00319 } 00320 00321 void FONT_OT_insert_lorem(wmOperatorType *ot) 00322 { 00323 /* identifiers */ 00324 ot->name= "Insert Lorem"; 00325 ot->description= "Insert placeholder text"; 00326 ot->idname= "FONT_OT_insert_lorem"; 00327 00328 /* api callbacks */ 00329 ot->exec= insert_lorem_exec; 00330 ot->poll= ED_operator_editfont; 00331 00332 /* flags */ 00333 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00334 } 00335 00336 /******************* paste file operator ********************/ 00337 00338 /* note this handles both ascii and utf8 unicode, previously 00339 * there were 3 functions that did effectively the same thing. */ 00340 00341 static int paste_file(bContext *C, ReportList *reports, const char *filename) 00342 { 00343 Scene *scene= CTX_data_scene(C); 00344 Object *obedit= CTX_data_edit_object(C); 00345 Curve *cu= obedit->data; 00346 EditFont *ef= cu->editfont; 00347 FILE *fp; 00348 int filelen; 00349 char *strp; 00350 00351 fp= fopen(filename, "r"); 00352 00353 if(!fp) { 00354 if(reports) 00355 BKE_reportf(reports, RPT_ERROR, "Failed to open file %s", filename); 00356 return OPERATOR_CANCELLED; 00357 } 00358 00359 fseek(fp, 0L, SEEK_END); 00360 filelen = ftell(fp); 00361 fseek(fp, 0L, SEEK_SET); 00362 00363 strp= MEM_callocN(filelen+4, "tempstr"); 00364 00365 // fread() instead of read(), because windows read() converts text 00366 // to DOS \r\n linebreaks, causing double linebreaks in the 3d text 00367 filelen = fread(strp, 1, filelen, fp); 00368 fclose(fp); 00369 strp[filelen]= 0; 00370 00371 if(cu->len+filelen<MAXTEXT) { 00372 int tmplen; 00373 wchar_t *mem = MEM_callocN((sizeof(wchar_t)*filelen)+(4*sizeof(wchar_t)), "temporary"); 00374 tmplen = BLI_strncpy_wchar_from_utf8(mem, strp, filelen + 1); 00375 wcscat(ef->textbuf, mem); 00376 MEM_freeN(mem); 00377 cu->len += tmplen; 00378 cu->pos= cu->len; 00379 } 00380 MEM_freeN(strp); 00381 00382 text_update_edited(C, scene, obedit, 1, FO_EDIT); 00383 00384 return OPERATOR_FINISHED; 00385 } 00386 00387 static int paste_file_exec(bContext *C, wmOperator *op) 00388 { 00389 char *path; 00390 int retval; 00391 00392 path= RNA_string_get_alloc(op->ptr, "filepath", NULL, 0); 00393 retval= paste_file(C, op->reports, path); 00394 MEM_freeN(path); 00395 00396 return retval; 00397 } 00398 00399 static int paste_file_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 00400 { 00401 if(RNA_struct_property_is_set(op->ptr, "filepath")) 00402 return paste_file_exec(C, op); 00403 00404 WM_event_add_fileselect(C, op); 00405 00406 return OPERATOR_RUNNING_MODAL; 00407 } 00408 00409 void FONT_OT_file_paste(wmOperatorType *ot) 00410 { 00411 /* identifiers */ 00412 ot->name= "Paste File"; 00413 ot->description= "Paste contents from file"; 00414 ot->idname= "FONT_OT_file_paste"; 00415 00416 /* api callbacks */ 00417 ot->exec= paste_file_exec; 00418 ot->invoke= paste_file_invoke; 00419 ot->poll= ED_operator_editfont; 00420 00421 /* flags */ 00422 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00423 00424 /* properties */ 00425 WM_operator_properties_filesel(ot, FOLDERFILE|TEXTFILE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH); 00426 } 00427 00428 /******************* text to object operator ********************/ 00429 00430 static void txt_add_object(bContext *C, TextLine *firstline, int totline, float offset[3]) 00431 { 00432 Scene *scene= CTX_data_scene(C); 00433 Curve *cu; 00434 Object *obedit; 00435 Base *base; 00436 struct TextLine *tmp; 00437 int nchars = 0, a; 00438 float rot[3] = {0.f, 0.f, 0.f}; 00439 00440 obedit= add_object(scene, OB_FONT); 00441 base= scene->basact; 00442 00443 00444 ED_object_base_init_transform(C, base, NULL, rot); /* seems to assume view align ? TODO - look into this, could be an operator option */ 00445 where_is_object(scene, obedit); 00446 00447 obedit->loc[0] += offset[0]; 00448 obedit->loc[1] += offset[1]; 00449 obedit->loc[2] += offset[2]; 00450 00451 cu= obedit->data; 00452 cu->vfont= get_builtin_font(); 00453 cu->vfont->id.us++; 00454 00455 for(tmp=firstline, a=0; cu->len<MAXTEXT && a<totline; tmp=tmp->next, a++) 00456 nchars += strlen(tmp->line) + 1; 00457 00458 if(cu->str) MEM_freeN(cu->str); 00459 if(cu->strinfo) MEM_freeN(cu->strinfo); 00460 00461 cu->str= MEM_callocN(nchars+4, "str"); 00462 cu->strinfo= MEM_callocN((nchars+4)*sizeof(CharInfo), "strinfo"); 00463 00464 cu->str[0]= '\0'; 00465 cu->len= 0; 00466 cu->pos= 0; 00467 00468 for(tmp=firstline, a=0; cu->len<MAXTEXT && a<totline; tmp=tmp->next, a++) { 00469 strcat(cu->str, tmp->line); 00470 cu->len+= strlen(tmp->line); 00471 00472 if(tmp->next) { 00473 strcat(cu->str, "\n"); 00474 cu->len++; 00475 } 00476 00477 cu->pos= cu->len; 00478 } 00479 00480 WM_event_add_notifier(C, NC_OBJECT|NA_ADDED, obedit); 00481 } 00482 00483 void ED_text_to_object(bContext *C, Text *text, int split_lines) 00484 { 00485 RegionView3D *rv3d= CTX_wm_region_view3d(C); 00486 TextLine *line; 00487 float offset[3]; 00488 int linenum= 0; 00489 00490 if(!text || !text->lines.first) return; 00491 00492 if(split_lines) { 00493 for(line=text->lines.first; line; line=line->next) { 00494 /* skip lines with no text, but still make space for them */ 00495 if(line->line[0] == '\0') { 00496 linenum++; 00497 continue; 00498 } 00499 00500 /* do the translation */ 00501 offset[0] = 0; 00502 offset[1] = -linenum; 00503 offset[2] = 0; 00504 00505 if(rv3d) 00506 mul_mat3_m4_v3(rv3d->viewinv, offset); 00507 00508 txt_add_object(C, line, 1, offset); 00509 00510 linenum++; 00511 } 00512 } 00513 else { 00514 offset[0]= 0.0f; 00515 offset[1]= 0.0f; 00516 offset[2]= 0.0f; 00517 00518 txt_add_object(C, text->lines.first, BLI_countlist(&text->lines), offset); 00519 } 00520 } 00521 00522 /********************** utilities ***************************/ 00523 00524 static short next_word(Curve *cu) 00525 { 00526 short s; 00527 for(s=cu->pos; (cu->str[s]) && (cu->str[s]!=' ') && (cu->str[s]!='\n') && 00528 (cu->str[s]!=1) && (cu->str[s]!='\r'); s++); 00529 if(cu->str[s]) return(s+1); else return(s); 00530 } 00531 00532 static short prev_word(Curve *cu) 00533 { 00534 short s; 00535 00536 if(cu->pos==0) return(0); 00537 for(s=cu->pos-2; (cu->str[s]) && (cu->str[s]!=' ') && (cu->str[s]!='\n') && 00538 (cu->str[s]!=1) && (cu->str[s]!='\r'); s--); 00539 if(cu->str[s]) return(s+1); else return(s); 00540 } 00541 00542 static int kill_selection(Object *obedit, int ins) /* 1 == new character */ 00543 { 00544 Curve *cu= obedit->data; 00545 EditFont *ef= cu->editfont; 00546 int selend, selstart, direction; 00547 int offset = 0; 00548 int getfrom; 00549 00550 direction = BKE_font_getselection(obedit, &selstart, &selend); 00551 if(direction) { 00552 int size; 00553 if(ins) offset = 1; 00554 if(cu->pos >= selstart) cu->pos = selstart+offset; 00555 if((direction == -1) && ins) { 00556 selstart++; 00557 selend++; 00558 } 00559 getfrom = selend+offset; 00560 if(ins==0) getfrom++; 00561 size = (cu->len * sizeof(wchar_t)) - (selstart * sizeof(wchar_t)) + (offset*sizeof(wchar_t)); 00562 memmove(ef->textbuf+selstart, ef->textbuf+getfrom, size); 00563 memmove(ef->textbufinfo+selstart, ef->textbufinfo+getfrom, ((cu->len-selstart)+offset)*sizeof(CharInfo)); 00564 cu->len -= (selend-selstart)+offset; 00565 cu->selstart = cu->selend = 0; 00566 } 00567 00568 return(direction); 00569 } 00570 00571 /******************* set style operator ********************/ 00572 00573 static EnumPropertyItem style_items[]= { 00574 {CU_CHINFO_BOLD, "BOLD", 0, "Bold", ""}, 00575 {CU_CHINFO_ITALIC, "ITALIC", 0, "Italic", ""}, 00576 {CU_CHINFO_UNDERLINE, "UNDERLINE", 0, "Underline", ""}, 00577 {CU_CHINFO_SMALLCAPS, "SMALL_CAPS", 0, "Small Caps", ""}, 00578 {0, NULL, 0, NULL, NULL}}; 00579 00580 static int set_style(bContext *C, const int style, const int clear) 00581 { 00582 Object *obedit= CTX_data_edit_object(C); 00583 Curve *cu= obedit->data; 00584 EditFont *ef= cu->editfont; 00585 int i, selstart, selend; 00586 00587 if(!BKE_font_getselection(obedit, &selstart, &selend)) 00588 return OPERATOR_CANCELLED; 00589 00590 for(i=selstart; i<=selend; i++) { 00591 if(clear) 00592 ef->textbufinfo[i].flag &= ~style; 00593 else 00594 ef->textbufinfo[i].flag |= style; 00595 } 00596 00597 DAG_id_tag_update(obedit->data, 0); 00598 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 00599 00600 return OPERATOR_FINISHED; 00601 } 00602 00603 static int set_style_exec(bContext *C, wmOperator *op) 00604 { 00605 const int style= RNA_enum_get(op->ptr, "style"); 00606 const int clear= RNA_boolean_get(op->ptr, "clear"); 00607 00608 return set_style(C, style, clear); 00609 } 00610 00611 void FONT_OT_style_set(wmOperatorType *ot) 00612 { 00613 /* identifiers */ 00614 ot->name= "Set Style"; 00615 ot->description= "Set font style"; 00616 ot->idname= "FONT_OT_style_set"; 00617 00618 /* api callbacks */ 00619 ot->exec= set_style_exec; 00620 ot->poll= ED_operator_editfont; 00621 00622 /* flags */ 00623 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00624 00625 /* properties */ 00626 RNA_def_enum(ot->srna, "style", style_items, CU_CHINFO_BOLD, "Style", "Style to set selection to"); 00627 RNA_def_boolean(ot->srna, "clear", 0, "Clear", "Clear style rather than setting it"); 00628 } 00629 00630 /******************* toggle style operator ********************/ 00631 00632 static int toggle_style_exec(bContext *C, wmOperator *op) 00633 { 00634 Object *obedit= CTX_data_edit_object(C); 00635 Curve *cu= obedit->data; 00636 int style, clear, selstart, selend; 00637 00638 if(!BKE_font_getselection(obedit, &selstart, &selend)) 00639 return OPERATOR_CANCELLED; 00640 00641 style= RNA_enum_get(op->ptr, "style"); 00642 00643 cu->curinfo.flag ^= style; 00644 clear= (cu->curinfo.flag & style) == 0; 00645 00646 return set_style(C, style, clear); 00647 } 00648 00649 void FONT_OT_style_toggle(wmOperatorType *ot) 00650 { 00651 /* identifiers */ 00652 ot->name= "Toggle Style"; 00653 ot->description= "Toggle font style"; 00654 ot->idname= "FONT_OT_style_toggle"; 00655 00656 /* api callbacks */ 00657 ot->exec= toggle_style_exec; 00658 ot->poll= ED_operator_editfont; 00659 00660 /* flags */ 00661 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00662 00663 /* properties */ 00664 RNA_def_enum(ot->srna, "style", style_items, CU_CHINFO_BOLD, "Style", "Style to set selection to"); 00665 } 00666 00667 /******************* copy text operator ********************/ 00668 00669 static void copy_selection(Object *obedit) 00670 { 00671 int selstart, selend; 00672 00673 if(BKE_font_getselection(obedit, &selstart, &selend)) { 00674 Curve *cu= obedit->data; 00675 EditFont *ef= cu->editfont; 00676 00677 memcpy(ef->copybuf, ef->textbuf+selstart, ((selend-selstart)+1)*sizeof(wchar_t)); 00678 ef->copybuf[(selend-selstart)+1]=0; 00679 memcpy(ef->copybufinfo, ef->textbufinfo+selstart, ((selend-selstart)+1)*sizeof(CharInfo)); 00680 } 00681 } 00682 00683 static int copy_text_exec(bContext *C, wmOperator *UNUSED(op)) 00684 { 00685 Object *obedit= CTX_data_edit_object(C); 00686 00687 copy_selection(obedit); 00688 00689 return OPERATOR_FINISHED; 00690 } 00691 00692 void FONT_OT_text_copy(wmOperatorType *ot) 00693 { 00694 /* identifiers */ 00695 ot->name= "Copy Text"; 00696 ot->description= "Copy selected text to clipboard"; 00697 ot->idname= "FONT_OT_text_copy"; 00698 00699 /* api callbacks */ 00700 ot->exec= copy_text_exec; 00701 ot->poll= ED_operator_editfont; 00702 } 00703 00704 /******************* cut text operator ********************/ 00705 00706 static int cut_text_exec(bContext *C, wmOperator *UNUSED(op)) 00707 { 00708 Scene *scene= CTX_data_scene(C); 00709 Object *obedit= CTX_data_edit_object(C); 00710 int selstart, selend; 00711 00712 if(!BKE_font_getselection(obedit, &selstart, &selend)) 00713 return OPERATOR_CANCELLED; 00714 00715 copy_selection(obedit); 00716 kill_selection(obedit, 0); 00717 00718 text_update_edited(C, scene, obedit, 1, FO_EDIT); 00719 00720 return OPERATOR_FINISHED; 00721 } 00722 00723 void FONT_OT_text_cut(wmOperatorType *ot) 00724 { 00725 /* identifiers */ 00726 ot->name= "Cut Text"; 00727 ot->description= "Cut selected text to clipboard"; 00728 ot->idname= "FONT_OT_text_cut"; 00729 00730 /* api callbacks */ 00731 ot->exec= cut_text_exec; 00732 ot->poll= ED_operator_editfont; 00733 00734 /* flags */ 00735 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00736 } 00737 00738 /******************* paste text operator ********************/ 00739 00740 static int paste_selection(Object *obedit, ReportList *reports) 00741 { 00742 Curve *cu= obedit->data; 00743 EditFont *ef= cu->editfont; 00744 int len= wcslen(ef->copybuf); 00745 00746 // Verify that the copy buffer => [copy buffer len] + cu->len < MAXTEXT 00747 if(cu->len + len <= MAXTEXT) { 00748 if(len) { 00749 int size = (cu->len * sizeof(wchar_t)) - (cu->pos*sizeof(wchar_t)) + sizeof(wchar_t); 00750 memmove(ef->textbuf+cu->pos+len, ef->textbuf+cu->pos, size); 00751 memcpy(ef->textbuf+cu->pos, ef->copybuf, len * sizeof(wchar_t)); 00752 00753 memmove(ef->textbufinfo+cu->pos+len, ef->textbufinfo+cu->pos, (cu->len-cu->pos+1)*sizeof(CharInfo)); 00754 memcpy(ef->textbufinfo+cu->pos, ef->copybufinfo, len*sizeof(CharInfo)); 00755 00756 cu->len += len; 00757 cu->pos += len; 00758 00759 return 1; 00760 } 00761 } 00762 else 00763 BKE_report(reports, RPT_WARNING, "Text too long"); 00764 00765 return 0; 00766 } 00767 00768 static int paste_text_exec(bContext *C, wmOperator *op) 00769 { 00770 Scene *scene= CTX_data_scene(C); 00771 Object *obedit= CTX_data_edit_object(C); 00772 00773 if(!paste_selection(obedit, op->reports)) 00774 return OPERATOR_CANCELLED; 00775 00776 text_update_edited(C, scene, obedit, 1, FO_EDIT); 00777 00778 return OPERATOR_FINISHED; 00779 } 00780 00781 void FONT_OT_text_paste(wmOperatorType *ot) 00782 { 00783 /* identifiers */ 00784 ot->name= "Paste Text"; 00785 ot->description= "Paste text from clipboard"; 00786 ot->idname= "FONT_OT_text_paste"; 00787 00788 /* api callbacks */ 00789 ot->exec= paste_text_exec; 00790 ot->poll= ED_operator_editfont; 00791 00792 /* flags */ 00793 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00794 } 00795 00796 /************************ move operator ************************/ 00797 00798 static EnumPropertyItem move_type_items[]= { 00799 {LINE_BEGIN, "LINE_BEGIN", 0, "Line Begin", ""}, 00800 {LINE_END, "LINE_END", 0, "Line End", ""}, 00801 {PREV_CHAR, "PREVIOUS_CHARACTER", 0, "Previous Character", ""}, 00802 {NEXT_CHAR, "NEXT_CHARACTER", 0, "Next Character", ""}, 00803 {PREV_WORD, "PREVIOUS_WORD", 0, "Previous Word", ""}, 00804 {NEXT_WORD, "NEXT_WORD", 0, "Next Word", ""}, 00805 {PREV_LINE, "PREVIOUS_LINE", 0, "Previous Line", ""}, 00806 {NEXT_LINE, "NEXT_LINE", 0, "Next Line", ""}, 00807 {PREV_PAGE, "PREVIOUS_PAGE", 0, "Previous Page", ""}, 00808 {NEXT_PAGE, "NEXT_PAGE", 0, "Next Page", ""}, 00809 {0, NULL, 0, NULL, NULL}}; 00810 00811 static int move_cursor(bContext *C, int type, int select) 00812 { 00813 Scene *scene= CTX_data_scene(C); 00814 Object *obedit= CTX_data_edit_object(C); 00815 Curve *cu= obedit->data; 00816 EditFont *ef= cu->editfont; 00817 int cursmove= -1; 00818 00819 switch(type) { 00820 case LINE_BEGIN: 00821 if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1; 00822 while(cu->pos>0) { 00823 if(ef->textbuf[cu->pos-1]=='\n') break; 00824 if(ef->textbufinfo[cu->pos-1].flag & CU_CHINFO_WRAP) break; 00825 cu->pos--; 00826 } 00827 cursmove=FO_CURS; 00828 break; 00829 00830 case LINE_END: 00831 if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1; 00832 while(cu->pos<cu->len) { 00833 if(ef->textbuf[cu->pos]==0) break; 00834 if(ef->textbuf[cu->pos]=='\n') break; 00835 if(ef->textbufinfo[cu->pos].flag & CU_CHINFO_WRAP ) break; 00836 cu->pos++; 00837 } 00838 cursmove=FO_CURS; 00839 break; 00840 00841 case PREV_WORD: 00842 if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1; 00843 cu->pos= prev_word(cu); 00844 cursmove= FO_CURS; 00845 break; 00846 00847 case NEXT_WORD: 00848 if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1; 00849 cu->pos= next_word(cu); 00850 cursmove= FO_CURS; 00851 break; 00852 00853 case PREV_CHAR: 00854 if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1; 00855 cu->pos--; 00856 cursmove=FO_CURS; 00857 break; 00858 00859 case NEXT_CHAR: 00860 if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1; 00861 cu->pos++; 00862 cursmove= FO_CURS; 00863 00864 break; 00865 00866 case PREV_LINE: 00867 if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1; 00868 cursmove=FO_CURSUP; 00869 break; 00870 00871 case NEXT_LINE: 00872 if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1; 00873 cursmove= FO_CURSDOWN; 00874 break; 00875 00876 case PREV_PAGE: 00877 if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1; 00878 cursmove=FO_PAGEUP; 00879 break; 00880 00881 case NEXT_PAGE: 00882 if((select) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1; 00883 cursmove=FO_PAGEDOWN; 00884 break; 00885 } 00886 00887 if(cursmove == -1) 00888 return OPERATOR_CANCELLED; 00889 00890 if(select == 0) { 00891 if(cu->selstart) { 00892 struct Main *bmain= CTX_data_main(C); 00893 cu->selstart = cu->selend = 0; 00894 update_string(cu); 00895 BKE_text_to_curve(bmain, scene, obedit, FO_SELCHANGE); 00896 } 00897 } 00898 00899 if(cu->pos>cu->len) cu->pos= cu->len; 00900 else if(cu->pos>=MAXTEXT) cu->pos= MAXTEXT; 00901 else if(cu->pos<0) cu->pos= 0; 00902 00903 text_update_edited(C, scene, obedit, select, cursmove); 00904 00905 if(select) 00906 cu->selend = cu->pos; 00907 00908 return OPERATOR_FINISHED; 00909 } 00910 00911 static int move_exec(bContext *C, wmOperator *op) 00912 { 00913 int type= RNA_enum_get(op->ptr, "type"); 00914 00915 return move_cursor(C, type, 0); 00916 } 00917 00918 void FONT_OT_move(wmOperatorType *ot) 00919 { 00920 /* identifiers */ 00921 ot->name= "Move Cursor"; 00922 ot->description= "Move cursor to position type"; 00923 ot->idname= "FONT_OT_move"; 00924 00925 /* api callbacks */ 00926 ot->exec= move_exec; 00927 ot->poll= ED_operator_editfont; 00928 00929 /* flags */ 00930 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00931 00932 /* properties */ 00933 RNA_def_enum(ot->srna, "type", move_type_items, LINE_BEGIN, "Type", "Where to move cursor to"); 00934 } 00935 00936 /******************* move select operator ********************/ 00937 00938 static int move_select_exec(bContext *C, wmOperator *op) 00939 { 00940 int type= RNA_enum_get(op->ptr, "type"); 00941 00942 return move_cursor(C, type, 1); 00943 } 00944 00945 void FONT_OT_move_select(wmOperatorType *ot) 00946 { 00947 /* identifiers */ 00948 ot->name= "Move Select"; 00949 ot->description= "Make selection from current cursor position to new cursor position type"; 00950 ot->idname= "FONT_OT_move_select"; 00951 00952 /* api callbacks */ 00953 ot->exec= move_select_exec; 00954 ot->poll= ED_operator_editfont; 00955 00956 /* flags */ 00957 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00958 00959 /* properties */ 00960 RNA_def_enum(ot->srna, "type", move_type_items, LINE_BEGIN, "Type", "Where to move cursor to, to make a selection"); 00961 } 00962 00963 /************************* change spacing **********************/ 00964 00965 static int change_spacing_exec(bContext *C, wmOperator *op) 00966 { 00967 Scene *scene= CTX_data_scene(C); 00968 Object *obedit= CTX_data_edit_object(C); 00969 Curve *cu= obedit->data; 00970 EditFont *ef= cu->editfont; 00971 int kern, delta= RNA_int_get(op->ptr, "delta"); 00972 00973 kern = ef->textbufinfo[cu->pos-1].kern; 00974 kern += delta; 00975 CLAMP(kern, -20, 20); 00976 00977 if(ef->textbufinfo[cu->pos-1].kern == kern) 00978 return OPERATOR_CANCELLED; 00979 00980 ef->textbufinfo[cu->pos-1].kern = kern; 00981 00982 text_update_edited(C, scene, obedit, 1, FO_EDIT); 00983 00984 return OPERATOR_FINISHED; 00985 } 00986 00987 void FONT_OT_change_spacing(wmOperatorType *ot) 00988 { 00989 /* identifiers */ 00990 ot->name= "Change Spacing"; 00991 ot->description= "Change font spacing"; 00992 ot->idname= "FONT_OT_change_spacing"; 00993 00994 /* api callbacks */ 00995 ot->exec= change_spacing_exec; 00996 ot->poll= ED_operator_editfont; 00997 00998 /* flags */ 00999 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01000 01001 /* properties */ 01002 RNA_def_int(ot->srna, "delta", 1, -20, 20, "Delta", "Amount to decrease or increase character spacing with", -20, 20); 01003 } 01004 01005 /************************* change character **********************/ 01006 01007 static int change_character_exec(bContext *C, wmOperator *op) 01008 { 01009 Scene *scene= CTX_data_scene(C); 01010 Object *obedit= CTX_data_edit_object(C); 01011 Curve *cu= obedit->data; 01012 EditFont *ef= cu->editfont; 01013 int character, delta= RNA_int_get(op->ptr, "delta"); 01014 01015 if(cu->pos <= 0) 01016 return OPERATOR_CANCELLED; 01017 01018 character= ef->textbuf[cu->pos - 1]; 01019 character += delta; 01020 CLAMP(character, 0, 255); 01021 01022 if(character == ef->textbuf[cu->pos - 1]) 01023 return OPERATOR_CANCELLED; 01024 01025 ef->textbuf[cu->pos - 1]= character; 01026 01027 text_update_edited(C, scene, obedit, 1, FO_EDIT); 01028 01029 return OPERATOR_FINISHED; 01030 } 01031 01032 void FONT_OT_change_character(wmOperatorType *ot) 01033 { 01034 /* identifiers */ 01035 ot->name= "Change Character"; 01036 ot->description= "Change font character code"; 01037 ot->idname= "FONT_OT_change_character"; 01038 01039 /* api callbacks */ 01040 ot->exec= change_character_exec; 01041 ot->poll= ED_operator_editfont; 01042 01043 /* flags */ 01044 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01045 01046 /* properties */ 01047 RNA_def_int(ot->srna, "delta", 1, -255, 255, "Delta", "Number to increase or decrease character code with", -255, 255); 01048 } 01049 01050 /******************* line break operator ********************/ 01051 01052 static int line_break_exec(bContext *C, wmOperator *op) 01053 { 01054 Scene *scene= CTX_data_scene(C); 01055 Object *obedit= CTX_data_edit_object(C); 01056 Curve *cu= obedit->data; 01057 EditFont *ef= cu->editfont; 01058 const int ctrl= RNA_boolean_get(op->ptr, "ctrl"); 01059 01060 if(ctrl) { 01061 insert_into_textbuf(obedit, 1); 01062 if(ef->textbuf[cu->pos]!='\n') 01063 insert_into_textbuf(obedit, '\n'); 01064 } 01065 else 01066 insert_into_textbuf(obedit, '\n'); 01067 01068 cu->selstart = cu->selend = 0; 01069 01070 text_update_edited(C, scene, obedit, 1, FO_EDIT); 01071 01072 return OPERATOR_FINISHED; 01073 } 01074 01075 void FONT_OT_line_break(wmOperatorType *ot) 01076 { 01077 /* identifiers */ 01078 ot->name= "Line Break"; 01079 ot->description= "Insert line break at cursor position"; 01080 ot->idname= "FONT_OT_line_break"; 01081 01082 /* api callbacks */ 01083 ot->exec= line_break_exec; 01084 ot->poll= ED_operator_editfont; 01085 01086 /* flags */ 01087 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01088 01089 /* properties */ 01090 RNA_def_boolean(ot->srna, "ctrl", 0, "Ctrl", ""); // XXX what is this? 01091 } 01092 01093 /******************* delete operator **********************/ 01094 01095 static EnumPropertyItem delete_type_items[]= { 01096 {DEL_ALL, "ALL", 0, "All", ""}, 01097 {DEL_NEXT_CHAR, "NEXT_CHARACTER", 0, "Next Character", ""}, 01098 {DEL_PREV_CHAR, "PREVIOUS_CHARACTER", 0, "Previous Character", ""}, 01099 {DEL_SELECTION, "SELECTION", 0, "Selection", ""}, 01100 {DEL_NEXT_SEL, "NEXT_OR_SELECTION", 0, "Next or Selection", ""}, 01101 {DEL_PREV_SEL, "PREVIOUS_OR_SELECTION", 0, "Previous or Selection", ""}, 01102 {0, NULL, 0, NULL, NULL}}; 01103 01104 static int delete_exec(bContext *C, wmOperator *op) 01105 { 01106 Scene *scene= CTX_data_scene(C); 01107 Object *obedit= CTX_data_edit_object(C); 01108 Curve *cu= obedit->data; 01109 EditFont *ef= cu->editfont; 01110 int x, selstart, selend, type= RNA_enum_get(op->ptr, "type"); 01111 01112 if(cu->len == 0) 01113 return OPERATOR_CANCELLED; 01114 01115 if(BKE_font_getselection(obedit, &selstart, &selend)) { 01116 if(type == DEL_NEXT_SEL) type= DEL_SELECTION; 01117 else if(type == DEL_PREV_SEL) type= DEL_SELECTION; 01118 } 01119 else { 01120 if(type == DEL_NEXT_SEL) type= DEL_NEXT_CHAR; 01121 else if(type == DEL_PREV_SEL) type= DEL_PREV_CHAR; 01122 } 01123 01124 switch(type) { 01125 case DEL_ALL: 01126 cu->len = cu->pos = 0; 01127 ef->textbuf[0]= 0; 01128 break; 01129 case DEL_SELECTION: 01130 if(!kill_selection(obedit, 0)) 01131 return OPERATOR_CANCELLED; 01132 break; 01133 case DEL_PREV_CHAR: 01134 if(cu->pos<=0) 01135 return OPERATOR_CANCELLED; 01136 01137 for(x=cu->pos;x<=cu->len;x++) 01138 ef->textbuf[x-1]= ef->textbuf[x]; 01139 for(x=cu->pos;x<=cu->len;x++) 01140 ef->textbufinfo[x-1]= ef->textbufinfo[x]; 01141 01142 cu->pos--; 01143 ef->textbuf[--cu->len]='\0'; 01144 break; 01145 case DEL_NEXT_CHAR: 01146 if(cu->pos>=cu->len) 01147 return OPERATOR_CANCELLED; 01148 01149 for(x=cu->pos;x<cu->len;x++) 01150 ef->textbuf[x]= ef->textbuf[x+1]; 01151 for(x=cu->pos;x<cu->len;x++) 01152 ef->textbufinfo[x]= ef->textbufinfo[x+1]; 01153 01154 ef->textbuf[--cu->len]='\0'; 01155 break; 01156 default: 01157 return OPERATOR_CANCELLED; 01158 } 01159 01160 text_update_edited(C, scene, obedit, 1, FO_EDIT); 01161 01162 return OPERATOR_FINISHED; 01163 } 01164 01165 void FONT_OT_delete(wmOperatorType *ot) 01166 { 01167 /* identifiers */ 01168 ot->name= "Delete"; 01169 ot->description= "Delete text by cursor position"; 01170 ot->idname= "FONT_OT_delete"; 01171 01172 /* api callbacks */ 01173 ot->exec= delete_exec; 01174 ot->poll= ED_operator_editfont; 01175 01176 /* flags */ 01177 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01178 01179 /* properties */ 01180 RNA_def_enum(ot->srna, "type", delete_type_items, DEL_ALL, "Type", "Which part of the text to delete"); 01181 } 01182 01183 /*********************** insert text operator *************************/ 01184 01185 static int insert_text_exec(bContext *C, wmOperator *op) 01186 { 01187 Scene *scene= CTX_data_scene(C); 01188 Object *obedit= CTX_data_edit_object(C); 01189 char *inserted_utf8; 01190 wchar_t *inserted_text; 01191 int a, len; 01192 01193 if(!RNA_struct_property_is_set(op->ptr, "text")) 01194 return OPERATOR_CANCELLED; 01195 01196 inserted_utf8= RNA_string_get_alloc(op->ptr, "text", NULL, 0); 01197 len= BLI_strlen_utf8(inserted_utf8); 01198 01199 inserted_text= MEM_callocN(sizeof(wchar_t)*(len+1), "FONT_insert_text"); 01200 BLI_strncpy_wchar_from_utf8(inserted_text, inserted_utf8, len+1); 01201 01202 for(a=0; a<len; a++) 01203 insert_into_textbuf(obedit, inserted_text[a]); 01204 01205 MEM_freeN(inserted_text); 01206 MEM_freeN(inserted_utf8); 01207 01208 kill_selection(obedit, 1); 01209 text_update_edited(C, scene, obedit, 1, FO_EDIT); 01210 01211 return OPERATOR_FINISHED; 01212 } 01213 01214 static int insert_text_invoke(bContext *C, wmOperator *op, wmEvent *evt) 01215 { 01216 Scene *scene= CTX_data_scene(C); 01217 Object *obedit= CTX_data_edit_object(C); 01218 Curve *cu= obedit->data; 01219 EditFont *ef= cu->editfont; 01220 static int accentcode= 0; 01221 uintptr_t ascii = evt->ascii; 01222 int alt= evt->alt, shift= evt->shift, ctrl= evt->ctrl; 01223 int event= evt->type, val= evt->val; 01224 wchar_t inserted_text[2]= {0}; 01225 01226 if(RNA_struct_property_is_set(op->ptr, "text")) 01227 return insert_text_exec(C, op); 01228 01229 if(RNA_struct_property_is_set(op->ptr, "accent")) { 01230 if(cu->len!=0 && cu->pos>0) 01231 accentcode= 1; 01232 return OPERATOR_FINISHED; 01233 } 01234 01235 /* tab should exit editmode, but we allow it to be typed using modifier keys */ 01236 if(event==TABKEY) { 01237 if((alt||ctrl||shift) == 0) 01238 return OPERATOR_PASS_THROUGH; 01239 else 01240 ascii= 9; 01241 } 01242 else if(event==BACKSPACEKEY) 01243 ascii= 0; 01244 01245 if(val && (ascii || evt->utf8_buf[0])) { 01246 /* handle case like TAB (== 9) */ 01247 if( (ascii > 31 && ascii < 254 && ascii != 127) || 01248 (ascii==13) || 01249 (ascii==10) || 01250 (ascii==8) || 01251 (evt->utf8_buf[0])) 01252 { 01253 01254 if (evt->utf8_buf[0]) { 01255 BLI_strncpy_wchar_from_utf8(inserted_text, evt->utf8_buf, 1); 01256 ascii= inserted_text[0]; 01257 insert_into_textbuf(obedit, ascii); 01258 accentcode= 0; 01259 } 01260 else if(accentcode) { 01261 if(cu->pos>0) { 01262 inserted_text[0]= findaccent(ef->textbuf[cu->pos-1], ascii); 01263 ef->textbuf[cu->pos-1]= inserted_text[0]; 01264 } 01265 accentcode= 0; 01266 } 01267 else if(cu->len<MAXTEXT-1) { 01268 if(alt) { 01269 /* might become obsolete, apple has default values for this, other OS's too? */ 01270 if(ascii=='t') ascii= 137; 01271 else if(ascii=='c') ascii= 169; 01272 else if(ascii=='f') ascii= 164; 01273 else if(ascii=='g') ascii= 176; 01274 else if(ascii=='l') ascii= 163; 01275 else if(ascii=='r') ascii= 174; 01276 else if(ascii=='s') ascii= 223; 01277 else if(ascii=='y') ascii= 165; 01278 else if(ascii=='.') ascii= 138; 01279 else if(ascii=='1') ascii= 185; 01280 else if(ascii=='2') ascii= 178; 01281 else if(ascii=='3') ascii= 179; 01282 else if(ascii=='%') ascii= 139; 01283 else if(ascii=='?') ascii= 191; 01284 else if(ascii=='!') ascii= 161; 01285 else if(ascii=='x') ascii= 215; 01286 else if(ascii=='>') ascii= 187; 01287 else if(ascii=='<') ascii= 171; 01288 } 01289 01290 inserted_text[0]= ascii; 01291 insert_into_textbuf(obedit, ascii); 01292 } 01293 01294 kill_selection(obedit, 1); 01295 text_update_edited(C, scene, obedit, 1, FO_EDIT); 01296 } 01297 else { 01298 inserted_text[0]= ascii; 01299 insert_into_textbuf(obedit, ascii); 01300 text_update_edited(C, scene, obedit, 1, FO_EDIT); 01301 } 01302 } 01303 else if(val && event == BACKSPACEKEY) { 01304 if(alt && cu->len!=0 && cu->pos>0) 01305 accentcode= 1; 01306 01307 return OPERATOR_PASS_THROUGH; 01308 } 01309 else 01310 return OPERATOR_PASS_THROUGH; 01311 01312 if(inserted_text[0]) { 01313 /* store as utf8 in RNA string */ 01314 char inserted_utf8[8] = {0}; 01315 01316 BLI_strncpy_wchar_as_utf8(inserted_utf8, inserted_text, sizeof(inserted_utf8)); 01317 RNA_string_set(op->ptr, "text", inserted_utf8); 01318 } 01319 01320 /* reset property? */ 01321 accentcode= 0; 01322 01323 return OPERATOR_FINISHED; 01324 } 01325 01326 void FONT_OT_text_insert(wmOperatorType *ot) 01327 { 01328 /* identifiers */ 01329 ot->name= "Insert Text"; 01330 ot->description= "Insert text at cursor position"; 01331 ot->idname= "FONT_OT_text_insert"; 01332 01333 /* api callbacks */ 01334 ot->exec= insert_text_exec; 01335 ot->invoke= insert_text_invoke; 01336 ot->poll= ED_operator_editfont; 01337 01338 /* flags */ 01339 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01340 01341 /* properties */ 01342 RNA_def_string(ot->srna, "text", "", 0, "Text", "Text to insert at the cursor position"); 01343 RNA_def_boolean(ot->srna, "accent", 0, "Accent mode", "Next typed character will strike through previous, for special character input"); 01344 } 01345 01346 01347 /*********************** textbox add operator *************************/ 01348 static int textbox_add_exec(bContext *C, wmOperator *UNUSED(op)) 01349 { 01350 Object *obedit= CTX_data_active_object(C); 01351 Curve *cu= obedit->data; 01352 int i; 01353 01354 if (cu->totbox < 256) { 01355 for (i = cu->totbox; i>cu->actbox; i--) cu->tb[i]= cu->tb[i-1]; 01356 cu->tb[cu->actbox]= cu->tb[cu->actbox-1]; 01357 cu->actbox++; 01358 cu->totbox++; 01359 } 01360 01361 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 01362 return OPERATOR_FINISHED; 01363 } 01364 01365 void FONT_OT_textbox_add(wmOperatorType *ot) 01366 { 01367 /* identifiers */ 01368 ot->name= "Add Textbox"; 01369 ot->description= "Add a new text box"; 01370 ot->idname= "FONT_OT_textbox_add"; 01371 01372 /* api callbacks */ 01373 ot->exec= textbox_add_exec; 01374 ot->poll= ED_operator_object_active_editable_font; 01375 01376 /* flags */ 01377 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01378 01379 01380 } 01381 01382 01383 01384 /*********************** textbox remove operator *************************/ 01385 01386 01387 01388 static int textbox_remove_exec(bContext *C, wmOperator *op) 01389 { 01390 Object *obedit= CTX_data_active_object(C); 01391 Curve *cu= obedit->data; 01392 int i; 01393 int index = RNA_int_get(op->ptr, "index"); 01394 01395 01396 if (cu->totbox > 1) { 01397 for (i = index; i < cu->totbox; i++) cu->tb[i]= cu->tb[i+1]; 01398 cu->totbox--; 01399 if (cu->actbox >= index) 01400 cu->actbox--; 01401 } 01402 01403 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 01404 01405 return OPERATOR_FINISHED; 01406 } 01407 01408 void FONT_OT_textbox_remove(wmOperatorType *ot) 01409 { 01410 /* identifiers */ 01411 ot->name= "Remove Textbox"; 01412 ot->description= "Remove the textbox"; 01413 ot->idname= "FONT_OT_textbox_remove"; 01414 01415 /* api callbacks */ 01416 ot->exec= textbox_remove_exec; 01417 ot->poll= ED_operator_object_active_editable_font; 01418 01419 /* flags */ 01420 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01421 01422 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "The current text box", 0, INT_MAX); 01423 } 01424 01425 01426 01427 /***************** editmode enter/exit ********************/ 01428 01429 void make_editText(Object *obedit) 01430 { 01431 Curve *cu= obedit->data; 01432 EditFont *ef= cu->editfont; 01433 01434 if(ef==NULL) { 01435 ef= cu->editfont= MEM_callocN(sizeof(EditFont), "editfont"); 01436 01437 ef->textbuf= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "texteditbuf"); 01438 ef->textbufinfo= MEM_callocN((MAXTEXT+4)*sizeof(CharInfo), "texteditbufinfo"); 01439 ef->copybuf= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "texteditcopybuf"); 01440 ef->copybufinfo= MEM_callocN((MAXTEXT+4)*sizeof(CharInfo), "texteditcopybufinfo"); 01441 ef->oldstr= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "oldstrbuf"); 01442 ef->oldstrinfo= MEM_callocN((MAXTEXT+4)*sizeof(CharInfo), "oldstrbuf"); 01443 } 01444 01445 // Convert the original text to wchar_t 01446 BLI_strncpy_wchar_from_utf8(ef->textbuf, cu->str, MAXTEXT+4); /* length is bogus */ 01447 wcscpy(ef->oldstr, ef->textbuf); 01448 01449 cu->len= wcslen(ef->textbuf); 01450 01451 memcpy(ef->textbufinfo, cu->strinfo, (cu->len)*sizeof(CharInfo)); 01452 memcpy(ef->oldstrinfo, cu->strinfo, (cu->len)*sizeof(CharInfo)); 01453 01454 if(cu->pos>cu->len) cu->pos= cu->len; 01455 01456 if(cu->pos) 01457 cu->curinfo = ef->textbufinfo[cu->pos-1]; 01458 else 01459 cu->curinfo = ef->textbufinfo[0]; 01460 01461 // Convert to UTF-8 01462 update_string(cu); 01463 } 01464 01465 void load_editText(Object *obedit) 01466 { 01467 Curve *cu= obedit->data; 01468 EditFont *ef= cu->editfont; 01469 01470 MEM_freeN(ef->oldstr); 01471 ef->oldstr= NULL; 01472 MEM_freeN(ef->oldstrinfo); 01473 ef->oldstrinfo= NULL; 01474 01475 update_string(cu); 01476 01477 if(cu->strinfo) 01478 MEM_freeN(cu->strinfo); 01479 cu->strinfo= MEM_callocN((cu->len+4)*sizeof(CharInfo), "texteditinfo"); 01480 memcpy(cu->strinfo, ef->textbufinfo, (cu->len)*sizeof(CharInfo)); 01481 01482 cu->len= strlen(cu->str); 01483 01484 /* this memory system is weak... */ 01485 01486 if(cu->selboxes) { 01487 MEM_freeN(cu->selboxes); 01488 cu->selboxes= NULL; 01489 } 01490 } 01491 01492 void free_editText(Object *obedit) 01493 { 01494 BKE_free_editfont((Curve *)obedit->data); 01495 } 01496 01497 /********************** set case operator *********************/ 01498 01499 static EnumPropertyItem case_items[]= { 01500 {CASE_LOWER, "LOWER", 0, "Lower", ""}, 01501 {CASE_UPPER, "UPPER", 0, "Upper", ""}, 01502 {0, NULL, 0, NULL, NULL}}; 01503 01504 static int set_case(bContext *C, int ccase) 01505 { 01506 Scene *scene= CTX_data_scene(C); 01507 Object *obedit= CTX_data_edit_object(C); 01508 Curve *cu= obedit->data; 01509 EditFont *ef= cu->editfont; 01510 wchar_t *str; 01511 int len; 01512 01513 len= wcslen(ef->textbuf); 01514 str= ef->textbuf; 01515 while(len) { 01516 if(*str>='a' && *str<='z') 01517 *str-= 32; 01518 len--; 01519 str++; 01520 } 01521 01522 if(ccase == CASE_LOWER) { 01523 len= wcslen(ef->textbuf); 01524 str= ef->textbuf; 01525 while(len) { 01526 if(*str>='A' && *str<='Z') { 01527 *str+= 32; 01528 } 01529 len--; 01530 str++; 01531 } 01532 } 01533 01534 text_update_edited(C, scene, obedit, 1, FO_EDIT); 01535 01536 return OPERATOR_FINISHED; 01537 } 01538 01539 static int set_case_exec(bContext *C, wmOperator *op) 01540 { 01541 return set_case(C, RNA_enum_get(op->ptr, "case")); 01542 } 01543 01544 void FONT_OT_case_set(wmOperatorType *ot) 01545 { 01546 /* identifiers */ 01547 ot->name= "Set Case"; 01548 ot->description= "Set font case"; 01549 ot->idname= "FONT_OT_case_set"; 01550 01551 /* api callbacks */ 01552 ot->exec= set_case_exec; 01553 ot->poll= ED_operator_editfont; 01554 01555 /* flags */ 01556 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01557 01558 /* properties */ 01559 RNA_def_enum(ot->srna, "case", case_items, CASE_LOWER, "Case", "Lower or upper case"); 01560 } 01561 01562 /********************** toggle case operator *********************/ 01563 01564 static int toggle_case_exec(bContext *C, wmOperator *UNUSED(op)) 01565 { 01566 Object *obedit= CTX_data_edit_object(C); 01567 Curve *cu= obedit->data; 01568 EditFont *ef= cu->editfont; 01569 wchar_t *str; 01570 int len, ccase= CASE_UPPER; 01571 01572 len= wcslen(ef->textbuf); 01573 str= ef->textbuf; 01574 while(len) { 01575 if(*str>='a' && *str<='z') { 01576 ccase= CASE_LOWER; 01577 break; 01578 } 01579 01580 len--; 01581 str++; 01582 } 01583 01584 return set_case(C, ccase); 01585 } 01586 01587 void FONT_OT_case_toggle(wmOperatorType *ot) 01588 { 01589 /* identifiers */ 01590 ot->name= "Toggle Case"; 01591 ot->description= "Toggle font case"; 01592 ot->idname= "FONT_OT_case_toggle"; 01593 01594 /* api callbacks */ 01595 ot->exec= toggle_case_exec; 01596 ot->poll= ED_operator_editfont; 01597 01598 /* flags */ 01599 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01600 } 01601 01602 /* **************** Open Font ************** */ 01603 01604 static void font_ui_template_init(bContext *C, wmOperator *op) 01605 { 01606 PropertyPointerRNA *pprop; 01607 01608 op->customdata= pprop= MEM_callocN(sizeof(PropertyPointerRNA), "OpenPropertyPointerRNA"); 01609 uiIDContextProperty(C, &pprop->ptr, &pprop->prop); 01610 } 01611 01612 static int font_open_cancel(bContext *UNUSED(C), wmOperator *op) 01613 { 01614 MEM_freeN(op->customdata); 01615 op->customdata= NULL; 01616 return OPERATOR_CANCELLED; 01617 } 01618 01619 static int font_open_exec(bContext *C, wmOperator *op) 01620 { 01621 struct Main *bmain= CTX_data_main(C); 01622 VFont *font; 01623 PropertyPointerRNA *pprop; 01624 PointerRNA idptr; 01625 char filepath[FILE_MAX]; 01626 RNA_string_get(op->ptr, "filepath", filepath); 01627 01628 font= load_vfont(bmain, filepath); 01629 01630 if(!font) { 01631 if(op->customdata) MEM_freeN(op->customdata); 01632 return OPERATOR_CANCELLED; 01633 } 01634 01635 if(!op->customdata) 01636 font_ui_template_init(C, op); 01637 01638 /* hook into UI */ 01639 pprop= op->customdata; 01640 01641 if(pprop->prop) { 01642 /* when creating new ID blocks, use is already 1, but RNA 01643 * pointer se also increases user, so this compensates it */ 01644 font->id.us--; 01645 01646 RNA_id_pointer_create(&font->id, &idptr); 01647 RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr); 01648 RNA_property_update(C, &pprop->ptr, pprop->prop); 01649 } 01650 01651 MEM_freeN(op->customdata); 01652 01653 return OPERATOR_FINISHED; 01654 } 01655 01656 static int open_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 01657 { 01658 VFont *font=NULL; 01659 char *path; 01660 01661 PointerRNA idptr; 01662 PropertyPointerRNA *pprop; 01663 01664 font_ui_template_init(C, op); 01665 01666 /* hook into UI */ 01667 pprop= op->customdata; 01668 01669 if(pprop->prop) { 01670 idptr= RNA_property_pointer_get((PointerRNA *)pprop, pprop->prop); 01671 font= idptr.id.data; 01672 } 01673 01674 path = (font && strcmp(font->name, FO_BUILTIN_NAME) != 0)? font->name: U.fontdir; 01675 01676 if(RNA_struct_property_is_set(op->ptr, "filepath")) 01677 return font_open_exec(C, op); 01678 01679 RNA_string_set(op->ptr, "filepath", path); 01680 WM_event_add_fileselect(C, op); 01681 01682 return OPERATOR_RUNNING_MODAL; 01683 } 01684 01685 void FONT_OT_open(wmOperatorType *ot) 01686 { 01687 /* identifiers */ 01688 ot->name= "Open Font"; 01689 ot->idname= "FONT_OT_open"; 01690 01691 /* api callbacks */ 01692 ot->exec= font_open_exec; 01693 ot->invoke= open_invoke; 01694 ot->cancel= font_open_cancel; 01695 01696 /* flags */ 01697 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01698 01699 /* properties */ 01700 WM_operator_properties_filesel(ot, FOLDERFILE|FTFONTFILE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH|WM_FILESEL_RELPATH); 01701 } 01702 01703 /******************* delete operator *********************/ 01704 01705 static int font_unlink_exec(bContext *C, wmOperator *op) 01706 { 01707 VFont *builtin_font; 01708 01709 PointerRNA idptr; 01710 PropertyPointerRNA pprop; 01711 01712 uiIDContextProperty(C, &pprop.ptr, &pprop.prop); 01713 01714 if(pprop.prop==NULL) { 01715 BKE_report(op->reports, RPT_ERROR, "Incorrect context for running font unlink"); 01716 return OPERATOR_CANCELLED; 01717 } 01718 01719 builtin_font = get_builtin_font(); 01720 01721 RNA_id_pointer_create(&builtin_font->id, &idptr); 01722 RNA_property_pointer_set(&pprop.ptr, pprop.prop, idptr); 01723 RNA_property_update(C, &pprop.ptr, pprop.prop); 01724 01725 return OPERATOR_FINISHED; 01726 } 01727 01728 void FONT_OT_unlink(wmOperatorType *ot) 01729 { 01730 /* identifiers */ 01731 ot->name= "Unlink"; 01732 ot->idname= "FONT_OT_unlink"; 01733 ot->description= "Unlink active font data block"; 01734 01735 /* api callbacks */ 01736 ot->exec= font_unlink_exec; 01737 } 01738 01739 01740 /* **************** undo for font object ************** */ 01741 01742 static void undoFont_to_editFont(void *strv, void *ecu) 01743 { 01744 Curve *cu= (Curve *)ecu; 01745 EditFont *ef= cu->editfont; 01746 char *str= strv; 01747 01748 cu->pos= *((short *)str); 01749 cu->len= *((short *)(str+2)); 01750 01751 memcpy(ef->textbuf, str+4, (cu->len+1)*sizeof(wchar_t)); 01752 memcpy(ef->textbufinfo, str+4 + (cu->len+1)*sizeof(wchar_t), cu->len*sizeof(CharInfo)); 01753 01754 cu->selstart = cu->selend = 0; 01755 01756 update_string(cu); 01757 } 01758 01759 static void *editFont_to_undoFont(void *ecu) 01760 { 01761 Curve *cu= (Curve *)ecu; 01762 EditFont *ef= cu->editfont; 01763 char *str; 01764 01765 // The undo buffer includes [MAXTEXT+6]=actual string and [MAXTEXT+4]*sizeof(CharInfo)=charinfo 01766 str= MEM_callocN((MAXTEXT+6)*sizeof(wchar_t) + (MAXTEXT+4)*sizeof(CharInfo), "string undo"); 01767 01768 // Copy the string and string information 01769 memcpy(str+4, ef->textbuf, (cu->len+1)*sizeof(wchar_t)); 01770 memcpy(str+4 + (cu->len+1)*sizeof(wchar_t), ef->textbufinfo, cu->len*sizeof(CharInfo)); 01771 01772 *((short *)str)= cu->pos; 01773 *((short *)(str+2))= cu->len; 01774 01775 return str; 01776 } 01777 01778 static void free_undoFont(void *strv) 01779 { 01780 MEM_freeN(strv); 01781 } 01782 01783 static void *get_undoFont(bContext *C) 01784 { 01785 Object *obedit= CTX_data_edit_object(C); 01786 if(obedit && obedit->type==OB_FONT) { 01787 return obedit->data; 01788 } 01789 return NULL; 01790 } 01791 01792 /* and this is all the undo system needs to know */ 01793 void undo_push_font(bContext *C, const char *name) 01794 { 01795 undo_editmode_push(C, name, get_undoFont, free_undoFont, undoFont_to_editFont, editFont_to_undoFont, NULL); 01796 }