Blender V2.61 - r43446

editfont.c

Go to the documentation of this file.
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 }