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