Blender  V2.59
editfont.c
Go to the documentation of this file.
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 }