📄 utilobj.cpp
字号:
//UtilObj.cpp, (c)2000, 2001, 2002, 2003, 2004, 2005 by R. Lackner
//
// This file is part of RLPlot.
//
// RLPlot 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.
//
// RLPlot 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 RLPlot; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#include "rlplot.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <fcntl.h> //file open flags
#include <sys/stat.h> //I/O flags
#ifdef _WINDOWS
#include <io.h> //for read/write
#else
#define O_BINARY 0x0
#include <unistd.h>
#endif
Default defs;
static LineDEF ETbgnn = {0.0, 1.0, 0x00e8e8e8L, 0L};
static LineDEF ETbgna = {0.0, 1.0, 0x00ffffffL, 0L};
static LineDEF ETbgmn = {0.0, 1.0, 0x00cbcbcbL, 0L};
static LineDEF ETbgma = {0.0, 1.0, 0x00ffffc0L, 0L};
static LineDEF yLine = {0.0, 1.0, 0x0000ffffL, 0L};
extern const LineDEF BlackLine = {0.0, 1.0, 0x00000000L, 0L};
extern const LineDEF GrayLine = {0.0, 1.0, 0x00c0c0c0L, 0L};
static FillDEF ETfbnn = {FILL_NONE, 0x00e8e8e8L, 1.0, NULL, 0x00ffffffL};
static FillDEF ETfbna = {FILL_NONE, 0x00ffffffL, 1.0, NULL, 0x00ffffffL};
static FillDEF ETfbmn = {FILL_NONE, 0x00e8cbcbL, 1.0, NULL, 0x00ffffffL};
static FillDEF ETfbma = {FILL_NONE, 0x00ffffc0L, 1.0, NULL, 0x00ffffffL};
static FillDEF yFill = {FILL_NONE, 0x0000ffffL, 1.0, NULL, 0x0000ffffL};
extern char TmpTxt[500];
extern unsigned long cObsW; //count objects written
extern GraphObj *CurrGO, *TrackGO; //Selected Graphic Objects
extern dragHandle *CurrHandle;
extern UndoObj Undo;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Process fields with user input text
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
EditText *CurrText = 0L, *scroll_et = 0;
int scroll_dist = 0;
EditText::EditText(void *par, char *msg, int r, int c)
{
loc.x = loc.y = crb.x = rb.x = crb.y = rb.y = 0; Value = 0.0;
row = r; col = c; disp = 0L; text = 0L;
CursorPos = length = Align = 0; type = ET_UNKNOWN; TextCol=0x00000000L;
bgLine = &ETbgnn; bgFill = &ETfbnn; parent = par;
if(msg && msg[0]) {
SetText(msg); FindType();
}
else {
Align = TXA_VCENTER | TXA_HRIGHT;
type = ET_UNKNOWN;
}
m1 = m2 = -1; //cursor positions track marks
ftext = 0L; //store formula text result here
}
EditText::~EditText()
{
HideCopyMark();
if(CurrText == this) CurrText = 0L;
if(text) free(text); text = 0L;
if(ftext) free(ftext); ftext = 0L;
}
bool
EditText::AddChar(int ci, anyOutput *Out, void *data_obj)
{
char byte1, byte2, c, *tmp;
POINT MyPos;
int i;
if(ci < 254 && ci > 31) c = (char)ci;
else if(ci == 27) { //Esc
m1 = m2 = -1; Redraw(Out, true); return true;
}
else return false;
if(parent) {
((DataObj*)parent)->Command(CMD_MRK_DIRTY, 0L, 0L);
((DataObj*)parent)->Command(CMD_SAVEPOS, 0L, 0L);
}
Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
bgLine = &ETbgna; bgFill = &ETfbna; TextCol = 0x00000000L;
if(text)length = strlen(text);
else length = 0;
if(text) tmp = (char *)realloc(text, length+2);
else tmp = (char *)calloc(2, sizeof(char));
if(!tmp) return false;
text = tmp;
byte1 = byte2 = 0;
//replace mark by character if mark exists
if(hasMark()) { //delete marked part of text
if(m1 > m2) Swap(m1, m2);
if(m2 >= (short int)strlen(text)) text[m1] = 0;
else strcpy(text+m1, text+m2);
CursorPos = m1;
m1 = m2 = -1;
}
byte1 = text[CursorPos];
i = CursorPos;
text[i++] = c;
while(byte1) {
byte2 = byte1; byte1 = text[i]; text[i++] = byte2;
}
text[i] = byte1; CursorPos++; type = ET_UNKNOWN;
Redraw(Out, true);
MyPos.y = loc.y;
MyPos.x = Align & TXA_HRIGHT ? crb.x - 2 : loc.x + 2;
if(Out)Out->TextCursor(text, MyPos, (POINT *) NULL, &CursorPos,
scroll_et == this ? scroll_dist : scroll_dist=0);
if(parent && text) {
((DataObj*)parent)->Command(CMD_ETRACC, text[0] == '=' && ci != ')' ? this : 0L, 0L);
}
return true;
}
void
EditText::Update(int select, anyOutput *Out, POINT *MousePos)
{
POINT MyPos;
if(!parent && !disp) disp = Out;
if(select != 1 && select != 5) m1 = m2 = -1; //no mark;
switch(select) {
case 0: //just redraw with current settings
Redraw(Out, true);
break;
case 5: //dialog control
if(!text)Align = TXA_VCENTER | TXA_HLEFT;
case 1: //active spread sheet cell with cursor
if((type & 0xff) == ET_FORMULA) Align = TXA_VCENTER | TXA_HLEFT;
if(!text && !(text = (char *) calloc(10, sizeof(char))))return;
if(CursorPos > (int)strlen(text)) CursorPos = (int)strlen(text);
if(MousePos && (type & 0xff) == ET_TEXT && (text && text[0] == '\'' && (bgLine == &ETbgnn || bgLine == &ETbgmn))) {
MousePos->x += 4;
}
bgLine = &ETbgna; bgFill = &ETfbna; TextCol = 0x00000000L;
if(Out) {
Redraw(Out, true);
MyPos.y = loc.y; MyPos.x = Align & TXA_HRIGHT ? crb.x - 4 : loc.x + 4;
if(MousePos && MousePos->x && MousePos->y) {
Out->TextCursor(text, MyPos, MousePos,&CursorPos,
scroll_et == this ? scroll_dist : scroll_dist=0);
}
else if(select ==1) Out->TextCursor(text, MyPos, NULL, &CursorPos,
scroll_et == this ? scroll_dist : (scroll_dist=0)+2);
}
break;
case 2: //inactive spreadsheet cell
if((type & 0xff) == ET_FORMULA) Align = TXA_VCENTER | TXA_HRIGHT;
if(crb.x > rb.x) {
crb.x = rb.x; crb.y = rb.y;
}
if(CurrText == this) FindType();
bgLine = &ETbgnn; bgFill = &ETfbnn; TextCol = 0x00000000L;
if(Out) Redraw(Out, true);
break;
case 10: //value filled in by external app.
if(text && text[0]) {
type = ET_VALUE;
Align = TXA_VCENTER | TXA_HRIGHT;
sscanf(text, "%lf", &Value);
}
break;
case 20: //update value only
FindType();
break;
}
}
bool
EditText::Redraw(anyOutput *Out, bool display)
{
RECT rc;
POINT MyPos;
char *txt, tmptxt[80];
int w, h, o_crbx;
bool b_clip = false;
anyOutput *opc;
anyResult *fmres;
if(!parent && disp) Out = disp;
if(loc.x <1 || rb.x < 1 || loc.y <1 || rb.y <1) return false;
o_crbx = crb.x; crb.x = rb.x; crb.y = rb.y;
if (Out) {
if (m1 >m2) Swap(m1, m2);
if(((type & 0xff) == ET_UNKNOWN) && text && text[0]) FindType();
Out->TxtSet.Align = Align; Out->TxtSet.ColTxt = TextCol;
Out->TxtSet.ColBg = bgLine->color;
if(text && text[0]) {
Out->oGetTextExtent(text, strlen(text), &w, &h);
if(CurrText == this) {
while((crb.x - loc.x) < (w+(h>>1))) crb.x += (rb.x - loc.x);
if(o_crbx > loc.x && o_crbx > crb.x && o_crbx < 4000) crb.x = o_crbx;
}
else if((crb.x - loc.x) < (w+(h>>1))) b_clip = true;
}
Out->SetFill(bgFill); Out->SetLine(bgLine);
rc.left = loc.x; rc.right = crb.x;
rc.top = loc.y+1; rc.bottom = crb.y-2;
Out->oRectangle(loc.x, loc.y, crb.x-1, crb.y-1);
if((!text || !text[0]) && (type & 0xff) == ET_VALUE){
sprintf(tmptxt, "%g", Value);
if(text = (char*)realloc(text, strlen(tmptxt)+2)) strcpy(text, tmptxt);
CursorPos = 0;
}
if(ftext) free(ftext); ftext = 0L;
if(text && text[0]){
if((type & 0xff) == ET_FORMULA && (bgLine == &ETbgnn || bgLine == &ETbgmn)) {
Out->TxtSet.Align = TXA_HLEFT | TXA_VCENTER;
if(type & ET_CIRCULAR) strcpy (tmptxt, "#CIRC.");
else if((fmres = do_formula((DataObj*)parent, text+1)) && fmres->type != ET_ERROR) {
b_clip = false;
if(fmres->type == ET_VALUE) {
sprintf(tmptxt, "%g", Value = fmres->value);
fit_num_rect(Out, rb.x - loc.x, tmptxt);
Out->TxtSet.Align = TXA_HRIGHT | TXA_VCENTER;
}
else if(fmres->type == ET_TEXT) {
if(ftext) free (ftext); ftext = 0L;
if(fmres->text) ftext = strdup(fmres->text);
if(fmres->text && strlen(fmres->text)<sizeof(tmptxt)) strcpy(tmptxt, fmres->text);
else if(fmres->text) sprintf(tmptxt,"#SIZE");
else tmptxt[0] = 0;
}
else strcpy(tmptxt, "#VALUE");
}
else sprintf(tmptxt, "#ERROR");
txt = tmptxt;
}
else if((type &0xff) == ET_VALUE) {
Out->oGetTextExtent(text, strlen(text), &w, &h);
if(w >= (rb.x - loc.x-8) && (bgLine == &ETbgnn || bgLine == &ETbgmn)) {
sprintf(tmptxt, "%g", Value);
fit_num_rect(Out, rb.x - loc.x, tmptxt);
txt = tmptxt; b_clip = false;
}
else txt = text;
}
else if((type & 0xff) == ET_TEXT) {
if(text && text[0] == '\'' && (bgLine == &ETbgnn || bgLine == &ETbgmn)) {
txt = text+1;
}
else txt = text;
}
else txt = text;
MyPos.y = (loc.y+rb.y)>>1;
if(Out->TxtSet.Align & TXA_HRIGHT) { //right justified text
MyPos.x = crb.x-4;
}
else { //left justified text
MyPos.x = loc.x+4;
}
if(b_clip && (opc = NewBitmapClass(w+22, rb.y-loc.y, Out->hres, Out->vres))){
if(scroll_et != this || parent) {
scroll_et = this; scroll_dist = 0;
}
opc->Erase(bgFill->color);
opc->SetTextSpec(&Out->TxtSet); opc->TxtSet.Align = TXA_HLEFT | TXA_VCENTER;
opc->oTextOut(4,(rb.y-loc.y)>>1, txt, strlen(txt));
if(!parent && CursorPos) {
Out->oGetTextExtent(txt, CursorPos, &w, &h);
while((scroll_dist + w)>(rc.right-rc.left-10)) scroll_dist -=10;
while((scroll_dist + w)<12) scroll_dist +=10;
if(scroll_dist >0) scroll_dist=0;
}
else scroll_dist=0;
Out->CopyBitmap(rc.left+1, rc.top+1, opc, 1-scroll_dist, 1,
rc.right-rc.left-4, rc.bottom-rc.top-2, false);
DelBitmapClass(opc);
}
else {
if(display && hasMark() && mx1 > loc.x && mx2 < crb.x) {
Out->SetFill(&yFill); Out->SetLine(&yLine);
Out->oRectangle(mx1, rc.top, mx2, rc.bottom);
Out->SetFill(bgFill); Out->SetLine(bgLine);
}
scroll_dist = 0;
Out->oTextOut(MyPos.x, MyPos.y, txt, 0);
}
}
if(display) {
if(!(Out->UpdateRect(&rc, false))) return false;
if(hasMark() && mx1 > loc.x && mx2 < rb.x) {
rc.left = mx1; rc.right = mx2;
Out->UpdateRect(&rc, true);
Out->MrkMode = MRK_NONE;
}
}
return true;
}
return false;
}
void
EditText::Mark(anyOutput *Out, int mark)
{
LineDEF *ol = bgLine;
FillDEF *of = bgFill;
DWORD ocol = TextCol;
m1 = m2 = -1;
if(!parent) return;
switch (mark){
case 0: //normal not active
bgLine = &ETbgnn; bgFill = &ETfbnn; TextCol = 0x00000000L;
break;
case 1: //normal active
bgLine = &ETbgna; bgFill = &ETfbna; TextCol = 0x00000000L;
break;
case 2: //mark not active
bgLine = &ETbgmn; bgFill = &ETfbmn; TextCol = 0x00c00000L;
break;
case 3: //mark active
bgLine = &ETbgma; bgFill = &ETfbma; TextCol = 0x00ff0000L;
break;
}
if(!mark || mark == 2) {
loc.y--; rb.y++;
}
Redraw(Out, true);
if(!mark || mark == 2) {
loc.y++; rb.y--;
}
bgLine = ol; bgFill = of; TextCol = ocol;
}
bool
EditText::Command(int cmd, anyOutput *Out, void *data_obj)
{
int i, j, k, w, h;
POINT MyPos;
MouseEvent *mev;
static RECT rMark;
bool bRet;
char *tag1, *tag2;
unsigned char *pt;
MyPos.y = loc.y;
MyPos.x = Align & TXA_HRIGHT ? crb.x - 4 : loc.x + 4;
if(!(text)) return false;
if(!parent && disp) Out = disp; //Dialog !
switch(cmd) {
case CMD_MRK_DIRTY:
type = ET_UNKNOWN;
if(CurrText == this) {
Command(CMD_REDRAW, Out, data_obj);
if(parent)((DataObj*)parent)->Command(CMD_MRK_DIRTY, Out, 0L);
}
else if(parent) {
((DataObj*)parent)->Command(CMD_REDRAW, Out, 0L);
((DataObj*)parent)->Command(CMD_MRK_DIRTY, Out, 0L);
}
else return Command(CMD_REDRAW, Out, data_obj);
return true;
case CMD_SETFONT:
if (!text || !text[0]) return false;
type = ET_TEXT;
if(hasMark()) {
Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
switch (*((int*)data_obj)) {
case FONT_HELVETICA:
tag1 = (char*)"<face=helvetica>"; tag2 = (char*)"</face>"; break;
case FONT_TIMES:
tag1 = (char*)"<face=times>"; tag2 = (char*)"</face>"; break;
case FONT_COURIER:
tag1 = (char*)"<face=courier>"; tag2 = (char*)"</face>"; break;
case FONT_GREEK:
tag1 = (char*)"<face=greek>"; tag2 = (char*)"</face>"; break;
default:
return false;
}
if(m1 < m2) {
j = m1; k = m2;
}
else if(m1 > m2) {
j = m2; k = m1;
}
else return false; //empty mark !
for(i = 0; i < j; i++) TmpTxt[i] = text[i];
for(j = 0, w = i; tag1[j]; j++) TmpTxt[i++] = tag1[j];
for( ; w < k; w++) TmpTxt[i++] = text[w];
for(j = 0; tag2[j]; j++) TmpTxt[i++] = tag2[j];
for( ; TmpTxt[i++] = text[w]; w++);
m1 += (w = strlen(tag1)); m2 += w; CursorPos += w;
CleanTags(TmpTxt, &m1, &m2, &CursorPos);
if(text = (char*)realloc(text, strlen(TmpTxt)+2)) strcpy(text, TmpTxt);
Command(CMD_REDRAW, Out, 0L);
return true;
}
return false;
case CMD_SETSTYLE:
if (!text || !text[0]) return false;
type = ET_TEXT;
if(hasMark()) {
Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
switch (*((int*)data_obj)) {
case TXS_BOLD:
tag1 = (char*)"<b>"; tag2 = (char*)"</b>"; break;
case ~TXS_BOLD:
tag1 = (char*)"</b>"; tag2 = (char*)"<b>"; break;
case TXS_ITALIC:
tag1 = (char*)"<i>"; tag2 = (char*)"</i>"; break;
case ~TXS_ITALIC:
tag1 = (char*)"</i>"; tag2 = (char*)"<i>"; break;
case TXS_UNDERLINE:
tag1 = (char*)"<u>"; tag2 = (char*)"</u>"; break;
case ~TXS_UNDERLINE:
tag1 = (char*)"</u>"; tag2 = (char*)"<u>"; break;
case TXS_SUPER:
tag1 = (char*)"<sup>"; tag2 = (char*)"</sup>"; break;
case ~TXS_SUPER:
tag1 = (char*)"</sup>"; tag2 = (char*)"<sup>"; break;
case TXS_SUB:
tag1 = (char*)"<sub>"; tag2 = (char*)"</sub>"; break;
case ~TXS_SUB:
tag1 = (char*)"</sub>"; tag2 = (char*)"<sub>"; break;
default:
return false;
}
if(m1 < m2) {
j = m1; k = m2;
}
else if(m1 > m2) {
j = m2; k = m1;
}
else return false; //empty mark !
for(i = 0; i < j; i++) TmpTxt[i] = text[i];
for(j = 0, w = i; tag1[j]; j++) TmpTxt[i++] = tag1[j];
for( ; w < k; w++) TmpTxt[i++] = text[w];
for(j = 0; tag2[j]; j++) TmpTxt[i++] = tag2[j];
for( ; TmpTxt[i++] = text[w]; w++);
m1 += (w = strlen(tag1)); m2 += w; CursorPos += w;
CleanTags(TmpTxt, &m1, &m2, &CursorPos);
if(text = (char*)realloc(text, strlen(TmpTxt)+2)) strcpy(text, TmpTxt);
Command(CMD_REDRAW, Out, 0L);
return true;
}
return false;
case CMD_ADDTXT:
if(data_obj && *((char*)data_obj) && text &&
(type == ET_TEXT || type == ET_UNKNOWN || type == ET_FORMULA)){
if(hasMark()) Command(CMD_DELETE, 0L, 0L);
else Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
if(m1 > -1 && m2 > -1) Command(CMD_DELETE, 0L, 0L);
for(i = 0; i < CursorPos && text[i]; i++) TmpTxt[i] = text[i];
j = i + sprintf(TmpTxt+i, "%s", (char*)data_obj);
if(text[i]) sprintf(TmpTxt+j, "%s", text+i);
if(text = (char*)realloc(text, strlen(TmpTxt)+2)) strcpy(text, TmpTxt);
CursorPos += strlen((char*)data_obj);
Out->Focus();
Update(1, Out, 0L);
}
return true;
case CMD_BACKSP:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -