1289 lines
28 KiB
C
1289 lines
28 KiB
C
/**
|
|
* $Id$
|
|
*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
* All rights reserved.
|
|
*
|
|
* The Original Code is: all of this file.
|
|
*
|
|
* Contributor(s): none yet.
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <wchar.h>
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#ifndef WIN32
|
|
#include <unistd.h>
|
|
#else
|
|
#include <io.h>
|
|
#endif
|
|
|
|
#include "MTC_matrixops.h"
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BLI_blenlib.h"
|
|
#include "BLI_arithb.h"
|
|
|
|
#include "DNA_curve_types.h"
|
|
#include "DNA_object_types.h"
|
|
#include "DNA_vfont_types.h"
|
|
#include "DNA_scene_types.h"
|
|
#include "DNA_text_types.h"
|
|
#include "DNA_view3d_types.h"
|
|
#include "DNA_userdef_types.h"
|
|
|
|
#include "BKE_depsgraph.h"
|
|
#include "BKE_font.h"
|
|
#include "BKE_object.h"
|
|
#include "BKE_global.h"
|
|
#include "BKE_main.h"
|
|
#include "BKE_utildefines.h"
|
|
|
|
#include "BIF_editfont.h"
|
|
#include "BIF_editmode_undo.h"
|
|
#include "BIF_toolbox.h"
|
|
#include "BIF_space.h"
|
|
#include "BIF_mywindow.h"
|
|
|
|
#include "BDR_editobject.h"
|
|
|
|
#include "mydevice.h"
|
|
|
|
#include "blendef.h"
|
|
|
|
#define MAXTEXT 32766
|
|
|
|
/* -- prototypes --------*/
|
|
VFont *get_builtin_font(void);
|
|
|
|
int textediting=0;
|
|
|
|
extern struct SelBox *selboxes; /* from blenkernel/font.c */
|
|
|
|
static char findaccent(char char1, unsigned int code)
|
|
{
|
|
char new= 0;
|
|
|
|
if(char1=='a') {
|
|
if(code=='`') new= 224;
|
|
else if(code==39) new= 225;
|
|
else if(code=='^') new= 226;
|
|
else if(code=='~') new= 227;
|
|
else if(code=='"') new= 228;
|
|
else if(code=='o') new= 229;
|
|
else if(code=='e') new= 230;
|
|
else if(code=='-') new= 170;
|
|
}
|
|
else if(char1=='c') {
|
|
if(code==',') new= 231;
|
|
if(code=='|') new= 162;
|
|
}
|
|
else if(char1=='e') {
|
|
if(code=='`') new= 232;
|
|
else if(code==39) new= 233;
|
|
else if(code=='^') new= 234;
|
|
else if(code=='"') new= 235;
|
|
}
|
|
else if(char1=='i') {
|
|
if(code=='`') new= 236;
|
|
else if(code==39) new= 237;
|
|
else if(code=='^') new= 238;
|
|
else if(code=='"') new= 239;
|
|
}
|
|
else if(char1=='n') {
|
|
if(code=='~') new= 241;
|
|
}
|
|
else if(char1=='o') {
|
|
if(code=='`') new= 242;
|
|
else if(code==39) new= 243;
|
|
else if(code=='^') new= 244;
|
|
else if(code=='~') new= 245;
|
|
else if(code=='"') new= 246;
|
|
else if(code=='/') new= 248;
|
|
else if(code=='-') new= 186;
|
|
else if(code=='e') new= 143;
|
|
}
|
|
else if(char1=='s') {
|
|
if(code=='s') new= 167;
|
|
}
|
|
else if(char1=='u') {
|
|
if(code=='`') new= 249;
|
|
else if(code==39) new= 250;
|
|
else if(code=='^') new= 251;
|
|
else if(code=='"') new= 252;
|
|
}
|
|
else if(char1=='y') {
|
|
if(code==39) new= 253;
|
|
else if(code=='"') new= 255;
|
|
}
|
|
else if(char1=='A') {
|
|
if(code=='`') new= 192;
|
|
else if(code==39) new= 193;
|
|
else if(code=='^') new= 194;
|
|
else if(code=='~') new= 195;
|
|
else if(code=='"') new= 196;
|
|
else if(code=='o') new= 197;
|
|
else if(code=='e') new= 198;
|
|
}
|
|
else if(char1=='C') {
|
|
if(code==',') new= 199;
|
|
}
|
|
else if(char1=='E') {
|
|
if(code=='`') new= 200;
|
|
else if(code==39) new= 201;
|
|
else if(code=='^') new= 202;
|
|
else if(code=='"') new= 203;
|
|
}
|
|
else if(char1=='I') {
|
|
if(code=='`') new= 204;
|
|
else if(code==39) new= 205;
|
|
else if(code=='^') new= 206;
|
|
else if(code=='"') new= 207;
|
|
}
|
|
else if(char1=='N') {
|
|
if(code=='~') new= 209;
|
|
}
|
|
else if(char1=='O') {
|
|
if(code=='`') new= 210;
|
|
else if(code==39) new= 211;
|
|
else if(code=='^') new= 212;
|
|
else if(code=='~') new= 213;
|
|
else if(code=='"') new= 214;
|
|
else if(code=='/') new= 216;
|
|
else if(code=='e') new= 141;
|
|
}
|
|
else if(char1=='U') {
|
|
if(code=='`') new= 217;
|
|
else if(code==39) new= 218;
|
|
else if(code=='^') new= 219;
|
|
else if(code=='"') new= 220;
|
|
}
|
|
else if(char1=='Y') {
|
|
if(code==39) new= 221;
|
|
}
|
|
else if(char1=='1') {
|
|
if(code=='4') new= 188;
|
|
if(code=='2') new= 189;
|
|
}
|
|
else if(char1=='3') {
|
|
if(code=='4') new= 190;
|
|
}
|
|
else if(char1==':') {
|
|
if(code=='-') new= 247;
|
|
}
|
|
else if(char1=='-') {
|
|
if(code==':') new= 247;
|
|
if(code=='|') new= 135;
|
|
if(code=='+') new= 177;
|
|
}
|
|
else if(char1=='|') {
|
|
if(code=='-') new= 135;
|
|
if(code=='=') new= 136;
|
|
}
|
|
else if(char1=='=') {
|
|
if(code=='|') new= 136;
|
|
}
|
|
else if(char1=='+') {
|
|
if(code=='-') new= 177;
|
|
}
|
|
|
|
if(new) return new;
|
|
else return char1;
|
|
}
|
|
|
|
wchar_t *copybuf=NULL;
|
|
wchar_t *copybufinfo=NULL;
|
|
|
|
static wchar_t *textbuf=NULL;
|
|
static CharInfo *textbufinfo=NULL;
|
|
static wchar_t *oldstr=NULL;
|
|
static CharInfo *oldstrinfo=NULL;
|
|
|
|
void update_string(Curve *cu)
|
|
{
|
|
int len;
|
|
|
|
// Free the old curve string
|
|
MEM_freeN(cu->str);
|
|
|
|
// Calculate the actual string length in UTF-8 variable characters
|
|
len = wcsleninu8(textbuf);
|
|
|
|
// Alloc memory for UTF-8 variable char length string
|
|
cu->str = MEM_callocN(len + sizeof(wchar_t), "str");
|
|
|
|
// Copy the wchar to UTF-8
|
|
wcs2utf8s(cu->str, textbuf);
|
|
}
|
|
|
|
static int insert_into_textbuf(Curve *cu, unsigned long c)
|
|
{
|
|
if (cu->len<MAXTEXT-1) {
|
|
int x;
|
|
|
|
for(x= cu->len; x>cu->pos; x--) textbuf[x]= textbuf[x-1];
|
|
for(x= cu->len; x>cu->pos; x--) textbufinfo[x]= textbufinfo[x-1];
|
|
textbuf[cu->pos]= c;
|
|
textbufinfo[cu->pos] = cu->curinfo;
|
|
textbufinfo[cu->pos].kern = 0;
|
|
if (G.obedit->actcol>0)
|
|
textbufinfo[cu->pos].mat_nr = G.obedit->actcol;
|
|
else
|
|
textbufinfo[cu->pos].mat_nr = 0;
|
|
|
|
cu->pos++;
|
|
cu->len++;
|
|
textbuf[cu->len]='\0';
|
|
|
|
update_string(cu);
|
|
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void add_lorem(void)
|
|
{
|
|
char *p, *p2;
|
|
int i;
|
|
Curve *cu=G.obedit->data;
|
|
static char* lastlorem;
|
|
|
|
if (lastlorem)
|
|
p= lastlorem;
|
|
else
|
|
p= BIF_lorem;
|
|
|
|
i= rand()/(RAND_MAX/6)+4;
|
|
|
|
for (p2=p; *p2 && i; p2++) {
|
|
insert_into_textbuf(cu, *p2);
|
|
if (*p2=='.') i--;
|
|
}
|
|
lastlorem = p2+1;
|
|
if (strlen(lastlorem)<5) lastlorem = BIF_lorem;
|
|
|
|
insert_into_textbuf(cu, '\n');
|
|
insert_into_textbuf(cu, '\n');
|
|
DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
}
|
|
|
|
void load_3dtext_fs(char *file)
|
|
{
|
|
FILE *fp;
|
|
int filelen;
|
|
char *strp;
|
|
Curve *cu=G.obedit->data;
|
|
|
|
fp= fopen(file, "r");
|
|
if (!fp) return;
|
|
|
|
fseek(fp, 0L, SEEK_END);
|
|
filelen = ftell(fp);
|
|
fseek(fp, 0L, SEEK_SET);
|
|
|
|
strp = MEM_callocN(filelen+4, "tempstr");
|
|
|
|
filelen = fread(strp, 1, filelen, fp);
|
|
fclose(fp);
|
|
strp[filelen]= 0;
|
|
|
|
if(cu->len+filelen<MAXTEXT)
|
|
{
|
|
int tmplen;
|
|
wchar_t *mem = MEM_callocN((sizeof(wchar_t)*filelen)+(4*sizeof(wchar_t)), "temporary");
|
|
tmplen = utf8towchar(mem, strp);
|
|
wcscat(textbuf, mem);
|
|
MEM_freeN(mem);
|
|
cu->len += tmplen;
|
|
cu->pos= cu->len;
|
|
}
|
|
MEM_freeN(strp);
|
|
|
|
update_string(cu);
|
|
|
|
DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
}
|
|
|
|
VFont *get_builtin_font(void)
|
|
{
|
|
VFont *vf;
|
|
|
|
for (vf= G.main->vfont.first; vf; vf= vf->id.next)
|
|
if (BLI_streq(vf->name, "<builtin>"))
|
|
return vf;
|
|
|
|
return load_vfont("<builtin>");
|
|
}
|
|
|
|
|
|
void txt_export_to_object(struct Text *text)
|
|
{
|
|
ID *id;
|
|
Curve *cu;
|
|
struct TextLine *tmp;
|
|
int nchars = 0;
|
|
// char sdir[FILE_MAXDIR];
|
|
// char sfile[FILE_MAXFILE];
|
|
|
|
if(!text || !text->lines.first) return;
|
|
|
|
id = (ID *)text;
|
|
|
|
if (G.obedit && G.obedit->type==OB_FONT) return;
|
|
check_editmode(OB_FONT);
|
|
|
|
add_object(OB_FONT);
|
|
|
|
base_init_from_view3d(BASACT, G.vd);
|
|
G.obedit= BASACT->object;
|
|
where_is_object(G.obedit);
|
|
|
|
cu= G.obedit->data;
|
|
|
|
/*
|
|
// renames object, careful with long filenames.
|
|
|
|
if (text->name) {
|
|
//ID *find_id(char *type, char *name)
|
|
BLI_split_dirfile(text->name, sdir, sfile);
|
|
// rename_id((ID *)G.obedit, sfile);
|
|
rename_id((ID *)cu, sfile);
|
|
id->us++;
|
|
}
|
|
*/
|
|
cu->vfont= get_builtin_font();
|
|
cu->vfont->id.us++;
|
|
|
|
tmp= text->lines.first;
|
|
while(cu->len<MAXTEXT && tmp) {
|
|
nchars += strlen(tmp->line) + 1;
|
|
tmp = tmp->next;
|
|
}
|
|
|
|
if(cu->str) MEM_freeN(cu->str);
|
|
if(cu->strinfo) MEM_freeN(cu->strinfo);
|
|
|
|
cu->str= MEM_mallocN(nchars+4, "str");
|
|
cu->strinfo= MEM_callocN((nchars+4)*sizeof(CharInfo), "strinfo");
|
|
cu->totbox= cu->actbox= 1;
|
|
cu->tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "textbox");
|
|
cu->tb[0].w = cu->tb[0].h = 0.0;
|
|
|
|
tmp= text->lines.first;
|
|
strcpy(cu->str, tmp->line);
|
|
cu->len= strlen(tmp->line);
|
|
cu->pos= cu->len;
|
|
|
|
tmp= tmp->next;
|
|
|
|
while(cu->len<MAXTEXT && tmp) {
|
|
strcat(cu->str, "\n");
|
|
strcat(cu->str, tmp->line);
|
|
cu->len+= strlen(tmp->line) + 1;
|
|
cu->pos= cu->len;
|
|
tmp= tmp->next;
|
|
}
|
|
|
|
make_editText();
|
|
exit_editmode(EM_FREEDATA|EM_WAITCURSOR);
|
|
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
}
|
|
|
|
|
|
void txt_export_to_objects(struct Text *text)
|
|
{
|
|
ID *id;
|
|
Curve *cu;
|
|
struct TextLine *curline;
|
|
int nchars;
|
|
int linenum = 0;
|
|
float offset[3] = {0.0,0.0,0.0};
|
|
|
|
if(!text || !text->lines.first) return;
|
|
|
|
id = (ID *)text;
|
|
|
|
if (G.obedit && G.obedit->type==OB_FONT) return;
|
|
check_editmode(OB_FONT);
|
|
|
|
curline = text->lines.first;
|
|
while(curline){
|
|
/*skip lines with no text, but still make space for them*/
|
|
if(curline->line[0] == '\0'){
|
|
linenum++;
|
|
curline = curline->next;
|
|
continue;
|
|
}
|
|
|
|
nchars = 0;
|
|
add_object(OB_FONT);
|
|
|
|
base_init_from_view3d(BASACT, G.vd);
|
|
G.obedit= BASACT->object;
|
|
where_is_object(G.obedit);
|
|
|
|
/* Do the translation */
|
|
offset[0] = 0;
|
|
offset[1] = -linenum;
|
|
offset[2] = 0;
|
|
|
|
Mat4Mul3Vecfl(G.vd->viewinv,offset);
|
|
|
|
G.obedit->loc[0] += offset[0];
|
|
G.obedit->loc[1] += offset[1];
|
|
G.obedit->loc[2] += offset[2];
|
|
/* End Translation */
|
|
|
|
cu= G.obedit->data;
|
|
|
|
cu->vfont= get_builtin_font();
|
|
cu->vfont->id.us++;
|
|
|
|
nchars = strlen(curline->line) + 1;
|
|
|
|
if(cu->str) MEM_freeN(cu->str);
|
|
if(cu->strinfo) MEM_freeN(cu->strinfo);
|
|
|
|
cu->str= MEM_mallocN(nchars+4, "str");
|
|
cu->strinfo= MEM_callocN((nchars+4)*sizeof(CharInfo), "strinfo");
|
|
cu->totbox= cu->actbox= 1;
|
|
cu->tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "textbox");
|
|
cu->tb[0].w = cu->tb[0].h = 0.0;
|
|
|
|
strcpy(cu->str, curline->line);
|
|
cu->len= strlen(curline->line);
|
|
cu->pos= cu->len;
|
|
|
|
make_editText();
|
|
exit_editmode(EM_FREEDATA|EM_WAITCURSOR);
|
|
|
|
linenum++;
|
|
curline = curline->next;
|
|
}
|
|
BIF_undo_push("Add Text as Objects");
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
}
|
|
|
|
static short next_word(Curve *cu)
|
|
{
|
|
short s;
|
|
for (s=cu->pos; (cu->str[s]) && (cu->str[s]!=' ') && (cu->str[s]!='\n') &&
|
|
(cu->str[s]!=1) && (cu->str[s]!='\r'); s++);
|
|
if (cu->str[s]) return(s+1); else return(s);
|
|
}
|
|
|
|
static short prev_word(Curve *cu)
|
|
{
|
|
short s;
|
|
|
|
if (cu->pos==0) return(0);
|
|
for (s=cu->pos-2; (cu->str[s]) && (cu->str[s]!=' ') && (cu->str[s]!='\n') &&
|
|
(cu->str[s]!=1) && (cu->str[s]!='\r'); s--);
|
|
if (cu->str[s]) return(s+1); else return(s);
|
|
}
|
|
|
|
|
|
|
|
static int killselection(int ins) /* 1 == new character */
|
|
{
|
|
int selend, selstart, direction;
|
|
Curve *cu= G.obedit->data;
|
|
int offset = 0;
|
|
int getfrom;
|
|
|
|
direction = getselection(&selstart, &selend);
|
|
if (direction) {
|
|
int size;
|
|
if (ins) offset = 1;
|
|
if (cu->pos >= selstart) cu->pos = selstart+offset;
|
|
if ((direction == -1) && ins) {
|
|
selstart++;
|
|
selend++;
|
|
}
|
|
getfrom = selend+offset;
|
|
if (ins==0) getfrom++;
|
|
size = (cu->len * sizeof(wchar_t)) - (selstart * sizeof(wchar_t)) + (offset*sizeof(wchar_t));
|
|
memmove(textbuf+selstart, textbuf+getfrom, size);
|
|
memmove(textbufinfo+selstart, textbufinfo+getfrom, ((cu->len-selstart)+offset)*sizeof(CharInfo));
|
|
cu->len -= (selend-selstart)+offset;
|
|
cu->selstart = cu->selend = 0;
|
|
}
|
|
return(direction);
|
|
}
|
|
|
|
static void copyselection(void)
|
|
{
|
|
int selstart, selend;
|
|
|
|
if (getselection(&selstart, &selend)) {
|
|
memcpy(copybuf, textbuf+selstart, ((selend-selstart)+1)*sizeof(wchar_t));
|
|
copybuf[(selend-selstart)+1]=0;
|
|
memcpy(copybufinfo, textbufinfo+selstart, ((selend-selstart)+1)*sizeof(CharInfo));
|
|
}
|
|
}
|
|
|
|
static void pasteselection(void)
|
|
{
|
|
Curve *cu= G.obedit->data;
|
|
|
|
int len= wcslen(copybuf);
|
|
|
|
// Verify that the copy buffer => [copy buffer len] + cu->len < MAXTEXT
|
|
if(cu->len + len <= MAXTEXT)
|
|
{
|
|
if (len) {
|
|
int size = (cu->len * sizeof(wchar_t)) - (cu->pos*sizeof(wchar_t)) + sizeof(wchar_t);
|
|
memmove(textbuf+cu->pos+len, textbuf+cu->pos, size);
|
|
memcpy(textbuf+cu->pos, copybuf, len * sizeof(wchar_t));
|
|
|
|
memmove(textbufinfo+cu->pos+len, textbufinfo+cu->pos, (cu->len-cu->pos+1)*sizeof(CharInfo));
|
|
memcpy(textbufinfo+cu->pos, copybufinfo, len*sizeof(CharInfo));
|
|
|
|
cu->len += len;
|
|
cu->pos += len;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
error("Text too long");
|
|
}
|
|
}
|
|
|
|
int style_to_sel(int style, int toggle)
|
|
{
|
|
int selstart, selend;
|
|
int i;
|
|
Curve *cu;
|
|
|
|
if (G.obedit && (G.obedit->type == OB_FONT)) {
|
|
cu= G.obedit->data;
|
|
|
|
if (getselection(&selstart, &selend)) {
|
|
for (i=selstart; i<=selend; i++) {
|
|
if (toggle==0) {
|
|
textbufinfo[i].flag &= ~style;
|
|
} else {
|
|
textbufinfo[i].flag |= style;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int mat_to_sel(void) {
|
|
int selstart, selend;
|
|
int i;
|
|
Curve *cu;
|
|
|
|
if (G.obedit && (G.obedit->type == OB_FONT)) {
|
|
cu= G.obedit->data;
|
|
|
|
if (getselection(&selstart, &selend)) {
|
|
for (i=selstart; i<=selend; i++) {
|
|
textbufinfo[i].mat_nr = G.obedit->actcol;
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void do_textedit(unsigned short event, short val, unsigned long _ascii)
|
|
{
|
|
Curve *cu;
|
|
static int accentcode= 0;
|
|
int x, doit=0, cursmove=0;
|
|
unsigned long ascii = _ascii;
|
|
short kern;
|
|
|
|
cu= G.obedit->data;
|
|
|
|
if(ascii) {
|
|
|
|
/* handle case like TAB (TAB==9) */
|
|
if( (ascii > 31 && ascii < 254 && ascii != 127) || (ascii==13) || (ascii==10) || (ascii==8)) {
|
|
|
|
if(accentcode) {
|
|
if(cu->pos>0) textbuf[cu->pos-1]= findaccent(textbuf[cu->pos-1], ascii);
|
|
accentcode= 0;
|
|
}
|
|
else if(cu->len<MAXTEXT-1) {
|
|
if(G.qual & LR_ALTKEY ) {
|
|
|
|
/* might become obsolete, apple has default values for this, other OS's too? */
|
|
|
|
if(ascii=='t') ascii= 137;
|
|
else if(ascii=='c') ascii= 169;
|
|
else if(ascii=='f') ascii= 164;
|
|
else if(ascii=='g') ascii= 176;
|
|
else if(ascii=='l') ascii= 163;
|
|
else if(ascii=='r') ascii= 174;
|
|
else if(ascii=='s') ascii= 223;
|
|
else if(ascii=='v') ascii= 1001;
|
|
else if(ascii=='y') ascii= 165;
|
|
else if(ascii=='.') ascii= 138;
|
|
else if(ascii=='1') ascii= 185;
|
|
else if(ascii=='2') ascii= 178;
|
|
else if(ascii=='3') ascii= 179;
|
|
else if(ascii=='%') ascii= 139;
|
|
else if(ascii=='?') ascii= 191;
|
|
else if(ascii=='!') ascii= 161;
|
|
else if(ascii=='x') ascii= 215;
|
|
else if(ascii=='>') ascii= 187;
|
|
else if(ascii=='<') ascii= 171;
|
|
}
|
|
if(ascii==1001) {
|
|
int file, filelen;
|
|
char *strp;
|
|
|
|
/* this should be solved by clipboard support */
|
|
#ifdef __WIN32_DISABLED
|
|
file= open("C:\\windows\\temp\\cutbuf", O_BINARY|O_RDONLY);
|
|
#else
|
|
file= open("/tmp/.cutbuffer", O_BINARY|O_RDONLY);
|
|
#endif
|
|
if(file>0) {
|
|
|
|
filelen = BLI_filesize(file);
|
|
|
|
strp= MEM_mallocN(filelen+4, "tempstr");
|
|
read(file, strp, filelen);
|
|
close(file);
|
|
strp[filelen]= 0;
|
|
|
|
if(cu->len+filelen<MAXTEXT) {
|
|
int tmplen;
|
|
wchar_t *mem = MEM_callocN((sizeof(wchar_t)*filelen)+(4*sizeof(wchar_t)), "temporary");
|
|
tmplen = utf8towchar(mem, strp);
|
|
wcscat(textbuf, mem);
|
|
MEM_freeN(mem);
|
|
cu->len += tmplen;
|
|
cu->pos= cu->len;
|
|
}
|
|
MEM_freeN(strp);
|
|
}
|
|
}
|
|
else {
|
|
insert_into_textbuf(cu, ascii);
|
|
}
|
|
}
|
|
|
|
killselection(1);
|
|
|
|
doit= 1;
|
|
}
|
|
else
|
|
{
|
|
insert_into_textbuf(cu, ascii);
|
|
doit = 1;
|
|
}
|
|
}
|
|
else if(val) {
|
|
cursmove= 0;
|
|
|
|
switch(event) {
|
|
case ENDKEY:
|
|
if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
|
|
while(cu->pos<cu->len) {
|
|
if( textbuf[cu->pos]==0) break;
|
|
if( textbuf[cu->pos]=='\n') break;
|
|
if( textbufinfo[cu->pos].flag & CU_WRAP ) break;
|
|
cu->pos++;
|
|
}
|
|
cursmove=FO_CURS;
|
|
break;
|
|
|
|
case HOMEKEY:
|
|
if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
|
|
while(cu->pos>0) {
|
|
if( textbuf[cu->pos-1]=='\n') break;
|
|
if( textbufinfo[cu->pos-1].flag & CU_WRAP ) break;
|
|
cu->pos--;
|
|
}
|
|
cursmove=FO_CURS;
|
|
break;
|
|
|
|
case RETKEY:
|
|
if(G.qual & LR_CTRLKEY) {
|
|
insert_into_textbuf(cu, 1);
|
|
if (textbuf[cu->pos]!='\n') insert_into_textbuf(cu, '\n');
|
|
}
|
|
else {
|
|
insert_into_textbuf(cu, '\n');
|
|
}
|
|
cu->selstart = cu->selend = 0;
|
|
doit= 1;
|
|
break;
|
|
|
|
case RIGHTARROWKEY:
|
|
if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
|
|
if (G.qual & LR_CTRLKEY) {
|
|
cu->pos= next_word(cu);
|
|
cursmove= FO_CURS;
|
|
}
|
|
else if (G.qual & LR_ALTKEY) {
|
|
kern = textbufinfo[cu->pos-1].kern;
|
|
kern += 1;
|
|
if (kern>20) kern = 20;
|
|
textbufinfo[cu->pos-1].kern = kern;
|
|
doit = 1;
|
|
}
|
|
else {
|
|
cu->pos++;
|
|
cursmove= FO_CURS;
|
|
}
|
|
|
|
break;
|
|
|
|
case LEFTARROWKEY:
|
|
if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
|
|
if (G.qual & LR_CTRLKEY) {
|
|
cu->pos= prev_word(cu);
|
|
cursmove= FO_CURS;
|
|
}
|
|
else if (G.qual & LR_ALTKEY) {
|
|
kern = textbufinfo[cu->pos-1].kern;
|
|
kern -= 1;
|
|
if (kern<-20) kern = -20;
|
|
textbufinfo[cu->pos-1].kern = kern;
|
|
doit = 1;
|
|
}
|
|
else {
|
|
cu->pos--;
|
|
cursmove=FO_CURS;
|
|
}
|
|
break;
|
|
|
|
case UPARROWKEY:
|
|
if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
|
|
if(G.qual & LR_ALTKEY) {
|
|
if (cu->pos && textbuf[cu->pos - 1] < 255) {
|
|
textbuf[cu->pos - 1]++;
|
|
doit= 1;
|
|
}
|
|
}
|
|
else cursmove=FO_CURSUP;
|
|
break;
|
|
|
|
case PAGEUPKEY:
|
|
if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
|
|
cursmove=FO_PAGEUP;
|
|
break;
|
|
|
|
case DOWNARROWKEY:
|
|
if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
|
|
if(G.qual & LR_ALTKEY) {
|
|
if (cu->pos && textbuf[cu->pos - 1] > 1) {
|
|
textbuf[cu->pos - 1]--;
|
|
doit= 1;
|
|
}
|
|
}
|
|
else cursmove= FO_CURSDOWN;
|
|
break;
|
|
|
|
case PAGEDOWNKEY:
|
|
if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
|
|
cursmove=FO_PAGEDOWN;
|
|
break;
|
|
|
|
case BACKSPACEKEY:
|
|
if(cu->len!=0) {
|
|
if(G.qual & LR_ALTKEY) {
|
|
if(cu->pos>0) accentcode= 1;
|
|
}
|
|
else if (G.qual & LR_CTRLKEY) {
|
|
cu->len = cu->pos = 0;
|
|
textbuf[0]= 0;
|
|
doit= 1;
|
|
}
|
|
else {
|
|
if (killselection(0)==0) {
|
|
if (cu->pos>0) {
|
|
for(x=cu->pos;x<=cu->len;x++) textbuf[x-1]= textbuf[x];
|
|
for(x=cu->pos;x<=cu->len;x++) textbufinfo[x-1]= textbufinfo[x];
|
|
cu->pos--;
|
|
textbuf[--cu->len]='\0';
|
|
doit=1;
|
|
}
|
|
} else doit=1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DELKEY:
|
|
if(cu->len!=0) {
|
|
if (killselection(0)==0) {
|
|
if(cu->pos<cu->len) {
|
|
for(x=cu->pos;x<cu->len;x++) textbuf[x]= textbuf[x+1];
|
|
for(x=cu->pos;x<cu->len;x++) textbufinfo[x]= textbufinfo[x+1];
|
|
textbuf[--cu->len]='\0';
|
|
doit=1;
|
|
}
|
|
} else doit=1;
|
|
}
|
|
break;
|
|
|
|
case IKEY:
|
|
if (G.qual & LR_CTRLKEY) {
|
|
cu->curinfo.flag ^= CU_ITALIC;
|
|
if (style_to_sel(CU_ITALIC, cu->curinfo.flag & CU_ITALIC)) doit= 1;
|
|
allqueue(REDRAWBUTSEDIT, 0);
|
|
}
|
|
break;
|
|
|
|
case BKEY:
|
|
if (G.qual & LR_CTRLKEY) {
|
|
cu->curinfo.flag ^= CU_BOLD;
|
|
if (style_to_sel(CU_BOLD, cu->curinfo.flag & CU_BOLD)) doit= 1;
|
|
allqueue(REDRAWBUTSEDIT, 0);
|
|
}
|
|
break;
|
|
|
|
case UKEY:
|
|
if (G.qual & LR_CTRLKEY) {
|
|
cu->curinfo.flag ^= CU_UNDERLINE;
|
|
if (style_to_sel(CU_UNDERLINE, cu->curinfo.flag & CU_UNDERLINE)) doit= 1;
|
|
allqueue(REDRAWBUTSEDIT, 0);
|
|
}
|
|
break;
|
|
|
|
case XKEY:
|
|
if (G.qual & LR_CTRLKEY) {
|
|
copyselection();
|
|
killselection(0);
|
|
doit= 1;
|
|
}
|
|
break;
|
|
|
|
case CKEY:
|
|
if (G.qual & LR_CTRLKEY) {
|
|
copyselection();
|
|
}
|
|
break;
|
|
|
|
case VKEY:
|
|
if (G.qual & LR_CTRLKEY) {
|
|
pasteselection();
|
|
doit= 1;
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
if(cursmove) {
|
|
if ((G.qual & LR_SHIFTKEY)==0) {
|
|
if (cu->selstart) {
|
|
cu->selstart = cu->selend = 0;
|
|
update_string(cu);
|
|
text_to_curve(G.obedit, FO_SELCHANGE);
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
}
|
|
}
|
|
if(cu->pos>cu->len) cu->pos= cu->len;
|
|
else if(cu->pos>=MAXTEXT) cu->pos= MAXTEXT;
|
|
else if(cu->pos<0) cu->pos= 0;
|
|
}
|
|
}
|
|
if(doit || cursmove) {
|
|
|
|
if (cu->pos) {
|
|
cu->curinfo = textbufinfo[cu->pos-1];
|
|
} else cu->curinfo = textbufinfo[0];
|
|
|
|
if (G.obedit->totcol>0) {
|
|
G.obedit->actcol = textbufinfo[cu->pos-1].mat_nr;
|
|
}
|
|
allqueue(REDRAWBUTSEDIT, 0);
|
|
update_string(cu);
|
|
text_to_curve(G.obedit, cursmove);
|
|
if (cursmove && (G.qual & LR_SHIFTKEY)) {
|
|
cu->selend = cu->pos;
|
|
DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
|
|
}
|
|
if(cursmove==0) {
|
|
DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
|
|
}
|
|
|
|
BIF_undo_push("Textedit");
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
}
|
|
}
|
|
|
|
void paste_unicodeText(char *filename)
|
|
{
|
|
Curve *cu= G.obedit->data;
|
|
int filelen, doit= 0;
|
|
char *strp;
|
|
FILE *fp = NULL;
|
|
|
|
fp= fopen(filename, "r");
|
|
|
|
if(fp) {
|
|
|
|
fseek( fp, 0L, SEEK_END );
|
|
filelen = ftell( fp );
|
|
fseek( fp, 0L, SEEK_SET );
|
|
|
|
strp= MEM_mallocN(filelen+4, "tempstr");
|
|
//fread() instead of read(),
|
|
//because windows read() converts text to DOS \r\n linebreaks
|
|
//causing double linebreaks in the 3d text
|
|
filelen = fread(strp, 1, filelen, fp);
|
|
fclose(fp);
|
|
strp[filelen]= 0;
|
|
|
|
|
|
if(cu->len+filelen<MAXTEXT)
|
|
{
|
|
int tmplen;
|
|
wchar_t *mem = MEM_callocN((sizeof(wchar_t)*filelen)+(4*sizeof(wchar_t)), "temporary");
|
|
tmplen = utf8towchar(mem, strp);
|
|
// mem =utf8s2wc(strp);
|
|
wcscat(textbuf, mem);
|
|
MEM_freeN(mem);
|
|
cu->len += tmplen;
|
|
cu->pos= cu->len;
|
|
}
|
|
MEM_freeN(strp);
|
|
doit = 1;
|
|
}
|
|
if(doit) {
|
|
update_string(cu);
|
|
text_to_curve(G.obedit, 0);
|
|
DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
BIF_undo_push("Paste text");
|
|
}
|
|
}
|
|
|
|
void paste_editText(void)
|
|
{
|
|
Curve *cu= G.obedit->data;
|
|
int filelen, doit= 0;
|
|
char *strp;
|
|
FILE *fp = NULL;
|
|
|
|
#ifdef WIN32
|
|
fp= fopen("C:\\windows\\temp\\cutbuf.txt", "r");
|
|
|
|
// The following is more likely to work on all Win32 installations.
|
|
// suggested by Douglas Toltzman. Needs windows include files...
|
|
/*
|
|
char tempFileName[MAX_PATH];
|
|
DWORD pathlen;
|
|
static const char cutbufname[]="cutbuf.txt";
|
|
|
|
if ((pathlen=GetTempPath(sizeof(tempFileName),tempFileName)) > 0 &&
|
|
pathlen + sizeof(cutbufname) <= sizeof(tempFileName))
|
|
{
|
|
strcat(tempFileName,cutbufname);
|
|
file= open(tempFileName, O_BINARY|O_RDONLY);
|
|
}
|
|
*/
|
|
#else
|
|
fp= fopen("/tmp/.cutbuffer", "r");
|
|
#endif
|
|
|
|
if(fp) {
|
|
|
|
fseek(fp, 0L, SEEK_END);
|
|
filelen = ftell( fp );
|
|
fseek(fp, 0L, SEEK_SET);
|
|
|
|
strp= MEM_mallocN(filelen+4, "tempstr");
|
|
// fread() instead of read(),
|
|
// because windows read() converts text to DOS \r\n linebreaks
|
|
// causing double linebreaks in the 3d text
|
|
filelen = fread(strp, 1, filelen, fp);
|
|
fclose(fp);
|
|
strp[filelen]= 0;
|
|
|
|
if(cu->len+filelen<MAXTEXT) {
|
|
int tmplen;
|
|
wchar_t *mem = MEM_callocN((sizeof(wchar_t) * filelen) + (4 * sizeof(wchar_t)), "temporary");
|
|
tmplen = utf8towchar(mem, strp);
|
|
wcscat(textbuf, mem);
|
|
MEM_freeN(mem);
|
|
cu->len += tmplen;
|
|
cu->pos= cu->len;
|
|
}
|
|
MEM_freeN(strp);
|
|
doit = 1;
|
|
}
|
|
if(doit) {
|
|
update_string(cu);
|
|
text_to_curve(G.obedit, 0);
|
|
DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
BIF_undo_push("Paste text");
|
|
}
|
|
}
|
|
|
|
|
|
void make_editText(void)
|
|
{
|
|
Curve *cu;
|
|
cu= G.obedit->data;
|
|
|
|
if(textbuf==NULL) textbuf= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "texteditbuf");
|
|
if(textbufinfo==NULL) textbufinfo= MEM_callocN((MAXTEXT+4)*sizeof(CharInfo), "texteditbufinfo");
|
|
if(copybuf==NULL) copybuf= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "texteditcopybuf");
|
|
if(copybufinfo==NULL) copybufinfo= MEM_callocN((MAXTEXT+4)*sizeof(CharInfo), "texteditcopybufinfo");
|
|
if(oldstr==NULL) oldstr= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "oldstrbuf");
|
|
|
|
// Convert the original text to wchar_t
|
|
utf8towchar(textbuf, cu->str);
|
|
wcscpy(oldstr, textbuf);
|
|
|
|
cu->len= wcslen(textbuf);
|
|
|
|
memcpy(textbufinfo, cu->strinfo, (cu->len)*sizeof(CharInfo));
|
|
|
|
oldstrinfo= cu->strinfo;
|
|
cu->strinfo= textbufinfo;
|
|
|
|
if(cu->pos>cu->len) cu->pos= cu->len;
|
|
|
|
if (cu->pos) {
|
|
cu->curinfo = textbufinfo[cu->pos-1];
|
|
} else cu->curinfo = textbufinfo[0];
|
|
|
|
// Convert to UTF-8
|
|
update_string(cu);
|
|
|
|
DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
|
|
|
|
textediting= 1;
|
|
BIF_undo_push("Original");
|
|
}
|
|
|
|
|
|
void load_editText(void)
|
|
{
|
|
Curve *cu;
|
|
|
|
cu= G.obedit->data;
|
|
|
|
MEM_freeN(oldstr);
|
|
oldstr= NULL;
|
|
MEM_freeN(oldstrinfo);
|
|
oldstrinfo= NULL;
|
|
|
|
update_string(cu);
|
|
|
|
cu->strinfo= MEM_callocN((cu->len+4)*sizeof(CharInfo), "texteditinfo");
|
|
memcpy(cu->strinfo, textbufinfo, (cu->len)*sizeof(CharInfo));
|
|
|
|
cu->len= strlen(cu->str);
|
|
|
|
/* this memory system is weak... */
|
|
MEM_freeN(textbuf);
|
|
MEM_freeN(textbufinfo);
|
|
textbuf= NULL;
|
|
textbufinfo= NULL;
|
|
|
|
if (selboxes) {
|
|
MEM_freeN(selboxes);
|
|
selboxes= NULL;
|
|
}
|
|
|
|
textediting= 0;
|
|
|
|
DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
|
|
|
|
}
|
|
|
|
|
|
void remake_editText(void)
|
|
{
|
|
Curve *cu;
|
|
|
|
if(okee("Reload original text")==0) return;
|
|
|
|
// Copy the oldstr to textbuf temporary global variable
|
|
wcscpy(textbuf, oldstr);
|
|
|
|
// Set the object length and position
|
|
cu= G.obedit->data;
|
|
cu->len= wcslen(textbuf);
|
|
if(cu->pos>cu->len) cu->pos= cu->len;
|
|
|
|
update_string(cu);
|
|
|
|
DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
|
|
BIF_undo_push("Reload");
|
|
}
|
|
|
|
|
|
void free_editText(void)
|
|
{
|
|
if(oldstr) MEM_freeN(oldstr);
|
|
if(oldstrinfo) MEM_freeN(oldstrinfo);
|
|
if(textbuf) MEM_freeN(textbuf);
|
|
textbuf = oldstr = NULL;
|
|
textbufinfo = oldstrinfo = NULL;
|
|
textediting= 0;
|
|
}
|
|
|
|
|
|
void add_primitiveFont(int dummy_argument)
|
|
{
|
|
Curve *cu;
|
|
|
|
if (G.obedit && G.obedit->type==OB_FONT) return;
|
|
check_editmode(OB_FONT);
|
|
|
|
add_object_draw(OB_FONT);
|
|
base_init_from_view3d(BASACT, G.vd);
|
|
|
|
where_is_object(BASACT->object);
|
|
|
|
cu= BASACT->object->data;
|
|
|
|
cu->vfont= cu->vfontb= cu->vfonti= cu->vfontbi= get_builtin_font();
|
|
cu->vfont->id.us+=4;
|
|
cu->str= MEM_mallocN(12, "str");
|
|
strcpy(cu->str, "Text");
|
|
cu->pos= 4;
|
|
cu->strinfo= MEM_callocN(12*sizeof(CharInfo), "strinfo");
|
|
cu->totbox= cu->actbox= 1;
|
|
cu->tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "textbox");
|
|
cu->tb[0].w = cu->tb[0].h = 0.0;
|
|
|
|
if (U.flag & USER_ADD_EDITMODE)
|
|
enter_editmode(EM_WAITCURSOR);
|
|
|
|
allqueue(REDRAWALL, 0);
|
|
}
|
|
|
|
void to_upper(void)
|
|
{
|
|
Curve *cu;
|
|
int len, ok;
|
|
wchar_t *str;
|
|
|
|
if(G.obedit==0) {
|
|
return;
|
|
}
|
|
|
|
ok= 0;
|
|
cu= G.obedit->data;
|
|
|
|
len= wcslen(textbuf);
|
|
str= textbuf;
|
|
while(len) {
|
|
if( *str>=97 && *str<=122) {
|
|
ok= 1;
|
|
*str-= 32;
|
|
}
|
|
len--;
|
|
str++;
|
|
}
|
|
|
|
if(ok==0) {
|
|
len= wcslen(textbuf);
|
|
str= textbuf;
|
|
while(len) {
|
|
if( *str>=65 && *str<=90) {
|
|
*str+= 32;
|
|
}
|
|
len--;
|
|
str++;
|
|
}
|
|
}
|
|
DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
BIF_undo_push("To upper");
|
|
|
|
update_string(cu);
|
|
}
|
|
|
|
|
|
/* **************** undo for font object ************** */
|
|
|
|
static void undoFont_to_editFont(void *strv)
|
|
{
|
|
Curve *cu= G.obedit->data;
|
|
char *str= strv;
|
|
|
|
cu->pos= *((short *)str);
|
|
cu->len= *((short *)(str+2));
|
|
|
|
memcpy(textbuf, str+4, (cu->len+1)*sizeof(wchar_t));
|
|
memcpy(textbufinfo, str+4 + (cu->len+1)*sizeof(wchar_t), cu->len*sizeof(CharInfo));
|
|
|
|
cu->selstart = cu->selend = 0;
|
|
DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
|
|
|
|
update_string(cu);
|
|
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
}
|
|
|
|
static void *editFont_to_undoFont(void)
|
|
{
|
|
Curve *cu= G.obedit->data;
|
|
char *str;
|
|
|
|
// The undo buffer includes [MAXTEXT+6]=actual string and [MAXTEXT+4]*sizeof(CharInfo)=charinfo
|
|
str= MEM_callocN((MAXTEXT+6)*sizeof(wchar_t) + (MAXTEXT+4)*sizeof(CharInfo), "string undo");
|
|
|
|
// Copy the string and string information
|
|
memcpy(str+4, textbuf, (cu->len+1)*sizeof(wchar_t));
|
|
memcpy(str+4 + (cu->len+1)*sizeof(wchar_t), textbufinfo, cu->len*sizeof(CharInfo));
|
|
|
|
*((short *)str)= cu->pos;
|
|
*((short *)(str+2))= cu->len;
|
|
|
|
return str;
|
|
}
|
|
|
|
static void free_undoFont(void *strv)
|
|
{
|
|
MEM_freeN(strv);
|
|
}
|
|
|
|
/* and this is all the undo system needs to know */
|
|
void undo_push_font(char *name)
|
|
{
|
|
undo_editmode_push(name, free_undoFont, undoFont_to_editFont, editFont_to_undoFont, NULL);
|
|
}
|
|
|
|
|
|
|
|
/***/
|