[rlplot] 01/23: Imported Upstream version 0.99.14
Andreas Tille
tille at debian.org
Wed Jun 29 09:50:54 UTC 2016
This is an automated email from the git hooks/post-receive script.
tille pushed a commit to branch master
in repository rlplot.
commit 31a7665dc2f1a80608c8ba489bc2dd303411100b
Author: Andreas Tille <tille at debian.org>
Date: Wed Jun 29 11:43:53 2016 +0200
Imported Upstream version 0.99.14
---
Axes.cpp | 1741 ++++++++++
Export.cpp | 1325 ++++++++
Fileio.cpp | 3353 +++++++++++++++++++
Makefile | 118 +
Makefile.win | 97 +
ODbuttons.cpp | 1273 ++++++++
Output.cpp | 1829 +++++++++++
PlotObs.cpp | 4427 +++++++++++++++++++++++++
PropertyDlg.cpp | 7777 ++++++++++++++++++++++++++++++++++++++++++++
QT_Spec.cpp | 2667 +++++++++++++++
QT_Spec.h | 284 ++
README | 131 +
RLPLOT.ICO | Bin 0 -> 766 bytes
RLPLOT.RC | 337 ++
RLPlot.bmp | Bin 0 -> 630 bytes
RLPlot.xpm | 47 +
TheDialog.cpp | 4479 ++++++++++++++++++++++++++
TheDialog.h | 527 +++
UtilObj.cpp | 2950 +++++++++++++++++
Utils.cpp | 1946 +++++++++++
Version.h | 20 +
WinSpec.cpp | 2422 ++++++++++++++
WinSpec.h | 130 +
exprlp.cpp | 532 +++
gpl.txt | 340 ++
mfcalc.cpp | 2299 +++++++++++++
mfcalc.y | 1247 ++++++++
resource.h | 86 +
rlp_math.cpp | 411 +++
rlplot.1 | 105 +
rlplot.cpp | 9618 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
rlplot.h | 2495 +++++++++++++++
rlplot.spec | 62 +
spreadwi.cpp | 1833 +++++++++++
34 files changed, 56908 insertions(+)
diff --git a/Axes.cpp b/Axes.cpp
new file mode 100755
index 0000000..320ff5b
--- /dev/null
+++ b/Axes.cpp
@@ -0,0 +1,1741 @@
+//Axes.cpp, Copyright 2000, 2001, 2002, 2003, 2004 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
+//
+// This module contains most of the axis-object and related stuff
+// like ticks and grid lines.
+#include "rlplot.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+extern char TmpTxt[];
+extern Default defs;
+extern GraphObj *CurrGO, *TrackGO; //Selected Graphic Objects
+extern Axis **CurrAxes;
+extern UndoObj Undo;
+
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// define an object for each grid line
+GridLine::GridLine(GraphObj *par, DataObj *d, int which, DWORD df):
+ GraphObj(par, d)
+{
+ FileIO(INIT_VARS);
+ type = which;
+ flags = df;
+ if(flags & AXIS_RADIAL) type |= DL_CIRCULAR; //default to circular grid
+ Id = GO_GRIDLINE;
+ if(parent) parent->Command(CMD_GET_GRIDLINE, &LineDef, 0L);
+ bModified = false;
+}
+
+GridLine::GridLine(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+ bModified = false;
+}
+
+GridLine::~GridLine()
+{
+ int i;
+
+ if(bModified) Undo.InvalidGO(this);
+ if(cpts) free(cpts); cpts = 0L;
+ if(gl1) free(gl1); gl1 = 0L;
+ if(gl2) free(gl2); gl2 = 0L;
+ if(gl3) free(gl3); gl3 = 0L;
+ if(ls) {
+ for(i = 0; i < 3; i++) if(ls[i]) delete(ls[i]);
+ free(ls); ls = 0L;
+ }
+ if(mo) DelBitmapClass(mo); mo = 0L;
+}
+
+void
+GridLine::DoPlot(anyOutput *o)
+{
+ int tmp, ix, iy, ir;
+ AxisDEF *axdef;
+
+ if(!parent || !o) return;
+ o->SetLine(&LineDef);
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ if(!type) type = DL_LEFT | DL_BOTTOM;
+ if(type & DL_CIRCULAR) {
+ axdef = (AxisDEF*)((Axis*)(parent->parent))->GetAxis();
+ ix = o->co2ix(axdef->Center.fx + parent->GetSize(SIZE_GRECT_LEFT));
+ iy = o->co2iy(axdef->Center.fy + parent->GetSize(SIZE_GRECT_TOP));
+ ir = abs((int)(parent->GetSize(SIZE_YBASE))-iy);
+ ncpts = 0;
+ cpts = MakeArc(ix, iy, ir, 0x0f, &ncpts);
+ SetMinMaxRect(&rDims, ix-ir, iy-ir, ix+ir, iy+ir);
+ IncrementMinMaxRect(&rDims, 3);
+ o->oPolyline(cpts, (int)ncpts);
+ return;
+ }
+ if(parent && parent->Id == GO_TICK) {
+ pts[0].x = pts[1].x = pts[2].x = pts[3].x = (long)parent->GetSize(SIZE_XBASE);
+ pts[0].y = pts[1].y = pts[2].y = pts[3].y = (long)parent->GetSize(SIZE_YBASE);
+ if(type & DL_LEFT) {
+ tmp = o->fx2ix(parent->GetSize(SIZE_BOUNDS_LEFT));
+ if(tmp < pts[0].x) pts[0].x = tmp;
+ if(tmp > pts[1].x) pts[1].x = tmp;
+ }
+ if(type & DL_RIGHT) {
+ tmp = o->fx2ix(parent->GetSize(SIZE_BOUNDS_RIGHT));
+ if(tmp < pts[0].x) pts[0].x = tmp;
+ if(tmp > pts[1].x) pts[1].x = tmp;
+ }
+ if(type & DL_YAXIS) {
+ tmp = iround(parent->GetSize(SIZE_YAXISX));
+ if(tmp < pts[0].x) pts[0].x = tmp;
+ if(tmp > pts[1].x) pts[1].x = tmp;
+ }
+ if(type & DL_TOP) {
+ tmp = o->fy2iy(parent->GetSize(SIZE_BOUNDS_TOP));
+ if(tmp < pts[2].y) pts[2].y = tmp;
+ if(tmp > pts[3].y) pts[3].y = tmp;
+ }
+ if(type & DL_BOTTOM) {
+ tmp = o->fy2iy(parent->GetSize(SIZE_BOUNDS_BOTTOM));
+ if(tmp < pts[2].y) pts[2].y = tmp;
+ if(tmp > pts[3].y) pts[3].y = tmp;
+ }
+ if(type & DL_XAXIS) {
+ tmp = iround(parent->GetSize(SIZE_XAXISY));
+ if(tmp < pts[2].y) pts[2].y = tmp;
+ if(tmp > pts[3].y) pts[3].y = tmp;
+ }
+ SetMinMaxRect(&rDims, pts[0].x, pts[2].y, pts[1].x, pts[3].y);
+ IncrementMinMaxRect(&rDims, 3);
+ if(pts[0].x != pts[1].x || pts[0].y != pts[1].y) o->oPolyline(pts, 2);
+ if(pts[2].x != pts[3].x || pts[2].y != pts[3].y) o->oPolyline(pts+2, 2);
+ }
+}
+
+void
+GridLine::DoMark(anyOutput *o, bool mark)
+{
+ if(cpts && mark){
+ InvertLine(cpts, ncpts, &LineDef, &rDims, o, mark);
+ }
+ else if(cpts) {
+ InvertLine(cpts, ncpts, &LineDef, &rDims, o, mark);
+ }
+
+}
+
+bool
+GridLine::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ POINT p1;
+
+ switch(cmd){
+ case CMD_SET_DATAOBJ:
+ Id = GO_GRIDLINE;
+ return true;
+ case CMD_SETSCROLL:
+ case CMD_SET_GO3D:
+ case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ return false;
+ case CMD_SET_GRIDLINE:
+ if(tmpl) memcpy(&LineDef, tmpl, sizeof(LineDEF));
+ return true;
+ case CMD_SET_GRIDTYPE:
+ if(tmpl)type = *((int*)tmpl);
+ return true;
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(IsInRect(&rDims, p1.x = mev->x, p1.y = mev->y)) {
+ if(cpts && (type & DL_CIRCULAR) && IsCloseToPL(p1, cpts, ncpts)) {
+ o->ShowMark(this, MRK_GODRAW);
+ return true;
+ }
+ else if(!(type & DL_CIRCULAR)){
+ o->ShowMark(&rDims, MRK_INVERT);
+ CurrGO = this;
+ return true;
+ }
+ }
+ break;
+ }
+ return false;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Gridline for axes and plots in 3D space
+GridLine3D::GridLine3D(GraphObj *par, DataObj *d, int which, DWORD df):
+ GridLine(par, d, which, df)
+{
+ Id = GO_GRIDLINE3D;
+}
+
+GridLine3D::GridLine3D(int src):GridLine(src)
+{
+}
+
+GridLine3D::~GridLine3D()
+{
+ int i;
+
+ if(cpts) free(cpts); cpts = 0L;
+ if(gl1) free(gl1); gl1 = 0L;
+ if(gl2) free(gl2); gl2 = 0L;
+ if(gl3) free(gl3); gl3 = 0L;
+ if(ls) {
+ for(i = 0; i < 6; i++) if(ls[i]) delete(ls[i]);
+ free(ls); ls = 0L;
+ }
+ if(mo) DelBitmapClass(mo); mo = 0L;
+}
+
+void
+GridLine3D::DoMark(anyOutput *o, bool mark)
+{
+ int i;
+ POINT3D *gl;
+
+ if(mark){
+ if(ls){
+ memcpy(&mrc, &rDims, sizeof(RECT));
+ IncrementMinMaxRect(&mrc, 6 + o->un2ix(LineDef.width));
+ mo = GetRectBitmap(&mrc, o);
+ for(i = 0; i < 6; i++) if(ls[i]) {
+ switch(i) {
+ case 0: case 1:
+ gl = gl1; break;
+ case 2: case 3:
+ gl = gl2; break;
+ case 4: case 5:
+ gl = gl3; break;
+ }
+ if(gl) {
+ if(gl[0].x && gl[0].y && gl[1].x && gl[1].y) {
+ pts[0].x = gl[0].x; pts[1].x = gl[1].x;
+ pts[0].y = gl[0].y; pts[1].y = gl[1].y;
+ InvertLine(pts, 2, &LineDef, &mrc, o, mark);
+ }
+ if(gl[2].x && gl[2].y && gl[3].x && gl[3].y) {
+ pts[0].x = gl[2].x; pts[1].x = gl[3].x;
+ pts[0].y = gl[2].y; pts[1].y = gl[3].y;
+ InvertLine(pts, 2, &LineDef, &mrc, o, mark);
+ }
+ }
+ }
+ }
+ }
+ else if(mo) RestoreRectBitmap(&mo, &mrc, o);
+}
+
+
+void
+GridLine3D:: DoPlot(anyOutput *o)
+{
+ fPOINT3D p1, p2, pn;
+ int i;
+
+ if(!parent || !o) return;
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ if(!gl1) gl1 = (POINT3D*)calloc(4, sizeof(POINT3D));
+ if(!gl2) gl2 = (POINT3D*)calloc(4, sizeof(POINT3D));
+ if(!gl3) gl3 = (POINT3D*)calloc(4, sizeof(POINT3D));
+ if(!ls) ls = (line_segment**)calloc(6, sizeof(line_segment*));
+ o->ActualSize(&rDims);
+ Swap(rDims.left, rDims.right); Swap(rDims.top, rDims.bottom);
+ if(gl1 && gl2 && gl3 && ls) {
+ for(i = 0; i < 6; i++) if(ls[i]) {
+ delete(ls[i]); ls[i] = 0L;
+ }
+ if(type & 0x01) {
+ pn.fx = parent->GetSize(SIZE_BOUNDS_XMIN); pn.fy = parent->GetSize(SIZE_BOUNDS_YMIN);
+ pn.fz = parent->GetSize(SIZE_MINE); o->fvec2ivec(&pn, &p1);
+ pn.fx = parent->GetSize(SIZE_BOUNDS_XMAX); o->fvec2ivec(&pn, &p2);
+ gl1[0].x = iround(p1.fx); gl1[0].y = iround(p1.fy);
+ gl1[1].x = iround(p2.fx); gl1[1].y = iround(p2.fy);
+ gl1[0].z = iround(p1.fz); gl1[1].z = iround(p2.fz);
+ if(ls[0] = new line_segment(this, data, &LineDef, &gl1[0], &gl1[1]))
+ ls[0]->DoPlot(o);
+ UpdateMinMaxRect(&rDims, gl1[0].x, gl1[0].y);
+ UpdateMinMaxRect(&rDims, gl1[1].x, gl1[1].y);
+ }
+ if(type & 0x02) {
+ pn.fx = parent->GetSize(SIZE_BOUNDS_XMIN); pn.fy = parent->GetSize(SIZE_BOUNDS_YMIN);
+ pn.fz = parent->GetSize(SIZE_MINE); o->fvec2ivec(&pn, &p1);
+ pn.fy = parent->GetSize(SIZE_BOUNDS_YMAX); o->fvec2ivec(&pn, &p2);
+ gl1[2].x = iround(p1.fx); gl1[2].y = iround(p1.fy);
+ gl1[3].x = iround(p2.fx); gl1[3].y = iround(p2.fy);
+ gl1[2].z = iround(p1.fz); gl1[3].z = iround(p2.fz);
+ if(ls[1] = new line_segment(this, data, &LineDef, &gl1[2], &gl1[3]))
+ ls[1]->DoPlot(o);
+ UpdateMinMaxRect(&rDims, gl1[2].x, gl1[2].y);
+ UpdateMinMaxRect(&rDims, gl1[3].x, gl1[3].y);
+ }
+ if(type & 0x04) {
+ pn.fx = parent->GetSize(SIZE_BOUNDS_XMIN); pn.fy = parent->GetSize(SIZE_MINE);
+ pn.fz = parent->GetSize(SIZE_BOUNDS_ZMIN); o->fvec2ivec(&pn, &p1);
+ pn.fx = parent->GetSize(SIZE_BOUNDS_XMAX); o->fvec2ivec(&pn, &p2);
+ gl2[0].x = iround(p1.fx); gl2[0].y = iround(p1.fy);
+ gl2[1].x = iround(p2.fx); gl2[1].y = iround(p2.fy);
+ gl2[0].z = iround(p1.fz); gl2[1].z = iround(p2.fz);
+ if(ls[2] = new line_segment(this, data, &LineDef, &gl2[0], &gl2[1]))
+ ls[2]->DoPlot(o);
+ UpdateMinMaxRect(&rDims, gl2[0].x, gl2[0].y);
+ UpdateMinMaxRect(&rDims, gl2[1].x, gl2[1].y);
+ }
+ if(type & 0x08) {
+ pn.fx = parent->GetSize(SIZE_BOUNDS_XMIN); pn.fy = parent->GetSize(SIZE_MINE);
+ pn.fz = parent->GetSize(SIZE_BOUNDS_ZMIN); o->fvec2ivec(&pn, &p1);
+ pn.fz = parent->GetSize(SIZE_BOUNDS_ZMAX); o->fvec2ivec(&pn, &p2);
+ gl2[2].x = iround(p1.fx); gl2[2].y = iround(p1.fy);
+ gl2[3].x = iround(p2.fx); gl2[3].y = iround(p2.fy);
+ gl2[2].z = iround(p1.fz); gl2[3].z = iround(p2.fz);
+ if(ls[3] = new line_segment(this, data, &LineDef, &gl2[2], &gl2[3]))
+ ls[3]->DoPlot(o);
+ UpdateMinMaxRect(&rDims, gl2[2].x, gl2[2].y);
+ UpdateMinMaxRect(&rDims, gl2[3].x, gl2[3].y);
+ }
+ if(type & 0x10) {
+ pn.fx = parent->GetSize(SIZE_MINE); pn.fy = parent->GetSize(SIZE_BOUNDS_YMIN);
+ pn.fz = parent->GetSize(SIZE_BOUNDS_ZMIN); o->fvec2ivec(&pn, &p1);
+ pn.fy = parent->GetSize(SIZE_BOUNDS_YMAX); o->fvec2ivec(&pn, &p2);
+ gl3[0].x = iround(p1.fx); gl3[0].y = iround(p1.fy);
+ gl3[1].x = iround(p2.fx); gl3[1].y = iround(p2.fy);
+ gl3[0].z = iround(p1.fz); gl3[1].z = iround(p2.fz);
+ if(ls[4] = new line_segment(this, data, &LineDef, &gl3[0], &gl3[1]))
+ ls[4]->DoPlot(o);
+ UpdateMinMaxRect(&rDims, gl3[0].x, gl3[0].y);
+ UpdateMinMaxRect(&rDims, gl3[1].x, gl3[1].y);
+ }
+ if(type & 0x20) {
+ pn.fx = parent->GetSize(SIZE_MINE); pn.fy = parent->GetSize(SIZE_BOUNDS_YMIN);
+ pn.fz = parent->GetSize(SIZE_BOUNDS_ZMIN); o->fvec2ivec(&pn, &p1);
+ pn.fz = parent->GetSize(SIZE_BOUNDS_ZMAX); o->fvec2ivec(&pn, &p2);
+ gl3[2].x = iround(p1.fx); gl3[2].y = iround(p1.fy);
+ gl3[3].x = iround(p2.fx); gl3[3].y = iround(p2.fy);
+ gl3[2].z = iround(p1.fz); gl3[3].z = iround(p2.fz);
+ if(ls[5] = new line_segment(this, data, &LineDef, &gl3[2], &gl3[3]))
+ ls[5]->DoPlot(o);
+ UpdateMinMaxRect(&rDims, gl3[2].x, gl3[2].y);
+ UpdateMinMaxRect(&rDims, gl3[3].x, gl3[3].y);
+ }
+ }
+ IncrementMinMaxRect(&rDims, 4);
+}
+
+bool
+GridLine3D::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i;
+
+ switch(cmd) {
+ case CMD_SET_DATAOBJ:
+ Id = GO_GRIDLINE3D;
+ return true;
+ case CMD_MOUSE_EVENT:
+ if(tmpl && ls) switch (((MouseEvent *)tmpl)->Action) {
+ case MOUSE_LBUP:
+ for(i = 0; i < 6; i++) if(ls[i] &&
+ ls[i]->ObjThere(((MouseEvent *)tmpl)->x, ((MouseEvent *)tmpl)->y)) {
+ o->ShowMark(this, MRK_GODRAW);
+ return true;
+ }
+ }
+ break;
+ default:
+ return GridLine::Command(cmd, tmpl, o);
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Radial Gridline for polar plots: spokes for the plot
+GridRadial::GridRadial(GraphObj *par, DataObj *d, int which, DWORD df):
+ GridLine(par, d, which, df)
+{
+ Id = GO_GRIDRADIAL;
+}
+
+GridRadial::GridRadial(int src):GridLine(src)
+{
+}
+
+GridRadial::~GridRadial()
+{
+ if(mo) DelBitmapClass(mo); mo = 0L;
+}
+
+void
+GridRadial::DoPlot(anyOutput *o)
+{
+ AxisDEF *axdef;
+
+ if(!parent || !o) return;
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ o->SetLine(&LineDef);
+ if(parent->Id == GO_TICK && parent->parent && parent->parent->Id == GO_AXIS) {
+ axdef = (AxisDEF*)((Axis*)(parent->parent))->GetAxis();
+ pts[0].x = iround(parent->GetSize(SIZE_XBASE));
+ pts[0].y = iround(parent->GetSize(SIZE_YBASE));
+ pts[1].x = o->co2ix(axdef->Center.fx + parent->GetSize(SIZE_GRECT_LEFT));
+ pts[1].y = o->co2iy(axdef->Center.fy + parent->GetSize(SIZE_GRECT_TOP));
+ SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+ IncrementMinMaxRect(&rDims, 3);
+ o->oPolyline(pts, 2);
+ }
+}
+
+void
+GridRadial::DoMark(anyOutput *o, bool mark)
+{
+ if(mark) {
+ memcpy(&mrc, &rDims, sizeof(RECT));
+ IncrementMinMaxRect(&mrc, 6 + o->un2ix(LineDef.width));
+ mo = GetRectBitmap(&mrc, o);
+ InvertLine(pts, 2, &LineDef, &rDims, o, mark);
+ }
+ else if(mo) RestoreRectBitmap(&mo, &mrc, o);
+}
+
+bool
+GridRadial::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ POINT p1;
+
+ switch(cmd) {
+ case CMD_SET_DATAOBJ:
+ Id = GO_GRIDRADIAL;
+ return true;
+ case CMD_MOUSE_EVENT:
+ if(tmpl) switch (((MouseEvent *)tmpl)->Action) {
+ case MOUSE_LBUP:
+ if(IsInRect(&rDims, p1.x=((MouseEvent *)tmpl)->x, p1.y=((MouseEvent *)tmpl)->y)){
+ if(IsCloseToPL(p1, pts, 2)) {
+ o->ShowMark(this, MRK_GODRAW);
+ return true;
+ }
+ }
+ }
+ break;
+ default:
+ return GridLine::Command(cmd, tmpl, o);
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Each axis tick is a graphic object managing tick labels and grid lines
+Tick::Tick(GraphObj *par, DataObj *d, double val, DWORD Flags):GraphObj(par, d)
+{
+ FileIO(INIT_VARS);
+ value = val; flags = Flags;
+ Id = GO_TICK; bModified = false;
+}
+
+Tick::Tick(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+ bModified = false;
+}
+
+Tick::~Tick()
+{
+ Command(CMD_FLUSH, 0L, 0L);
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ if(bModified) Undo.InvalidGO(this);
+}
+
+double
+Tick::GetSize(int select)
+{
+ switch(select){
+ case SIZE_LB_XPOS: return lbx;
+ case SIZE_XBASE: return fix;
+ case SIZE_LB_YPOS: return lby;
+ case SIZE_YBASE: return fiy;
+ case SIZE_ZBASE: return fiz;
+ case SIZE_LB_XDIST:
+ if(parent && parent->Id == GO_AXIS) return parent->GetSize(SIZE_TLB_XDIST);
+ return 0.0f;
+ case SIZE_LB_YDIST:
+ if(parent && parent->Id == GO_AXIS) return parent->GetSize(SIZE_TLB_YDIST);
+ return 0.0f;
+ case SIZE_MINE: return value;
+ default:
+ if(parent) return parent->GetSize(select);
+ }
+ return 0.0;
+}
+
+bool
+Tick::SetSize(int select, double value)
+{
+ switch(select & 0xfff) {
+ case SIZE_AXIS_TICKS:
+ size = value;
+ break;
+ case SIZE_LB_XDIST:
+ case SIZE_LB_YDIST:
+ if(label)return label->SetSize(select, value);
+ break;
+ case SIZE_TICK_ANGLE:
+ angle = value;
+ }
+ return false;
+}
+
+bool
+Tick::SetColor(int select, DWORD col)
+{
+ switch(select & 0xfff) {
+ case COL_AXIS:
+ if(label)label->SetColor((select & UNDO_STORESET) ?
+ COL_TEXT | UNDO_STORESET : COL_TEXT, col);
+ return true;
+ case COL_BG:
+ if(label) return label->SetColor(select, col);
+ return false;
+ }
+ return false;
+}
+
+void
+Tick::DoMark(anyOutput *o, bool mark)
+{
+ if(mark){
+ memcpy(&mrc, &rDims, sizeof(RECT));
+ IncrementMinMaxRect(&mrc, 6);
+ mo = GetRectBitmap(&mrc, o);
+ InvertLine(pts, 2, defs.GetOutLine(), &rDims, o, mark);
+ }
+ else RestoreRectBitmap(&mo, &mrc, o);
+}
+
+bool
+Tick::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ TextDEF *LabelDef;
+ GraphObj **tmpPlots;
+
+ switch(cmd){
+ case CMD_FLUSH:
+ if(Grid) DeleteGO(Grid); Grid = 0L;
+ if(label) DeleteGO(label); label = 0L;
+ if(name) free(name); name = 0L;
+ if(ls) delete(ls); ls = 0L;
+ return true;
+ case CMD_HIDE_MARK:
+ if(!tmpl || !o) return false;
+ if(tmpl == (void*)label){
+ label->DoMark(o, false);
+ return true;
+ }
+ else if(tmpl == (void*)Grid){
+ Grid->DoMark(o, false);
+ return true;
+ }
+ return false;
+ case CMD_SET_TICKSTYLE:
+ flags &= ~0x07;
+ flags |= (0x07 & *((DWORD*)tmpl));
+ return true;
+ case CMD_TICK_TYPE:
+ if(tmpl) type = *((int*)tmpl);
+ return true;
+ case CMD_SETSCROLL:
+ case CMD_REDRAW:
+ //this commands are usually issued from a child or from Undo
+ bModified = true;
+ return parent ? parent->Command(CMD_REDRAW, 0L, o) : false;
+ case CMD_MUTATE:
+ bModified = true;
+ if(!parent || !(tmpPlots = (GraphObj **)tmpl) || !tmpPlots[0] || !tmpPlots[1]) return false;
+ if(label == tmpPlots[0]) {
+ Undo.MutateGO((GraphObj**)&label, tmpPlots[1], 0L, o);
+ return true;
+ }
+ break;
+ case CMD_DELOBJ:
+ bModified = true;
+ if(parent && tmpl && o) {
+ if(tmpl == Grid) {
+ Undo.DeleteGO((GraphObj**)(&Grid), 0L, o);
+ flags &= ~AXIS_GRIDLINE;
+ return parent->Command(CMD_REDRAW, 0L, o);
+ }
+ if(tmpl == label) {
+ Undo.DeleteGO((GraphObj**)(&label), 0L, o);
+ label = 0L;
+ return parent->Command(CMD_REDRAW, 0L, o);
+ }
+ }
+ return false;
+ case CMD_SET_GO3D:
+ case CMD_GET_GRIDLINE:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ return false;
+ case CMD_SET_GRIDTYPE:
+ if(tmpl && *((int*)tmpl)) gl_type = *((int*)tmpl);
+ case CMD_SET_GRIDLINE:
+ if(Grid && tmpl) return Grid->Command(cmd, tmpl, o);
+ return false;
+ case CMD_SET_DATAOBJ:
+ Id = GO_TICK;
+ if(Grid) Grid->Command(cmd, tmpl, o);
+ if(label) label->Command(cmd, tmpl, o);
+ return true;
+ case CMD_MOUSE_EVENT:
+ if((flags & AXIS_GRIDLINE) && Grid && Grid->Command(cmd, tmpl, o)) return true;
+ if(label && label->Command(cmd, tmpl, o)) return true;
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO &&
+ IsCloseToLine(&pts[0], &pts[1], mev->x, mev->y)) {
+ if(pts[0].x == pts[1].x || pts[0].y == pts[1].y) {
+ o->ShowMark(&rDims, MRK_INVERT);
+ CurrGO = this;
+ }
+ else o->ShowMark(this, MRK_GODRAW);
+ return true;
+ }
+ break;
+ }
+ return false;
+ case CMD_TLB_TXTDEF:
+ if(label) return label->Command(CMD_SETTEXTDEF, tmpl, o);
+ else return false;
+ case CMD_SETTEXT:
+ if(label) return label->Command(cmd, tmpl, o);
+ if(!(LabelDef = (TextDEF *)calloc(1, sizeof(TextDEF))))return false;
+ LabelDef->ColTxt = parent ? parent->GetColor(COL_AXIS) : defs.Color(COL_AXIS);
+ LabelDef->ColBg = parent ? parent->GetColor(COL_BG) : defs.Color(COL_AXIS);
+ LabelDef->RotBL = LabelDef->RotCHAR = 0.0f;
+ LabelDef->fSize = parent ? parent->GetSize(SIZE_TICK_LABELS) : defs.GetSize(SIZE_TICK_LABELS);
+ switch(flags & 0x70) {
+ case AXIS_USER: LabelDef->Align = TXA_VCENTER | TXA_HCENTER; break;
+ case AXIS_LEFT: LabelDef->Align = TXA_VCENTER | TXA_HRIGHT; break;
+ case AXIS_RIGHT: LabelDef->Align = TXA_VCENTER | TXA_HLEFT; break;
+ case AXIS_TOP: LabelDef->Align = TXA_VBOTTOM | TXA_HCENTER; break;
+ case AXIS_BOTTOM: LabelDef->Align = TXA_VTOP | TXA_HCENTER; break;
+ default: LabelDef->Align = TXA_VTOP | TXA_HRIGHT; break;
+ }
+ LabelDef->Style = TXS_NORMAL;
+ LabelDef->Mode = TXM_TRANSPARENT;
+ LabelDef->Font = FONT_HELVETICA;
+ LabelDef->text = tmpl && *((char*)tmpl) ? strdup((char*)tmpl) : 0L;
+ label = new Label(this, 0L, fix, fiy, LabelDef, LB_X_PARENT | LB_Y_PARENT);
+ if(LabelDef->text) free(LabelDef->text);
+ delete (LabelDef);
+ return true;
+ }
+ return false;
+}
+
+void
+Tick::DoPlot(double six, double csx, anyOutput *o)
+{
+ fPOINT3D dp1, dp2;
+ POINT3D ip2, p31, p32;
+
+ if(!parent || parent->Id != GO_AXIS) return;
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ if(ls) delete(ls); ls = 0L;
+ if(!((Axis*)parent)->GetValuePos(value, &fix, &fiy, &fiz, o))return;
+ lbx = fix; lby = fiy;
+ if(flags & AXIS_ANGULAR) {
+ dp1.fx = o->co2fix(parent->GetSize(SIZE_XCENT)+parent->GetSize(SIZE_GRECT_LEFT));
+ dp1.fy = o->co2fiy(parent->GetSize(SIZE_YCENT)+parent->GetSize(SIZE_GRECT_TOP));
+ dp1.fz = o->un2fix(parent->GetSize(SIZE_DRADIUS));
+ six = (fix - dp1.fx)/dp1.fz; csx = (dp1.fy - fiy)/dp1.fz;
+ lbx += (o->un2fix(defs.GetSize(SIZE_AXIS_TICKS)*3.0*six));
+ lby -= (o->un2fiy(defs.GetSize(SIZE_AXIS_TICKS)*3.0*csx));
+ }
+ switch(type & 0x0f) {
+ case 1: lsi = sin(angle/57.29577951); lcsi = cos(angle/57.29577951); break;
+ default: lsi = -csx; lcsi = six; break;
+ }
+ if(flags & AXIS_MINORTICK) {
+ ip2.x = o->un2ix(0.5 * size * lcsi); ip2.y = o->un2iy(0.5 * size * lsi);
+ }
+ else {
+ ip2.x = o->un2ix(size * lcsi); ip2.y = o->un2iy(size * lsi);
+ }
+ if(flags & AXIS_3D){
+ dp1.fx = dp1.fy = dp1.fz = 0.0;
+ switch(type & 0x0f){
+ case 2: dp1.fx = size; dp1.fy = dp1.fz = 0.0; break;
+ case 3: dp1.fy = -size; dp1.fx = dp1.fz = 0.0; break;
+ case 4: dp1.fz = size; dp1.fx = dp1.fy = 0.0; break;
+ }
+ if(dp1.fx != dp1.fy || dp1.fx != dp1.fz) {
+ if(flags & AXIS_MINORTICK) {
+ dp1.fx *= 0.5; dp1.fy *= 0.5; dp1.fz *= 0.5;
+ }
+ o->uvec2ivec(&dp1, &dp2);
+ ip2.x = iround(dp2.fx); ip2.y = iround(dp2.fy);
+ ip2.z = iround(dp2.fz);
+ }
+ }
+ switch (flags &0x03) {
+ case AXIS_NOTICKS:
+ return; //no ticks
+ case AXIS_POSTICKS: //ticks are positive
+ break;
+ case AXIS_NEGTICKS: //ticks are negative
+ ip2.x *= -1; ip2.y *= -1; break;
+ case AXIS_SYMTICKS: //symmetrical ticks around axis: process later
+ break;
+ }
+ pts[1].x = iround(fix); pts[1].y = iround(fiy);
+ p31.z = p32.z = iround(fiz);
+ if((flags &0x03) == AXIS_SYMTICKS) { //tick is symetrical !
+ pts[1].x -= (ip2.x >>1); pts[1].y -= (ip2.y >>1);
+ p31.z -= (ip2.z >>1); p32.z = p31.z;
+ }
+ p31.x = p32.x = pts[0].x = pts[1].x; p31.y = p32.y = pts[0].y = pts[1].y;
+ pts[1].x += ip2.x; pts[1].y += ip2.y; p32.z += ip2.z;
+ p32.x += ip2.x; p32.y += ip2.y;
+ SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+ IncrementMinMaxRect(&rDims, 6);
+ if(parent && parent->Id == GO_AXIS && (flags & AXIS_3D)){
+ if(ls = new line_segment(this, data, &((Axis*)parent)->axline, &p31, &p32)){
+ ls->DoPlot(o);
+ }
+ }
+ else o->oSolidLine(pts);
+ if(flags & AXIS_MINORTICK) return;
+ if(flags & AXIS_GRIDLINE) {
+ if(!Grid){
+ if(flags & AXIS_3D) {
+ Grid = new GridLine3D(this, data, gl_type, flags);
+ }
+ else if((flags & AXIS_ANGULAR) == AXIS_ANGULAR){
+ Grid = new GridRadial(this, data, gl_type, flags);
+ }
+ else {
+ Grid = new GridLine(this, data, gl_type, flags);
+ }
+ }
+ if(Grid) Grid->DoPlot(o);
+ // we lost the line definition from the parent axis
+ if(parent) parent->Command(CMD_RESET_LINE, 0L, o);
+ }
+ if(label){
+ if(flags & AXIS_3D) label->SetSize(SIZE_ZPOS, fiz);
+ label->DoPlot(o);
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Axes are graphic objects containing ticks
+Axis::Axis(GraphObj *par, DataObj *d, AxisDEF *ax, DWORD flags):
+ GraphObj(par, d)
+{
+ if(!(axis = (AxisDEF*)malloc(sizeof(AxisDEF))))return;
+ FileIO(INIT_VARS);
+ if(flags & AXIS_3D) GridLine.pattern = 0L;
+ if(ax->owner){
+ if(axis) free(axis);
+ axis = ax;
+ }
+ else {
+ if(axis) {
+ memcpy((void*)axis, (void*)ax, sizeof(AxisDEF));
+ axis->owner = (void*)this;
+ }
+ }
+ axis->flags = flags;
+ if ((flags & AXIS_ANGULAR) || (flags & AXIS_RADIAL)) {
+ GridLine.color = colAxis;
+ GridLine.pattern = 0x0;
+ }
+ Id = GO_AXIS;
+}
+
+Axis::Axis(int src):GraphObj(0L, 0L)
+{
+ if(!(axis = (AxisDEF*)malloc(sizeof(AxisDEF))))return;
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+Axis::~Axis()
+{
+ Undo.InvalidGO(this);
+ if(axis && axis->owner == (void*)this){
+ if(axis->breaks) free(axis->breaks);
+ free(axis);
+ }
+ Command(CMD_FLUSH, 0L, 0L);
+ if(ssMATval) free(ssMATval); if(ssMATlbl) free(ssMATlbl);
+ if(ssMITval) free(ssMITval); ssMATval = ssMATlbl = ssMITval = 0L;
+ if(axisLabel) DeleteGO(axisLabel); axisLabel = 0L;
+ if(mo) DelBitmapClass(mo); mo = 0L;
+}
+
+double
+Axis::GetSize(int select)
+{
+ switch(select) {
+ case SIZE_LB_XDIST: return lbdist.fx;
+ case SIZE_LB_YDIST: return lbdist.fy;
+ case SIZE_TLB_XDIST: return tlbdist.fx;
+ case SIZE_TLB_YDIST: return tlbdist.fy;
+ case SIZE_LB_XPOS: return(flim[0].fx + flim[1].fx)/2.0f;
+ case SIZE_LB_YPOS: return(flim[0].fy + flim[1].fy)/2.0f;
+ case SIZE_TICK_LABELS: return sizAxTickLabel;
+ case SIZE_AXIS_TICKS: return sizAxTick;
+ case SIZE_AXIS_LINE: return sizAxLine;
+ case SIZE_XPOS: return axis->loc[0].fx;
+ case SIZE_XPOS+1: return axis->loc[1].fx;
+ case SIZE_YPOS: return axis->loc[0].fy;
+ case SIZE_YPOS+1: return axis->loc[1].fy;
+ case SIZE_ZPOS: return axis->loc[0].fz;
+ case SIZE_ZPOS+1: return axis->loc[1].fz;
+ case SIZE_XCENT: return axis->Center.fx;
+ case SIZE_YCENT: return axis->Center.fy;
+ case SIZE_RADIUS1: case SIZE_RADIUS2: case SIZE_DRADIUS:
+ return axis->Radius;
+ }
+ //DEBUG: we should return a reasonable value for SIZE_BOUNDS_...
+ // if the axis is not scaling (i.e. parent == this).
+ if(parent) return parent->GetSize(select);
+ else return defs.GetSize(select);
+}
+
+DWORD
+Axis::GetColor(int select)
+{
+ switch(select){
+ case COL_AXIS:
+ return colAxis;
+ }
+ if(parent) return parent->GetColor(select);
+ else return defs.Color(select);
+}
+
+bool
+Axis::SetSize(int select, double value)
+{
+ int i;
+
+ switch(select & 0xfff) {
+ case SIZE_AXIS_LINE:
+ sizAxLine = value;
+ break;
+ case SIZE_LB_XDIST:
+ lbdist.fx = value;
+ if(axisLabel)axisLabel->SetSize(select,value);
+ break;
+ case SIZE_LB_YDIST:
+ lbdist.fy = value;
+ if(axisLabel)axisLabel->SetSize(select,value);
+ break;
+ case SIZE_TLB_XDIST:
+ case SIZE_TLB_YDIST:
+ case SIZE_AXIS_TICKS:
+ case SIZE_TICK_ANGLE:
+ switch (select){
+ case SIZE_TLB_XDIST:
+ tlbdist.fx = value; select = SIZE_LB_XDIST;
+ break;
+ case SIZE_TLB_YDIST:
+ tlbdist.fy = value; select = SIZE_LB_YDIST;
+ break;
+ case SIZE_AXIS_TICKS:
+ sizAxTick = value;
+ break;
+ case SIZE_TICK_ANGLE:
+ tick_angle = value;
+ break;
+ }
+ if(Ticks && NumTicks) for(i = 0; i < NumTicks; i++)
+ if(Ticks[i]) Ticks[i]->SetSize(select, value);
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool
+Axis::SetColor(int select, DWORD col)
+{
+ int i;
+
+ switch(select & 0xfff) {
+ case COL_AXIS:
+ if(colAxis == col) return true;
+ if(select & UNDO_STORESET){
+ Undo.ValDword(this, &colAxis, UNDO_CONTINUE);
+ Undo.ValDword(this, &tlbdef.ColTxt, UNDO_CONTINUE);
+ }
+ colAxis = col;
+ if (axis && (axis->flags & AXIS_ANGULAR) || (axis->flags & AXIS_RADIAL)) {
+ GridLine.color = colAxis;
+ }
+ if(Ticks && NumTicks) for(i = 0; i < NumTicks; i++)
+ if(Ticks[i]) Ticks[i]->SetColor(select, colAxis);
+ if(axisLabel) axisLabel->SetColor((select & UNDO_STORESET) ?
+ COL_TEXT | UNDO_STORESET : COL_TEXT, col);
+ tlbdef.ColTxt = col;
+ return true;
+ case COL_BG:
+ if(Ticks && NumTicks) for(i = 0; i < NumTicks; i++)
+ if(Ticks[i]) Ticks[i]->SetColor(select, col);
+ if(axisLabel) axisLabel->SetColor(select, col);
+ return true;
+ }
+ return false;
+}
+
+void
+Axis::DoPlot(anyOutput *o)
+{
+ lfPOINT fp1, fp2;
+ fPOINT3D loc, cu1, cu2, rc;
+ double tmp, dx, dy;
+ int i, j, ix, iy;
+ fRECT scaleRC;
+ AxisDEF tmp_axis;
+
+ if(!o || !parent) return;
+ if(mo)DelBitmapClass(mo); mo = 0L;
+ if(l_segs){
+ for (i = 0; i < nl_segs; i++) if(l_segs[i]) delete(l_segs[i]);
+ free(l_segs); l_segs = 0L; nl_segs = 0;
+ }
+ dx = parent->GetSize(SIZE_GRECT_LEFT); dy = parent->GetSize(SIZE_GRECT_TOP);
+ if(!type) {
+ if(fabs(axis->loc[1].fx - axis->loc[0].fx) >
+ fabs(axis->loc[1].fy - axis->loc[0].fy)) {
+ if((axis->flags) & AXIS_3D){
+ if(fabs(axis->loc[1].fz - axis->loc[0].fz) >
+ fabs(axis->loc[1].fx - axis->loc[0].fx)) type = 3;
+ else type = 1;
+ }
+ else type = 1;
+ }
+ else {
+ if((axis->flags) & AXIS_3D){
+ if(fabs(axis->loc[1].fz - axis->loc[0].fz) >
+ fabs(axis->loc[1].fy - axis->loc[0].fy)) type = 3;
+ else type = 2;
+ }
+ else type = 2;
+ }
+ }
+ //find default type for grid lines
+ if(!gl_type){
+ if(axis->flags & AXIS_3D) {
+ switch(type) {
+ case 1: gl_type = 0x30; break;
+ case 2: gl_type = 0x0c; break;
+ case 3: gl_type = 0x03; break;
+ default: gl_type = 0x26; break;
+ }
+ }
+ else {
+ gl_type = type == 2 ? DL_LEFT | DL_RIGHT : DL_TOP | DL_BOTTOM;
+ }
+ }
+ if(!Ticks && (axis->flags & 0x03) != AXIS_NOTICKS)CreateTicks();
+ if(axis->owner == this && !scaleOut) scaleOut = new anyOutput();
+ if(scaleOut) {
+ // set scaling information in scaleOut
+ scaleOut->hres = o->hres; scaleOut->vres = o->vres;
+ scaleOut->VPscale = o->VPscale;
+ scaleOut->VPorg.fx = o->VPorg.fx; scaleOut->VPorg.fy = o->VPorg.fy;
+ memcpy(&tmp_axis, axis, sizeof(AxisDEF));
+ tmp_axis.loc[0].fx += dx; tmp_axis.loc[1].fx += dx;
+ tmp_axis.loc[0].fy += dy; tmp_axis.loc[1].fy += dy;
+ if(parent->Id == GO_PLOT3D && (axis->flags & AXIS_3D)) {
+ //set 3D information in scaleOut
+ cu1.fx = axis->loc[0].fx +dx; cu1.fy = axis->loc[0].fy +dy;
+ cu1.fz = axis->loc[0].fz; cu2.fx = axis->loc[1].fx +dx;
+ cu2.fy = axis->loc[1].fy +dy; cu2.fz = axis->loc[1].fz;
+ rc.fx = parent->GetSize(SIZE_XCENTER) +dx;
+ rc.fy = parent->GetSize(SIZE_YCENTER) +dy;
+ rc.fz = parent->GetSize(SIZE_ZCENTER);
+ scaleOut->SetSpace(&cu1, &cu2, defs.cUnits, ((Plot3D*)parent)->RotDef, &rc,
+ &tmp_axis, &tmp_axis, &tmp_axis);
+ }
+ else {
+ // set axis and rectangle in scaleOut
+ scaleRC.Xmin = scaleRC.Xmax = dx;
+ scaleRC.Ymin = scaleRC.Ymax = dy;
+ scaleRC.Xmin += axis->loc[0].fx; scaleRC.Ymin += axis->loc[1].fy;
+ scaleRC.Xmax += axis->loc[1].fx; scaleRC.Ymax += axis->loc[0].fy;
+ scaleOut->SetRect(scaleRC, o->units, &tmp_axis, &tmp_axis);
+ }
+ }
+ axline.width = sizAxLine;
+ axline.patlength = 1.0;
+ axline.color = colAxis;
+ axline.pattern = 0L; //solid line, no pattern
+ o->SetLine(&axline);
+ if(axis->flags & AXIS_ANGULAR) {
+ pts[1].x = i = o->un2ix(axis->Radius); pts[1].y = j = o->un2iy(axis->Radius);
+ pts[0].x = ix = o->co2ix(axis->Center.fx + dx);
+ pts[0].y = iy = o->co2iy(axis->Center.fy + dy);
+ o->oCircle(ix-i, iy-j, ix+i, iy+j);
+ if(Ticks && NumTicks) for(i = 0; i < NumTicks; i++)
+ if(Ticks[i]) Ticks[i]->DoPlot(0.0, 1.0, o);
+ rDims.left = ix-i; rDims.right = ix +i;
+ rDims.top = iy -i; rDims.bottom = iy+i;
+ IncrementMinMaxRect(&rDims, o->un2ix(axline.width*4.0));
+ return;
+ }
+ if(axis->flags & AXIS_3D){
+ loc.fx= axis->loc[0].fx; loc.fy= axis->loc[0].fy; loc.fz = axis->loc[0].fz;
+ o->cvec2ivec(&loc, &flim[0]);
+ loc.fx= axis->loc[1].fx; loc.fy= axis->loc[1].fy; loc.fz = axis->loc[1].fz;
+ o->cvec2ivec(&loc, &flim[1]);
+ }
+ else {
+ flim[0].fz = flim[1].fz = 0.0;
+ if(parent) switch(axis->flags & 0x70) {
+ case AXIS_USER: //leave unchanged
+ fp1.fx = axis->loc[0].fx; fp1.fy = axis->loc[0].fy;
+ fp2.fx = axis->loc[1].fx; fp2.fy = axis->loc[1].fy;
+ break;
+ case AXIS_LEFT:
+ if(axis->flags & AXIS_X_DATA) {
+ axis->loc[0].fx = axis->loc[1].fx = fp1.fx = fp2.fx =
+ parent->GetSize(SIZE_BOUNDS_LEFT);
+ }
+ else {
+ axis->loc[0].fx = axis->loc[1].fx = fp1.fx = fp2.fx =
+ parent->GetSize(SIZE_DRECT_LEFT);
+ }
+ if(axis->flags & AXIS_Y_DATA) {
+ fp1.fy = parent->GetSize(SIZE_BOUNDS_BOTTOM);
+ fp2.fy = parent->GetSize(SIZE_BOUNDS_TOP);
+ }
+ else {
+ fp1.fy = parent->GetSize(SIZE_DRECT_TOP);
+ fp2.fy = parent->GetSize(SIZE_DRECT_BOTTOM);
+ }
+ break;
+ case AXIS_RIGHT:
+ if(axis->flags & AXIS_X_DATA) {
+ axis->loc[0].fx = axis->loc[1].fx = fp1.fx = fp2.fx =
+ parent->GetSize(SIZE_BOUNDS_RIGHT);
+ }
+ else {
+ axis->loc[0].fx = axis->loc[1].fx = fp1.fx = fp2.fx =
+ parent->GetSize(SIZE_DRECT_RIGHT);
+ }
+ if(axis->flags & AXIS_Y_DATA) {
+ fp1.fy = parent->GetSize(SIZE_BOUNDS_BOTTOM);
+ fp2.fy = parent->GetSize(SIZE_BOUNDS_TOP);
+ }
+ else {
+ fp1.fy = parent->GetSize(SIZE_DRECT_TOP);
+ fp2.fy = parent->GetSize(SIZE_DRECT_BOTTOM);
+ }
+ break;
+ case AXIS_TOP:
+ if(axis->flags & AXIS_Y_DATA) {
+ axis->loc[0].fy = axis->loc[1].fy = fp1.fy = fp2.fy =
+ parent->GetSize(SIZE_BOUNDS_TOP);
+ }
+ else {
+ axis->loc[0].fy = axis->loc[1].fy = fp1.fy = fp2.fy =
+ parent->GetSize(SIZE_DRECT_TOP);
+ }
+ if(axis->flags & AXIS_X_DATA) {
+ fp1.fx = parent->GetSize(SIZE_BOUNDS_LEFT);
+ fp2.fx = parent->GetSize(SIZE_BOUNDS_RIGHT);
+ }
+ else {
+ fp1.fx = parent->GetSize(SIZE_DRECT_LEFT);
+ fp2.fx = parent->GetSize(SIZE_DRECT_RIGHT);
+ }
+ break;
+ case AXIS_BOTTOM:
+ if(axis->flags & AXIS_Y_DATA) {
+ axis->loc[0].fy = axis->loc[1].fy = fp1.fy = fp2.fy =
+ parent->GetSize(SIZE_BOUNDS_BOTTOM);
+ }
+ else {
+ axis->loc[0].fy = axis->loc[1].fy = fp1.fy = fp2.fy =
+ parent->GetSize(SIZE_DRECT_BOTTOM);
+ }
+ if(axis->flags & AXIS_X_DATA) {
+ fp1.fx = parent->GetSize(SIZE_BOUNDS_LEFT);
+ fp2.fx = parent->GetSize(SIZE_BOUNDS_RIGHT);
+ }
+ else {
+ fp1.fx = parent->GetSize(SIZE_DRECT_LEFT);
+ fp2.fx = parent->GetSize(SIZE_DRECT_RIGHT);
+ }
+ break;
+ }
+ if(axis->flags & AXIS_X_DATA) {
+ flim[0].fx = o->fx2fix(fp1.fx); flim[1].fx = o->fx2fix(fp2.fx);
+ }
+ else {
+ flim[0].fx = o->co2fix(fp1.fx + dx); flim[1].fx = o->co2fix(fp2.fx + dx);
+ axis->loc[0].fx = fp1.fx; axis->loc[1].fx = fp2.fx;
+ }
+ if(axis->flags & AXIS_Y_DATA) {
+ flim[0].fy = o->fy2fiy(fp1.fy); flim[1].fy = o->fy2fiy(fp2.fy);
+ }
+ else {
+ flim[0].fy = o->co2fiy(fp1.fy + dy); flim[1].fy = o->co2fiy(fp2.fy + dy);
+ axis->loc[0].fy = fp1.fy; axis->loc[1].fy = fp2.fy;
+ }
+ }
+ pts[0].x = iround(flim[0].fx); pts[1].x = iround(flim[1].fx);
+ pts[0].y = iround(flim[0].fy); pts[1].y = iround(flim[1].fy);
+ pts3D[0].x = pts[0].x; pts3D[1].x = pts[1].x;
+ pts3D[0].y = pts[0].y; pts3D[1].y = pts[1].y;
+ pts3D[0].z = iround(flim[0].fz); pts3D[1].z = iround(flim[1].fz);
+ SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+ IncrementMinMaxRect(&rDims, 3);
+ //calculate sine and cosine for ticks in any direction of axis
+ si = flim[1].fy - flim[0].fy;
+ tmp = (flim[1].fx - flim[0].fx);
+ si = fabs(si) > 0.0001 ? si/sqrt(si*si + tmp*tmp) : 0.0;
+ csi = flim[1].fx - flim[0].fx;
+ tmp = (flim[1].fy - flim[0].fy);
+ csi = fabs(csi) > 0.0001 ? csi/sqrt(csi*csi + tmp*tmp) : 0.0;
+ //draw axis line
+ if(axis->breaks && axis->nBreaks)DrawBreaks(o);
+ else if((axis->flags) & AXIS_3D){
+ if(!(l_segs = (line_segment**)calloc(1, sizeof(line_segment*))))return;
+ l_segs[0] = new line_segment(this, data, &axline, &pts3D[0], &pts3D[1]);
+ nl_segs = 1;
+ if(l_segs[0])l_segs[0]->DoPlot(o);
+ }
+ else o->oSolidLine(pts);
+ //now execute the draw routine of label and every tick
+ if(axisLabel){
+ if(axis->flags & AXIS_3D) axisLabel->SetSize(SIZE_ZPOS, (pts3D[0].z + pts3D[1].z)>>1);
+ axisLabel->DoPlot(o);
+ }
+ if(Ticks && NumTicks) for(i = 0; i < NumTicks; i++)
+ if(Ticks[i]) Ticks[i]->DoPlot(si, csi, o);
+}
+
+void
+Axis::DoMark(anyOutput *o, bool mark)
+{
+ LineDEF mrkLine;
+ int x1, y1, x2, y2;
+ double minw = defs.GetSize(SIZE_DATA_LINE);
+
+ if(axis->flags & AXIS_ANGULAR) {
+ if(mark) {
+ memcpy(&mrc, &rDims, sizeof(RECT));
+ IncrementMinMaxRect(&mrc, 6 + o->un2ix(axline.width));
+ mo = GetRectBitmap(&mrc, o);
+ memcpy(&mrkLine, &axline, sizeof(LineDEF));
+ mrkLine.width = axline.width < minw ? minw * 3.0 : axline.width *3.0;;
+ x1 = o->co2ix(axis->Center.fx) - o->un2ix(axis->Radius);
+ y1 = o->co2iy(axis->Center.fy) - o->un2iy(axis->Radius);
+ x2 = o->co2ix(axis->Center.fx) + o->un2ix(axis->Radius);
+ y2 = o->co2iy(axis->Center.fy) + o->un2iy(axis->Radius);
+ o->SetLine(&mrkLine);
+ o->oArc(x1, y1, x2, y2, 4);
+ mrkLine.color ^= 0x00ffffffL;
+ mrkLine.width = axline.width;
+ o->SetLine(&mrkLine);
+ o->oArc(x1, y1, x2, y2, 4);
+ o->UpdateRect(&mrc, false);
+ }
+ else RestoreRectBitmap(&mo, &mrc, o);
+ return;
+ }
+ if(mark){
+ memcpy(&mrc, &rDims, sizeof(RECT));
+ IncrementMinMaxRect(&mrc, 6 + o->un2ix(axline.width));
+ mo = GetRectBitmap(&mrc, o);
+ InvertLine(pts, 2, &axline, &rDims, o, mark);
+ }
+ else RestoreRectBitmap(&mo, &mrc, o);
+}
+
+bool
+Axis::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ GraphObj **tmpPlots;
+ void *sv_ptr;
+ int i;
+
+ switch (cmd) {
+ case CMD_HIDE_MARK:
+ if(!tmpl || !o) return false;
+ if(tmpl == (void*)axisLabel){
+ axisLabel->DoMark(o, false);
+ return true;
+ }
+ if(Ticks && NumTicks) for(i = 0; i < NumTicks; i++) {
+ if(Ticks[i]) {
+ if(tmpl == (void*)Ticks[i]) {
+ Ticks[i]->DoMark(o, false);
+ return true;
+ }
+ else if(Ticks[i]->Command(cmd, tmpl, o)) return true;
+ }
+ }
+ if(axisLabel && axisLabel->Id == GO_MLABEL)
+ if(axisLabel->Command(cmd, tmpl, o)) return true;
+ return false;
+ case CMD_SET_DATAOBJ:
+ Id = GO_AXIS;
+ data = (DataObj*)tmpl;
+ if(Ticks) for(i = 0; i< NumTicks; i++) if(Ticks[i]) Ticks[i]->Command(cmd, tmpl, o);
+ if(axisLabel) axisLabel->Command(cmd, tmpl, o);
+ case CMD_TICK_TYPE:
+ if(cmd == CMD_TICK_TYPE){
+ if(tmpl) tick_type = *((int*)tmpl);
+ else return false;
+ }
+ case CMD_SET_TICKSTYLE:
+ if(cmd == CMD_SET_TICKSTYLE){
+ axis->flags &= ~0x07; axis->flags |= (*((DWORD*)tmpl) & 0x07);
+ }
+ case CMD_SET_GRIDTYPE:
+ if(cmd == CMD_SET_GRIDTYPE && tmpl && *((int*)tmpl)) {
+ gl_type = *((int*)tmpl);
+ }
+ case CMD_TLB_TXTDEF: //do all ticks
+ if(Ticks) for(i = 0; i< NumTicks; i++) if(Ticks[i]) Ticks[i]->Command(cmd, tmpl, o);
+ if(cmd == CMD_TLB_TXTDEF && tmpl) {
+ memcpy(&tlbdef, tmpl, sizeof(TextDEF));
+ tlbdef.text = 0L;
+ }
+ return true;
+ case CMD_SET_GRIDLINE:
+ if(tmpl) memcpy(&GridLine, tmpl, sizeof(LineDEF));
+ if(Ticks) for(i = 0; i< NumTicks; i++) if(Ticks[i]) Ticks[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_GET_GRIDLINE:
+ if(tmpl) memcpy(tmpl, &GridLine, sizeof(LineDEF));
+ return true;
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(axis->flags & AXIS_ANGULAR) {
+ i = (mev->x - pts[0].x) * (mev->x - pts[0].x) +
+ (mev->y - pts[0].y) * (mev->y - pts[0].y);
+ i = isqr(i) - pts[1].x;
+ if(i < 4 && i > -4){
+ o->ShowMark(this, MRK_GODRAW);
+ return true;
+ }
+ }
+ else if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO &&
+ IsCloseToLine(&pts[0], &pts[1], mev->x, mev->y)) {
+ if(pts[0].x == pts[1].x || pts[0].y == pts[1].y){
+ o->ShowMark(&rDims, MRK_INVERT);
+ CurrGO = this;
+ }
+ else o->ShowMark(this, MRK_GODRAW);
+ return true;
+ }
+ break;
+ }
+ if(axisLabel && axisLabel->Command(cmd, tmpl, o)) return true;
+ if(Ticks) for(i = 0; i < NumTicks; i++)
+ if(Ticks[i] && Ticks[i]->Command(cmd, tmpl, o)) return true;
+ return false;
+ case CMD_SET_AXDEF:
+ if(tmpl) {
+ if(axis && axis->owner == (void*)this) {
+ if(axis->breaks) free(axis->breaks);
+ free(axis);
+ }
+ }
+ axis = (AxisDEF*)tmpl;
+ if(axis) return true;
+ return false;
+ case CMD_CAN_DELETE:
+ if(axis->owner == (void*)this) return true;
+ return false;
+ case CMD_DROP_LABEL:
+ if(axisLabel)DeleteGO(axisLabel);
+ if(axisLabel = (Label*)tmpl) {
+ axisLabel->parent = this;
+ }
+ return true;
+ case CMD_DELOBJ:
+ o->HideMark();
+ if(!tmpl || !parent) return false;
+ if(Ticks && NumTicks) for(i = 0; i < NumTicks; i++){
+ if(Ticks[i] == tmpl) {
+ Undo.DeleteGO((GraphObj**)(&Ticks[i]), 0L, o);
+ return parent->Command(CMD_REDRAW, 0L, o);
+ }
+ else if(Ticks[i] && Ticks[i]->Command(cmd, tmpl, o))
+ return parent->Command(CMD_REDRAW, 0L, o);
+ }
+ if(tmpl == (void*)axisLabel) {
+ Undo.DeleteGO((GraphObj**)(&axisLabel), 0L, o);
+ return parent->Command(CMD_REDRAW, 0L, o);
+ }
+ break;
+ case CMD_MUTATE:
+ if(!parent || !(tmpPlots = (GraphObj **)tmpl) || !tmpPlots[0] || !tmpPlots[1]) return false;
+ if(axisLabel == tmpPlots[0]) {
+ Undo.MutateGO(&axisLabel, tmpPlots[1], 0L, o);
+ return true;
+ }
+ break;
+ case CMD_REPL_GO:
+ if(!(tmpPlots = (GraphObj **)tmpl) || !tmpPlots[0] || !tmpPlots[1]) return false;
+ if(Ticks) for(i = 0; i < NumTicks; i++) if(Ticks[i] && Ticks[i] == tmpPlots[0]){
+ return bModified = ReplaceGO((GraphObj**)&Ticks[i], tmpPlots);
+ }
+ if(axisLabel && axisLabel == tmpPlots[0])
+ return bModified = ReplaceGO((GraphObj**)&axisLabel, tmpPlots);
+ return false;
+ case CMD_UPDATE:
+ UpdateTicks();
+ case CMD_SETSCROLL:
+ cmd = CMD_REDRAW;
+ case CMD_REDRAW:
+ bModified = true;
+ case CMD_SET_GO3D:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ return false;
+ case CMD_RESET_LINE:
+ return o->SetLine(&axline);
+ case CMD_FLUSH:
+ if(Ticks) {
+ for(i = 0; i < NumTicks; i++) if(Ticks[i]) DeleteGO(Ticks[i]);
+ free(Ticks); NumTicks = 0; Ticks = 0L;
+ }
+ if(l_segs){
+ for (i = 0; i < nl_segs; i++) if(l_segs[i]) delete(l_segs[i]);
+ free(l_segs); l_segs = 0L; nl_segs = 0;
+ }
+ if(scaleOut) delete(scaleOut);
+ scaleOut = drawOut = 0L;
+ axis->Start = axis->min;
+ return true;
+ case CMD_AUTOSCALE: //we receive this command to update ticks after rescaling
+ if(axis && (AxisDEF*)tmpl == axis && (axis->flags & AXIS_AUTOSCALE) &&
+ (axis->flags & AXIS_AUTOTICK)) return Command(CMD_FLUSH, tmpl, o);
+ break;
+ case CMD_SAVE_TICKS:
+ SavVarInit(200 * NumTicks);
+ if(Ticks) for(i = 0; i < NumTicks; i++) {
+ if(Ticks[i]) Ticks[i]->FileIO(SAVE_VARS);
+ }
+ sv_ptr = SavVarFetch();
+ Undo.SavVarBlock(this, &sv_ptr, 0);
+ if(axis->flags & AXIS_AUTOTICK){
+ Undo.ValDword(this, &axis->flags, UNDO_CONTINUE);
+ axis->flags &= ~(AXIS_AUTOTICK | AXIS_AUTOSCALE);
+ }
+ bModified = true;
+ return true;
+ }
+ return false;
+}
+
+void
+Axis::SetTick(long idx, double val, DWORD flags, char *txt)
+{
+ char *l;
+
+ if((flags & AXIS_ANGULAR) && !(flags & 0x03)) flags |= AXIS_POSTICKS;
+ Ticks[idx] = new Tick(this, data, val, flags);
+ if(!txt) {
+ WriteNatFloatToBuff(TmpTxt, val);
+ l = strdup(TmpTxt+1);
+ }
+ else l = strdup(txt);
+ if(!gl_type) {
+ }
+ if(Ticks[idx]) {
+ Ticks[idx]->Command(CMD_SET_GRIDTYPE, (void*) &gl_type, 0L);
+ if(l) Ticks[idx]->Command(CMD_SETTEXT, l, 0L);
+ Ticks[idx]->Command(CMD_TLB_TXTDEF, &tlbdef, 0L);
+ if(flags & AXIS_GRIDLINE) Ticks[idx]->Command(CMD_SET_GRIDLINE, &GridLine, 0L);
+ Ticks[idx]->SetSize(SIZE_TICK_ANGLE, tick_angle);
+ Ticks[idx]->SetSize(SIZE_AXIS_TICKS, sizAxTick);
+ Ticks[idx]->Command(CMD_TICK_TYPE, &tick_type, 0L);
+ }
+ if(l) free(l);
+}
+
+void
+Axis::CreateTicks()
+{
+ int i, n, nstep;
+ char *format;
+ double fVal, tmp;
+ DWORD flags;
+
+ Command(CMD_FLUSH, 0L, 0L);
+ if((axis->flags & 0xf000) == AXIS_LOG) { //log-axis
+ if(axis->Start > defs.min4log) tmp = log10(axis->Start);
+ else switch (type){
+ case 1: //x axis
+ case 2: //y axis
+ case 3: //z axis
+ axis->Start = tmp = log10(base4log(axis, type-1));
+ if(axis->Start <= 0.0) axis->Start = 1.0;
+ break;
+ default: return;
+ }
+ n = (int)(log10(axis->max) - tmp);
+ Ticks = (Tick**)calloc(100, sizeof(Tick*));
+ for(NumTicks=0, i=(int)floor(tmp); NumTicks <90; i++){
+ SetTick(NumTicks++, pow(10.0, i), axis->flags, 0L);
+ if(n < 5) {
+ flags = n ? axis->flags | AXIS_MINORTICK : axis->flags;
+ SetTick(NumTicks++, 5.0*pow(10.0, i), axis->flags, 0L);
+ SetTick(NumTicks++, 3.0*pow(10.0, i), flags, 0L);
+ SetTick(NumTicks++, 4.0*pow(10.0, i), flags, 0L);
+ SetTick(NumTicks++, 6.0*pow(10.0, i), flags, 0L);
+ SetTick(NumTicks++, 7.0*pow(10.0, i), flags, 0L);
+ SetTick(NumTicks++, 8.0*pow(10.0, i), flags, 0L);
+ SetTick(NumTicks++, 9.0*pow(10.0, i), flags, 0L);
+ if(n < 3) SetTick(NumTicks++, 2.0*pow(10.0, i), axis->flags, 0L);
+ else SetTick(NumTicks++, 2.0*pow(10.0, i), axis->flags | AXIS_MINORTICK, 0L);
+ }
+ else {
+ SetTick(NumTicks++, 5.0*pow(10.0, i), axis->flags | AXIS_MINORTICK, 0L);
+ }
+ }
+ }
+ else { //linear axis
+ if((axis->flags & 0xf000) == AXIS_RECI) {
+ NiceStep(axis, 8);
+ format = GetNumFormat(floor(log10(axis->Step)));
+ fVal = axis->Start;
+ }
+ else {
+ NiceStep(axis, 4);
+ format = GetNumFormat(floor(log10(fabs(axis->max - axis->min))));
+ fVal = axis->Start;
+ }
+ nstep = 1+(int)((axis->max-axis->min)/axis->Step);
+ Ticks = (Tick**)calloc(nstep+2, sizeof(Tick*));
+ if(!Ticks) return;
+ for(NumTicks = 0; NumTicks < nstep && fVal <= axis->max;
+ NumTicks++, fVal += axis->Step) {
+ sprintf(TmpTxt, format, fVal);
+ SetTick(NumTicks, fVal, axis->flags, TmpTxt);
+ }
+ }
+}
+
+void
+Axis::ManuTicks(double sa, double st, int n, DWORD flags)
+{
+ int j, m;
+ char *format;
+ double fVal, mival, mist;
+
+ Command(CMD_FLUSH, 0L, 0L);
+ mist = st/(double)(n+1);
+ m = (int)(((axis->max-axis->min) / st)*(double)(n+1))+n+2;
+ format = GetNumFormat(floor(log10(st)));
+ Ticks = (Tick**)calloc(m, sizeof(Tick*));
+ for(NumTicks = 0, fVal = sa; NumTicks < m && fVal <= axis->max; NumTicks++) {
+ sprintf(TmpTxt, format, fVal);
+ SetTick(NumTicks, fVal, flags, TmpTxt);
+ for(j = 0; j < n; j++) {
+ mival = fVal+mist*(double)j +mist;
+ if(mival < axis->max) {
+ sprintf(TmpTxt, format, mival);
+ NumTicks++;
+ SetTick(NumTicks, mival, flags | AXIS_MINORTICK, TmpTxt);
+ }
+ }
+ fVal += st;
+ }
+}
+
+bool
+Axis::GetValuePos(double val, double *fix, double *fiy, double *fiz, anyOutput *op)
+{
+ double tmp1;
+ int i;
+ bool bRet = true;
+ anyOutput *o;
+ fPOINT3D p1, p2;
+ lfPOINT fdp, fip;
+
+ *fix = *fiy = *fiz = 0.0;
+ if(!op || !parent || (val < axis->min && val < axis->max) ||
+ (val > axis->min && val > axis->max)) return false;
+ for(i = 0; i < axis->nBreaks && bRet; i++)
+ if((val >= axis->breaks[i].fx && val <= axis->breaks[i].fy) ||
+ (val <= axis->breaks[i].fx && val >= axis->breaks[i].fy)) bRet = false;
+ if(axis->owner == this && scaleOut) o = scaleOut;
+ else o = op;
+ if(axis->flags & AXIS_3D) {
+ p1.fx = GetSize(SIZE_XPOS); p1.fy = GetSize(SIZE_YPOS); p1.fz = GetSize(SIZE_ZPOS);
+ tmp1 = defs.cUnits == 1 ? 2.54 : defs.cUnits == 2 ? 1.0 : 25.4;
+ tmp1 /= op->VPscale;
+ switch(type) {
+ case 1: p1.fx += (tmp1 * (op->fx2fix(val)- op->Box1.Xmin)/op->hres); break;
+ case 2: p1.fy += (tmp1 * (op->fy2fiy(val)- op->Box1.Ymax)/op->vres); break;
+ case 3: p1.fz += (tmp1 * (op->fz2fiz(val)- op->Box1z.fx)/op->hres); break;
+ default: return false;
+ }
+ op->cvec2ivec(&p1, &p2);
+ *fix = p2.fx; *fiy = p2.fy; *fiz = p2.fz;
+ if((p2.fx < (flim[0].fx-1) && p2.fx < (flim[1].fx-1)) ||
+ (p2.fx > (flim[0].fx+1) && p2.fx > (flim[1].fx+1)) ||
+ (p2.fy < (flim[0].fy-1) && p2.fy < (flim[1].fy-1)) ||
+ (p2.fy > (flim[0].fy+1) && p2.fy > (flim[1].fy+1)) ||
+ (p2.fz < (flim[0].fz-1) && p2.fz < (flim[1].fz-1)) ||
+ (p2.fz > (flim[0].fz+1) && p2.fz > (flim[1].fz+1))) bRet = false;
+ return bRet;
+ }
+ else if(axis->flags & AXIS_ANGULAR) {
+ fdp.fx = val; fdp.fy = parent->GetSize(SIZE_BOUNDS_TOP);
+ op->fp2fip(&fdp, &fip); *fix = fip.fx; *fiy = fip.fy;
+ return bRet;
+ }
+ else if(type == 1 && fabs(flim[1].fx-flim[0].fx)>10.0) { //x dominant
+ tmp1 = (o->fx2fix(val)-flim[0].fx)/(flim[1].fx-flim[0].fx);
+ *fix = flim[0].fx - tmp1*(flim[0].fx - flim[1].fx);
+ *fiy = flim[0].fy - tmp1*(flim[0].fy - flim[1].fy);
+ }
+ else if(type == 2 && fabs(flim[1].fy-flim[0].fy)>10.0){ //y dominant
+ tmp1 = (o->fy2fiy(val)-flim[1].fy)/(flim[0].fy-flim[1].fy);
+ *fix = flim[1].fx + tmp1*(flim[0].fx - flim[1].fx);
+ *fiy = flim[1].fy + tmp1*(flim[0].fy - flim[1].fy);
+ }
+ if(tmp1 < -.005f || tmp1 > 1.005) return false;
+ return bRet;
+}
+
+void
+Axis::BreakSymbol(POINT3D *p1, double dsi, double dcsi, bool connect, anyOutput *o)
+{
+ POINT *sym = 0L, *csym = 0L;
+ static POINT lp;
+ int j, n = 0;
+ double tmp;
+
+ switch (brksym){
+ case 2:
+ n = o->un2ix(brksymsize);
+ if(!(sym = (POINT*)calloc(2, sizeof(POINT))))return;
+ if(!(csym = (POINT*)calloc(2, sizeof(POINT)))){
+ free(sym);
+ return;
+ }
+ sym[0].x = (int)((-(n>>1))*dsi) + (int)((n>>2)*dcsi);
+ sym[0].y = (int)((-(n>>1))*dcsi) + (int)((n>>2)*dsi);
+ sym[1].x = (int)((n>>1)*dsi) - (int)((n>>2)*dcsi);
+ sym[1].y = (int)((n>>1)*dcsi) - (int)((n>>2)*dsi);
+ n = 2;
+ break;
+ case 3:
+ n = o->un2ix(brksymsize);
+ if(!(sym = (POINT*)calloc(2, sizeof(POINT))))return;
+ if(!(csym = (POINT*)calloc(2, sizeof(POINT)))){
+ free(sym);
+ return;
+ }
+ sym[0].x = (int)((-(n>>1))*dsi);
+ sym[0].y = (int)((-(n>>1))*dcsi);
+ sym[1].x = (int)((n>>1)*dsi);
+ sym[1].y = (int)((n>>1)*dcsi);
+ n = 2;
+ break;
+ case 4:
+ n = o->un2ix(brksymsize);
+ if(!(sym = (POINT*)calloc(n, sizeof(POINT))))return;
+ if(!(csym = (POINT*)calloc(n, sizeof(POINT)))){
+ free(sym);
+ return;
+ }
+ for(j = 0; j< n; j++) {
+ tmp = (double)j*6.283185307/(double)n;
+ tmp = sin(tmp)*(double)n/6.0;
+ sym[j].x = (int)((j-(n>>1))*dsi) + (int)(tmp*dcsi);
+ sym[j].y = (int)((j-(n>>1))*dcsi) + (int)(tmp*dsi);
+ }
+ break;
+ }
+ if(sym && csym && n) {
+ if(brksym == 3 && connect) {
+ csym[0].x = lp.x; csym[0].y = lp.y;
+ csym[1].x = sym[0].x + p1->x; csym[1].y = sym[0].y + p1->y;
+ o->oPolyline(csym, 2);
+ }
+ for(j = 0; j < n; j++) {
+ csym[j].x = sym[j].x + p1->x;
+ csym[j].y = sym[j].y + p1->y;
+ }
+ o->oPolyline(csym, n);
+ lp.x = csym[n-1].x; lp.y = csym[n-1].y;
+ }
+ if(sym) free(sym); if(csym) free(csym);
+}
+
+void
+Axis::DrawBreaks(anyOutput *o)
+{
+ fPOINT3D *pts, np, tmp_p;
+ double dx, dy, dz, d, dn, da, lsi, lcsi;
+ POINT pbs[2];
+ int i, j;
+
+ dx = flim[0].fx > flim[1].fx ? flim[1].fx : flim[0].fx;
+ dy = flim[0].fy > flim[1].fy ? flim[1].fy : flim[0].fy;
+ dz = flim[0].fz > flim[1].fz ? flim[0].fz + (flim[0].fz - flim[1].fz)*50.0 :
+ flim[1].fz + (flim[1].fz - flim[0].fz)*50.0;
+ if(axis->flags & AXIS_3D){
+ if(!(l_segs = (line_segment**)calloc(2+axis->nBreaks, sizeof(line_segment*))))return;
+ nl_segs = 0;
+ }
+ if(!(pts = (fPOINT3D*)calloc(2+axis->nBreaks, sizeof(fPOINT3D))))return;
+ memcpy(pts, &flim[0], sizeof(fPOINT3D));
+ for (i = 1; i < (2+axis->nBreaks); i++) {
+ switch (i) {
+ case 1:
+ memcpy(&np, &flim[1], sizeof(fPOINT3D));
+ break;
+ default:
+ GetValuePos(axis->breaks[i-2].fx, &np.fx, &np.fy, &np.fz, o);
+ break;
+ }
+ for(j = 0; j < i; j++) {
+ dn = (d = np.fx-dx) * d; dn += ((d = np.fy-dy) * d);
+ dn += ((d = np.fz-dz) * d); da = (d = pts[j].fx-dx) * d;
+ da += ((d = pts[j].fy-dy)*d); da += ((d = pts[j].fz-dz)*d);
+ if(dn < da) {
+ memcpy(&tmp_p, &pts[j], sizeof(fPOINT3D));
+ memcpy(&pts[j], &np, sizeof(fPOINT3D));
+ memcpy(&np, &tmp_p, sizeof(fPOINT3D));
+ }
+ }
+ memcpy(&pts[i], &np, sizeof(fPOINT3D));
+ }
+ for(i = 1; i < (2+axis->nBreaks); i++) {
+ dn = (d = pts[i].fx-pts[i-1].fx) * d; dn += ((d = pts[i].fy-pts[i-1].fy) * d);
+ dn += ((d = pts[i].fz-pts[i-1].fz) * d); dn = sqrt(dn);
+ da = o->un2fix(brkgap/2.0);
+ if(dn > 0.01) {
+ np.fx = da * (pts[i].fx-pts[i-1].fx)/dn;
+ np.fy = da * (pts[i].fy-pts[i-1].fy)/dn;
+ np.fz = da * (pts[i].fz-pts[i-1].fz)/dn;
+ d = (pts[i].fx - pts[i-1].fx) * (pts[i].fx - pts[i-1].fx);
+ d += ((pts[i].fy - pts[i-1].fy) * (pts[i].fy - pts[i-1].fy));
+ d = sqrt(d); if(d < 1.0) d = 1.0;
+ lsi = (pts[i].fy - pts[i-1].fy)/d;
+ lcsi = (pts[i].fx -pts[i-1].fx)/d;
+ if(i == 1) {
+ pts3D[0].x = pbs[0].x = iround(pts[i-1].fx);
+ pts3D[0].y = pbs[0].y = iround(pts[i-1].fy);
+ pts3D[0].z = iround(pts[i-1].fz);
+ }
+ else {
+ pts3D[0].x = pbs[0].x = iround(pts[i-1].fx + np.fx);
+ pts3D[0].y = pbs[0].y = iround(pts[i-1].fy + np.fy);
+ pts3D[0].z = iround(pts[i-1].fz + np.fz);
+ BreakSymbol(&pts3D[0], lsi, -lcsi, true, o);
+ }
+ if(i == (1+axis->nBreaks)) {
+ pts3D[1].x = pbs[1].x = iround(pts[i].fx);
+ pts3D[1].y = pbs[1].y = iround(pts[i].fy);
+ pts3D[1].z = iround(pts[i].fz);
+ }
+ else {
+ pts3D[1].x = pbs[1].x = iround(pts[i].fx - np.fx);
+ pts3D[1].y = pbs[1].y = iround(pts[i].fy - np.fy);
+ pts3D[1].z = iround(pts[i].fz - np.fz);
+ BreakSymbol(&pts3D[1], lsi, -lcsi, false, o);
+ }
+ if(axis->flags & AXIS_3D) {
+ if(l_segs[nl_segs] = new line_segment(this, data, &axline, &pts3D[0], &pts3D[1])){
+ l_segs[nl_segs]->DoPlot(o); nl_segs++;
+ }
+ }
+ else o->oSolidLine(pbs);
+ }
+ }
+ free(pts);
+}
+
+void
+Axis::UpdateTicks()
+{
+ int i, j, k, l;
+ double tmpval;
+ AccRange *rT=0L, *rL=0L, *rMT=0L;
+
+ if(!ssMATval || !(rT = new AccRange(ssMATval))) return;
+ if(Ticks) {
+ Undo.DropListGO(this, (GraphObj***)&Ticks, &NumTicks, 0L);
+ }
+ if(ssMATlbl) rL = new AccRange(ssMATlbl);
+ if(ssMITval) rMT = new AccRange(ssMITval);
+ if(!(Ticks = ((Tick**)calloc(rT->CountItems()+ (( rMT != 0L) ? rMT->CountItems() : 0) +4,
+ sizeof(Tick*))))) return;
+ rT->GetFirst(&i, &j); if(!(rT->GetNext(&i, &j)))return;
+ if(rL) rL->GetFirst(&k, &l);
+ NumTicks =0;
+ do{
+ if(rL) rL->GetNext(&k, &l);
+ if(data->GetValue(j, i, &tmpval)) {
+ if(!(Ticks[NumTicks] = new Tick(this, data, tmpval, axis->flags)))return;
+ if(rL) {
+ if(Ticks[NumTicks] && data->GetText(l, k, TmpTxt, TMP_TXT_SIZE))
+ Ticks[NumTicks]->Command(CMD_SETTEXT, TmpTxt, 0L);
+ }
+ Ticks[NumTicks]->SetSize(SIZE_TICK_ANGLE, tick_angle);
+ Ticks[NumTicks]->Command(CMD_TICK_TYPE, &tick_type, 0L);
+ }
+ NumTicks++;
+ }while(rT->GetNext(&i, &j));
+ if(rMT) {
+ if(rMT->GetFirst(&i, &j) && rMT->GetNext(&i, &j)) do {
+ if(data->GetValue(j, i, &tmpval) && 0L!=(Ticks[NumTicks] = new Tick(this, data,
+ tmpval, axis->flags | AXIS_MINORTICK))) {
+ Ticks[NumTicks]->SetSize(SIZE_TICK_ANGLE, tick_angle);
+ Ticks[NumTicks]->Command(CMD_TICK_TYPE, &tick_type, 0L);
+ NumTicks++;
+ }
+ }while(rMT->GetNext(&i, &j));
+ }
+ Command(CMD_TLB_TXTDEF, &tlbdef, 0L); SetSize(SIZE_TLB_XDIST, tlbdist.fx);
+ SetSize(SIZE_TLB_YDIST, tlbdist.fy);
+ if(rT) delete(rT); if(rL) delete(rL); if(rMT) delete(rMT);
+}
diff --git a/Export.cpp b/Export.cpp
new file mode 100755
index 0000000..4470367
--- /dev/null
+++ b/Export.cpp
@@ -0,0 +1,1325 @@
+//Export.cpp, Copyright (c) 2002, 2003, 2004 R.Lackner
+//export graph files
+//
+// 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 <time.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
+
+extern Default defs;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// export to *.wmf file (windows meta file)
+// this code is based on information from the following books
+// G. Born, 'Referenzhandbuch Dateiformate',
+// Addison-Wesley ISBN 3-89319-815-6
+// T. Hogan, 'Die PC-referenz f�r Programmierer',
+// Microsoft Press: Systema Verlag GmbH ISBN 3-89390-250-3
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+typedef struct {
+ unsigned short mtType, mtHeader, mtVersion, mtSize0, mtSize1, mtNoObj;
+ unsigned mtMaxRec;
+ unsigned short mtnoPar;
+}wmf_header;
+
+class ExportWMF:public anyOutput {
+public:
+ HatchOut *hgo;
+
+ ExportWMF(GraphObj *g, char *FileName, float res, DWORD flags);
+ ~ExportWMF();
+ bool SetLine(LineDEF *lDef);
+ bool SetFill(FillDEF *fill);
+ bool SetTextSpec(TextDEF *set);
+ bool StartPage();
+ bool EndPage();
+ bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L);
+ bool oPolyline(POINT * pts, int cp, char *nam = 0L);
+ bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
+ bool oSolidLine(POINT *p);
+ bool oTextOut(int x, int y, char *txt, int cb);
+ bool oPolygon(POINT *pts, int cp, char *nam = 0L);
+
+private:
+ int oFile;
+ unsigned file_size, rec_size;
+ wmf_header header;
+ unsigned short currGDIobj, maxGDIobj;
+ unsigned short hPen, hBrush, hFont;
+ GraphObj *go;
+ char *name;
+
+ unsigned short wmfCreateSolidBrush(DWORD color);
+ unsigned short wmfCreateFontIndirect(short, short, short, short, short, unsigned char,
+ unsigned char, unsigned char, unsigned char, unsigned char, unsigned char,
+ unsigned char, unsigned char, char *);
+ unsigned short wmfCreateSolidPen(DWORD color, unsigned short width);
+ void wmfDeleteObject(unsigned short obj);
+ void wmfEllipse(unsigned short, unsigned short, unsigned short, unsigned short);
+ void wmfPolyline(POINT *pts, unsigned short cp);
+ void wmfPolygon(POINT *pts, unsigned short cp);
+ void wmfRectangle(unsigned short, unsigned short, unsigned short, unsigned short);
+ void wmfSelectObject(unsigned short o);
+ void wmfSetBkColor(DWORD col);
+ void wmfSetBkMode(unsigned m);
+ void wmfSetTextAlign(unsigned a);
+ void wmfSetTextColor(DWORD col);
+ void wmfTextOut(unsigned short, unsigned short, char *, unsigned short);
+};
+
+ExportWMF::ExportWMF(GraphObj *g, char *FileName, float res, DWORD flags)
+{
+ currGDIobj = maxGDIobj = 0;
+ hgo =0L;
+ DeskRect.left = DeskRect.top = 0;
+ DeskRect.right = DeskRect.bottom = 0x4fffffff;
+ dFillCol = 0xffffffffL;
+ hPen = 0xffff, hBrush = 0xffff, hFont = 0xffff;
+ hres = vres = res;
+ go = g;
+ if(FileName)name = strdup(FileName);
+ else name = 0L;
+ oFile = 0;
+ rec_size = 28;
+ header.mtType = 1;
+ header.mtHeader = 9;
+ header.mtVersion = 0x300;
+ header.mtSize0 = 1000;
+ header.mtSize1 = 0;
+ header.mtNoObj = 64;
+ header.mtMaxRec = 100;
+ header.mtnoPar = 0;
+}
+
+ExportWMF::~ExportWMF()
+{
+ if(hgo) delete hgo;
+ if(name) free(name);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//overloaded functions from the anyOutput class
+bool
+ExportWMF::SetLine(LineDEF *lDef)
+{
+ unsigned short iw;
+
+ if(hPen == 0xffff || lDef->width != LineWidth || lDef->width != LineWidth ||
+ lDef->pattern != dPattern || lDef->color != dLineCol) {
+ LineWidth = lDef->width;
+ iw = (unsigned short)(0.5 + un2fix(lDef->width));
+ dPattern = lDef->pattern;
+ RLP.finc = 256.0/((float)(un2fix(lDef->patlength*8.0)));
+ RLP.fp = 0.0;
+ if(iLine == iw && dLineCol == lDef->color && hPen != 0xffff) return true;
+ iLine = iw;
+ dLineCol = lDef->color;
+ if(hPen != 0xffff) wmfDeleteObject(hPen);
+ iw = iw > 0 ? iw : 1;
+ hPen = wmfCreateSolidPen(dLineCol, iw);
+ wmfSelectObject(hPen);
+ }
+ return true;
+}
+
+bool
+ExportWMF::SetFill(FillDEF *fill)
+{
+ if(!fill) return false;
+ if((fill->type & 0xff) != FILL_NONE) {
+ if(!hgo) hgo = new HatchOut(this);
+ if(hgo) hgo->SetFill(fill);
+ }
+ else {
+ if(hgo) delete hgo;
+ hgo = 0L;
+ }
+ if(dFillCol != fill->color) {
+ if(hBrush != 0xffff) wmfDeleteObject(hBrush);
+ hBrush = wmfCreateSolidBrush(dFillCol = fill->color);
+ wmfSelectObject(hBrush);
+ }
+ dFillCol2 = fill->color2;
+ return true;
+}
+
+bool
+ExportWMF::SetTextSpec(TextDEF *set)
+{
+ unsigned char lfcs, lfpaf;
+ char *face;
+ bool IsModified, RetVal;
+
+ switch(set->Font){
+ case FONT_HELVETICA:
+ default:
+ lfcs = 0;
+ lfpaf = 2 | 2<<4;
+ face = "Arial";
+ break;
+ case FONT_TIMES:
+ lfcs = 0;
+ lfpaf = 2 | 1<<4;
+ face = "Times New Roman";
+ break;
+ case FONT_COURIER:
+ lfcs = 2;
+ lfpaf = 1 | 3<<4;
+ face = "Courier New";
+ break;
+ }
+ if(!set->iSize && set->fSize > 0.001f) set->iSize = un2iy(set->fSize);
+ if(!set->iSize) return false;
+ if(hFont == 0xffff || TxtSet.iSize != set->iSize || TxtSet.Style != set->Style ||
+ TxtSet.RotBL != set->RotBL || TxtSet.RotCHAR != set->RotCHAR ||
+ TxtSet.Font != set->Font || TxtSet.fSize != set->fSize) IsModified = true;
+ else IsModified = false;
+ RetVal = anyOutput::SetTextSpec(set);
+ if (IsModified && RetVal) {
+ hFont = wmfCreateFontIndirect(TxtSet.iSize, 0,
+ iround(TxtSet.RotBL*10), iround(TxtSet.RotBL*10),
+ (TxtSet.Style & TXS_BOLD) ? 700 : 400,
+ (TxtSet.Style & TXS_ITALIC) ? 1 : 0,
+ (TxtSet.Style & TXS_UNDERLINE) ? 1 : 0,
+ 0, lfcs, 0, 0, 2, lfpaf, face);
+ }
+ if(hFont != 0xffff) wmfSelectObject(hFont);
+ return true;
+}
+
+bool
+ExportWMF::StartPage()
+{
+ if(!go) return false;
+ if(name) {
+ if(-1 ==(oFile = open(name, O_RDWR | O_BINARY | O_CREAT | O_TRUNC,
+ S_IWRITE | S_IREAD))) {
+ ErrorBox("Could not open output file");
+ return false;
+ }
+ }
+ else {
+ oFile = 2; //stdout
+ }
+ VPorg.fy = -un2fiy(go->GetSize(SIZE_GRECT_TOP));
+ VPorg.fx = -un2fix(go->GetSize(SIZE_GRECT_LEFT));
+ write(oFile, &header, 18);
+ return true;
+}
+
+bool
+ExportWMF::EndPage()
+{
+ unsigned short end_token[3] = {3, 0, 0};
+
+ write(oFile, &end_token, 6);
+// file_size = tell(oFile);
+ file_size = lseek(oFile, 0L, SEEK_CUR);
+ lseek(oFile, 0L, SEEK_SET);
+ header.mtSize0 = (file_size>>1)&0xffff;
+ header.mtSize1 = file_size>>17;
+ header.mtNoObj = maxGDIobj;
+ header.mtMaxRec = rec_size;
+ write(oFile, &header, 18);
+ oFile = close(oFile);
+ return true;
+}
+
+bool
+ExportWMF::oCircle(int x1, int y1, int x2, int y2, char* nam)
+{
+ wmfEllipse(x1, y1, x2, y2);
+ if(hgo) return hgo->oCircle(x1, y1, x2, y2);
+ return true;
+}
+
+bool
+ExportWMF::oPolyline(POINT * pts, int cp, char * nam)
+{
+ int i;
+
+ if(cp < 1) return false;
+ if (dPattern) for (i = 1; i < cp; i++) PatLine(pts[i-1], pts[i]);
+ else wmfPolyline(pts, cp);
+ return true;
+}
+
+bool
+ExportWMF::oRectangle(int x1, int y1, int x2, int y2, char *nam)
+{
+ wmfRectangle(x1, y1, x2, y2);
+ if(hgo) return hgo->oRectangle(x1, y1, x2, y2, 0L);
+ return true;
+}
+
+bool
+ExportWMF::oSolidLine(POINT *p)
+{
+ wmfPolyline(p, 2);
+ return true;
+}
+
+bool
+ExportWMF::oTextOut(int x, int y, char *txt, int cb)
+{
+ if(!txt || !txt[0]) return false;
+ if(hFont != 0xffff) wmfSelectObject(hFont);
+ wmfSetTextColor(TxtSet.ColTxt);
+ wmfSetBkColor(TxtSet.ColBg);
+ wmfSetTextAlign(((TxtSet.Align & TXA_HRIGHT) ? 2 : (TxtSet.Align &
+ TXA_HCENTER) ? 6 : 0) | ((TxtSet.Align & TXA_VBOTTOM) ? 8 : 0));
+ wmfSetBkMode(TxtSet.Mode ? 1 : 2);
+ wmfTextOut(x, (TxtSet.Align & TXA_VCENTER) ? y - TxtSet.iSize/2 : y, txt,
+ (cb > 0) ? cb : strlen(txt));
+ return true;
+}
+
+bool
+ExportWMF::oPolygon(POINT *pts, int cp, char *nam)
+{
+ wmfPolygon(pts, cp);
+ if(hgo) return hgo->oPolygon(pts, cp);
+ return true;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//templates for wmf file records
+typedef struct{
+ unsigned Size;
+ unsigned short Id;
+ unsigned short Value;
+}wmfObjShort;
+
+typedef struct{
+ unsigned Size;
+ unsigned short Id;
+}wmfObjCol;
+
+typedef struct{
+ unsigned Size;
+ unsigned short Id;
+ unsigned short Style;
+ DWORD Col;
+ unsigned short Hatch;
+}wmfLogBrush;
+
+typedef struct{
+ unsigned Size;
+ unsigned short Id;
+ short lfh, lfw, lfesc, lfori, lfwei;
+ unsigned char lfita, lfund, lfsto, lfcse, lfopre, lfclp, lfqua, lfpaqu;
+ char face[32];
+}wmfLogFont;
+
+typedef struct{
+ unsigned Size;
+ unsigned short Id;
+ unsigned short Style;
+ unsigned Width;
+ DWORD col;
+}wmfLogPen;
+
+typedef struct{
+ unsigned Size;
+ unsigned short Id;
+ unsigned short x1, y1, x2, y2;
+}wmfRect;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//the following routines resemble the corresponding GDI calls
+unsigned short
+ExportWMF::wmfCreateSolidBrush(DWORD color)
+{
+ wmfLogBrush lb = {7, 0x2fc, 0, color, 0};
+
+ write(oFile, &lb, 14);
+ currGDIobj++;
+ maxGDIobj = currGDIobj > maxGDIobj ? currGDIobj : maxGDIobj;
+ return currGDIobj-1;
+}
+
+unsigned short
+ExportWMF::wmfCreateFontIndirect(short lfHeight, short lfWidth, short lfEscapement,
+ short lfOrientation, short lfWeight, unsigned char lfItalic, unsigned char lfUnderline,
+ unsigned char lfStrikeOut, unsigned char lfCharSet, unsigned char lfOutPrecision,
+ unsigned char lfClipPrecision, unsigned char lfQuality, unsigned char lfPitchAndFamily,
+ char *FaceName)
+{
+ wmfLogFont lf = {28, 0x2fb, lfHeight, lfWidth, lfEscapement, lfOrientation, lfWeight,
+ lfItalic, lfUnderline, lfStrikeOut, lfCharSet, lfOutPrecision, lfClipPrecision,
+ lfQuality, lfPitchAndFamily, "Arial"};
+
+ if(FaceName && FaceName[0]) strcpy(lf.face, FaceName);
+ write(oFile, &lf, 56);
+ currGDIobj++;
+ maxGDIobj = currGDIobj > maxGDIobj ? currGDIobj : maxGDIobj;
+ return currGDIobj-1;
+}
+
+unsigned short
+ExportWMF::wmfCreateSolidPen(DWORD color, unsigned short width)
+{
+ wmfLogPen lp = {8, 0x2fa, 0, width, color};
+
+ write(oFile, &lp, 16);
+ currGDIobj++;
+ maxGDIobj = currGDIobj > maxGDIobj ? currGDIobj : maxGDIobj;
+ return currGDIobj-1;
+}
+
+void
+ExportWMF::wmfDeleteObject(unsigned short obj)
+{
+ wmfObjShort wo = {4, 0x1f0, obj};
+
+ if(currGDIobj == obj+1) {
+// write(oFile, &wo, 8);
+// currGDIobj--;
+ }
+}
+
+void
+ExportWMF::wmfEllipse(unsigned short ix1, unsigned short iy1, unsigned short ix2, unsigned short iy2)
+{
+ wmfRect rc = {7, 0x418, iy2, ix2, iy1, ix1};
+
+ write(oFile, &rc, 14);
+}
+
+void
+ExportWMF::wmfPolyline(POINT *pts, unsigned short cp)
+{
+ wmfObjShort pl = {4+cp*2, 0x325, cp};
+ unsigned short v[2];
+ int i;
+
+ write(oFile, &pl, 8);
+ for(i = 0; i < cp; i++) {
+ v[0] = (unsigned short)pts[i].x;
+ v[1] = (unsigned short)pts[i].y;
+ write(oFile, &v, 4);
+ }
+ if(pl.Size > rec_size) rec_size = pl.Size;
+}
+
+void
+ExportWMF::wmfPolygon(POINT *pts, unsigned short cp)
+{
+ wmfObjShort pl = {4+cp*2, 0x324, cp};
+ unsigned short v[2];
+ int i;
+
+ write(oFile, &pl, 8);
+ for(i = 0; i < cp; i++) {
+ v[0] = (unsigned short)pts[i].x;
+ v[1] = (unsigned short)pts[i].y;
+ write(oFile, &v, 4);
+ }
+ if(pl.Size > rec_size) rec_size = pl.Size;
+}
+
+void
+ExportWMF::wmfRectangle(unsigned short ix1, unsigned short iy1, unsigned short ix2, unsigned short iy2)
+{
+ wmfRect rc = {7, 0x41B, iy2, ix2, iy1, ix1};
+
+ write(oFile, &rc, 14);
+}
+
+void
+ExportWMF::wmfSelectObject(unsigned short o)
+{
+ wmfObjShort so = {4, 0x12D, o};
+
+ write(oFile, &so, 8);
+}
+
+void
+ExportWMF::wmfSetBkColor(DWORD col)
+{
+ wmfObjCol co = {5, 0x201};
+
+ write(oFile, &co, 6);
+ write(oFile, &col, 4);
+}
+
+void
+ExportWMF::wmfSetBkMode(unsigned m)
+{
+ wmfObjShort mo = {5, 0x102, m & 0xffff};
+ unsigned short p;
+
+ write(oFile, &mo, 8);
+ p = m>>16;
+ write(oFile, &p, 2);
+}
+
+//cmSetMapMode()
+//cmSetPolyFillMode()
+
+void
+ExportWMF::wmfSetTextAlign(unsigned a)
+{
+ wmfObjShort ao = {5, 0x12E, a & 0xffff};
+ unsigned short p;
+
+ write(oFile, &ao, 8);
+ p = a>>16;
+ write(oFile, &p, 2);
+}
+
+void
+ExportWMF::wmfSetTextColor(DWORD col)
+{
+ wmfObjCol tc = {5, 0x209};
+
+ write(oFile, &tc, 6);
+ write(oFile, &col, 4);
+}
+
+//cmSetWindowExt()
+//cmSetWindowOrg()
+
+void
+ExportWMF::wmfTextOut(unsigned short ix1, unsigned short iy1, char *txt, unsigned short cb)
+{
+ wmfObjShort to = {6, 0x521, cb};
+ unsigned short le, v[2] = {iy1, ix1};
+
+ le = cb &1 ? cb+1 : cb;
+ to.Size += le>>1;
+ write(oFile, &to, 8);
+ write(oFile, txt, le);
+ write(oFile, &v, 4);
+ if(to.Size > rec_size) rec_size = to.Size;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Entry point to export graph to Windows Meta File
+void DoExportWmf(GraphObj *g, char *FileName, float res, DWORD flags)
+{
+ ExportWMF *ex;
+
+ ex = new ExportWMF(g, FileName, res, flags);
+ if(ex->StartPage()) {
+ g->DoPlot(ex);
+ ex->EndPage();
+ }
+ delete(ex);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// export to *.svg file (scalable vector graphic)
+// this code is based on information from the following books
+// H. Spona, 'Das Einsteigerseminar SVG-Webgrafiken mit XML',
+// vmi, ISBN 3-8266-7181-3
+// M. Salathe, 'SVG Scalabe Vector Graphics ...f�r professionelle Einsteiger',
+// M&T, ISBN 3-8272-6188-0
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class ExportSVG:public anyOutput {
+public:
+ HatchOut *hgo;
+
+ ExportSVG(GraphObj *g, char *FileName, DWORD flags);
+ ~ExportSVG();
+ bool SetLine(LineDEF *lDef);
+ bool SetFill(FillDEF *fill);
+ bool SetTextSpec(TextDEF *set);
+ bool StartPage();
+ bool EndPage();
+ bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L);
+ bool oPolyline(POINT * pts, int cp, char *nam = 0L);
+ bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
+ bool oSolidLine(POINT *p);
+ bool oTextOut(int x, int y, char *txt, int cb);
+ bool oPolygon(POINT *pts, int cp, char * nam = 0L);
+
+private:
+ int iLineWidth;
+ bool bUseGroupLine, bOutputPending;
+ GraphObj *go;
+ char *name, indent[80], output[120], tHatchStyle[80];
+ FILE *oFile;
+ DWORD flags;
+
+ void Indent(bool ind);
+ void AddToOutput(char *txt);
+ char *ColName(DWORD col);
+};
+
+ExportSVG::ExportSVG(GraphObj *g, char *FileName, DWORD flg)
+{
+ hgo =0L;
+ DeskRect.left = DeskRect.top = 0;
+ DeskRect.right = DeskRect.bottom = 0x4fffffff;
+ dFillCol = 0xffffffffL;
+ hres = vres = 1000.0f;
+ go = g;
+ if(FileName)name = strdup(FileName);
+ else name = 0L;
+ oFile = 0L;
+ flags = flg;
+ strcpy(indent, " ");
+ strcpy(tHatchStyle, "style=\"stroke:black; stroke-width:1\"");
+ bUseGroupLine = false;
+}
+
+ExportSVG::~ExportSVG()
+{
+ if(hgo) delete hgo;
+ if(name) free(name);
+}
+
+bool
+ExportSVG::SetLine(LineDEF *lDef)
+{
+ LineWidth = lDef->width;
+ if(1 >(iLineWidth = iround(un2fix(lDef->width)))) iLineWidth = 1;
+ dPattern = lDef->pattern;
+ dLineCol = lDef->color;
+ RLP.finc = (float)(256.0/un2fix(lDef->patlength*8.0));
+ RLP.fp = 0.0;
+ return true;
+}
+
+bool
+ExportSVG::SetFill(FillDEF *fill)
+{
+ int iL;
+
+ if(!fill) return false;
+ if((fill->type & 0xff) != FILL_NONE) {
+ if(!hgo) hgo = new HatchOut(this);
+ if(hgo) hgo->SetFill(fill);
+ if(fill->hatch) {
+ if(1 >(iL = iround(un2fix(fill->hatch->width)))) iL = 1;
+ sprintf(tHatchStyle, "style=\"fill:none; stroke:%s; stroke-width:%d\"",
+ ColName(fill->hatch->color), iL);
+ }
+ }
+ else {
+ if(hgo) delete hgo;
+ hgo = 0L;
+ }
+ dFillCol = fill->color;
+ dFillCol2 = fill->color2;
+ return true;
+}
+
+bool
+ExportSVG::SetTextSpec(TextDEF *set)
+{
+ if(!set->iSize && set->fSize > 0.0f) set->iSize = un2iy(set->fSize);
+ if(!set->iSize) return false;
+ return anyOutput::SetTextSpec(set);
+}
+
+bool
+ExportSVG::StartPage()
+{
+ int w, h;
+
+ if(!go) return false;
+ w = un2ix(go->GetSize(SIZE_GRECT_RIGHT) - go->GetSize(SIZE_GRECT_LEFT))/10;
+ h = un2iy(go->GetSize(SIZE_GRECT_BOTTOM) - go->GetSize(SIZE_GRECT_TOP))/10;
+ w++; h++;
+ if(name) {
+ oFile = fopen(name, "w");
+ if(!oFile) {
+ ErrorBox("Could not open\noutput file!");
+ return false;
+ }
+ }
+ else oFile = stdout;
+ if(flags & 0x01) fprintf(oFile, "Content-Type: image/svg+xml\n\n");
+ VPorg.fy = -un2fiy(go->GetSize(SIZE_GRECT_TOP));
+ VPorg.fx = -un2fix(go->GetSize(SIZE_GRECT_LEFT));
+ fprintf(oFile, "<?xml version=\"1.0\"?>\n"
+ "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20001102//EN\"\n"
+ " \"http://www.w3.org/TR/2000/CR-SVG-20001102/DTD/svg-20001102.dtd\">\n");
+ fprintf(oFile, "<svg %s width=\"%d\" height=\"%d\" style=\"stroke-linecap:round\">\n",
+ defs.svgAttr ? defs.svgAttr : "", w, h);
+ if(defs.svgScript) {
+ fprintf(oFile, "<defs>\n<script type=\"text/ecmascript\"><![CDATA[\n");
+ fprintf(oFile, "\n%s\n", defs.svgScript);
+ fprintf(oFile, "\n]]></script>\n</defs>\n\n");
+ }
+ fprintf(oFile, "<g transform=\"scale(0.1)\" style=\"font-family:Helvetica\">\n");
+ return true;
+}
+
+bool
+ExportSVG::EndPage()
+{
+ fprintf(oFile, "</g>\n</svg>\n");
+ fclose (oFile);
+ return true;
+}
+
+bool
+ExportSVG::oCircle(int x1, int y1, int x2, int y2, char* nam)
+{
+ if(x1 > x2) Swap(x1, x2);
+ if(y1 > y2) Swap(y1, y2);
+
+ if(hgo){
+ fprintf(oFile, "%s<g> <!-- %s with pattern -->\n", indent,
+ (x2-x1) == (y2-y1) ? "circle" : "ellipse");
+ Indent(true);
+ }
+ fprintf(oFile, "%s<%s%s%s%s cx=\"%d\" cy=\"%d\" ", indent,
+ (x2-x1) == (y2-y1) ? "circle" : "ellipse", nam? " name=\"" : "",
+ nam ? nam : "", nam ? "\"" : "", (x1+x2)/2, (y1+y2)/2);
+ if((x2-x1) == (y2-y1)) fprintf(oFile, "r=\"%d\"", (x2-x1)/2);
+ else fprintf(oFile, "rx=\"%d\" ry=\"%d\"", (x2-x1)/2, (y2-y1)/2);
+ fprintf(oFile, " style=\"fill:%s; stroke:%s; stroke-width:%d\"/>\n",
+ ColName(dFillCol), ColName(dLineCol), iLineWidth);
+ if(hgo) {
+ fprintf(oFile, "%s<g %s> <!-- hatch -->\n", indent, tHatchStyle);
+ Indent(true);
+ bUseGroupLine = true;
+ hgo->oCircle(x1, y1, x2, y2);
+ Indent(false);
+ bUseGroupLine = false;
+ fprintf(oFile, "%s</g>\n", indent);
+ Indent(false);
+ fprintf(oFile, "%s</g>\n", indent);
+ }
+ return true;
+}
+
+bool
+ExportSVG::oPolyline(POINT *pts, int cp, char *nam)
+{
+ int i;
+ char tmptxt[40];
+
+ if(cp < 2) return false;
+ if (dPattern){
+ fprintf(oFile, "%s<g style=\"stroke:%s; stroke-width:%d; stroke-linecap:round\">"
+ "<!-- pattern line -->\n", indent, ColName(dLineCol), iLineWidth);
+ Indent(true);
+ bUseGroupLine = true;
+ for (i = 1; i < cp; i++) PatLine(pts[i-1], pts[i]);
+ Indent(false);
+ fprintf(oFile, "%s</g>\n", indent);
+ bUseGroupLine = false;
+ }
+ else {
+ if(cp == 2) return oSolidLine(pts);
+ bOutputPending = false;
+ sprintf(output, "<polyline points=\"");
+ for(i = 0; i < cp; i++) {
+ sprintf(tmptxt, "%d %d ", pts[i].x, pts[i].y);
+ AddToOutput(tmptxt);
+ }
+ i = strlen(output);
+ if(i) output[i-1] = 0;
+ strcat(output, "\"");
+ if(!bUseGroupLine) {
+ strcpy(tmptxt, " style = \"fill:none; ");
+ AddToOutput(tmptxt);
+ sprintf(tmptxt, "; stroke:%s; ", ColName(dLineCol));
+ AddToOutput(tmptxt);
+ sprintf(tmptxt, "stroke-width:%d\"/>",iLineWidth);
+ AddToOutput(tmptxt);
+ }
+ else strcat(output, "/>");
+ fprintf(oFile, "%s%s\n", indent, output);
+ if(bOutputPending)Indent(false);
+ }
+ return true;
+}
+
+bool
+ExportSVG::oRectangle(int x1, int y1, int x2, int y2, char *nam)
+{
+ if(x1 > x2) Swap(x1, x2);
+ if(y1 > y2) Swap(y1, y2);
+ if(hgo){
+ fprintf(oFile, "%s<g> <!-- rectangle with pattern -->\n", indent);
+ Indent(true);
+ }
+ fprintf(oFile, "%s<rect%s%s%s x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" "
+ "style=\"fill:%s; stroke:%s; stroke-width:%d\"/>\n",
+ indent, nam? " name=\"" : "", nam ? nam : "", nam ? "\"" : "",
+ x1, y1, x2-x1-1, y2-y1-1, ColName(dFillCol), ColName(dLineCol), iLineWidth);
+ if(hgo) {
+ fprintf(oFile, "%s<g %s> <!-- hatch -->\n", indent, tHatchStyle);
+ Indent(true);
+ bUseGroupLine = true;
+ hgo->oRectangle(x1, y1, x2, y2, 0L);
+ Indent(false);
+ bUseGroupLine = false;
+ fprintf(oFile, "%s</g>\n", indent);
+ Indent(false);
+ fprintf(oFile, "%s</g>\n", indent);
+ }
+ return true;
+}
+
+bool
+ExportSVG::oSolidLine(POINT *p)
+{
+ if(bUseGroupLine) fprintf(oFile, "%s<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\"/>\n",
+ indent, p[0].x, p[0].y, p[1].x, p[1].y);
+ else fprintf(oFile, "%s<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" "
+ "style=\"stroke:%s; stroke-width:%d\"/>\n",
+ indent, p[0].x, p[0].y, p[1].x, p[1].y, ColName(dLineCol), iLineWidth);
+ return true;
+}
+
+bool
+ExportSVG::oTextOut(int x, int y, char *txt, int cb)
+{
+ int h, ix, iy;
+ char tmptxt[140], *nt;
+
+ h = TxtSet.iSize;
+ if(TxtSet.Align & TXA_VCENTER) iy = y + h/3;
+ else if(TxtSet.Align & TXA_VBOTTOM) iy = y;
+ else iy = y + iround(h*.8f);
+ ix = x;
+ sprintf(output, "<text x=\"%d\" y=\"%d\" ", ix, iy);
+ if(fabs(TxtSet.RotBL) >.01 || fabs(TxtSet.RotCHAR) >.01) {
+ sprintf(tmptxt,"transform=\"rotate(%.0f,%d,%d)\" ", -TxtSet.RotBL, ix, iy);
+ strcat(output, tmptxt);
+ }
+ strcpy(tmptxt, "style=\"font-family:");
+ switch(TxtSet.Font) {
+ case FONT_TIMES: strcat(tmptxt, "Times;"); break;
+ case FONT_COURIER: strcat(tmptxt, "Courier;"); break;
+ default: strcat(tmptxt, "Helvetica;"); break;
+ }
+ if(TxtSet.Style & TXS_ITALIC) strcat(tmptxt, " font-style:italic;");
+ if(TxtSet.Style & TXS_BOLD) strcat(tmptxt, " font-weight:bold;");
+ if(TxtSet.Style & TXS_UNDERLINE) strcat(tmptxt, " text-decoration:underline;");
+ AddToOutput(tmptxt);
+ sprintf(tmptxt, " fill:%s; stroke:%s; ", ColName(TxtSet.ColTxt),
+ ColName(TxtSet.ColTxt));
+ AddToOutput(tmptxt);
+ sprintf(tmptxt, "font-size:%d; text-anchor:%s \">", TxtSet.iSize,
+ (TxtSet.Align & TXA_HRIGHT) ? "end" : (TxtSet.Align & TXA_HCENTER) ? "middle":"start");
+ AddToOutput(tmptxt);
+ nt = str2xml(txt);
+ if((strlen(indent)+strlen(nt)+strlen(output)) <110) strcat(output, nt);
+ else {
+ fprintf(oFile, "%s%s\n", indent, output);
+ strcpy(output, nt);
+ }
+ if((strlen(indent) + strlen(output)) <104)
+ fprintf(oFile, "%s%s</text>\n", indent, output);
+ else {
+ fprintf(oFile, "%s%s\n", indent, output);
+ fprintf(oFile, "</text>\n");
+ }
+ return true;
+}
+
+bool
+ExportSVG::oPolygon(POINT *pts, int cp, char *nam)
+{
+ int i;
+ char tmptxt[40];
+
+ if(cp <3) return false;
+ if(hgo){
+ fprintf(oFile, "%s<g> <!-- polygon with pattern -->\n", indent);
+ Indent(true);
+ }
+ bOutputPending = false;
+ sprintf(output, "<polygon%s%s%s points=\"",
+ nam? " name=\"" : "", nam ? nam : "", nam ? "\"" : "");
+ for(i = 0; i < cp; i++) {
+ sprintf(tmptxt, "%d %d ", pts[i].x, pts[i].y);
+ AddToOutput(tmptxt);
+ }
+ i = strlen(output);
+ if(i) output[i-1] = 0;
+ strcat(output, "\" ");
+ sprintf(tmptxt, "style=\"fill:%s; ", ColName(dFillCol));
+ AddToOutput(tmptxt);
+ sprintf(tmptxt, "stroke:%s; ", ColName(dLineCol));
+ AddToOutput(tmptxt);
+ sprintf(tmptxt, "stroke-width:%d\"/>",iLineWidth);
+ AddToOutput(tmptxt);
+ if(output)fprintf(oFile, "%s%s\n", indent, output);
+ if(bOutputPending)Indent(false);
+ if(hgo) {
+ fprintf(oFile, "%s<g %s> <!-- hatch -->\n", indent, tHatchStyle);
+ Indent(true);
+ bUseGroupLine = true;
+ hgo->oPolygon(pts, cp);
+ Indent(false);
+ bUseGroupLine = false;
+ fprintf(oFile, "%s</g>\n", indent);
+ Indent(false);
+ fprintf(oFile, "%s</g>\n", indent);
+ }
+ return true;
+}
+
+void
+ExportSVG::Indent(bool ind)
+{
+ int i = strlen(indent);
+
+ if(i > 20 && ind) return;
+ if(ind) strcat(indent, " ");
+ else if(i>2) indent[i-3] = 0;
+}
+
+void
+ExportSVG::AddToOutput(char *txt)
+{
+ if((strlen(txt) + strlen(output) + strlen(indent)) < 110)strcat(output, txt);
+ else {
+ fprintf(oFile, "%s%s\n", indent, output);
+ if(!bOutputPending) Indent(true);
+ bOutputPending = true;
+ strcpy(output, txt);
+ }
+}
+char *
+ExportSVG::ColName(DWORD col)
+{
+ static char txt1[20], txt2[20];
+ static int sw;
+
+ switch(col) {
+ case 0x00000000: return "black";
+ case 0x000000ff: return "red";
+ case 0x0000ff00: return "lime";
+ case 0x0000ffff: return "yellow";
+ case 0x00ff0000: return "blue";
+ case 0x00ff00ff: return "magenta";
+ case 0x00ffff00: return "cyan";
+ case 0x00ffffff: return "white";
+ }
+ sw++;
+ if(sw & 0x01) {
+ sprintf(txt1, "rgb(%d,%d,%d)", col & 0xff, (col>>8) & 0xff, (col>>16) &0xff);
+ return txt1;
+ }
+ else {
+ sprintf(txt2, "rgb(%d,%d,%d)", col & 0xff, (col>>8) & 0xff, (col>>16) &0xff);
+ return txt2;
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Entry point to export graph to *.svg
+void DoExportSvg(GraphObj *g, char *FileName, DWORD flags)
+{
+ ExportSVG *ex;
+
+ ex = new ExportSVG(g, FileName, flags);
+ if(ex->StartPage()) {
+ g->DoPlot(ex);
+ ex->EndPage();
+ }
+ HideTextCursor();
+ delete(ex);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// export to *.eps file (encapsulated post script).
+// This code is based on information from the following book
+// G. Born, 'Referenzhandbuch Dateiformate',
+// Addison-Wesley ISBN 3-89319-815-6
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class ExportEPS:public anyOutput {
+public:
+ HatchOut *hgo;
+
+ ExportEPS(GraphObj *g, char *FileName, DWORD flags);
+ ~ExportEPS();
+ bool SetLine(LineDEF *lDef);
+ bool SetFill(FillDEF *fill);
+ bool SetTextSpec(TextDEF *set);
+ bool StartPage();
+ bool EndPage();
+ bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L);
+ bool oPolyline(POINT * pts, int cp, char *nam = 0L);
+ bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
+ bool oSolidLine(POINT *p);
+ bool oTextOut(int x, int y, char *txt, int cb);
+ bool oPolygon(POINT *pts, int cp, char *nam = 0L);
+
+private:
+ RECT BoundBox;
+ fRECT SolLines[2000];
+ int nSolLines;
+ GraphObj *go;
+ char *name;
+ FILE *oFile;
+ DWORD CurrCol;
+
+ float ix2eps(int x);
+ float iy2eps(int y);
+ char *col2eps(DWORD color);
+ void FlushSolLines();
+ void AddSolLine(float x1, float y1, float x2, float y2);
+};
+
+ExportEPS::ExportEPS(GraphObj *g, char *FileName, DWORD flags)
+{
+ hgo =0L;
+ nSolLines = 0;
+ DeskRect.left = DeskRect.top = 0;
+ DeskRect.right = DeskRect.bottom = 0x4fffffff;
+ dFillCol = 0xffffffffL;
+ hres = vres = 720.0f;
+ go = g;
+ if(FileName)name = strdup(FileName);
+ else name = 0L;
+ oFile = 0L;
+}
+
+ExportEPS::~ExportEPS()
+{
+ if(hgo) delete hgo;
+ if(name) free(name);
+}
+
+bool
+ExportEPS::SetLine(LineDEF *lDef)
+{
+ if(LineWidth != lDef->width || dLineCol != lDef->color) {
+ FlushSolLines();
+ LineWidth = lDef->width;
+ CurrCol = dLineCol = lDef->color;
+ fprintf(oFile, "\nnewpath %.1f setlinewidth %s ",
+ un2fix(LineWidth)/10.0f, col2eps(dLineCol));
+ }
+ dPattern = lDef->pattern;
+ RLP.finc = (float)(256.0/un2fix(lDef->patlength*8.0));
+ RLP.fp = 0.0;
+ return true;
+}
+
+bool
+ExportEPS::SetFill(FillDEF *fill)
+{
+ if(!fill) return false;
+ if((fill->type & 0xff) != FILL_NONE) {
+ if(!hgo) hgo = new HatchOut(this);
+ if(hgo) hgo->SetFill(fill);
+ }
+ else {
+ if(hgo) delete hgo;
+ hgo = 0L;
+ }
+ dFillCol = fill->color;
+ dFillCol2 = fill->color2;
+ return true;
+}
+
+bool
+ExportEPS::SetTextSpec(TextDEF *set)
+{
+ char FontName[30];
+
+ if(!set->iSize && set->fSize > 0.0f) set->iSize = un2iy(set->fSize);
+ if(!set->iSize) return false;
+ if(set->iSize == TxtSet.iSize && set->Style == TxtSet.Style &&
+ set->Font == TxtSet.Font){
+ anyOutput::SetTextSpec(set);
+ return true;
+ }
+ anyOutput::SetTextSpec(set);
+ switch(TxtSet.Font) {
+ case FONT_TIMES: sprintf(FontName, "(Times"); break;
+ case FONT_COURIER: sprintf(FontName, "(Courier"); break;
+ default: sprintf(FontName, "(Helvetica"); break; //Helvetica
+ }
+ if(TxtSet.Style & TXS_BOLD) strcat(FontName, "-Bold");
+ if(TxtSet.Style & TXS_ITALIC) strcat(FontName, "-Italic");
+ strcat(FontName, ")");
+ fprintf(oFile, "\n%s findfont %d scalefont setfont ", FontName, TxtSet.iSize/10);
+ return true;
+}
+
+bool
+ExportEPS::StartPage()
+{
+ time_t ti;
+
+ if(!go) return false;
+ ti = time(0L);
+ BoundBox.top = BoundBox.left = 0;
+ BoundBox.right = un2ix(go->GetSize(SIZE_GRECT_RIGHT) - go->GetSize(SIZE_GRECT_LEFT))/10;
+ BoundBox.bottom = un2iy(go->GetSize(SIZE_GRECT_BOTTOM) - go->GetSize(SIZE_GRECT_TOP))/10;
+ BoundBox.right++; BoundBox.bottom++;
+ if(name) {
+ oFile = fopen(name, "w");
+ if(!oFile) {
+ ErrorBox("Could not open\noutput file!");
+ return false;
+ }
+ }
+ else oFile = stdout;
+ VPorg.fy = -un2fiy(go->GetSize(SIZE_GRECT_TOP));
+ VPorg.fx = -un2fix(go->GetSize(SIZE_GRECT_LEFT));
+ fprintf(oFile, "%%!PS-Adobe-1.0 EPSF-3.0\n"
+ "%%%%BoundingBox: %d %d %d %d\n", BoundBox.left, BoundBox.top,
+ BoundBox.right, BoundBox.bottom);
+ fprintf(oFile, "%%%%Title: %s\n", name);
+ fprintf(oFile,"%%%%Creator: RLPlot version "SZ_VERSION"\n");
+ fprintf(oFile,"%%%%CreationDate: %s", ctime(&ti));
+ fprintf(oFile, "%%%%Pages: 1\n%%%%DocumentFonts: (atend)\n");
+ fprintf(oFile, "%%%%EndComments\n"
+ "%%%%BeginProlog\n"
+ "%%%%EndProlog\n"
+ "%%%%Page: 1 1");
+ return true;
+}
+
+bool
+ExportEPS::EndPage()
+{
+ fprintf(oFile, "\nshowpage\n%%%%Trailer\n");
+ fprintf(oFile, "%%%%DocumentFonts: Helvetica\n");
+ fprintf(oFile, "%%%%EOF\n");
+ fclose (oFile);
+ return true;
+}
+
+bool
+ExportEPS::oCircle(int x1, int y1, int x2, int y2, char* nam)
+{
+ FlushSolLines();
+ if((x2 - x1) == (y2 -y1)) {
+ fprintf(oFile, "\nnewpath %.1f %.1f %.1f 0 360 arc ", ix2eps((x1+x2)/2),
+ iy2eps((y1+y2)/2), (float)(x2-x1)/20.0f);
+ fprintf(oFile, "%s fill", col2eps(CurrCol = dFillCol));
+ if(hgo){
+ hgo->oCircle(x1, y1, x2, y2);
+ FlushSolLines();
+ }
+ fprintf(oFile, "\nnewpath %.1f %.1f %.1f 0 360 arc ", ix2eps((x1+x2)/2),
+ iy2eps((y1+y2)/2), (float)(x2-x1)/20.0f);
+ fprintf(oFile, "%s stroke", col2eps(CurrCol = dLineCol));
+ }
+ else if(x1 != x2 && y1 != y2){
+ fprintf(oFile, "\ngsave %.1f %.1f translate", (ix2eps((x1+x2)>>1)),
+ (iy2eps((y1+y2)>>1)));
+ if(abs(x2-x1) > abs(y2-y1)) {
+ fprintf(oFile, " 1 %lf scale", fabs(((double)(y2-y1))/((double)(x2-x1))));
+ fprintf(oFile, " 0 0 %.1lf 0 360 arc ", fabs(((double)(x2-x1))/20.0));
+ fprintf(oFile, "%s fill", col2eps(CurrCol = dFillCol));
+ fprintf(oFile, "\n 0 0 %.1lf 0 360 arc ", fabs(((double)(x2-x1))/20.0));
+ }
+ else {
+ fprintf(oFile, " %lf 1 scale", fabs(((double)(x2-x1))/((double)(y2-y1))));
+ fprintf(oFile, " 0 0 %.1lf 0 360 arc ", fabs(((double)(y2-y1))/20.0));
+ fprintf(oFile, "%s fill", col2eps(CurrCol = dFillCol));
+ fprintf(oFile, "\n 0 0 %.1lf 0 360 arc ", fabs(((double)(y2-y1))/20.0));
+ }
+ fprintf(oFile, "%s stroke grestore", col2eps(CurrCol = dLineCol));
+ if(hgo){
+ hgo->oCircle(x1, y1, x2, y2);
+ FlushSolLines();
+ }
+ }
+ return true;
+}
+
+bool
+ExportEPS::oPolyline(POINT * pts, int cp, char *nam)
+{
+ int i, j;
+
+ if(cp <1) return false;
+ if (dPattern){
+ for (i = 1; i < cp; i++) PatLine(pts[i-1], pts[i]);
+ return true;
+ }
+ else if(cp == 2) return oSolidLine(pts);
+ FlushSolLines();
+ if(CurrCol != dLineCol) {
+ fprintf(oFile, "\n%s ", col2eps(CurrCol = dLineCol));
+ }
+ for(i = cp-1, j = 0; i >= 0; i--, j++) {
+ if(!(j & 0x07)) fprintf(oFile, "\n");
+ fprintf(oFile, " %.1f %.1f", ix2eps(pts[i].x), iy2eps(pts[i].y));
+ }
+ fprintf(oFile, " moveto %d {lineto} repeat stroke ", cp-1);
+ return true;
+}
+
+
+bool
+ExportEPS::oRectangle(int x1, int y1, int x2, int y2, char *nam)
+{
+ FlushSolLines();
+ fprintf(oFile, "\n%.1f %.1f %.1f %.1f %.1f %.1f %.1f %.1f %.1f %.1f moveto 4 {lineto}"
+ " repeat %s fill", ix2eps(x1), iy2eps(y1), ix2eps(x1), iy2eps(y2), ix2eps(x2), iy2eps(y2),
+ ix2eps(x2), iy2eps(y1), ix2eps(x1), iy2eps(y1), col2eps(CurrCol = dFillCol));
+ if(hgo) hgo->oRectangle(x1, y1, x2, y2, 0L);
+ fprintf(oFile, "\n%.1f %.1f %.1f %.1f %.1f %.1f %.1f %.1f %.1f %.1f moveto 4 {lineto}"
+ " repeat %s stroke", ix2eps(x1), iy2eps(y1), ix2eps(x1), iy2eps(y2), ix2eps(x2), iy2eps(y2),
+ ix2eps(x2), iy2eps(y1), ix2eps(x1), iy2eps(y1), col2eps(CurrCol = dLineCol));
+ return true;
+}
+
+bool
+ExportEPS::oSolidLine(POINT *p)
+{
+ if(CurrCol != dLineCol) {
+ FlushSolLines();
+ fprintf(oFile, "\n%s ", col2eps(CurrCol = dLineCol));
+ }
+ AddSolLine(ix2eps(p[0].x), iy2eps(p[0].y), ix2eps(p[1].x), iy2eps(p[1].y));
+ return true;
+}
+
+bool
+ExportEPS::oTextOut(int x, int y, char *txt, int cb)
+{
+ int h, ix, iy, w;
+ float fx, fy;
+
+ FlushSolLines();
+ oGetTextExtent(txt, cb, &w, &h);
+ if(TxtSet.Align & TXA_VCENTER) iy = y + h/3;
+ else if(TxtSet.Align & TXA_VBOTTOM) iy = y;
+ else iy = y + iround(h*.8);
+ if(TxtSet.Align & TXA_HRIGHT) ix = x-w;
+ else if(TxtSet.Align & TXA_HCENTER) ix = x-w/2;
+ else ix = x;
+ fprintf(oFile,"\n");
+ if(fabs(TxtSet.RotBL) >.01 || fabs(TxtSet.RotCHAR) >.01) {
+ fprintf(oFile, "gsave %.1f %.1f translate %f rotate %.1f %.1f moveto\n",
+ ix2eps(x), iy2eps(y), TxtSet.RotBL, (float)(ix-x)/10.0f, (float)(iy-y)/-10.0f);
+ if(CurrCol != TxtSet.ColTxt) fprintf(oFile, "%s ", col2eps(CurrCol = TxtSet.ColTxt));
+ fprintf(oFile, "(%s) show grestore ", txt);
+ }
+ else {
+ fx = ix2eps(ix); fy = iy2eps(iy);
+ if(CurrCol != TxtSet.ColTxt) fprintf(oFile, "%s ", col2eps(CurrCol = TxtSet.ColTxt));
+ fprintf(oFile,"%.1f %.1f moveto (%s) show ", fx, fy, txt);
+ }
+ return true;
+}
+
+bool
+ExportEPS::oPolygon(POINT *pts, int cp, char *nam)
+{
+ int i, j;
+
+ if(cp <1) return false;
+ if(cp == 2) return oSolidLine(pts);
+ FlushSolLines();
+ for(i = cp-1, j = 0; i >= 0; i--, j++) {
+ if(!(j & 0x07)) fprintf(oFile, "\n");
+ fprintf(oFile, " %.1f %.1f", ix2eps(pts[i].x), iy2eps(pts[i].y));
+ }
+ fprintf(oFile, " moveto %d {lineto} repeat %s fill ", cp-1, col2eps(CurrCol = dFillCol));
+ if(hgo) hgo->oPolygon(pts, cp);
+ return oPolyline(pts, cp);
+}
+
+float
+ExportEPS::ix2eps(int x)
+{
+ return (float)x/10.0f;
+}
+
+float
+ExportEPS::iy2eps(int y)
+{
+ return (float)y/-10.0f + (float)BoundBox.bottom;
+}
+
+char *
+ExportEPS::col2eps(DWORD color)
+{
+ static char txt[50];
+ char tmptxt[10];
+ float r, g, b;
+
+ r = (float)(color & 0xff)/255.0f;
+ g = (float)((color>>8)&0xff)/255.0f;
+ b = (float)((color>>16)&0xff)/255.0f;
+ WriteFloatToBuff(tmptxt, r); strcpy(txt, tmptxt+1);
+ WriteFloatToBuff(tmptxt, g); strcat(txt, tmptxt);
+ WriteFloatToBuff(tmptxt, b); strcat(txt, tmptxt);
+ strcat(txt, " setrgbcolor");
+ return txt;
+}
+
+void
+ExportEPS::FlushSolLines()
+{
+ int i, j;
+
+ if(nSolLines <1) {
+ nSolLines = 0;
+ return;
+ }
+ if(nSolLines == 1) {
+ fprintf(oFile, "\n%.1f %.1f moveto %.1f %.1f lineto stroke ",
+ SolLines[0].Ymin, SolLines[0].Ymax, SolLines[0].Xmin, SolLines[0].Xmax);
+ nSolLines = 0;
+ return;
+ }
+ for(i = nSolLines-1, j = 0; i >=0; i--, j++) {
+ if(!(j & 0x03)) fprintf(oFile, "\n");
+ fprintf(oFile, " %.1f %.1f %.1f %.1f", SolLines[i].Xmin, SolLines[i].Xmax,
+ SolLines[i].Ymin, SolLines[i].Ymax);
+ }
+ if(j > 8 && ((j & 0x3) >=2 || (j & 0x03) == 0)) fprintf(oFile, "\n");
+ fprintf(oFile, " %d {moveto lineto} repeat stroke ", nSolLines);
+ nSolLines = 0;
+}
+
+void
+ExportEPS::AddSolLine(float x1, float y1, float x2, float y2)
+{
+ if(nSolLines >= 2000) FlushSolLines();
+ SolLines[nSolLines].Ymin = x1; SolLines[nSolLines].Ymax = y1;
+ SolLines[nSolLines].Xmin = x2; SolLines[nSolLines].Xmax = y2;
+ nSolLines++;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Entry point to export graph to *.eps
+void DoExportEps(GraphObj *g, char *FileName, DWORD flags)
+{
+ ExportEPS *ex;
+
+ ex = new ExportEPS(g, FileName, flags);
+ if(ex->StartPage()) {
+ g->DoPlot(ex);
+ ex->EndPage();
+ }
+ delete(ex);
+}
diff --git a/Fileio.cpp b/Fileio.cpp
new file mode 100755
index 0000000..50c52e2
--- /dev/null
+++ b/Fileio.cpp
@@ -0,0 +1,3353 @@
+//FileIO.cpp, Copyright (c) 2001, 2002, 2003, 2004, 2005 R.Lackner
+//read/write graphic objects
+//
+// 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 <time.h>
+#include <math.h>
+#include <ctype.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
+
+extern GraphObj *CurrGO; //Selected Graphic Objects
+extern Default defs;
+extern int dlgtxtheight;
+extern char TmpTxt[];
+
+static notary *Notary = 0L;
+static ReadCache *Cache = 0L;
+
+unsigned long cObsW; //count objects written
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// graphic input/output is driven by tables based on the descIO template
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+typedef struct {
+ char *label;
+ unsigned short type;
+ void *ptr;
+ long *count;
+ }descIO;
+
+//the type member of descIO describes the following data types pointed to by ptr
+enum {typNONE, typNZINT, typINT, typLFLOAT, typNZLFLOAT,
+ typDWORD, typULONG, typFRECT, typNZLFPOINT, typLFPOINT, typPOINT3D,
+ typAXDEF, typPTRAXDEF, typLINEDEF, typFILLDEF, typGOBJ, typOBJLST,
+ typFPLST, typFPLST3D, typIPLST, typTEXT, typTXTDEF, typPTRTXTDEF,
+ typLAST = 0x100};
+
+static char *ptr =0L;
+static long ptr_step = 2048;
+static int cbOut, sizeOut = 0, iFile = 0;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// output graph to file, elementary functions
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int OpenOutputFile(char *file)
+{
+ time_t ti;
+
+ if(ptr) free(ptr);
+ ptr = 0L; cbOut = 0;
+ if(file && BackupFile(file)) {
+ if(-1 ==(iFile = open(file, O_RDWR | O_BINARY | O_CREAT | O_TRUNC,
+ S_IWRITE | S_IREAD))) return -1;
+ ptr = (char *)malloc(sizeOut = 2048);
+ if(!ptr) goto openerr;
+ ti = time(0L);
+ cbOut = sprintf(ptr,";RLP 1.0\n;File \"%s\" created by RLPlot version "
+ ""SZ_VERSION"\n;Date/Time: %s",
+ file, ctime(&ti));
+ }
+ return iFile;
+openerr:
+ ptr = 0L; cbOut = sizeOut = 0;
+ close(iFile);
+ iFile = 0;
+ return -1;
+}
+
+void CloseOutputFile()
+{
+ if(iFile > 0){
+ if(cbOut) write(iFile, ptr, cbOut);
+ close(iFile);
+ }
+ if(ptr) free(ptr);
+ cbOut = sizeOut = 0;
+ ptr = 0L;
+}
+
+void AddStringToOutput(char *str, int length)
+{
+ int i;
+ char *tmp_ptr;
+
+ if((cbOut+length)< sizeOut) { //fit in buffer
+ memcpy(ptr+cbOut, str, length);
+ cbOut += length;
+ }
+ else if(iFile > 0){ //buffer full: write to file
+ i = sizeOut-cbOut;
+ memcpy(ptr+cbOut, str, i);
+ write(iFile, ptr, 2048);
+ memcpy(ptr, str+i, length-i);
+ cbOut = length-i;
+ }
+ else { //buffer full: resize buffer
+ if(tmp_ptr = (char*)realloc(ptr, sizeOut+ptr_step)){
+ ptr = tmp_ptr; sizeOut += ptr_step; ptr_step += (ptr_step >> 1);
+ AddStringToOutput(str, length);
+ }
+ }
+}
+
+void WriteTypObjLst(GraphObj **ptr, int count)
+{
+ int i, j, c, n;
+ char tmp[512];
+
+ if(!ptr) return;
+ for(i = c = 0; i <= count/16; i++) {
+ if(i) c = sprintf(tmp, " ");
+ for(j = 0; (n=i*16+j) <count && j < 16; j++) {
+ c += sprintf(tmp+c, "%s%ld", j ? " " : "", Notary->RegisterGO(ptr[n]));
+ }
+ if(n >= count) c += sprintf(tmp+c, "}");
+ c += sprintf(tmp+c, "\n");
+ AddStringToOutput(tmp, c);
+ }
+}
+
+void WriteTypIpLst(POINT *ptr, long count)
+{
+ long i, j, c, n;
+ char tmp[256];
+
+ if(!ptr) return;
+ for(i = 0; i <= count/8; i++) {
+ for(j = c = 0; (n =i*8+j) <count && j < 8; j++) {
+ c += sprintf(tmp+c, " %ld", ptr[n].x);
+ c += sprintf(tmp+c, " %ld", ptr[n].y);
+ }
+ if(n >= count) c += sprintf(tmp+c, "}");
+ c += sprintf(tmp+c, "\n");
+ AddStringToOutput(tmp, c);
+ }
+}
+
+void WriteTypFpLst(lfPOINT *ptr, long count)
+{
+ long i, j, c, n;
+ char tmp[256];
+
+ if(!ptr) return;
+ for(i = 0; i <= count/8; i++) {
+ for(j = c = 0; (n =i*8+j) <count && j < 8; j++) {
+ c += WriteFloatToBuff(tmp+c, ptr[n].fx);
+ c += WriteFloatToBuff(tmp+c, ptr[n].fy);
+ }
+ if(n >= count) c += sprintf(tmp+c, "}");
+ c += sprintf(tmp+c, "\n");
+ AddStringToOutput(tmp, c);
+ }
+}
+
+void WriteTypFpLst3D(fPOINT3D *ptr, long count)
+{
+ long i, j, c, n;
+ char tmp[256];
+
+ if(!ptr) return;
+ for(i = 0; i <= count/5; i++) {
+ for(j = c = 0; (n =i*5+j) <count && j < 5; j++) {
+ c += WriteFloatToBuff(tmp+c, ptr[n].fx);
+ c += WriteFloatToBuff(tmp+c, ptr[n].fy);
+ c += WriteFloatToBuff(tmp+c, ptr[n].fz);
+ }
+ if(n >= count && j) c += sprintf(tmp+c, "}\n");
+ else if(n < count) c += sprintf(tmp+c, "\n");
+ AddStringToOutput(tmp, c);
+ }
+}
+
+bool ExecOutput(long id, char *Class, descIO *Desc)
+{
+ static char buff[800];
+ int i, cb, last;
+ fRECT *fr;
+ AxisDEF *ax;
+ LineDEF *ld;
+ FillDEF *fd;
+ TextDEF *tx;
+
+ cb = sprintf(buff, "\n[%ld=%s]\n", id, Class);
+ cObsW++;
+ for(i = 0; Desc[i].label; i++) {
+ last = cb;
+ cb += sprintf(buff+cb,"%s=", Desc[i].label);
+ switch(Desc[i].type & 0xff){
+ case typNZINT:
+ if(!(*(int*)Desc[i].ptr)) {
+ cb = last;
+ break;
+ }
+ //if not zero value continue as if int
+ case typINT:
+ cb += sprintf(buff+cb," %d\n", *(int*)Desc[i].ptr);
+ break;
+ case typNZLFLOAT:
+ if(*((double*)Desc[i].ptr) < 0.0001) {
+ cb = last;
+ break;
+ }
+ //if not zero or negative continue as if float
+ case typLFLOAT:
+ cb += WriteFloatToBuff(buff+cb, *(double*)Desc[i].ptr);
+ cb += sprintf(buff+cb, "\n");
+ break;
+ case typDWORD:
+ cb += sprintf(buff+cb," 0x%08x\n", *(DWORD *)Desc[i].ptr);
+ break;
+ case typULONG:
+ cb += sprintf(buff+cb," %ld\n", *(unsigned long*)Desc[i].ptr);
+ break;
+ case typFRECT:
+ fr = (fRECT*)Desc[i].ptr;
+ cb += WriteFloatToBuff(buff+cb, fr->Xmin);
+ cb += WriteFloatToBuff(buff+cb, fr->Ymax);
+ cb += WriteFloatToBuff(buff+cb, fr->Xmax);
+ cb += WriteFloatToBuff(buff+cb, fr->Ymin);
+ cb += sprintf(buff+cb, "\n");
+ break;
+ case typNZLFPOINT:
+ if(((lfPOINT *)Desc[i].ptr)->fx == ((lfPOINT *)Desc[i].ptr)->fy &&
+ ((lfPOINT *)Desc[i].ptr)->fx == 0.0f){
+ cb = last;
+ break;
+ }
+ //if not zero continue as if fPOINT
+ case typLFPOINT:
+ cb += WriteFloatToBuff(buff+cb, ((lfPOINT *)Desc[i].ptr)->fx);
+ cb += WriteFloatToBuff(buff+cb, ((lfPOINT *)Desc[i].ptr)->fy);
+ cb += sprintf(buff+cb, "\n");
+ break;
+ case typPOINT3D:
+ cb += WriteFloatToBuff(buff+cb, ((fPOINT3D *)Desc[i].ptr)->fx);
+ cb += WriteFloatToBuff(buff+cb, ((fPOINT3D *)Desc[i].ptr)->fy);
+ cb += WriteFloatToBuff(buff+cb, ((fPOINT3D *)Desc[i].ptr)->fz);
+ cb += sprintf(buff+cb, "\n");
+ break;
+ case typAXDEF:
+ case typPTRAXDEF:
+ ax = (Desc[i].type & 0xff) == typAXDEF ? (AxisDEF *)Desc[i].ptr : *(AxisDEF **)Desc[i].ptr;
+ //we do not set ownership: reconstruct after read
+ cb += sprintf(buff+cb, "0x%08x", ax->flags);
+ cb += WriteFloatToBuff(buff+cb, ax->min);
+ cb += WriteFloatToBuff(buff+cb, ax->max);
+ cb += WriteFloatToBuff(buff+cb, ax->loc[0].fx);
+ cb += WriteFloatToBuff(buff+cb, ax->loc[0].fy);
+ cb += WriteFloatToBuff(buff+cb, ax->loc[0].fz);
+ cb += WriteFloatToBuff(buff+cb, ax->loc[1].fx);
+ cb += WriteFloatToBuff(buff+cb, ax->loc[1].fy);
+ cb += WriteFloatToBuff(buff+cb, ax->loc[1].fz);
+ cb += WriteFloatToBuff(buff+cb, ax->Start);
+ cb += WriteFloatToBuff(buff+cb, ax->Step);
+ cb += WriteFloatToBuff(buff+cb, ax->Center.fx);
+ cb += WriteFloatToBuff(buff+cb, ax->Center.fy);
+ cb += WriteFloatToBuff(buff+cb, ax->Radius);
+ cb += sprintf(buff+cb," %d", ax->nBreaks);
+ if(ax->nBreaks) {
+ cb += sprintf(buff+cb, " {");
+ AddStringToOutput(buff, cb);
+ cb = 0;
+ WriteTypFpLst(ax->breaks, ax->nBreaks);
+ }
+ cb += sprintf(buff+cb, "\n");
+ break;
+ case typLINEDEF:
+ ld = (LineDEF *)Desc[i].ptr;
+ cb += WriteFloatToBuff(buff+cb, ld->width);
+ cb += WriteFloatToBuff(buff+cb, ld->patlength);
+ cb += sprintf(buff+cb, ld->color ? " 0x%08x" : " 0x0", ld->color);
+ cb += sprintf(buff+cb, ld->pattern ? " 0x%08x\n" : " 0x0\n", ld->pattern);
+ break;
+ case typFILLDEF:
+ fd = (FillDEF *)Desc[i].ptr;
+ //we set the 'hatch' member to zero: reconstruct after read
+ cb += sprintf(buff+cb," %d 0x%08x", fd->type, fd->color);
+ cb += WriteFloatToBuff(buff+cb, fd->scale);
+ cb += sprintf(buff+cb," 0x0 0x%08x\n", fd->color2);
+ break;
+ case typGOBJ:
+ if(*(GraphObj **)(Desc[i].ptr)) cb +=
+ sprintf(buff+cb," %ld\n", Notary->RegisterGO(*(GraphObj **)(Desc[i].ptr)));
+ else cb = last;
+ break;
+ case typOBJLST:
+ if(!*(GraphObj ***)(Desc[i].ptr)){
+ cb = last;
+ break;
+ }
+ cb += sprintf(buff+cb, "(%ld){", Desc[i].count ? *Desc[i].count : 0L);
+ AddStringToOutput(buff, cb);
+ cb = 0;
+ WriteTypObjLst(*(GraphObj ***)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0L);
+ break;
+ case typIPLST:
+ if(!*(POINT**)(Desc[i].ptr)){
+ cb = last;
+ break;
+ }
+ cb += sprintf(buff+cb, "(%ld){", Desc[i].count ? *Desc[i].count : 0L);
+ AddStringToOutput(buff, cb);
+ cb = 0;
+ WriteTypIpLst(*(POINT**)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0L);
+ break;
+ case typFPLST:
+ if(!*(lfPOINT**)(Desc[i].ptr)){
+ cb = last;
+ break;
+ }
+ cb += sprintf(buff+cb, "(%ld){", Desc[i].count ? *Desc[i].count : 0L);
+ AddStringToOutput(buff, cb);
+ cb = 0;
+ WriteTypFpLst(*(lfPOINT**)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0L);
+ break;
+ case typFPLST3D:
+ if(!*(fPOINT3D**)(Desc[i].ptr)){
+ cb = last;
+ break;
+ }
+ cb += sprintf(buff+cb, "(%ld){", Desc[i].count ? *Desc[i].count : 0L);
+ AddStringToOutput(buff, cb);
+ cb = 0;
+ WriteTypFpLst3D(*(fPOINT3D**)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0L);
+ break;
+ case typTEXT:
+ if(!*(char**)(Desc[i].ptr)) cb = last;
+ else cb += sprintf(buff+cb, "\"%s\"\n", *(char**)(Desc[i].ptr));
+ break;
+ case typTXTDEF:
+ case typPTRTXTDEF:
+ tx = (Desc[i].type &0xff) == typTXTDEF ? (TextDEF *)Desc[i].ptr : *(TextDEF **)Desc[i].ptr;
+ if(!tx) {
+ cb = last;
+ break;
+ }
+ cb += sprintf(buff+cb, " 0x%08x 0x%08x %g %g %g %d %d %d %d",
+ tx->ColTxt, tx->ColBg, tx->fSize, tx->RotBL, tx->RotCHAR,
+ tx->Align, tx->Mode, tx->Style, tx->Font);
+ if(tx->text) cb += sprintf(buff+cb, " \"%s\"\n", tx->text);
+ else cb += sprintf(buff+cb, "\n");
+ break;
+ }
+ if(Desc[i].type & typLAST) break;
+ }
+ AddStringToOutput(buff, cb);
+ return true;
+}
+
+void ReadTypIpLst(POINT *ptr, long count, unsigned char *first)
+{
+ long f[20];
+ int j, k;
+ long i;
+
+ if(!ptr || !first) return;
+ k = sscanf((char*)first, "%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld",
+ &f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7], &f[8], &f[9],
+ &f[10], &f[11], &f[12], &f[13], &f[14], &f[15], &f[16], &f[17], &f[18], &f[19]);
+ for(i = 0, j = 0; j < k && i < count; i++, j += 2) {
+ ptr[i].x = f[j]; ptr[i].y = f[j+1];
+ }
+ while (i < count) {
+ if(!Cache->GetInt(&ptr[i].x) || !Cache->GetInt(&ptr[i].y)) return;
+ i++;
+ }
+}
+
+void ReadTypFpLst(lfPOINT *ptr, long count, unsigned char *first)
+{
+ double f[20];
+ int j, k;
+ long i;
+
+ if(!ptr || !first) return;
+ k = sscanf((char*)first, "%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf",
+ &f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7], &f[8], &f[9],
+ &f[10], &f[11], &f[12], &f[13], &f[14], &f[15], &f[16], &f[17], &f[18], &f[19]);
+ for(i = 0, j = 0; j < k && i < count; i++, j += 2) {
+ ptr[i].fx = f[j]; ptr[i].fy = f[j+1];
+ }
+ while (i < count) {
+ if(!Cache->GetFloat(&ptr[i].fx) || !Cache->GetFloat(&ptr[i].fy)) return;
+ i++;
+ }
+}
+
+void ReadTypFpLst3D(fPOINT3D *ptr, long count, unsigned char *first)
+{
+ double f[21];
+ int j, k;
+ long i;
+
+ if(!ptr || !first) return;
+ k = sscanf((char*)first, "%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf",
+ &f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7], &f[8], &f[9],
+ &f[10], &f[11], &f[12], &f[13], &f[14], &f[15], &f[16], &f[17], &f[18], &f[19], &f[20]);
+ for(i = 0, j = 0; j < k && i < count; i++, j += 3) {
+ ptr[i].fx = f[j]; ptr[i].fy = f[j+1]; ptr[i].fz = f[j+2];
+ }
+ while (i < count) {
+ if(!Cache->GetFloat(&ptr[i].fx) || !Cache->GetFloat(&ptr[i].fy) ||
+ !Cache->GetFloat(&ptr[i].fz)) return;
+ i++;
+ }
+}
+
+void TranslateEscChar(char *txt)
+{
+ int i, j;
+
+ if(txt && txt[0]) {
+ for(i = j = 0; txt[i]; i++) {
+ if(txt[i] == '\\') {
+ switch(txt[i+1]) {
+ case 'n':
+ txt[j++] = 0x0a; i++; break;
+ case 'r':
+ txt[j++] = 0x0d; i++; break;
+ case '"': case 0x27: case '\\':
+ txt[j++] = txt[++i]; break;
+ default:
+ txt[j++] = txt[i]; break;
+ }
+ }
+ else txt[j++] = txt[i];
+ }
+ txt[j] = 0;
+ }
+}
+
+void AddLines(char **txt)
+{
+ char tmp[1000], *ntxt;
+ bool mlines;
+ int i, j, cb = strlen(*txt);
+
+ do {
+ mlines = false;
+ Cache->ReadLine(tmp, sizeof(tmp));
+ for(i = strlen(tmp); i > 0 &&(tmp[i-1] < 33 || (tmp[i-1] ==
+ '"' && tmp[i-2] != '\\') || (tmp[i-1] == '\\' &&
+ (mlines = true))); tmp[--i] = 0);
+ for(i = 0; tmp[i] && (tmp[i] < 33 || tmp[i] == '"'); i++);
+ TranslateEscChar(tmp);
+ if(tmp[0] && (j = strlen(tmp+i)) && (ntxt = (char*)realloc(*txt, cb + j + 1))) {
+ strcpy(ntxt+cb, tmp+i);
+ cb += j; *(txt) = ntxt;
+ }
+ } while (mlines);
+}
+
+bool ExecInput(descIO *Desc)
+{
+ char c, tmp[1000], tmp2[20];
+ int i, j, k, l;
+ bool match, mlines;
+ unsigned long il, jl;
+ AxisDEF *ax;
+ POINT *lp;
+ lfPOINT *lfp;
+ fPOINT3D *lfp3d;
+ LineDEF *ld;
+ FillDEF *fd;
+ fRECT *fr;
+ GraphObj **gobs;
+ TextDEF *tx;
+
+ if(!Desc || !Desc[0].label) return false;
+ for(j = k = 0; ; ) {
+ do{
+ c = Cache->Getc();
+ switch (c) {
+ case '[': //next object
+ case 0: //probably eof
+ return true;
+ case '}': //a lists hang over
+ c = Cache->Getc();
+ break;
+ }
+ } while(c <33);
+ for(i = 1, tmp[0] = c; i < sizeof(tmp) && '=' != (tmp[i] = Cache->Getc()); i++){
+ if(tmp[i] < 32 && tmp[i]) i = -1; //some error conditions
+ else if(!tmp[i] && Cache->eof) return true;
+ else if(tmp[i] == '[') return true;
+ }
+ tmp[i] = 0;
+ match = mlines = false;
+ do {
+ if(0 == strcmp(tmp, Desc[j].label)) {
+ Cache->ReadLine(tmp, sizeof(tmp));
+ switch(Desc[j].type & 0xff){
+ case typNZINT:
+ case typINT:
+ sscanf(tmp, "%d", (int*)Desc[j].ptr);
+ break;
+ case typNZLFLOAT:
+ case typLFLOAT:
+ sscanf(tmp, "%lf", (double*)Desc[j].ptr);
+ break;
+ case typDWORD:
+ sscanf(tmp, "%x", (DWORD*)Desc[j].ptr);
+ break;
+ case typULONG:
+ sscanf(tmp, "%ld", (unsigned long*)Desc[j].ptr);
+ break;
+ case typFRECT:
+ fr = (fRECT*) Desc[j].ptr;
+ sscanf(tmp, "%lf%lf%lf%lf", &fr->Xmin, &fr->Ymax, &fr->Xmax, &fr->Ymin);
+ break;
+ case typNZLFPOINT:
+ case typLFPOINT:
+ lfp = (lfPOINT*) Desc[j].ptr;
+ sscanf(tmp, "%lf%lf", &lfp->fx, &lfp->fy);
+ break;
+ case typPOINT3D:
+ lfp3d = (fPOINT3D*) Desc[j].ptr;
+ sscanf(tmp, "%lf%lf%lf", &lfp3d->fx, &lfp3d->fy, &lfp3d->fz);
+ break;
+ case typPTRAXDEF:
+ case typAXDEF:
+ ax = (Desc[j].type & 0xff) == typAXDEF ? (AxisDEF *)Desc[j].ptr : *(AxisDEF **)Desc[j].ptr;
+ //pointer for typPTRAXDEF and memory allocated by the Axis module!
+ if(!ax) break;
+ sscanf(tmp, "%x%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%d", &ax->flags, &ax->min, &ax->max,
+ &ax->loc[0].fx, &ax->loc[0].fy, &ax->loc[0].fz, &ax->loc[1].fx,
+ &ax->loc[1].fy, &ax->loc[1].fz, &ax->Start, &ax->Step, &ax->Center.fx,
+ &ax->Center.fy, &ax->Radius, &ax->nBreaks);
+ if(ax->nBreaks) {
+ ax->breaks = (lfPOINT*)calloc(ax->nBreaks, sizeof(lfPOINT));
+ for(i = 0; tmp[i] && tmp[i-1] != '{'; i++);
+ if(tmp[i]) {
+ ReadTypFpLst(ax->breaks, ax->nBreaks, (unsigned char*)tmp+i);
+ SortAxisBreaks(ax);
+ }
+ }
+ break;
+ case typLINEDEF:
+ ld = (LineDEF*) Desc[j].ptr;
+ sscanf(tmp,"%lf%lf%x%x", &ld->width, &ld->patlength, &ld->color, &ld->pattern);
+ break;
+ case typFILLDEF:
+ fd = (FillDEF*) Desc[j].ptr;
+ sscanf(tmp, "%d%x%lf%x%x", &fd->type, &fd->color, &fd->scale, &fd->hatch, &fd->color2);
+ fd->hatch = 0L;
+ break;
+ case typGOBJ:
+ *(GraphObj**)(Desc[j].ptr) = Notary->PopGO(atol(tmp));
+ break;
+ case typOBJLST:
+ for(i = 0; i < 10 && tmp[i] != '(' && tmp[i]; i++);
+ if(!tmp[i]) break;
+ if(sscanf(tmp+i+1, "%ld", &il) && il) {
+ *Desc[j].count = il;
+ if(!*(GraphObj***)(Desc[j].ptr)){
+ *(GraphObj***)(Desc[j].ptr) = (GraphObj**)calloc(il, sizeof(GraphObj*));
+ }
+ if((gobs = *(GraphObj***)(Desc[j].ptr))){
+ while(tmp[i-1] != '{') i++; while(tmp[i-1] < 33) i++;
+ strcat(tmp, " ");
+ for( ;il >0; il--) {
+ for(l = 0; l < sizeof(tmp2); ){
+ if(tmp[i]) c = tmp[i++];
+ else if(!(c = Cache->Getc())) break;
+ if(c >='0' && c <='9') tmp2[l++] = c;
+ else {
+ tmp2[l] = 0;
+ if(l)break;
+ }
+ }
+ sscanf(tmp2, "%ld", &jl);
+ *gobs++ = Notary->PopGO(jl);
+ if(c == '}') break;
+ }
+ }
+ }
+ break;
+ case typIPLST:
+ for(i = 0; i < 10 && tmp[i] != '(' && tmp[i]; i++);
+ if(!tmp[i]) break;
+ if(sscanf(tmp+i+1, "%ld", &il) && il) {
+ *Desc[j].count = il;
+ if(!*(POINT**)(Desc[j].ptr)){
+ *(POINT**)(Desc[j].ptr) = (POINT*)calloc(il, sizeof(POINT));
+ }
+ if(!(lp = *(POINT**)(Desc[j].ptr)))return false;
+ while(tmp[i-1] != '{') i++; while(tmp[i-1] < 33) i++;
+ ReadTypIpLst(lp, il, (unsigned char*)tmp+i);
+ }
+ break;
+ case typFPLST:
+ for(i = 0; i < 10 && tmp[i] != '(' && tmp[i]; i++);
+ if(!tmp[i]) break;
+ if(sscanf(tmp+i+1, "%ld", &il) && il) {
+ *Desc[j].count = il;
+ if(!*(lfPOINT**)(Desc[j].ptr)){
+ *(lfPOINT**)(Desc[j].ptr) = (lfPOINT*)calloc(il, sizeof(lfPOINT));
+ }
+ if(!(lfp = *(lfPOINT**)(Desc[j].ptr)))return false;
+ while(tmp[i-1] != '{') i++; while(tmp[i-1] < 33) i++;
+ ReadTypFpLst(lfp, il, (unsigned char*)tmp+i);
+ }
+ break;
+ case typFPLST3D:
+ for(i = 0; i < 10 && tmp[i] != '(' && tmp[i]; i++);
+ if(!tmp[i]) break;
+ if(sscanf(tmp+i+1, "%ld", &il) && il) {
+ *Desc[j].count = il;
+ if(!*(fPOINT3D**)(Desc[j].ptr)){
+ *(fPOINT3D**)(Desc[j].ptr) = (fPOINT3D*)calloc(il, sizeof(fPOINT3D));
+ }
+ if(!Desc[j].ptr)return false;
+ while(tmp[i-1] != '{') i++; while(tmp[i-1] < 33) i++;
+ ReadTypFpLst3D(*(fPOINT3D**)(Desc[j].ptr), il, (unsigned char*)tmp+i);
+ }
+ break;
+ case typTEXT:
+ for(i = strlen(tmp); i > 0 &&(tmp[i-1] < 33 || (tmp[i-1] ==
+ '"' && tmp[i-2] != '\\') || (tmp[i-1] == '\\' &&
+ (mlines = true))); tmp[--i] = 0);
+ for(i = 0; tmp[i] && (tmp[i] < 33 || tmp[i] == '"'); i++);
+ TranslateEscChar(tmp);
+ if(tmp[0]){
+ *(char**)(Desc[j].ptr) = strdup(tmp+i);
+ if(mlines) AddLines((char**)(Desc[j].ptr));
+ }
+ break;
+ case typPTRTXTDEF:
+ case typTXTDEF:
+ tx = (Desc[j].type & 0xff) == typTXTDEF ? (TextDEF *)Desc[j].ptr : *(TextDEF **)Desc[j].ptr;
+ if(!tx) {
+ if((Desc[j].type & 0xff) == typTXTDEF) break; //prabably wrong usage of typTXTDEF instad of
+ // typPTRTXTDEF
+ tx = *(TextDEF **)(Desc[j].ptr) = (TextDEF*)calloc(1, sizeof(TextDEF));
+ if(!tx) return false; //memory allocation error
+ }
+ sscanf(tmp, "%x%x%lf%lf%lf%d%d%d%d", &tx->ColTxt, &tx->ColBg,
+ &tx->fSize, &tx->RotBL, &tx->RotCHAR,
+ &tx->Align, &tx->Mode, &tx->Style, &tx->Font);
+ tx->iSize = 0;
+ for(i = strlen(tmp); i >0 && tmp[i] != '"'; i--);
+ if(i) {
+ tmp[i] = 0;
+ for(l = 0; l <i && tmp[l] != '"'; l++);
+ if(i && tmp[l+1]) tx->text = strdup(tmp+l+1);
+ }
+ break;
+ }
+ match = true; j++; k++;
+ if(!Desc[j].label || (Desc[j-1].type & typLAST))
+ j = k = 0; //rewind: items in file not sorted
+ }
+ else {
+ j++;
+ k++;
+ if(!Desc[j].label || (Desc[j-1].type & typLAST)) { //Error:
+ if(k > j){ // item not defined in Desc
+ match = true; // read parameters,
+ Cache->ReadLine(tmp, sizeof(tmp)); // then continue
+ }
+ j= 0;
+ }
+ }
+ }while(!match);
+ }
+}
+
+bool SaveGraphAs(GraphObj *g)
+{
+ char *name = 0L;
+ int i;
+
+ if(Notary || !g) {
+ ErrorBox("Output pending or\nno graph.");
+ return false;
+ }
+ cObsW = 0;
+ Notary = new notary();
+ if(g->Id == GO_GRAPH || g->Id == GO_PAGE) {
+ if(((Graph*)g)->filename) name = ((Graph*)g)->filename;
+ }
+ name = SaveGraphAsName(name);
+ if (name && Notary) {
+ iFile = OpenOutputFile(name);
+ if(iFile >=0) {
+ if(g && g->FileIO(FILE_WRITE)){
+ if(g->Id == GO_GRAPH || g->Id == GO_PAGE) {
+ g->Command(CMD_FILENAME, name, 0L);
+ }
+ for(i = strlen(name); i >=0 && name[i] != '/' && name[i] != '\\'; i--);
+ if(name[i]) i++;
+ g->Command(CMD_SETNAME, name+i, 0L);
+ g->Command(CMD_UPDHISTORY, 0L, 0L);
+ }
+ else ErrorBox("Could not write\ndata to file.");
+ }
+ else ErrorBox("Open failed for\noutput file.");
+ CloseOutputFile();
+ }
+ if(Notary) delete Notary; Notary = 0L;
+ return true;
+}
+
+char *GraphToMem(GraphObj *g, long *size)
+{
+ static char *ret;
+
+ if(Notary || !g) {
+ ErrorBox("Output pending or\nno graph.");
+ return false;
+ }
+ cObsW = 0;
+ iFile = cbOut = sizeOut = 0; ptr = 0L; ptr_step = 2048;
+ if (Notary = new notary()) {
+ if(g && g->FileIO(FILE_WRITE)){
+ //all done
+ }
+ delete Notary; Notary = 0L;
+ if(ptr) ptr[cbOut] = 0;
+ ret = ptr; if(size) *size = cbOut;
+ iFile = cbOut = sizeOut = 0; ptr = 0L; ptr_step = 2048;
+ return ret;
+ }
+ return 0L;
+}
+
+void UpdGOfromMem(GraphObj *go, unsigned char *buff)
+{
+ int i=0;
+
+ if(!go || !buff) return;
+ iFile = cbOut = sizeOut = 0; ptr = 0L;
+ for(i = 0; buff[i] && buff[i] != ']'; i++);
+ if(!buff[i])return;
+ for(; buff[i] && buff[i] <33; i++);
+ if(!buff[i] || i < 4) return;
+ if(!(Cache = new MemCache(buff+i-1))) return;
+ if ((Notary = new notary()) && go->Id > GO_UNKNOWN && go->Id < GO_DEFRW) {
+ //notary not needed but saver if tree exists
+ go->Command(CMD_FLUSH, 0L, 0L);
+ go->FileIO(INIT_VARS); go->FileIO(FILE_READ);
+ delete Notary; Notary = 0L;
+ }
+ delete Cache; Cache = 0L;
+}
+
+bool OpenGraph(GraphObj *root, char *name, unsigned char *mem)
+{
+ unsigned char c, tmp[80];
+ char debug[80];
+ unsigned long id, lid;
+ int i;
+ unsigned int hv;
+ GraphObj *go;
+
+ if(Notary || Cache) {
+ ErrorBox("Output pending:\nRead Error.");
+ return false;
+ }
+ if(!(Notary = new notary()))return false;
+ if(mem) {
+ if(!(Cache = new MemCache(mem))) return false;
+ }
+ else if(Cache = new ReadCache()){
+ if(!Cache->Open(name)) {
+ delete Notary; delete Cache;
+ Notary = 0L; Cache = 0L;
+ ErrorBox("Error open file");
+ return false;
+ }
+ }
+ else return false;
+ //DEBUG: skipping header
+ do {
+ c = Cache->Getc();
+ } while(c && c != '[');
+ if(!c) goto ReadErr;
+ do {
+ for(i = 0; i < sizeof(tmp) && c != '=' && c; i++){
+ tmp[i] = c = Cache->Getc();
+ if(c == '[') i = -1;
+ }
+ if(!c) goto ReadErr;
+ tmp[i] = tmp[i-1] = 0; id=0;
+ sscanf((char*)tmp, "%ld", &id);
+ if(!id) goto ReadErr;
+ //go to class name
+ while((tmp[0] = Cache->Getc())<31 && tmp[0]);
+ if(!tmp[0]) goto ReadErr;
+ for(i = 1; i < sizeof(tmp) && c!= ']' && c; i++)
+ tmp[i] = c = Cache->Getc();
+ if(!c) goto ReadErr;
+ tmp[i-1] = 0;
+ go = 0L;
+ hv = HashValue(tmp);
+ switch(hv) {
+ case 3895: go = new Axis(FILE_READ); break;
+ case 886: go = new Bar(FILE_READ); break;
+ case 81384: go = new Symbol(FILE_READ); break;
+ case 62229: go = new Bubble(FILE_READ); break;
+ case 948: go = new Box(FILE_READ); break;
+ case 15411: go = new Arrow(FILE_READ); break;
+ case 1052406: go = new ErrorBar(FILE_READ); break;
+ case 324566: go = new Whisker(FILE_READ); break;
+ case 1031437: go = new DropLine(FILE_READ); break;
+ case 4839: go = new Tick(FILE_READ); break;
+ case 16832: go = new Label(FILE_READ); break;
+ case 1071373: go = new GridLine(FILE_READ); break;
+ case 963085: go = new DataLine(FILE_READ); break;
+ case 61662266: go = new DataPolygon(FILE_READ); break;
+ case 435228: go = new segment(FILE_READ); break;
+ case 1741325: go = new polyline(FILE_READ); break;
+ case 435258: go = new polygon(FILE_READ); break;
+ case 6888037: go = new rectangle(FILE_READ); break;
+ case 1780087: go = new roundrec(FILE_READ); break;
+ case 78813: go = new Sphere(FILE_READ); break;
+ case 15463: go = new Brick(FILE_READ); break;
+ case 69952: go = new Line3D(FILE_READ); break;
+ case 386257: go = new ellipse(FILE_READ); break;
+ case 95680: go = new mLabel(FILE_READ); break;
+ case 4819316: go = new PlotScatt(FILE_READ); break;
+ case 15935312: go = new BubblePlot(FILE_READ); break;
+ case 247376: go = new BoxPlot(FILE_READ); break;
+ case 317384: go = new StackBar(FILE_READ); break;
+ case 1205932: go = new PieChart(FILE_READ); break;
+ case 16664: go = new Graph(FILE_READ); break;
+ case 25108: go = new GoGroup(FILE_READ); break;
+ case 300976: go = new Scatt3D(FILE_READ); break;
+ case 297280: go = new Plane3D(FILE_READ); break;
+ case 19227098: go = new Regression(FILE_READ); break;
+ case 297997: go = new RegLine(FILE_READ); break;
+ case 4318417: go = new SDellipse(FILE_READ); break;
+ case 4843600: go = new PolarPlot(FILE_READ); break;
+ case 977452: go = new DensDisp(FILE_READ); break;
+ case 4465: go = new Page(FILE_READ); break;
+ case 75120: go = new Plot3D(FILE_READ); break;
+ case 17142080: go = new GridLine3D(FILE_READ); break;
+ case 246688: go = new Arrow3D(FILE_READ); break;
+ case 75562: go = new Ribbon(FILE_READ); break;
+ case 16503104: go = new DropLine3D(FILE_READ); break;
+ case 28859579: go = new svgOptions(FILE_READ); break;
+ case 70259: go = new Limits(FILE_READ); break;
+ case 17145824: go = new GridRadial(FILE_READ); break;
+ case 1074714: go = new Function(FILE_READ); break;
+ case 256075: go = new FitFunc(FILE_READ); break;
+ case 273377: go = new LegItem(FILE_READ); break;
+ case 1053744: go = new FreqDist(FILE_READ); break;
+ case 68748: go = new Legend(FILE_READ); break;
+ case 66800: go = new Grid3D(FILE_READ); break;
+ case 967843: go = new DefsRW(FILE_READ); break;
+ default:
+ sprintf(debug, "Object %ld in file\n(Class = \"%s\")\nhash #%d\nis unknown.",
+ id, tmp, hv);
+ InfoBox(debug);
+ }
+ if(go) {
+ if(((int)id) < 0) DeleteGO(go); //temporary objects have id < 0
+ else if(!Notary->PushGO(lid = id, go)) DeleteGO(go);
+ }
+ if('[' != Cache->Lastc()) do { //search next object
+ c = Cache->Getc();
+ } while(c && c != '[');
+ tmp[0] = 0;
+ }while (c);
+ Cache->Close();
+ if((go = Notary->PopGO(lid))) {
+ go->Command(CMD_SET_DATAOBJ, 0L, 0L);
+ if(root->Id == GO_PAGE) {
+ if(go->Id == GO_PAGE){
+ if(!(root->parent->Command(CMD_DROP_GRAPH,(void *)go, 0L))) DeleteGO(go);
+ }
+ else if(!(root->Command(CMD_DROP_GRAPH, (void *)go, 0L))) DeleteGO(go);
+ }
+ else if(!(root->Command(CMD_DROP_GRAPH, (void *)go, 0L))){
+ DeleteGO(go); go = 0L;
+ }
+ if(go) go->Command(CMD_FILENAME, name, 0L);
+ }
+ delete Notary;
+ Notary = 0L;
+ delete Cache;
+ Cache = 0L;
+ return true;
+
+ReadErr:
+ Cache->Close();
+ close(iFile);
+ delete Notary;
+ Notary = 0L;
+ delete Cache;
+ Cache = 0L;
+ if(!name || !defs.IniFile || strcmp(name, defs.IniFile))
+ ErrorBox("An error occured during read.");
+ return false;
+}
+
+bool InitVarsGO(descIO *Desc)
+{
+ int i;
+ AxisDEF *ax;
+ TextDEF *tx;
+
+ for(i = 0; Desc[i].label; i++) {
+ switch(Desc[i].type & 0xff) {
+ case typNZINT:
+ case typINT:
+ *(int*)Desc[i].ptr = 0;
+ break;
+ case typNZLFLOAT:
+ case typLFLOAT:
+ *(double*)Desc[i].ptr = 0.0;
+ break;
+ case typDWORD:
+ *(DWORD*)Desc[i].ptr = 0x0L;
+ break;
+ case typULONG:
+ *(unsigned long*)Desc[i].ptr = 0L;
+ break;
+ case typFRECT:
+ ((fRECT*)Desc[i].ptr)->Xmin = ((fRECT*)Desc[i].ptr)->Xmax =
+ ((fRECT*)Desc[i].ptr)->Ymin = ((fRECT*)Desc[i].ptr)->Ymax = 0.0;
+ break;
+ case typNZLFPOINT:
+ case typLFPOINT:
+ ((lfPOINT*)Desc[i].ptr)->fx = ((lfPOINT*)Desc[i].ptr)->fy = 0.0;
+ break;
+ case typPOINT3D:
+ ((fPOINT3D*)Desc[i].ptr)->fx = ((fPOINT3D*)Desc[i].ptr)->fy =
+ ((fPOINT3D*)Desc[i].ptr)->fz = 0.0;
+ break;
+ case typPTRAXDEF:
+ case typAXDEF:
+ ax = (Desc[i].type & 0xff) == typAXDEF ? (AxisDEF *)Desc[i].ptr : *(AxisDEF **)Desc[i].ptr;
+ if(!ax) break;
+ ax->owner = 0L; ax->flags = 0L; ax->breaks = 0L; ax->nBreaks = 0;
+ ax->min = ax->max = ax->Start = ax->Step = 0.0f;
+ ax->loc[0].fx = ax->loc[0].fy = ax->loc[0].fz = 0.0f;
+ ax->loc[1].fx = ax->loc[1].fy = ax->loc[1].fz = 0.0f;
+ ax->Center.fx = ax->Center.fy = ax->Radius = 0.0f;
+ break;
+ case typLINEDEF:
+ ((LineDEF*)Desc[i].ptr)->width = defs.GetSize(SIZE_HAIRLINE);
+ ((LineDEF*)Desc[i].ptr)->patlength = defs.GetSize(SIZE_PATLENGTH);
+ ((LineDEF*)Desc[i].ptr)->color = ((LineDEF*)Desc[i].ptr)->pattern = 0x0L;
+ break;
+ case typFILLDEF:
+ ((FillDEF*)Desc[i].ptr)->type = FILL_NONE;
+ ((FillDEF*)Desc[i].ptr)->color = 0x00ffffffL;
+ ((FillDEF*)Desc[i].ptr)->scale = 1.0f;
+ ((FillDEF*)Desc[i].ptr)->hatch = (LineDEF*)0L;
+ ((FillDEF*)Desc[i].ptr)->color2 = 0x00ffffffL;
+ break;
+ case typGOBJ:
+ *(GraphObj **)Desc[i].ptr = (GraphObj*)0L;
+ break;
+ case typOBJLST:
+ *Desc[i].count = 0L;
+ *(GraphObj ***)Desc[i].ptr = (GraphObj**)0L;
+ break;
+ case typIPLST:
+ *Desc[i].count = 0L;
+ *(POINT **)Desc[i].ptr = (POINT*)0L;
+ break;
+ case typFPLST:
+ *Desc[i].count = 0L;
+ *(lfPOINT **)Desc[i].ptr = (lfPOINT*)0L;
+ break;
+ case typFPLST3D:
+ *Desc[i].count = 0L;
+ *(fPOINT3D **)Desc[i].ptr = (fPOINT3D*)0L;
+ break;
+ case typTEXT:
+ *(char **)Desc[i].ptr = (char*)0L;
+ break;
+ case typTXTDEF:
+ tx = (TextDEF *)Desc[i].ptr;
+ tx->ColTxt = 0x0L, tx->ColBg = 0x00ffffffL;
+ tx->fSize = defs.GetSize(SIZE_TEXT);
+ tx->RotBL = tx->RotCHAR = 0.0;
+ tx->Align = tx->Mode = tx->Style = tx->Font = 0L;
+ tx->text = 0L;
+ break;
+ case typPTRTXTDEF:
+ *(TextDEF**)Desc[i].ptr = (TextDEF*)0L;
+ break;
+ }
+ if(Desc[i].type & typLAST) break;
+ }
+ return true;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Save object data to memory block
+static unsigned char *SavVarBuf = 0L;
+static long SavVarSize = 0, SavVarPos = 0;
+void SavVarInit(long len)
+{
+ if(SavVarBuf) free(SavVarBuf);
+ SavVarBuf = (unsigned char *)malloc(SavVarSize = len+4096);
+ SavVarPos = 0;
+}
+
+bool SavVarAdd(void *ptr, int size)
+{
+ int len;
+
+ if(SavVarBuf) {
+ len = sizeof(unsigned char *) + sizeof(int) + size;
+ while (SavVarSize <= SavVarPos+len) {
+ if(!(SavVarBuf = (unsigned char *)realloc(SavVarBuf, SavVarSize + 4096))) return false;
+ SavVarSize += 4096;
+ }
+ memcpy(SavVarBuf+SavVarPos, &ptr, sizeof(unsigned char *));
+ SavVarPos += sizeof(unsigned char *);
+ memcpy(SavVarBuf+SavVarPos, &size, sizeof(int)); SavVarPos += sizeof(int);
+ memcpy(SavVarBuf+SavVarPos, ptr, size); SavVarPos += size;
+ return true;
+ }
+ return false;
+}
+
+void *SavVarFetch()
+{
+ void *tmp;
+
+ SavVarAdd(0L, 0);
+ tmp = SavVarBuf = (unsigned char *)realloc(SavVarBuf, SavVarPos);
+ SavVarSize = SavVarPos = 0; SavVarBuf = 0L;
+ return tmp;
+}
+
+bool SaveVarGO(descIO *Desc)
+{
+ int i;
+ AxisDEF *ax;
+ TextDEF *tx;
+
+ for(i = 0; Desc[i].label; i++) {
+ switch(Desc[i].type & 0xff){
+ case typNZINT:
+ case typINT:
+ SavVarAdd(Desc[i].ptr, sizeof(int));
+ break;
+ case typNZLFLOAT:
+ case typLFLOAT:
+ SavVarAdd(Desc[i].ptr, sizeof(double));
+ break;
+ case typDWORD:
+ SavVarAdd(Desc[i].ptr, sizeof(DWORD));
+ break;
+ case typULONG:
+ SavVarAdd(Desc[i].ptr, sizeof(unsigned long));
+ break;
+ case typFRECT:
+ SavVarAdd(Desc[i].ptr, sizeof(fRECT));
+ break;
+ case typNZLFPOINT:
+ case typLFPOINT:
+ SavVarAdd(Desc[i].ptr, sizeof(lfPOINT));
+ break;
+ case typPOINT3D:
+ SavVarAdd(Desc[i].ptr, sizeof(fPOINT3D));
+ break;
+ case typAXDEF:
+ case typPTRAXDEF:
+ ax = (Desc[i].type & 0xff) == typAXDEF ? (AxisDEF *)Desc[i].ptr : *(AxisDEF **)Desc[i].ptr;
+ if(ax) {
+ SavVarAdd(ax, sizeof(AxisDEF));
+ if(ax->breaks && ax->nBreaks) {
+ SavVarAdd(ax->breaks, ax->nBreaks * sizeof(lfPOINT));
+ }
+ }
+ break;
+ case typLINEDEF:
+ SavVarAdd(Desc[i].ptr, sizeof(LineDEF));
+ break;
+ case typFILLDEF:
+ SavVarAdd(Desc[i].ptr, sizeof(FillDEF));
+ break;
+ case typGOBJ: case typOBJLST: //not supported
+ break;
+ case typIPLST: //probably in the future
+ break;
+ case typFPLST:
+ break;
+ case typFPLST3D:
+ SavVarAdd(*((void **)Desc[i].ptr), sizeof(fPOINT3D) * (*Desc[i].count));
+ break;
+ case typTEXT:
+ if(*(char**)(Desc[i].ptr)) SavVarAdd(Desc[i].ptr, strlen(*(char**)(Desc[i].ptr))+1);
+ break;
+ case typTXTDEF:
+ case typPTRTXTDEF:
+ tx = (Desc[i].type &0xff) == typTXTDEF ? (TextDEF *)Desc[i].ptr : *(TextDEF **)Desc[i].ptr;
+ if(tx) SavVarAdd(tx, sizeof(TextDEF) - sizeof(char*));
+ break;
+ }
+ if(Desc[i].type & typLAST) break;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Graphic object member funtions for IO
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+svgOptions::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"tagAttr", typTEXT, &svgattr, 0L},
+ {"Script", typLAST | typTEXT, &script, 0L}};
+
+ switch(rw) {
+ case INIT_VARS:
+ return InitVarsGO(Desc);
+ case FILE_READ:
+ return ExecInput(Desc);
+ }
+ return false;
+}
+
+bool
+Symbol::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"ssRef", typIPLST, &ssRef, &cssRef},
+ {"Idx", typINT, &idx, 0L},
+ {"Pos", typLFPOINT, &fPos, 0L},
+ {"Size", typLFLOAT, &size, 0L},
+ {"Line", typLINEDEF, &SymLine, 0L},
+ {"FillCol", typDWORD, &SymFill.color, 0L},
+ {"Text", typPTRTXTDEF, &SymTxt, 0L},
+ {"Name", typLAST | typTEXT, &name, 0L}};
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ size = parent ? parent->GetSize(SIZE_SYMBOL): defs.GetSize(SIZE_SYMBOL);
+ SymLine.color = parent ? parent->GetColor(COL_SYM_LINE) : defs.Color(COL_SYM_LINE);
+ SymLine.width = parent ? parent->GetSize(SIZE_SYM_LINE) : defs.GetSize(SIZE_SYM_LINE);
+ SymFill.type = FILL_NONE;
+ SymFill.color = parent ? parent->GetColor(COL_SYM_FILL) : defs.Color(COL_SYM_FILL);
+ SymFill.scale = 1.0f;
+ SymFill.hatch = (LineDEF *) 0L;
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ SymFill.hatch = (LineDEF *) 0L;
+ return true;
+ case FILE_WRITE:
+ return ExecOutput(Notary->RegisterGO(this), "Symbol", Desc);
+ }
+ return false;
+}
+
+
+bool
+Bubble::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"ssRef", typIPLST, &ssRef, &cssRef},
+ {"Pos", typLFPOINT, &fPos, 0L},
+ {"Size", typLFLOAT, &fs, 0L},
+ {"Line", typLINEDEF, &BubbleLine, 0L},
+ {"FillLine", typLINEDEF, &BubbleFillLine, 0L},
+ {"Fill", typFILLDEF, &BubbleFill, 0L},
+ {"Name", typLAST | typTEXT, &name, 0L}};
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ BubbleLine.width = defs.GetSize(SIZE_BUBBLE_LINE);
+ BubbleFillLine.width = defs.GetSize(SIZE_BUBBLE_HATCH_LINE);
+ BubbleLine.color = BubbleFillLine.color = defs.Color(COL_BUBBLE_LINE);
+ BubbleFill.color = defs.Color(COL_BUBBLE_FILL);
+ ssRef = 0L;
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ BubbleFill.hatch = &BubbleFillLine;
+ return true;
+ case FILE_WRITE:
+ return ExecOutput(Notary->RegisterGO(this), "Bubble", Desc);
+ }
+ return false;
+}
+
+bool
+Bar::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typINT, &type, 0L},
+ {"ssRef", typIPLST, &ssRef, &cssRef},
+ {"Pos", typLFPOINT, &fPos, 0L},
+ {"Size", typLFLOAT, &size, 0L},
+ {"Org", typLFPOINT, &BarBase, 0L},
+ {"Line", typLINEDEF, &BarLine, 0L},
+ {"Fill", typFILLDEF, &BarFill, 0L},
+ {"FillLine", typLINEDEF, &HatchLine, 0L},
+ {"Name", typLAST | typTEXT, &name, 0L}};
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ type = BAR_VERTB;
+ memcpy(&BarFill, defs.GetFill(), sizeof(FillDEF));
+ if(BarFill.hatch) memcpy(&HatchLine, BarFill.hatch, sizeof(LineDEF));
+ BarFill.hatch = &HatchLine;
+ memcpy(&BarLine, defs.GetOutLine(), sizeof(LineDEF));
+ size = parent ? parent->GetSize(SIZE_BAR): defs.GetSize(SIZE_BAR);
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ BarFill.hatch = &HatchLine;
+ return true;
+ case FILE_WRITE:
+ return ExecOutput(Notary->RegisterGO(this), "Bar", Desc);
+ }
+ return false;
+}
+
+void
+DataLine::FileValues(char *name, int type, double start, double step)
+{
+ FILE *file;
+ int i, c;
+ double fx;
+ lfPOINT *tfp;
+
+ if(!(file = fopen(name, "r"))) {
+ sprintf(TmpTxt, "DataLine: open failed for file \"%s\"", name);
+ ErrorBox(TmpTxt);
+ return;
+ }
+ if(Values) free(Values);
+ if(!(Values = (lfPOINT*)calloc( nPnt = 1000, sizeof(lfPOINT)))){
+ fclose(file);
+ return;
+ }
+ switch(type) {
+ case 1: //x and y values
+ i = 0;
+ do {
+ c = fscanf(file, "%lf%lf", &Values[i].fx, &Values[i].fy);
+ i++;
+ if(i >= nPnt &&(tfp = (lfPOINT*)realloc(Values, (nPnt+1000)*sizeof(lfPOINT)))){
+ Values = tfp; nPnt += 1000;
+ }
+ else if(i >= nPnt) break;
+ }while(c == 2);
+ i--;
+ break;
+ case 2: //only y values
+ i = 0; fx = start;
+ do {
+ c = fscanf(file, "%lf", &Values[i].fy);
+ Values[i].fx = fx;
+ i++; fx += step;
+ if(i >= nPnt &&(tfp = (lfPOINT*)realloc(Values, (nPnt+1000)*sizeof(lfPOINT)))){
+ Values = tfp; nPnt += 1000;
+ }
+ }while(c == 1);
+ i--;
+ break;
+ }
+ nPntSet = i-1;
+ fclose(file);
+}
+
+bool
+DataLine::FileIO(int rw)
+{
+ long i;
+ char *file1 = 0L;
+ char *file2 = 0L;
+ double Start = 0.0f, Step = 0.0f;
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"ssXref", typTEXT, &ssXref, 0L},
+ {"ssYref", typTEXT, &ssYref, 0L},
+ {"BgCol", typDWORD, &BgColor, 0L},
+ {"Line", typLINEDEF, &LineDef, 0L},
+ {"Data", typFPLST, &Values, &i},
+ {"file_xy", typTEXT, &file2, 0L},
+ {"start_x", typNZLFLOAT, &Start, 0L},
+ {"step_x", typNZLFLOAT, &Step, 0L},
+ {"file_y", typLAST | typTEXT, &file1, 0L}};
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ isPolygon = false;
+ nPnt = nPntSet = cp = 0;
+ memcpy(&LineDef, defs.GetLine(), sizeof(LineDEF));
+ BgColor = defs.Color(COL_BG);
+ pts = 0L; dirty = true; mo = 0L;
+ mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
+ min.fx = min.fy = max.fx = max.fy = 0.0f;
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ nPnt = i;
+ nPntSet = i-1;
+ if(file2)FileValues(file2, 1, 0.0f, 1.0f);
+ else if(file1)FileValues(file1, 2, Start, fabs(Step) > defs.min4log ? Step : 1.0);
+ if(file1) free(file1);
+ if(file2) free(file2);
+ if(i && Values)return true;
+ break;
+ case FILE_WRITE:
+ i = nPntSet+1;
+ return ExecOutput(Notary->RegisterGO(this), "DataLine", Desc);
+ }
+ return false;
+}
+
+bool
+DataPolygon::FileIO(int rw)
+{
+ long i;
+ char *file1 = 0L;
+ char *file2 = 0L;
+ double Start = 0.0f, Step = 0.0f;
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"ssXref", typTEXT, &ssXref, 0L},
+ {"ssYref", typTEXT, &ssYref, 0L},
+ {"BgCol", typDWORD, &BgColor, 0L},
+ {"Line", typLINEDEF, &LineDef, 0L},
+ {"FillLine", typLINEDEF, &pgFillLine, 0L},
+ {"Fill", typFILLDEF, &pgFill, 0L},
+ {"Data", typFPLST, &Values, &i},
+ {"file_xy", typTEXT, &file2, 0L},
+ {"start_x", typNZLFLOAT, &Start, 0L},
+ {"step_x", typNZLFLOAT, &Step, 0L},
+ {"file_y", typLAST | typTEXT, &file1, 0L}};
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ isPolygon = true;
+ memcpy(&LineDef, defs.GetLine(), sizeof(LineDEF));
+ LineDef.pattern = 0L;
+ BgColor = defs.Color(COL_BG);
+ memcpy(&pgFill, defs.GetFill(), sizeof(FillDEF));
+ if(pgFill.hatch) memcpy(&pgFillLine, pgFill.hatch, sizeof(LineDEF));
+ pgFill.hatch = &pgFillLine; dirty = true; mo = 0L;
+ mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
+ min.fx = min.fy = max.fx = max.fy = 0.0f;
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ nPnt = i;
+ nPntSet = i-1;
+ if(file2)FileValues(file2, 1, 0.0f, 1.0f);
+ else if(file1)FileValues(file1, 2, Start, fabs(Step) > defs.min4log ? Step : 1.0);
+ if(file1) free(file1);
+ if(file2) free(file2);
+ pgFill.hatch = &pgFillLine;
+ if(i && Values)return true;
+ break;
+ case FILE_WRITE:
+ i = nPntSet+1;
+ return ExecOutput(Notary->RegisterGO(this), "DataPolygon", Desc);
+ }
+ return false;
+}
+
+bool
+RegLine::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"type", typNZINT, &type, 0L},
+ {"nPoints", typINT, &nPoints, 0L},
+ {"BgCol", typDWORD, &BgColor, 0L},
+ {"Line", typLINEDEF, &LineDef, 0L},
+ {"Range", typFRECT, &lim, 0L},
+ {"uClip", typFRECT, &uclip, 0L},
+ {"mx", typNZLFLOAT, &mx, 0L},
+ {"my", typNZLFLOAT, &my, 0L},
+ {"li1", typLFPOINT, &l1, 0L},
+ {"li2", typLFPOINT, &l2, 0L},
+ {"li3", typLFPOINT, &l3, 0L},
+ {"li4", typLFPOINT, &l4, 0L},
+ {"li5", typLAST | typLFPOINT, &l5, 0L}};
+
+ switch(rw) {
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ cp = 0;
+ memcpy(&LineDef, defs.GetLine(), sizeof(LineDEF));
+ BgColor = defs.Color(COL_BG);
+ pts = 0L;
+ return true;
+ case FILE_READ:
+ return ExecInput(Desc);
+ case FILE_WRITE:
+ return ExecOutput(Notary->RegisterGO(this), "RegLine", Desc);
+ }
+ return false;
+}
+
+void
+SDellipse::RegGO(void *n)
+{
+ if(n) {
+ if(rl)rl->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+SDellipse::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"type", typNZINT, &type, 0L},
+ {"Line", typLINEDEF, &LineDef, 0L},
+ {"Range", typFRECT, &lim, 0L},
+ {"Regr", typGOBJ, &rl, 0L},
+ {"Data", typLAST | typFPLST, &val, &nPoints}};
+
+ switch(rw) {
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ memcpy(&LineDef, defs.GetOutLine(), sizeof(LineDEF));
+ pts = 0L;
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ if(rl) rl->parent = this;
+ return true;
+ case FILE_WRITE:
+ if(rl) rl->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "SDellipse", Desc);
+ }
+ return false;
+}
+
+bool
+ErrorBar::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"ssRef", typIPLST, &ssRef, &cssRef},
+ {"Pos", typLFPOINT, &fPos, 0L},
+ {"Err", typLFLOAT, &ferr, 0L},
+ {"Size", typLFLOAT, &SizeBar, 0L},
+ {"Line", typLAST | typLINEDEF, &ErrLine, 0L}};
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ SizeBar = defs.GetSize(SIZE_ERRBAR);
+ ErrLine.width = defs.GetSize(SIZE_ERRBAR_LINE);
+ ErrLine.color = defs.Color(COL_SYM_LINE);
+ return true;
+ case FILE_READ:
+ return ExecInput(Desc);
+ case FILE_WRITE:
+ return ExecOutput(Notary->RegisterGO(this), "ErrorBar", Desc);
+ }
+ return false;
+}
+
+bool
+Arrow::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"ssRef", typIPLST, &ssRef, &cssRef},
+ {"moveable", typNZINT, &moveable, 0L},
+ {"p1", typLFPOINT, &pos1, 0L},
+ {"p2", typLFPOINT, &pos2, 0L},
+ {"CapW", typLFLOAT, &cw, 0L},
+ {"CapL", typLFLOAT, &cl, 0L},
+ {"Line", typLAST | typLINEDEF, &LineDef, 0L}};
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ cw = defs.GetSize(SIZE_ARROW_CAPWIDTH);
+ cl = defs.GetSize(SIZE_ARROW_CAPLENGTH);
+ LineDef.color = parent ? parent->GetColor(COL_DATA_LINE) : defs.Color(COL_DATA_LINE);
+ LineDef.width = parent ? parent->GetSize(SIZE_ARROW_LINE) : defs.GetSize(SIZE_ARROW_LINE);
+ type = ARROW_LINE;
+ dh1 = dh2 = 0L;
+ return true;
+ case FILE_READ:
+ return ExecInput(Desc);
+ case FILE_WRITE:
+ return ExecOutput(Notary->RegisterGO(this), "Arrow", Desc);
+ }
+ return false;
+}
+
+bool
+Box::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"ssRef", typIPLST, &ssRef, &cssRef},
+ {"High", typLFPOINT, &pos1, 0L},
+ {"Low", typLFPOINT, &pos2, 0L},
+ {"Size", typLFLOAT, &size, 0L},
+ {"Line", typLINEDEF, &Outline, 0L},
+ {"FillLine", typLINEDEF, &Hatchline, 0L},
+ {"Fill", typFILLDEF, &Fill, 0L},
+ {"Name", typLAST | typTEXT, &name, 0L}};
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ memcpy(&Outline, defs.GetOutLine(), sizeof(LineDEF));
+ memcpy(&Fill, defs.GetFill(), sizeof(FillDEF));
+ if(Fill.hatch)memcpy(&Hatchline, Fill.hatch, sizeof(LineDEF));
+ Fill.hatch = &Hatchline;
+ size = defs.GetSize(SIZE_BAR);
+ ssRef = 0L;
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ Fill.hatch = &Hatchline;
+ return true;
+ case FILE_WRITE:
+ return ExecOutput(Notary->RegisterGO(this), "Box", Desc);
+ }
+ return false;
+}
+
+bool
+Whisker::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"ssRef", typIPLST, &ssRef, &cssRef},
+ {"High", typLFPOINT, &pos1, 0L},
+ {"Low", typLFPOINT, &pos2, 0L},
+ {"Size", typLFLOAT, &size, 0L},
+ {"Line", typLAST | typLINEDEF, &LineDef, 0L}};
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ size = defs.GetSize(SIZE_WHISKER);
+ LineDef.width = defs.GetSize(SIZE_WHISKER_LINE);
+ LineDef.color = defs.Color(COL_WHISKER);
+ return true;
+ case FILE_READ:
+ return ExecInput(Desc);
+ case FILE_WRITE:
+ return ExecOutput(Notary->RegisterGO(this), "Whisker", Desc);
+ }
+ return false;
+}
+
+bool
+DropLine::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typINT, &type, 0L},
+ {"ssRef", typIPLST, &ssRef, &cssRef},
+ {"Pos", typLFPOINT, &fPos, 0L},
+ {"Line", typLAST | typLINEDEF, &LineDef, 0L}};
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ LineDef.color = defs.Color(COL_SYM_LINE);
+ return true;
+ case FILE_READ:
+ return ExecInput(Desc);
+ case FILE_WRITE:
+ return ExecOutput(Notary->RegisterGO(this), "DropLine", Desc);
+ }
+ return false;
+}
+
+bool
+Sphere::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"Line", typLINEDEF, &Line, 0L},
+ {"Fill", typFILLDEF, &Fill, 0L},
+ {"Pos", typPOINT3D, &fPos, 0L},
+ {"Size", typLFLOAT, &size, 0L},
+ {"ssRef", typLAST | typIPLST, &ssRef, &cssRef}};
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ size = defs.GetSize(SIZE_SYMBOL);
+ Line.color = defs.Color(COL_SYM_LINE);
+ Line.width = defs.GetSize(SIZE_SYM_LINE);
+ Fill.color = defs.Color(COL_SYM_FILL);
+ scl = 0L; nscl = 0;
+ return true;
+ case FILE_READ:
+ return ExecInput(Desc);
+ case FILE_WRITE:
+ return ExecOutput(Notary->RegisterGO(this), "Sphere", Desc);
+ }
+ return false;
+}
+
+bool
+Plane3D::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Line", typLINEDEF, &Line, 0L},
+ {"Fill", typFILLDEF, &Fill, 0L},
+ {"values", typLAST | typFPLST3D, &dt, &ndt}};
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ ipl = 0L; pts = 0L;
+ return true;
+ case FILE_READ:
+ return ExecInput(Desc);
+ case FILE_WRITE:
+ return ExecOutput(Notary->RegisterGO(this), "Plane3D", Desc);
+ }
+ return false;
+}
+
+bool
+Brick::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Line", typLINEDEF, &Line, 0L},
+ {"Fill", typFILLDEF, &Fill, 0L},
+ {"Pos", typPOINT3D, &fPos, 0L},
+ {"depth", typLFLOAT, &depth, 0L},
+ {"width", typLFLOAT, &width, 0L},
+ {"height", typLFLOAT, &height, 0L},
+ {"flags", typDWORD, &flags, 0L},
+ {"ssRef", typLAST | typIPLST, &ssRef, &cssRef}};
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ Line.color = defs.Color(COL_SYM_LINE);
+ Line.width = defs.GetSize(SIZE_SYM_LINE);
+ Fill.color = defs.Color(COL_SYM_FILL);
+ faces = (plane**)calloc(6, sizeof(plane*));
+ mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
+ mo = 0L;
+ return true;
+ case FILE_READ:
+ return ExecInput(Desc);
+ case FILE_WRITE:
+ return ExecOutput(Notary->RegisterGO(this), "Brick", Desc);
+ }
+ return false;
+}
+
+bool
+DropLine3D::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typINT, &type, 0L},
+ {"Line", typLINEDEF, &Line, 0L},
+ {"Pos", typPOINT3D, &fPos, 0L},
+ {"ssRef", typLAST | typIPLST, &ssRef, &cssRef}};
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ Line.color = defs.Color(COL_SYM_LINE);
+ Line.width = defs.GetSize(SIZE_HAIRLINE); mo = 0L;
+ mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
+ ls[0] = ls[1] = ls[2] = ls[3] = ls[4] = ls[5] = 0L;
+ return true;
+ case FILE_READ:
+ return ExecInput(Desc);
+ case FILE_WRITE:
+ return ExecOutput(Notary->RegisterGO(this), "DropLine3D", Desc);
+ }
+ return false;
+}
+
+bool
+Arrow3D::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typINT, &type, 0L},
+ {"Line", typLINEDEF, &Line, 0L},
+ {"Org", typPOINT3D, &fPos1, 0L},
+ {"Pos", typPOINT3D, &fPos2, 0L},
+ {"CapW", typLFLOAT, &cw, 0L},
+ {"CapL", typLFLOAT, &cl, 0L},
+ {"ssRef", typLAST | typIPLST, &ssRef, &cssRef}};
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ cw = defs.GetSize(SIZE_ARROW_CAPWIDTH);
+ cl = defs.GetSize(SIZE_ARROW_CAPLENGTH);
+ Line.color = defs.Color(COL_ARROW);
+ Line.width = defs.GetSize(SIZE_ARROW_LINE);
+ ls[0] = ls[1] = ls[2] = 0L;
+ cap = 0L;
+ type = ARROW_LINE;
+ return true;
+ case FILE_READ:
+ return ExecInput(Desc);
+ case FILE_WRITE:
+ return ExecOutput(Notary->RegisterGO(this), "Arrow3D", Desc);
+ }
+ return false;
+}
+
+bool
+Line3D::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Line", typLINEDEF, &Line, 0L},
+ {"ssRefX", typTEXT, &x_range, 0L},
+ {"ssRefY", typTEXT, &y_range, 0L},
+ {"ssRefZ", typTEXT, &z_range, 0L},
+ {"values", typLAST | typFPLST3D, &values, &nPts}};
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ Line.color = defs.Color(COL_DATA_LINE);
+ Line.width = defs.GetSize(SIZE_DATA_LINE);
+ ls = 0L; pts = 0L; npts = 0L; mo=0L;
+ mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
+ min.fx = min.fy = min.fz = max.fx = max.fy = max.fz = 0.0;
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ if(nPts > 1) ls = (line_segment **)calloc(nPts-1, sizeof(line_segment*));
+ return true;
+ case FILE_WRITE:
+ return ExecOutput(Notary->RegisterGO(this), "Line3D", Desc);
+ }
+ return false;
+}
+
+bool
+Label::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"ssRef", typIPLST, &ssRef, &cssRef},
+ {"moveable", typNZINT, &moveable, 0L},
+ {"Pos", typNZLFPOINT, &fPos, 0L},
+ {"Dist", typNZLFPOINT, &fDist, 0L},
+ {"Flags", typDWORD, &flags, 0L},
+ {"TxtDef", typLAST | typTXTDEF, &TextDef, 0L}};
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ TextDef.ColTxt = 0x0L;
+ TextDef.ColBg = 0x00ffffffL;
+ TextDef.fSize = defs.GetSize(SIZE_TEXT);
+ TextDef.RotBL = TextDef.RotCHAR = 0.0;
+ TextDef.iSize = 0;
+ TextDef.Align = TXA_VTOP | TXA_HLEFT;
+ TextDef.Mode = TXM_TRANSPARENT;
+ TextDef.Style = TXS_NORMAL;
+ TextDef.Font = FONT_HELVETICA;
+ TextDef.text = 0L; bgcolor = 0x00ffffffL;
+ bgLine.width = 0.0; bgLine.patlength = 6.0;
+ bgLine.color = bgcolor; bgLine.pattern = 0L;
+ CursorPos = 0; defDisp = 0L; bBGvalid = bModified = false;
+ curr_z = 0.0; is3D = false; fmt_txt = 0L;
+ return true;
+ case FILE_READ:
+ return ExecInput(Desc);
+ case FILE_WRITE:
+ return ExecOutput(Notary->RegisterGO(this), "Label", Desc);
+ }
+ return false;
+}
+
+void
+mLabel::RegGO(void *n)
+{
+ int i;
+
+ if(n) {
+ if(Lines) for(i = 0; i < nLines; i++) if(Lines[i]) Lines[i]->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+mLabel::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"moveable", typNZINT, &moveable, 0L},
+ {"Pos", typNZLFPOINT, &fPos, 0L},
+ {"Dist", typNZLFPOINT, &fDist, 0L},
+ {"Flags", typDWORD, &flags, 0L},
+ {"TxtDef", typTXTDEF, &TextDef, 0L},
+ {"Lines", typLAST | typOBJLST, &Lines, &nLines}};
+ int i;
+
+ switch(rw) {
+ case SAVE_VARS:
+ //The lines inherit settings from this object.
+ //We need not save them in this context
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ TextDef.ColTxt = 0x0L;
+ TextDef.ColBg = 0x00ffffffL;
+ TextDef.fSize = defs.GetSize(SIZE_TEXT);
+ TextDef.RotBL = TextDef.RotCHAR = 0.0;
+ TextDef.iSize = 0;
+ TextDef.Align = TXA_VTOP | TXA_HLEFT;
+ TextDef.Mode = TXM_TRANSPARENT;
+ TextDef.Style = TXS_NORMAL;
+ TextDef.Font = FONT_HELVETICA;
+ TextDef.text = 0L;
+ undo_flags = 0L;
+ curr_z = 0.0; is3D = false;
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ if(Lines) for ( i = 0; i < nLines; i++)
+ if(Lines[i]) Lines[i]->parent = this;
+ return true;
+ case FILE_WRITE:
+ if(Lines) for ( i = 0; i < nLines; i++)
+ if(Lines[i]) Lines[i]->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "mLabel", Desc);
+ }
+ return false;
+}
+
+bool
+segment::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"moveable", typNZINT, &moveable, 0L},
+ {"cent", typLFPOINT, &fCent, 0L},
+ {"ri", typNZLFLOAT, &radius1, 0L},
+ {"ra", typLFLOAT, &radius2, 0L},
+ {"start", typLFLOAT, &angle1, 0L},
+ {"end", typLFLOAT, &angle2, 0L},
+ {"shout", typNZLFLOAT, &shift, 0L},
+ {"Line", typLINEDEF, &segLine, 0L},
+ {"FillLine", typLINEDEF, &segFillLine, 0L},
+ {"Fill", typLAST | typFILLDEF, &segFill, 0L}};
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ segLine.width = defs.GetSize(SIZE_SEGLINE);
+ pts = 0L; nPts = 0;
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ segFill.hatch = &segFillLine;
+ return true;
+ case FILE_WRITE:
+ return ExecOutput(Notary->RegisterGO(this), "segment", Desc);
+ }
+ return false;
+}
+
+bool
+polyline::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"moveable", typNZINT, &moveable, 0L},
+ {"Data", typFPLST, &Values, &nPoints},
+ {"Line", typLINEDEF, &pgLine, 0L},
+ {"FillLine", typLINEDEF, &pgFillLine, 0L},
+ {"Fill", typLAST | typFILLDEF, &pgFill, 0L}};
+
+ switch(rw) {
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ memcpy(&pgLine, defs.plLineDEF(0L), sizeof(LineDEF));
+ memcpy(&pgFill, defs.pgFillDEF(0L), sizeof(FillDEF));
+ if(pgFill.hatch) memcpy(&pgFillLine, pgFill.hatch, sizeof(LineDEF));
+ pgFill.hatch = &pgFillLine;
+ pts = 0L; nPts = 0;
+ pHandles = 0L;
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ pgFill.hatch = &pgFillLine;
+ return true;
+ case FILE_WRITE:
+ if(type != 1) Desc[3].type |= typLAST; //skip fill for polyline
+ return ExecOutput(Notary->RegisterGO(this),
+ type == 1 ? (char*)"polygon" : (char*)"polyline", Desc);
+ }
+ return false;
+}
+
+bool
+rectangle::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"moveable", typNZINT, &moveable, 0L},
+ {"p1", typLFPOINT, &fp1, 0L},
+ {"p2", typLFPOINT, &fp2, 0L},
+ {"Line", typLINEDEF, &Line, 0L},
+ {"FillLine", typLINEDEF, &FillLine, 0L},
+ {"Fill", typFILLDEF, &Fill, 0L},
+ {"Rad", typNZLFLOAT, &rad, 0L},
+ {"Name", typLAST | typTEXT, &name, 0L}};
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ memcpy(&Line, defs.pgLineDEF(0L), sizeof(LineDEF));
+ memcpy(&Fill, defs.pgFillDEF(0L), sizeof(FillDEF));
+ if(Fill.hatch) memcpy(&FillLine, Fill.hatch, sizeof(LineDEF));
+ Fill.hatch = &FillLine;
+ pts = 0L; nPts = 0L;
+ rad = defs.GetSize(SIZE_RRECT_RAD);
+ drc = 0L;
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ Fill.hatch = &FillLine;
+ return true;
+ case FILE_WRITE:
+ if(type != 2) rad = 0.0;
+ ExecOutput(Notary->RegisterGO(this),
+ type == 1? (char*)"ellipse" : type == 2? (char*)"roundrec" :
+ (char*)"rectangle", Desc);
+ return true;
+ }
+ return false;
+}
+
+void
+LegItem::RegGO(void *n)
+{
+ if(n) {
+ if(Sym) Sym->RegGO(n);
+ if(Desc) Desc->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+LegItem::FileIO(int rw)
+{
+ descIO Des[] = {
+ {"D_Line", typLINEDEF, &DataLine, 0L},
+ {"O_Line", typLINEDEF, &OutLine, 0L},
+ {"H_Line", typLINEDEF, &HatchLine, 0L},
+ {"Fill", typFILLDEF, &Fill, 0L},
+ {"Sym", typGOBJ, &Sym, 0L},
+ {"Text", typGOBJ, &Desc, 0L},
+ {"flags", typLAST | typDWORD, &flags, 0L}};
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Des);
+ case INIT_VARS:
+ InitVarsGO(Des);
+ Fill.hatch = &HatchLine;
+ return true;
+ case FILE_READ:
+ ExecInput(Des);
+ Fill.hatch = &HatchLine;
+ if(Sym) Sym->parent=this;
+ if(Desc) Desc->parent=this;
+ return true;
+ case FILE_WRITE:
+ if(Sym) Sym->FileIO(rw);
+ if(Desc) Desc->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "LegItem", Des);
+ }
+ return false;
+}
+
+void
+Legend::RegGO(void *n)
+{
+ int i;
+
+ if(n) {
+ if(Items) for(i = 0; i < nItems; i++) if(Items[i]) Items[i]->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+Legend::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"pos", typLFPOINT, &pos, 0L},
+ {"rec1", typFRECT, &B_Rect, 0L},
+ {"rec2", typFRECT, &D_Rect, 0L},
+ {"rec3", typFRECT, &F_Rect, 0L},
+ {"Items", typLAST | typOBJLST, &Items, &nItems}};
+ int i;
+ double d;
+
+ switch(rw) {
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ B_Rect.Ymin = defs.GetSize(SIZE_DRECT_TOP);
+ B_Rect.Xmin = defs.GetSize(SIZE_DRECT_LEFT);
+ B_Rect.Xmax = B_Rect.Xmin + 1.5*(d = defs.GetSize(SIZE_BAR));
+ B_Rect.Ymin += d*0.2;
+ B_Rect.Ymax = B_Rect.Ymin + d/2.0;
+ D_Rect.Ymin = 0.0; D_Rect.Xmin = d*0.7;
+ D_Rect.Xmax = d*1.3; D_Rect.Ymax = d*0.4;
+ F_Rect.Ymin = 0.0; F_Rect.Xmin = d*0.2;
+ F_Rect.Xmax = d*1.3; F_Rect.Ymax = d*0.4;
+ to = 0L;
+ trc.left = trc.right = trc.top = trc.bottom = 0;
+ if(!name) name=strdup("Legend");
+ return true;
+ case FILE_READ:
+ nItems = 0L;
+ ExecInput(Desc);
+ if(Items) for(i = 0; i < nItems; i++) if(Items[i]) Items[i]->parent=this;
+ return true;
+ case FILE_WRITE:
+ if(Items) for(i = 0; i < nItems; i++) if(Items[i]) Items[i]->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "Legend", Desc);
+ }
+ return false;
+}
+
+void
+PlotScatt::RegGO(void *n)
+{
+ int i;
+
+ if(n) {
+ if(TheLine) TheLine->RegGO(n);
+ if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->RegGO(n);
+ if(Errors) for(i = 0; i < nPoints; i++) if(Errors[i]) Errors[i]->RegGO(n);
+ if(Arrows) for(i = 0; i < nPoints; i++) if(Arrows[i]) Arrows[i]->RegGO(n);
+ if(DropLines) for(i = 0; i < nPoints; i++) if(DropLines[i]) DropLines[i]->RegGO(n);
+ if(Labels) for(i = 0; i < nPoints; i++) if(Labels[i]) Labels[i]->RegGO(n);
+ if(Bars) for(i = 0; i < nPoints; i++) if(Bars[i]) Bars[i]->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+PlotScatt::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Bounds", typFRECT, &Bounds, 0L},
+ {"DefSym", typNZINT, &DefSym, 0L},
+ {"baDist", typLFPOINT, &BarDist, 0L},
+ {"xRange", typTEXT, &xRange, 0L},
+ {"yRange", typTEXT, &yRange, 0L},
+ {"eRange", typTEXT, &ErrRange, 0L},
+ {"lRange", typTEXT, &LbRange, 0L},
+ {"x_axis", typNZINT, &use_xaxis, 0L},
+ {"y_axis", typNZINT, &use_yaxis, 0L},
+ {"Bars", typOBJLST, &Bars, &nPoints},
+ {"Symbols", typOBJLST, &Symbols, &nPoints},
+ {"PL", typGOBJ, &TheLine, 0L},
+ {"ErrBars", typOBJLST, &Errors, &nPoints},
+ {"Arrows", typOBJLST, &Arrows, &nPoints},
+ {"dLines", typOBJLST, &DropLines, &nPoints},
+ {"Labels", typLAST | typOBJLST, &Labels, &nPoints}};
+ int i;
+
+ switch(rw) {
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ DefSym = SYM_CIRCLE;
+ DefSel = 0x01;
+ dirty = true;
+ if(name) {
+ sprintf(TmpTxt, "xy-plot (%s)", name);
+ free(name); name=strdup(TmpTxt);
+ }
+ return true;
+ case FILE_READ:
+ nPoints = 0L;
+ ExecInput(Desc);
+ ForEach(FE_PARENT, 0L, 0L);
+ return true;
+ case FILE_WRITE:
+ if(TheLine) TheLine->FileIO(rw);
+ if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->FileIO(rw);
+ if(Errors) for(i = 0; i < nPoints; i++) if(Errors[i]) Errors[i]->FileIO(rw);
+ if(Arrows) for(i = 0; i < nPoints; i++) if(Arrows[i]) Arrows[i]->FileIO(rw);
+ if(DropLines) for(i = 0; i < nPoints; i++) if(DropLines[i]) DropLines[i]->FileIO(rw);
+ if(Labels) for(i = 0; i < nPoints; i++) if(Labels[i]) Labels[i]->FileIO(rw);
+ if(Bars) for(i = 0; i < nPoints; i++) if(Bars[i]) Bars[i]->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "PlotScatt", Desc);
+ }
+ return false;
+}
+
+void
+FreqDist::RegGO(void *n)
+{
+ int i;
+
+ if(n) {
+ if(plots) for(i = 0; i < nPlots; i++) if(plots[i]) plots[i]->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+FreqDist::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"ssRef", typTEXT, &ssRef, 0L},
+ {"x_axis", typNZINT, &use_xaxis, 0L},
+ {"y_axis", typNZINT, &use_yaxis, 0L},
+ {"cl_start", typNZLFLOAT, &start, 0L},
+ {"cl_size", typLFLOAT, &step, 0L},
+ {"BarLine", typLINEDEF, &BarLine, 0L},
+ {"BarFill", typFILLDEF, &BarFill, 0L},
+ {"BarFillLine", typLINEDEF, &HatchLine, 0L},
+ {"plots", typLAST | typOBJLST, &plots, &nPlots}};
+ int i;
+
+ switch(rw) {
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ memcpy(&BarFill, defs.GetFill(), sizeof(FillDEF));
+ BarFill.color = 0x00c0ffffL;
+ if(BarFill.hatch) memcpy(&HatchLine, BarFill.hatch, sizeof(LineDEF));
+ BarFill.hatch = &HatchLine;
+ memcpy(&BarLine, defs.GetOutLine(), sizeof(LineDEF));
+ curr_data=0L;
+ dirty = true;
+ if(name) {
+ sprintf(TmpTxt, "freq. dist. (%s)", name);
+ free(name); name=strdup(TmpTxt);
+ }
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ if(plots) for(i = 0; i < nPlots; i++) if(plots[i]) plots[i]->parent=this;
+ return true;
+ case FILE_WRITE:
+ if(plots) for(i = 0; i < nPlots; i++) if(plots[i]) plots[i]->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "FreqDist", Desc);
+ }
+ return false;
+}
+
+void
+Regression::RegGO(void *n)
+{
+ int i;
+
+ if(n) {
+ if(rLine) rLine->RegGO(n);
+ if(sde) sde->RegGO(n);
+ if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+Regression::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"Bounds", typFRECT, &Bounds, 0L},
+ {"xRange", typTEXT, &xRange, 0L},
+ {"yRange", typTEXT, &yRange, 0L},
+ {"x_axis", typNZINT, &use_xaxis, 0L},
+ {"y_axis", typNZINT, &use_yaxis, 0L},
+ {"Line", typGOBJ, &rLine, 0L},
+ {"Ellipse", typGOBJ, &sde, 0L},
+ {"Symbols", typLAST | typOBJLST, &Symbols, &nPoints}};
+ int i;
+
+ switch(rw) {
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ dirty = true;
+ if(name) {
+ sprintf(TmpTxt, "regression (%s)", name);
+ free(name); name=strdup(TmpTxt);
+ }
+ return true;
+ case FILE_READ:
+ nPoints = 0L;
+ return ExecInput(Desc);
+ case FILE_WRITE:
+ if(rLine) rLine->FileIO(rw);
+ if(sde) sde->FileIO(rw);
+ if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "Regression", Desc);
+ }
+ return false;
+}
+
+void
+BubblePlot::RegGO(void *n)
+{
+ int i;
+
+ if(n) {
+ if(Bubbles) for(i = 0; i < nPoints; i++) if(Bubbles[i]) Bubbles[i]->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+BubblePlot::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Bounds", typFRECT, &Bounds, 0L},
+ {"x_axis", typNZINT, &use_xaxis, 0L},
+ {"y_axis", typNZINT, &use_yaxis, 0L},
+ {"Line", typLINEDEF, &BubbleLine, 0L},
+ {"FillLine", typLINEDEF, &BubbleFillLine, 0L},
+ {"Fill", typFILLDEF, &BubbleFill, 0L},
+ {"Bubbles", typLAST | typOBJLST, &Bubbles, &nPoints}};
+ int i;
+
+ switch(rw) {
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ BubbleFill.color = defs.Color(COL_BUBBLE_FILL);
+ BubbleLine.color = defs.Color(COL_BUBBLE_LINE);
+ BubbleLine.width = defs.GetSize(SIZE_BUBBLE_LINE);
+ BubbleFillLine.color = defs.Color(COL_BUBBLE_FILLLINE);
+ BubbleFillLine.width = defs.GetSize(SIZE_BUBBLE_HATCH_LINE);
+ BubbleFill.hatch = &BubbleFillLine;
+ dirty = true;
+ if(name) {
+ sprintf(TmpTxt, "bubbles (%s)", name);
+ free(name); name=strdup(TmpTxt);
+ }
+ return true;
+ case FILE_READ:
+ return ExecInput(Desc);
+ case FILE_WRITE:
+ if(Bubbles) for(i = 0; i < nPoints; i++) if(Bubbles[i]) Bubbles[i]->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "BubblePlot", Desc);
+ }
+ return false;
+}
+
+void
+PolarPlot::RegGO(void *n)
+{
+ int i;
+
+ if(n) {
+ if(Plots) for(i = 0; i < nPlots; i++) if(Plots[i]) Plots[i]->RegGO(n);
+ if(Axes) for(i = 0; i < nAxes; i++) if(Axes[i]) Axes[i]->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+PolarPlot::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"Bounds", typFRECT, &Bounds, 0L},
+ {"ang_offs", typLFLOAT, &offs, 0L},
+ {"Plots", typOBJLST, &Plots, (long*)&nPlots},
+ {"Axes", typOBJLST, &Axes, (long*)&nAxes},
+ {"FillLine", typLINEDEF, &FillLine, 0L},
+ {"Fill", typLAST | typFILLDEF, &Fill, 0L}};
+ int i;
+
+ switch(rw) {
+ case INIT_VARS:
+ CurrDisp = 0L;
+ InitVarsGO(Desc);
+ if(name) {
+ sprintf(TmpTxt, "polar root (%s)", name);
+ free(name); name=strdup(TmpTxt);
+ }
+ return true;
+ case FILE_READ:
+ return ExecInput(Desc);
+ case FILE_WRITE:
+ if(Plots) for(i = 0; i < nPlots; i++) if(Plots[i]) Plots[i]->FileIO(rw);
+ if(Axes) for(i = 0; i < nAxes; i++) if(Axes[i]) Axes[i]->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "PolarPlot", Desc);
+ }
+ return false;
+}
+
+void
+BoxPlot::RegGO(void *n)
+{
+ int i;
+
+ if(n) {
+ if(Boxes) for(i = 0; i < nPoints; i++) if(Boxes[i]) Boxes[i]->RegGO(n);
+ if(Whiskers) for(i = 0; i < nPoints; i++) if(Whiskers[i]) Whiskers[i]->RegGO(n);
+ if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->RegGO(n);
+ if(TheLine) TheLine->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+BoxPlot::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Bounds", typFRECT, &Bounds, 0L},
+ {"boDist", typLFPOINT, &BoxDist, 0L},
+ {"x_axis", typNZINT, &use_xaxis, 0L},
+ {"y_axis", typNZINT, &use_yaxis, 0L},
+ {"Boxes", typOBJLST, &Boxes, &nPoints},
+ {"Whiskers", typOBJLST, &Whiskers, &nPoints},
+ {"Symbols", typOBJLST, &Symbols, &nPoints},
+ {"Line", typLAST | typGOBJ, &TheLine, 0L}};
+ int i;
+
+ switch(rw) {
+ case INIT_VARS:
+ dirty = true;
+ InitVarsGO(Desc);
+ if(name) {
+ sprintf(TmpTxt, "boxes (%s)", name);
+ free(name); name=strdup(TmpTxt);
+ }
+ return true;
+ case FILE_READ:
+ return ExecInput(Desc);
+ case FILE_WRITE:
+ if(Boxes) for(i = 0; i < nPoints; i++)
+ if(Boxes[i]) Boxes[i]->FileIO(rw);
+ if(Whiskers) for(i = 0; i < nPoints; i++)
+ if(Whiskers[i]) Whiskers[i]->FileIO(rw);
+ if(Symbols) for(i = 0; i < nPoints; i++)
+ if(Symbols[i]) Symbols[i]->FileIO(rw);
+ if(TheLine) TheLine->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "BoxPlot", Desc);
+ }
+ return false;
+}
+
+void
+DensDisp::RegGO(void *n)
+{
+ int i;
+
+ if(n) {
+ if(Boxes) for(i = 0; i < nPoints; i++) if(Boxes[i]) Boxes[i]->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+DensDisp::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"Bounds", typFRECT, &Bounds, 0L},
+ {"xRange", typTEXT, &xRange, 0L},
+ {"yRange", typTEXT, &yRange, 0L},
+ {"x_axis", typNZINT, &use_xaxis, 0L},
+ {"y_axis", typNZINT, &use_yaxis, 0L},
+ {"Line", typLINEDEF, &DefLine, 0L},
+ {"FillLine", typLINEDEF, &DefFillLine, 0L},
+ {"Fill", typFILLDEF, &DefFill, 0L},
+ {"Boxes", typLAST | typOBJLST, &Boxes, &nPoints}};
+ int i;
+
+ switch(rw) {
+ case INIT_VARS:
+ return InitVarsGO(Desc);
+ case FILE_READ:
+ return ExecInput(Desc);
+ case FILE_WRITE:
+ if(Boxes) for(i = 0; i < nPoints; i++) if(Boxes[i]) Boxes[i]->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "DensDisp", Desc);
+ }
+ return false;
+}
+
+void
+StackBar::RegGO(void *n)
+{
+ int i;
+
+ if(n) {
+ if(Boxes) for(i = 0; i < numPlots; i++) if(Boxes[i]) Boxes[i]->RegGO(n);
+ if(xyPlots) for(i = 0; i < numXY; i++) if(xyPlots[i]) xyPlots[i]->RegGO(n);
+ if(Polygons) for(i = 0; i < numPG; i++) if(Polygons[i]) Polygons[i]->RegGO(n);
+ if(Lines) for(i = 0; i < numPL; i++) if(Lines[i]) Lines[i]->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+StackBar::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Bounds", typFRECT, &Bounds, 0L},
+ {"x_axis", typNZINT, &use_xaxis, 0L},
+ {"y_axis", typNZINT, &use_yaxis, 0L},
+ {"cumData", typNZINT, &cum_data_mode, 0L},
+ {"StartVal", typNZLFLOAT, &StartVal, 0L},
+ {"Dspm", typNZLFPOINT, &dspm, 0L},
+ {"ssXrange", typTEXT, &ssXrange, 0L},
+ {"ssYrange", typTEXT, &ssYrange, 0L},
+ {"BoxBars", typOBJLST, &Boxes, (long*)&numPlots},
+ {"Plots", typOBJLST, &xyPlots, (long*)&numXY},
+ {"Polygons", typOBJLST, &Polygons, (long*)&numPG},
+ {"Lines", typLAST | typOBJLST, &Lines, (long*)&numPL}};
+ int i;
+
+ switch(rw) {
+ case INIT_VARS:
+ dirty = true; CumData = 0L;
+ InitVarsGO(Desc);
+ if(name) {
+ sprintf(TmpTxt, "stack (%s)", name);
+ free(name); name=strdup(TmpTxt);
+ }
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ return true;
+ case FILE_WRITE:
+ if(Boxes) for(i = 0; i < numPlots; i++) if(Boxes[i]) Boxes[i]->FileIO(rw);
+ if(xyPlots) for(i = 0; i < numXY; i++) if(xyPlots[i]) xyPlots[i]->FileIO(rw);
+ if(Polygons) for(i = 0; i < numPG; i++) if(Polygons[i]) Polygons[i]->FileIO(rw);
+ if(Lines) for(i = 0; i < numPL; i++) if(Lines[i]) Lines[i]->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "Stacked", Desc);
+ }
+ return false;
+}
+
+void
+PieChart::RegGO(void *n)
+{
+ int i;
+
+ if(n) {
+ if(Segments) for(i = 0; i < nPts; i++) if(Segments[i]) Segments[i]->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+PieChart::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"ssRefA", typTEXT, &ssRefA, 0L},
+ {"ssRefR", typTEXT, &ssRefR, 0L},
+ {"CtDef", typLFPOINT, &CtDef, 0L},
+ {"FacRad", typLFLOAT, &FacRad, 0L},
+ {"Segs", typLAST | typOBJLST, &Segments, (long*)&nPts}};
+ int i;
+
+ switch(rw) {
+ case INIT_VARS:
+ Bounds.Xmax = Bounds.Ymax = 100.0f;
+ Bounds.Xmin = Bounds.Ymin = -100.0f;
+ InitVarsGO(Desc);
+ CtDef.fx = 90.0; CtDef.fy = 360.0;
+ FacRad = 1.0;
+ if(name) {
+ sprintf(TmpTxt, "pie chart (%s)", name);
+ free(name); name=strdup(TmpTxt);
+ }
+ return true;
+ case FILE_READ:
+ return ExecInput(Desc);
+ case FILE_WRITE:
+ if(Segments) for(i = 0; i < nPts; i++) if(Segments[i]) Segments[i]->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "SegChart", Desc);
+ }
+ return false;
+}
+
+void
+GoGroup::RegGO(void *n)
+{
+ int i;
+
+ if(n) {
+ if(Objects) for(i = 0; i < nObs; i++) if(Objects[i]) Objects[i]->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+GoGroup::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Pos", typNZLFPOINT, &fPos, 0L},
+ {"Items", typLAST | typOBJLST, &Objects, (long*)&nObs}};
+ int i;
+
+ switch(rw) {
+ case INIT_VARS:
+ Bounds.Xmax = Bounds.Ymax = 100.0f;
+ Bounds.Xmin = Bounds.Ymin = -100.0f;
+ return InitVarsGO(Desc);
+ case FILE_READ:
+ return ExecInput(Desc);
+ case FILE_WRITE:
+ if(Objects) for(i = 0; i < nObs; i++) if(Objects[i]) Objects[i]->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "group", Desc);
+ }
+ return false;
+}
+
+void
+Scatt3D::RegGO(void *n)
+{
+ int i;
+
+ if(n) {
+ if(Line) Line->RegGO(n);
+ if(rib) rib->RegGO(n);
+ if(Balls) for(i = 0; i < nBalls; i++) if(Balls[i]) Balls[i]->RegGO(n);
+ if(Columns) for(i = 0; i < nColumns; i++) if(Columns[i]) Columns[i]->RegGO(n);
+ if(DropLines) for(i = 0; i < nDropLines; i++) if(DropLines[i]) DropLines[i]->RegGO(n);
+ if(Arrows) for(i = 0; i < nArrows; i++) if(Arrows[i]) Arrows[i]->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+Scatt3D::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"ssRefX", typTEXT, &ssRefX, 0L},
+ {"ssRefY", typTEXT, &ssRefY, 0L},
+ {"ssRefZ", typTEXT, &ssRefZ, 0L},
+ {"Line", typGOBJ, &Line, 0L},
+ {"Balls", typOBJLST, &Balls, &nBalls},
+ {"Columns", typOBJLST, &Columns, &nColumns},
+ {"DropLines", typOBJLST, &DropLines, &nDropLines},
+ {"ParaV", typGOBJ, &rib, 0L},
+ {"Arrows", typLAST | typOBJLST, &Arrows, &nArrows}};
+ int i;
+
+ switch(rw) {
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ c_flags = 0L;
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
+ xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
+ dirty = true;
+ if(name) {
+ sprintf(TmpTxt, "xyz-plot (%s)", name);
+ free(name); name=strdup(TmpTxt);
+ }
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ //now set parent in all children
+ if(Balls) for(i = 0; i < nBalls; i++) if(Balls[i]) Balls[i]->parent = this;
+ if(Columns) for(i = 0; i < nColumns; i++) if(Columns[i]) Columns[i]->parent = this;
+ if(DropLines) for(i = 0; i < nDropLines; i++) if(DropLines[i]) DropLines[i]->parent = this;
+ if(Arrows) for(i = 0; i < nArrows; i++) if(Arrows[i]) Arrows[i]->parent = this;
+ if(Line) Line->parent = this;
+ if(rib) rib->parent = this;
+ return true;
+ case FILE_WRITE:
+ if(Line) Line->FileIO(rw);
+ if(rib) rib->FileIO(rw);
+ if(Balls) for(i = 0; i < nBalls; i++) if(Balls[i]) Balls[i]->FileIO(rw);
+ if(Columns) for(i = 0; i < nColumns; i++) if(Columns[i]) Columns[i]->FileIO(rw);
+ if(DropLines) for(i = 0; i < nDropLines; i++) if(DropLines[i]) DropLines[i]->FileIO(rw);
+ if(Arrows) for(i = 0; i < nArrows; i++) if(Arrows[i]) Arrows[i]->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "Scatt3D", Desc);
+ }
+ return false;
+}
+
+void
+Ribbon::RegGO(void *n)
+{
+ int i;
+
+ if(n) {
+ if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+Ribbon::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"z-pos", typNZLFLOAT, &z_value},
+ {"z-width", typNZLFLOAT, &z_width},
+ {"relwidth", typNZLFLOAT, &relwidth},
+ {"ssRefX", typTEXT, &ssRefX, 0L},
+ {"ssRefY", typTEXT, &ssRefY, 0L},
+ {"ssRefZ", typTEXT, &ssRefZ, 0L},
+ {"Line", typLINEDEF, &Line, 0L},
+ {"Fill", typFILLDEF, &Fill, 0L},
+ {"values", typFPLST3D, &values, &nVal},
+ {"Planes", typLAST | typOBJLST, &planes, &nPlanes}};
+ int i;
+
+ switch(rw) {
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
+ xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
+ relwidth = 0.6; dirty = true;
+ if(name) {
+ sprintf(TmpTxt, "ribbon (%s)", name);
+ free(name); name=strdup(TmpTxt);
+ }
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ //now set parent in all children
+ if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->parent = this;
+ return true;
+ case FILE_WRITE:
+ if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "Ribbon", Desc);
+ }
+ return false;
+}
+
+void
+Grid3D::RegGO(void *n)
+{
+ int i;
+
+ if(n) {
+ if(lines) for(i = 0; i < nLines; i++) if(lines[i]) lines[i]->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+Grid3D::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"Start", typPOINT3D, &start, 0L},
+ {"Step", typPOINT3D, &step, 0L},
+ {"Line", typLINEDEF, &Line, 0L},
+ {"lines", typLAST | typOBJLST, &lines, &nLines}};
+ int i;
+
+ switch(rw) {
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
+ xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
+ step.fx = step.fz = 1.0;
+ if(name) {
+ sprintf(TmpTxt, "grid (%s)", name);
+ free(name); name=strdup(TmpTxt);
+ }
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ //now set parent in all children
+ if(lines) for(i = 0; i < nLines; i++) if(lines[i]) lines[i]->parent = this;
+ return true;
+ case FILE_WRITE:
+ if(lines) for(i = 0; i < nLines; i++) if(lines[i]) lines[i]->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "Grid3D", Desc);
+ }
+ return false;
+}
+
+bool
+Limits::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Bounds", typLAST | typFRECT, &Bounds, 0L}};
+
+ switch(rw) {
+ case INIT_VARS:
+ if(name) {
+ sprintf(TmpTxt, "limits (%s)", name);
+ free(name); name=strdup(TmpTxt);
+ }
+ return true;
+ case FILE_READ:
+ return ExecInput(Desc);
+ case FILE_WRITE:
+ return ExecOutput(Notary->RegisterGO(this), "Limits", Desc);
+ }
+ return false;
+}
+
+void
+Function::RegGO(void *n)
+{
+ if(n) {
+ if(dl)dl->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+Function::FileIO(int rw)
+{
+ char *tmp_cmdxy = 0L, *tmp_param = 0L;
+ descIO Desc[] = {
+ {"x1", typNZLFLOAT, &x1, 0L},
+ {"x2", typNZLFLOAT, &x2, 0L},
+ {"xstep", typNZLFLOAT, &xstep, 0L},
+ {"Line", typLINEDEF, &Line, 0L},
+ {"f_xy", typTEXT, &tmp_cmdxy, 0L},
+ {"param", typTEXT, &tmp_param, 0L},
+ {"DataLine", typLAST | typGOBJ, &dl, 0L}};
+ int i, j;
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ cmdxy = param = 0L;
+ memcpy(&Line, defs.GetLine(), sizeof(LineDEF));
+ if(name) {
+ sprintf(TmpTxt, "function (%s)", name);
+ free(name); name=strdup(TmpTxt);
+ }
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ if(tmp_cmdxy && tmp_cmdxy[0]) cmdxy = tmp_cmdxy;
+ if(tmp_param && tmp_param[0]) param = tmp_param;
+ if(dl) dl->parent = this;
+ return true;
+ case FILE_WRITE:
+ if(dl) dl->FileIO(rw);
+ if(cmdxy) {
+ for(i = j = 0; cmdxy[i]; i++) {
+ if(cmdxy[i] == '\n') j += sprintf(TmpTxt+j, "\\n");
+ else TmpTxt[j++] = cmdxy[i];
+ }
+ TmpTxt[j] = 0;
+ if(i) tmp_cmdxy = strdup(TmpTxt);
+ }
+ if(param) {
+ for(i = j = 0; param[i]; i++) {
+ if(param[i] == '\n') j += sprintf(TmpTxt+j, "\\n");
+ else TmpTxt[j++] = param[i];
+ }
+ TmpTxt[j] = 0;
+ if(i) tmp_param = strdup(TmpTxt);
+ }
+ ExecOutput(Notary->RegisterGO(this), "Function", Desc);
+ if(tmp_cmdxy) free(tmp_cmdxy);
+ if(tmp_param) free(tmp_param);
+ }
+ return false;
+}
+
+void
+FitFunc::RegGO(void *n)
+{
+ int i;
+
+ if(n) {
+ if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+FitFunc::FileIO(int rw)
+{
+ char *tmp_cmdxy = 0L, *tmp_parxy = 0L;
+ descIO Desc[] = {
+ {"ssXref", typTEXT, &ssXref, 0L},
+ {"ssYref", typTEXT, &ssYref, 0L},
+ {"x1", typNZLFLOAT, &x1, 0L},
+ {"x2", typNZLFLOAT, &x2, 0L},
+ {"xstep", typNZLFLOAT, &xstep, 0L},
+ {"conv", typNZLFLOAT, &conv, 0L},
+ {"chi2", typNZLFLOAT, &chi2, 0L},
+ {"maxiter", typNZINT, &maxiter, 0L},
+ {"Line", typLINEDEF, &Line, 0L},
+ {"f_xy", typTEXT, &tmp_cmdxy, 0L},
+ {"p_xy", typTEXT, &tmp_parxy, 0L},
+ {"Symbols", typLAST | typOBJLST, &Symbols, &nPoints}};
+ int i, j;
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ cmdxy = parxy = 0L;
+ memcpy(&Line, defs.GetLine(), sizeof(LineDEF));
+ conv = 1.0e-15; maxiter = 100;
+ dl = 0L;
+ if(name) {
+ sprintf(TmpTxt, "fit function (%s)", name);
+ free(name); name=strdup(TmpTxt);
+ }
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ if(tmp_cmdxy && tmp_cmdxy[0]) cmdxy = tmp_cmdxy;
+ if(tmp_parxy && tmp_parxy[0]) parxy = tmp_parxy;
+ if(Symbols) for(i = 0; i < nPoints; i++)
+ if(Symbols[i]) Symbols[i]->parent = this;
+ return true;
+ case FILE_WRITE:
+ if(cmdxy) {
+ for(i = j = 0; cmdxy[i]; i++) {
+ if(cmdxy[i] == '\n') j += sprintf(TmpTxt+j, "\\n");
+ else TmpTxt[j++] = cmdxy[i];
+ }
+ TmpTxt[j] = 0;
+ if(i) tmp_cmdxy = strdup(TmpTxt);
+ }
+ if(parxy) {
+ for(i = j = 0; parxy[i]; i++) {
+ if(parxy[i] == '\n') j += sprintf(TmpTxt+j, "\\n");
+ else TmpTxt[j++] = parxy[i];
+ }
+ TmpTxt[j] = 0;
+ if(i) tmp_parxy = strdup(TmpTxt);
+ }
+ if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "FitFunc", Desc);
+ }
+ return false;
+}
+
+bool
+GridLine::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"Line", typLINEDEF, &LineDef, 0L},
+ {"flags", typLAST | typDWORD, &flags, 0L}};
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ ncpts = 0; cpts = 0L; gl1 = gl2 = gl3 = 0L; ls = 0L;
+ mrc.left = mrc.right = mrc.top = mrc.bottom = 0; mo = 0L;
+ return true;
+ case FILE_READ:
+ return ExecInput(Desc);
+ case FILE_WRITE:
+ return ExecOutput(Notary->RegisterGO(this),
+ Id == GO_GRIDLINE ?(char*)"GridLine" :
+ Id == GO_GRIDRADIAL? (char*)"GridRadial" : (char*)"GridLine3D", Desc);
+ }
+ return false;
+}
+
+void
+Tick::RegGO(void *n)
+{
+ if(n) {
+ if(Grid && (flags & AXIS_GRIDLINE)) Grid->RegGO(n);
+ if(label) label->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+Tick::FileIO(int rw)
+{
+ GraphObj *gl = Grid;
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"Val", typLFLOAT, &value, 0L},
+ {"Flags", typDWORD, &flags, 0L},
+ {"Rot", typNZLFLOAT, &angle, 0L},
+ {"GridType", typINT, &gl_type, 0L},
+ {"Grid", typGOBJ, &gl, 0L},
+ {"Label", typGOBJ, &label, 0L},
+ {"Size", typLAST | typLFLOAT, &size, 0L}};
+
+ switch(rw) {
+ case SAVE_VARS:
+ if(Grid && (flags & AXIS_GRIDLINE)) Grid->FileIO(rw);
+ if(label) label->FileIO(rw);
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
+ fix = fiy = 0.0f; ls = 0L; Grid = 0L; mo = 0L;
+ size = defs.GetSize(SIZE_AXIS_TICKS);
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ Grid = (GridLine*) gl;
+ if(Grid)Grid->parent = this;
+ if(label)label->parent = this;
+ return true;
+ case FILE_WRITE:
+ if(Grid && (flags & AXIS_GRIDLINE)) Grid->FileIO(rw);
+ else gl = 0L;
+ if(label) label->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "Tick", Desc);
+ }
+ return false;
+}
+
+void
+Axis::TickFile(char *name)
+{
+ ReadCache *ca;
+ int i, j, k, nt;
+ char line[500], item[20];
+ Tick **ttck;
+
+ if(!name) return;
+ if(!(ca = new ReadCache())) return;
+ if(! ca->Open(name)) {
+ delete ca;
+ sprintf(TmpTxt, "Error open file \"%s\"\nfor axis ticks", name);
+ ErrorBox(TmpTxt);
+ return;
+ }
+ Command(CMD_FLUSH, 0L, 0L);
+ if(!(Ticks = ((Tick**)calloc(nt = 100, sizeof(Tick*))))) return;
+ for(i = 0; ; i++) {
+ j = k = 0;
+ ca->ReadLine(line, sizeof(line));
+ if(!line[0]) break;
+ while(line[j] && line[j] < 33) j++;
+ do{ item[k] = line[j++]; }
+ while(item[k] >32 && item[k++] != '=' && k <sizeof(item) && j <sizeof(line));
+ item[k--] = 0; if(!line[j-1])j--;
+ while(k && !(isdigit(item[k])))item[k--]=0;
+ while(line[j] && (line[j]<33 || line[j] == '"'))j++;
+ k = strlen(line);
+ while(k >=j && (line[k] < 33 || line[k] == '"')) line[k--] = 0;
+ //realloc table if necessary
+ if(NumTicks >= nt) {
+ if((ttck= (Tick**)realloc(Ticks, (nt += 1000)*sizeof(Tick*))))Ticks= ttck;
+ else NumTicks--;
+ }
+ //now add tick to table
+ if(!(Ticks[NumTicks] = new Tick(this, data, atof(item),
+ line[j] ? axis->flags : axis->flags | AXIS_MINORTICK)))break;
+ Ticks[NumTicks]->Command(CMD_SETTEXT, line+j, 0L);
+ NumTicks++;
+ }
+ ca->Close();
+ if(!NumTicks && Ticks) {
+ free(Ticks);
+ NumTicks = 0;
+ }
+ delete ca;
+}
+
+void
+Axis::RegGO(void *n)
+{
+ int i;
+
+ if(n) {
+ for(i = 0; Ticks && i< NumTicks; i++) if(Ticks[i]) Ticks[i]->RegGO(n);
+ if(axisLabel) axisLabel->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+Axis::FileIO(int rw)
+{
+ char *tickfile = 0L;
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"sAxLine", typLFLOAT, &sizAxLine, 0L},
+ {"sAxTick", typLFLOAT, &sizAxTick, 0L},
+ {"BrkGap", typLFLOAT, &brkgap, 0L},
+ {"BrkSymSize", typLFLOAT, &brksymsize, 0L},
+ {"BrkSym", typINT, &brksym, 0L},
+ {"sTickLabel", typLFLOAT, &sizAxTickLabel, 0L},
+ {"tick_type", typNZINT, &tick_type, 0L},
+ {"tick_angle", typNZLFLOAT, &tick_angle, 0L},
+ {"LbDist", typNZLFPOINT, &lbdist, 0L},
+ {"TickLbDist", typNZLFPOINT, &tlbdist, 0L},
+ {"Color", typDWORD, &colAxis, 0L},
+ {"AxisDef", typPTRAXDEF, &axis},
+ {"GridLine", typLINEDEF, &GridLine, 0L},
+ {"GridType", typINT, &gl_type, 0L},
+ {"Ticks", typOBJLST, &Ticks, (long*)&NumTicks},
+ {"Label", typGOBJ, &axisLabel, 0L},
+ {"TickFile", typTEXT, &tickfile, 0L},
+ {"ssRefTV", typTEXT, &ssMATval, 0L},
+ {"ssRefTL", typTEXT, &ssMATlbl, 0L},
+ {"ssRefMT", typTEXT, &ssMITval, 0L},
+ {"tlbDef", typLAST | typTXTDEF, &tlbdef, 0L}};
+ int i;
+
+ switch(rw) {
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ sizAxLine = defs.GetSize(SIZE_AXIS_LINE);
+ sizAxTick = defs.GetSize(SIZE_AXIS_TICKS);
+ sizAxTickLabel = defs.GetSize(SIZE_TICK_LABELS);
+ colAxis = parent ? parent->GetColor(COL_AXIS) : defs.Color(COL_AXIS);
+ GridLine.color = 0x00808080L;
+ GridLine.pattern = 0xf8f8f8f8L;
+ brksymsize = defs.GetSize(SIZE_TICK_LABELS);
+ brkgap = defs.GetSize(SIZE_AXIS_TICKS);
+ brksym = 2;
+ tlbdef.ColTxt = parent ? parent->GetColor(COL_AXIS) : defs.Color(COL_AXIS);
+ tlbdef.ColBg = parent ? parent->GetColor(COL_BG) : defs.Color(COL_AXIS);
+ tlbdef.RotBL = tlbdef.RotCHAR = 0.0f;
+ tlbdef.fSize = parent ? parent->GetSize(SIZE_TICK_LABELS) : defs.GetSize(SIZE_TICK_LABELS);
+ tlbdef.Align = TXA_VCENTER | TXA_HCENTER;
+ tlbdef.Style = TXS_NORMAL;
+ tlbdef.Mode = TXM_TRANSPARENT;
+ tlbdef.Font = FONT_HELVETICA;
+ tlbdef.text = 0L; l_segs = 0L; nl_segs = 0;
+ drawOut = scaleOut = 0L; bModified = false;
+ mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
+ mo = 0L;
+ return true;
+ case FILE_READ:
+ if(axisLabel)DeleteGO(axisLabel);
+ if(tickfile) free(tickfile); if(ssMATval) free(ssMATval);
+ if(ssMATlbl) free(ssMATlbl); if(ssMITval) free(ssMITval);
+ tickfile = 0L;
+ if(ExecInput(Desc) && tickfile && tickfile[0]){
+ TickFile(tickfile);
+ free(tickfile); tickfile = 0L;
+ }
+ if(axis) axis->owner = this;
+ if(axisLabel)axisLabel->parent = this;
+ if(Ticks && NumTicks) for(i = 0; i < NumTicks; i++) if(Ticks[i]) Ticks[i]->parent = this;
+ return true;
+ case FILE_WRITE:
+ //do all ticks
+ for(i = 0; Ticks && i< NumTicks; i++) if(Ticks[i]) Ticks[i]->FileIO(rw);
+ if(axisLabel) axisLabel->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "Axis", Desc);
+ }
+ return false;
+}
+
+void
+Plot3D::RegGO(void *n)
+{
+ int i;
+
+ if(n) {
+ if(plots) for(i = 0; plots && i< nPlots; i++) if(plots[i]) plots[i]->RegGO(n);
+ if(Axes) for(i = 0; i< nAxes; i++) if(Axes[i]) Axes[i]->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+Plot3D::FileIO(int rw)
+{
+ fPOINT3D rot_vec, rot_ang;
+ //DEBUG: must initialize rot_vec, rot_ang in case they are not present in file
+ descIO Desc[] = {
+ {"xBounds", typLFPOINT, &xBounds, 0L},
+ {"yBounds", typLFPOINT, &yBounds, 0L},
+ {"zBounds", typLFPOINT, &zBounds, 0L},
+ {"Corner1", typPOINT3D, &cub1, 0L},
+ {"Corner2", typPOINT3D, &cub2, 0L},
+ {"Center", typPOINT3D, &rotC, 0L},
+ {"rot_vec", typPOINT3D, &rot_vec, 0L},
+ {"rot_ang", typPOINT3D, &rot_ang, 0L},
+ {"Axes", typOBJLST, &Axes, (long*)&nAxes},
+ {"Plots", typLAST | typOBJLST, &plots, (long*)&nPlots}};
+ int i;
+
+ switch(rw) {
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ drag = 0L; moveable = 1;
+ //set up RotDef
+ RotDef[0] = 0.919384; RotDef[1] = 0.389104; RotDef[2] = -0.057709;
+ RotDef[3] = 0.327146; RotDef[4] = 0.944974; RotDef[5] = 1.0-RotDef[4];
+ cub1.fx = defs.GetSize(SIZE_GRECT_LEFT) + defs.GetSize(SIZE_DRECT_LEFT);
+ cub2.fx = defs.GetSize(SIZE_GRECT_LEFT) + defs.GetSize(SIZE_DRECT_RIGHT);
+ cub1.fy = defs.GetSize(SIZE_GRECT_TOP) + defs.GetSize(SIZE_DRECT_BOTTOM);
+ cub2.fy = defs.GetSize(SIZE_GRECT_TOP) + defs.GetSize(SIZE_DRECT_TOP);
+ cub1.fy += defs.GetSize(SIZE_DRECT_TOP); cub2.fy += defs.GetSize(SIZE_DRECT_TOP);
+ cub1.fz = 0.0;
+ cub2.fz = defs.GetSize(SIZE_DRECT_BOTTOM) - defs.GetSize(SIZE_DRECT_TOP);
+ rotC.fx = (cub1.fx + cub2.fx)/2.0; rotC.fy = (cub1.fy + cub2.fy)/2.0;
+ rotC.fz = (cub1.fz + cub2.fz)/2.0;
+ dispObs = 0L; nmaxObs = 0; crea_flags = 0L; dirty = true;
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
+ xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
+ if(name) {
+ sprintf(TmpTxt, "3D-root (%s)", name);
+ free(name); name=strdup(TmpTxt);
+ }
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ RotDef[0] = rot_vec.fx; RotDef[1] = rot_vec.fy; RotDef[2] = rot_vec.fz;
+ RotDef[3] = rot_ang.fx; RotDef[4] = rot_ang.fy; RotDef[5] = rot_ang.fz;
+ return true;
+ case FILE_WRITE:
+ rot_vec.fx = RotDef[0]; rot_vec.fy = RotDef[1]; rot_vec.fz = RotDef[2];
+ rot_ang.fx = RotDef[3]; rot_ang.fy = RotDef[4]; rot_ang.fz = RotDef[5];
+ //do all plots
+ for(i = 0; plots && i< nPlots; i++) if(plots[i]) plots[i]->FileIO(rw);
+ //do all axes
+ if(Axes) for(i = 0; i< nAxes; i++) if(Axes[i]) Axes[i]->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "Plot3D", Desc);
+ }
+ return false;
+}
+
+void
+Graph::RegGO(void *n)
+{
+ int i;
+
+ if(n) {
+ if(Plots) for(i = 0; i< NumPlots; i++) if(Plots[i]) Plots[i]->RegGO(n);
+ if(Axes) for(i = 0; i< NumAxes; i++) if(Axes[i]) Axes[i]->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+Graph::FileIO(int rw)
+{
+ int ixax, iyax;
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"Units", typNZINT, &units, 0L},
+ {"GRect", typFRECT, &GRect, 0L},
+ {"DRect", typFRECT, &DRect, 0L},
+ {"Bounds", typFRECT, &Bounds, 0L},
+ {"ColFrame", typDWORD, &ColGR, 0L},
+ {"ColFrameL", typDWORD, &ColGRL, 0L},
+ {"ColRec", typDWORD, &ColDR, 0L},
+ {"ColAxis", typDWORD, &ColAX, 0L},
+ {"Xaxis", typAXDEF, &x_axis, 0L},
+ {"Yaxis", typAXDEF, &y_axis, 0L},
+ {"DefXAxis", typINT, &ixax, 0L},
+ {"DefYAxis", typINT, &iyax, 0L},
+ {"Axes", typOBJLST, &Axes, (long*)&NumAxes},
+ {"Plots", typLAST | typOBJLST, &Plots, (long*)&NumPlots}};
+ int i;
+ bool bConvert = false;
+
+ ixax = iyax = -1;
+ switch(rw) {
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ units = defs.cUnits = defs.dUnits;
+ OwnDisp = false;
+ dirty = true;
+ GRect.Ymin = defs.GetSize(SIZE_GRECT_TOP); GRect.Ymax = defs.GetSize(SIZE_GRECT_BOTTOM);
+ GRect.Xmin = defs.GetSize(SIZE_GRECT_LEFT); GRect.Xmax = defs.GetSize(SIZE_GRECT_RIGHT);
+ DRect.Ymin = defs.GetSize(SIZE_DRECT_TOP); DRect.Ymax = defs.GetSize(SIZE_DRECT_BOTTOM);
+ DRect.Xmin = defs.GetSize(SIZE_DRECT_LEFT); DRect.Xmax = defs.GetSize(SIZE_DRECT_RIGHT);
+ ColGR = defs.Color(COL_GRECT); ColGRL = defs.Color(COL_GRECTLINE);
+ ColDR = defs.Color(COL_DRECT); ColBG = defs.Color(COL_BG);
+ ColAX = defs.Color(COL_AXIS);
+ x_axis.max = y_axis.max = 1.0;
+ x_axis.owner = y_axis.owner = (void *)this;
+ rcDim.left = rcDim.right = rcDim.top = rcDim.bottom = 0;
+ rcUpd.left = rcUpd.right = rcUpd.top = rcUpd.bottom = 0;
+ CurrGO = 0L; Disp = 0L; Sc_Plots = 0L;
+ AxisTempl = 0; nscp = 0; CurrDisp = 0L;
+ ToolMode = TM_STANDARD;
+ zoom_def = 0L; tl_pts = 0L; tl_nPts = 0;
+ tickstyle = zoom_level = 0;
+ frm_g = frm_d = 0L; filename = 0L;
+ rc_mrk.left = rc_mrk.right = rc_mrk.top = rc_mrk.bottom = -1;
+ return true;
+ case FILE_READ:
+ units = 0; //default to mm if statement mising in file
+ if((bConvert =ExecInput(Desc)) && ixax>=0 && iyax >=0 && Axes &&
+ NumAxes >= ixax+1 && NumAxes >= iyax) {
+ if(Axes[ixax]) Axes[ixax]->Command(CMD_SET_AXDEF, &x_axis, 0L);
+ if(Axes[iyax]) Axes[iyax]->Command(CMD_SET_AXDEF, &y_axis, 0L);
+ return true;
+ }
+ return bConvert;
+ case FILE_WRITE:
+ bModified = false;
+ //find default axes
+ if(Axes) for(i = 0; Axes && i < NumAxes; i++) {
+ if(Axes[i] && Axes[i]->GetAxis() == &x_axis) ixax = i;
+ else if(Axes[i] && Axes[i]->GetAxis() == &y_axis) iyax = i;
+ }
+ if(Id == GO_GRAPH && parent && parent->Id != GO_PAGE)RegGO(Notary);
+ //do all plots
+ if(Plots) for(i = 0; i< NumPlots; i++) if(Plots[i]) Plots[i]->FileIO(rw);
+ //do all axes
+ if(Axes) for(i = 0; i< NumAxes; i++) if(Axes[i]) Axes[i]->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "Graph", Desc);
+ }
+ return false;
+}
+
+void
+Page::RegGO(void *n)
+{
+ int i;
+
+ if(n) {
+ if(Plots) for(i = 0; i< NumPlots; i++) if(Plots[i]) Plots[i]->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+Page::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"Units", typNZINT, &units, 0L},
+ {"GRect", typFRECT, &GRect, 0L},
+ {"Plots", typLAST | typOBJLST, &Plots, (long*)&NumPlots}};
+ int i;
+
+ switch(rw) {
+ case INIT_VARS:
+ //assume that Graph::FileIO(INIT_VARS) has been executed
+ GRect.Xmin = GRect.Ymin = 0.0;
+ GetPaper(&GRect.Xmax, &GRect.Ymax);
+ ColBG = 0x00e8e8e8L;
+ LineDef.width = 0.0; LineDef.patlength = 1.0;
+ LineDef.color = LineDef.pattern = 0x0L;
+ FillDef.type = FILL_NONE;
+ FillDef.color = 0x00ffffffL; //use white paper
+ FillDef.scale = 1.0;
+ FillDef.hatch = 0L; filename =0L;
+ return true;
+ case FILE_READ:
+ Graph::FileIO(rw);
+ return true;
+ case FILE_WRITE:
+ //do all plots
+ bModified = false;
+ if(Plots) for(i = 0; i< NumPlots; i++) if(Plots[i]) Plots[i]->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "Page", Desc);
+ }
+ return false;
+}
+
+bool
+DefsRW::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"dUnits", typINT, &defs.dUnits, 0L},
+ {"cUnits", typINT, &defs.dUnits, 0L},
+ {"dtHeight", typINT, &dlgtxtheight, 0L},
+ {"File1", typTEXT, &defs.File1, 0L},
+ {"File2", typTEXT, &defs.File2, 0L},
+ {"File3", typTEXT, &defs.File3, 0L},
+ {"File4", typTEXT, &defs.File4, 0L},
+ {"File5", typTEXT, &defs.File5, 0L},
+ {"File6", typLAST | typTEXT, &defs.File6, 0L}};
+
+ switch(rw) {
+ case FILE_READ:
+ ExecInput(Desc);
+ return true;
+ case FILE_WRITE:
+ Notary = new notary();
+ unlink(defs.IniFile);
+ iFile = OpenOutputFile(defs.IniFile);
+ if(iFile >=0) {
+ ExecOutput(-1, "Defaults", Desc);
+ }
+ CloseOutputFile(); if(Notary) delete Notary; Notary = 0L;
+ return true;
+ }
+ return false;
+}
diff --git a/Makefile b/Makefile
new file mode 100755
index 0000000..46f1ebf
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,118 @@
+# Makefile, Copyright 2002-2004 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
+#
+# This Makefile assumes that you installed Trolltechs QT in /usr/local/qt
+# visit: http://www.trolltech.com for download and licence information
+#
+QTDIR = /usr/lib/qt3
+CC = g++
+#CFLAGS = -I$(QTDIR)/include -pipe -O2 -g
+CFLAGS = -I$(QTDIR)/include -pipe -O2
+LIBS = -L$(QTDIR)/lib -L/usr/X11R6/lib
+QTLIBS = -lqt-mt
+X11LIBS = -lX11 -lm
+SRCDIR = ./
+
+GENOBJ = exprlp.o rlplot.o Output.o Utils.o UtilObj.o\
+ Fileio.o Export.o PlotObs.o Axes.o mfcalc.o rlp_math.o
+
+OBJECTS = moc_QT_Spec.o QT_Spec.o Output.o Utils.o UtilObj.o\
+ TheDialog.o rlplot.o Fileio.o PropertyDlg.o spreadwi.o\
+ Export.o PlotObs.o Axes.o ODbuttons.o mfcalc.o rlp_math.o
+
+all:
+ make rlplot QTDIR=$(QTDIR)
+ make exprlp
+ make clean
+
+rlplot: $(OBJECTS)
+ $(CC) $(LIBS) -o rlplot $(OBJECTS) $(QTLIBS) $(X11LIBS)
+
+exprlp: $(GENOBJ)
+ $(CC) -o exprlp $(GENOBJ)
+
+clean:
+ rm -f *.o *~
+ rm moc_QT_Spec.cpp
+
+####### Compile
+
+moc_QT_Spec.o: moc_QT_Spec.cpp $(SRCDIR)QT_Spec.h
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+moc_QT_Spec.cpp: $(SRCDIR)QT_Spec.h
+ $(QTDIR)/bin/moc $(SRCDIR)QT_Spec.h -o moc_QT_Spec.cpp
+
+mfcalc.o: $(SRCDIR)mfcalc.cpp
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+rlp_math.o: $(SRCDIR)rlp_math.cpp
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+#$(SRCDIR)mfcalc.cpp: $(SRCDIR)mfcalc.y
+# bison -l -o $@ $<
+
+exprlp.o: $(SRCDIR)exprlp.cpp
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+QT_Spec.o: $(SRCDIR)QT_Spec.cpp $(SRCDIR)QT_Spec.h $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+Output.o: $(SRCDIR)Output.cpp $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+Utils.o: $(SRCDIR)Utils.cpp $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+UtilObj.o: $(SRCDIR)UtilObj.cpp $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+TheDialog.o: $(SRCDIR)TheDialog.cpp $(SRCDIR)TheDialog.h $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+rlplot.o: $(SRCDIR)rlplot.cpp $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+Fileio.o: $(SRCDIR)Fileio.cpp $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+PropertyDlg.o: $(SRCDIR)PropertyDlg.cpp $(SRCDIR)rlplot.h $(SRCDIR)TheDialog.h
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+spreadwi.o: $(SRCDIR)spreadwi.cpp $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+Export.o: $(SRCDIR)Export.cpp $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+PlotObs.o: $(SRCDIR)PlotObs.cpp $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+ODbuttons.o: $(SRCDIR)ODbuttons.cpp $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+Axes.o: $(SRCDIR)Axes.cpp $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+
+
+
+
+
+
diff --git a/Makefile.win b/Makefile.win
new file mode 100755
index 0000000..f5ca7d1
--- /dev/null
+++ b/Makefile.win
@@ -0,0 +1,97 @@
+# Makefile.win, Copyright 2002-2004 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
+#
+CC = cl.exe
+CFLAGS = /nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD
+LIBS = kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib\
+ shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
+SRCDIR =
+
+GENOBJ = exprlp.obj rlplot.obj Output.obj Utils.obj UtilObj.obj\
+ FileIO.obj Export.obj PlotObs.obj Axes.obj mfcalc.obj rlp_math.obj
+
+OBJECTS = WinSpec.obj Output.obj Utils.obj UtilObj.obj\
+ TheDialog.obj rlplot.obj FileIO.obj PropertyDlg.obj spreadwi.obj\
+ Export.obj PlotObs.obj ODbuttons.obj Axes.obj mfcalc.obj rlp_math.obj
+
+RLPlot: $(OBJECTS) RLPLOT.res
+ link.exe $(LIBS) /nologo /subsystem:windows /incremental:no /pdb:"RLPlot.pdb"\
+ /machine:I386 /out:"RLPlot.exe" $(OBJECTS) RLPLOT.res
+
+exprlp: $(GENOBJ)
+ $(CC) -o exprlp $(GENOBJ)
+
+clean:
+ del *.obj
+ del *.pch
+ del *.idb
+ del *.res
+
+####### Compile
+RLPLOT.res: $(SRCDIR)RLPLOT.RC
+ rc.exe /d "NDEBUG" $(SRCDIR)RLPLOT.RC
+
+mfcalc.obj: $(SRCDIR)mfcalc.cpp $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $(SRCDIR)mfcalc.cpp
+
+rlp_math.obj: $(SRCDIR)rlp_math.cpp $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $(SRCDIR)rlp_math.cpp
+
+exprlp.obj: $(SRCDIR)exprlp.cpp
+ $(CC) $(CFLAGS) -o $@ -c $(SRCDIR)exprlp.cpp
+
+WinSpec.obj: $(SRCDIR)WinSpec.cpp $(SRCDIR)WinSpec.h $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $(SRCDIR)WinSpec.cpp
+
+Output.obj: $(SRCDIR)Output.cpp $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $(SRCDIR)Output.cpp
+
+Utils.obj: $(SRCDIR)Utils.cpp $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $(SRCDIR)Utils.cpp
+
+UtilObj.obj: $(SRCDIR)UtilObj.cpp $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $(SRCDIR)UtilObj.cpp
+
+TheDialog.obj: $(SRCDIR)TheDialog.cpp $(SRCDIR)TheDialog.h $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $(SRCDIR)TheDialog.cpp
+
+rlplot.obj: $(SRCDIR)rlplot.cpp $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $(SRCDIR)rlplot.cpp
+
+FileIO.obj: $(SRCDIR)FileIO.cpp $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $(SRCDIR)FileIO.cpp
+
+PropertyDlg.obj: $(SRCDIR)PropertyDlg.cpp $(SRCDIR)rlplot.h $(SRCDIR)TheDialog.h
+ $(CC) $(CFLAGS) -o $@ -c $(SRCDIR)PropertyDlg.cpp
+
+spreadwi.obj: $(SRCDIR)spreadwi.cpp $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $(SRCDIR)spreadwi.cpp
+
+Export.obj: $(SRCDIR)Export.cpp $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $(SRCDIR)Export.cpp
+
+PlotObs.obj: $(SRCDIR)PlotObs.cpp $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $(SRCDIR)PlotObs.cpp
+
+ODbuttons.obj: $(SRCDIR)ODbuttons.cpp $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $(SRCDIR)ODbuttons.cpp
+
+Axes.obj: $(SRCDIR)Axes.cpp $(SRCDIR)rlplot.h
+ $(CC) $(CFLAGS) -o $@ -c $(SRCDIR)Axes.cpp
+
diff --git a/ODbuttons.cpp b/ODbuttons.cpp
new file mode 100755
index 0000000..f4d94c4
--- /dev/null
+++ b/ODbuttons.cpp
@@ -0,0 +1,1273 @@
+//ODbuttons.cpp, Copyright (c) 2001, 2002, 2003, 2004 R.Lackner
+//Property dialogs for graphic objects
+//
+// 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
+//
+// Tis module contains the different graphic buttons for dialogs
+#include "rlplot.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "TheDialog.h"
+
+extern int ODtickstyle;
+extern int AxisTempl3D;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Common code to modify drawing order in any dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Exceute drawing order buttons as owner drwn buttons
+void OD_DrawOrder(int cmd, void *par, RECT *rec, anyOutput *o,
+ void *data, int id)
+{
+ LineDEF Line = {.0f, 1.0f, 0x0L, 0x0L};
+ FillDEF Fill = {FILL_NONE, 0x0080ffffL, 1.0, 0L};
+ POINT pts[5];
+ RECT hrc;
+ int i, j, x, y;
+
+ Fill.color = 0x0080ffffL;
+ switch(cmd) {
+ case OD_MBTRACK:
+ if(!data) return;
+ x = ((MouseEvent*)data)->x; y = ((MouseEvent*)data)->y;
+ memcpy(&hrc, rec, sizeof(RECT));
+ IncrementMinMaxRect(&hrc, -6);
+ if(IsInRect(&hrc, x, y)) Fill.color = 0x00e0ffffL;
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ pts[0].x = rec->left+10; pts[0].y = rec->bottom-3;
+ pts[1].x = rec->right-9; pts[1].y = rec->bottom-3;
+ pts[2].x = rec->right-3; pts[2].y = rec->bottom-9;
+ pts[3].x = rec->left+16; pts[3].y = rec->bottom-9;
+ pts[4].x = pts[0].x; pts[4].y = pts[0].y;
+ o->SetLine(&Line); o->SetFill(&Fill);
+ for(i = 0; i < 5; i++){
+ o->oPolygon(pts, 5);
+ for(j = 0; j < 5; j++) {
+ pts[j].y -=4;
+ }
+ }
+ pts[0].x = pts[1].x = pts[3].x = rec->left+4;
+ pts[2].x = rec->left+1; pts[4].x = rec->left+7;
+ switch (id) {
+ case 600:
+ pts[0].y = pts[3].y = rec->top+6; pts[1].y = rec->bottom-3;
+ pts[2].y = pts[4].y = rec->top+9;
+ break;
+ case 601:
+ pts[0].y = pts[3].y = rec->top+12; pts[1].y = rec->bottom-9;
+ pts[2].y = pts[4].y = rec->top+15;
+ break;
+ case 602:
+ pts[0].y = pts[3].y = rec->bottom-9; pts[1].y = rec->top+12;
+ pts[2].y = pts[4].y = rec->bottom-12;
+ break;
+ case 603:
+ pts[0].y = pts[3].y = rec->bottom-3; pts[1].y = rec->top+6;
+ pts[2].y = pts[4].y = rec->bottom-6;
+ break;
+ }
+ Fill.color = 0x0fL; o->SetFill(&Fill);
+ o->oPolyline(pts, 2); o->oPolygon(pts+2, 3);
+ o->UpdateRect(rec, false);
+ break;
+ }
+}
+
+int ExecDrawOrderButt(GraphObj *parent, GraphObj *obj, int id)
+{
+ switch(id){
+ case 600:
+ parent->Command(CMD_MOVE_TOP, obj, 0L);
+ return -1;
+ case 601:
+ parent->Command(CMD_MOVE_UP, obj, 0L);
+ return -1;
+ case 602:
+ parent->Command(CMD_MOVE_DOWN, obj, 0L);
+ return -1;
+ case 603:
+ parent->Command(CMD_MOVE_BOTTOM, obj, 0L);
+ return -1;
+ }
+ return id;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Execute line style as owner drawn buttons
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void OD_LineStyleTempl(int cmd, void *par, RECT *rec, anyOutput *o,
+ void *data, int id)
+{
+ LineDEF Line = {.1f, 1.0f, 0x0L, 0x0L};
+ FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
+ POINT pts[10];
+ int ix, iy, np;
+
+ switch(cmd) {
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ Line.color = cmd == OD_DRAWSELECTED ? 0x00000000L : 0x00d0d0d0L;
+ Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00d0d0d0L;
+ ix = (rec->left + rec->right)/2;
+ iy = (rec->top +rec->bottom)/2;
+ o->SetLine(&Line);
+ pts[0].x = pts[3].x = pts[4].x = rec->left;
+ pts[0].y = pts[1].y = pts[4].y = rec->top;
+ pts[1].x = pts[2].x = rec->right-1;
+ pts[2].y = pts[3].y = rec->bottom-1;
+ o->oPolyline(pts, 5);
+ Line.color = 0x00000000L;
+ o->SetLine(&Line);
+ o->SetFill(&Fill);
+ o->oRectangle(rec->left+3, rec->top+3, rec->right-3, rec->bottom-3);
+ np = 0;
+ switch(id) {
+ case 201:
+ pts[np].x = rec->left+15; pts[np++].y = rec->bottom-15;
+ pts[np].x = rec->right-15; pts[np++].y = rec->top+15;
+ break;
+ case 206:
+ pts[np].x = rec->left+15; pts[np++].y = rec->bottom-10;
+ case 202:
+ pts[np].x = rec->left+15; pts[np++].y = rec->bottom-15;
+ pts[np].x = ix; pts[np++].y = pts[np-1].y;
+ pts[np].x = ix; pts[np++].y = iy;
+ pts[np].x = rec->right-15; pts[np++].y = iy;
+ pts[np].x = pts[np-1].x; pts[np++].y = rec->top+15;
+ if(id == 206){
+ pts[np].x = rec->right-8; pts[np++].y = rec->top+15;
+ }
+ break;
+ case 207:
+ pts[np].x = rec->left+8; pts[np++].y = rec->bottom-15;
+ case 203:
+ pts[np].x = rec->left+15; pts[np++].y = rec->bottom-15;
+ pts[np].x = pts[np-1].x; pts[np++].y = iy;
+ pts[np].x = ix; pts[np++].y = iy;
+ pts[np].x = ix; pts[np++].y = rec->top+15;
+ pts[np].x = rec->right-15; pts[np++].y = pts[np-1].y;
+ if(id == 207){
+ pts[np].x = rec->right-15; pts[np++].y = rec->top+7;
+ }
+ break;
+ case 208:
+ pts[np].x = rec->left+8; pts[np++].y = rec->bottom-15;
+ case 204:
+ pts[np].x = rec->left+15; pts[np++].y = rec->bottom-15;
+ pts[np].x = (pts[np-1].x + ix)>>1; pts[np++].y = pts[np-1].y;
+ pts[np].x = pts[np-1].x; pts[np++].y = iy;
+ pts[np].x = (rec->right-15 + ix)>>1; pts[np++].y = iy;
+ pts[np].x = pts[np-1].x; pts[np++].y = rec->top+15;
+ pts[np].x = rec->right-15; pts[np++].y = pts[np-1].y;
+ if(id == 208) pts[np-1].x += 6;
+ break;
+ case 209:
+ pts[np].x = rec->left+15; pts[np++].y = rec->bottom-10;
+ case 205:
+ pts[np].x = rec->left+15; pts[np++].y = rec->bottom-15;
+ pts[np].x = pts[0].x; pts[np++].y = (pts[np-1].y +iy)>>1;
+ pts[np].x = ix; pts[np++].y = pts[np-1].y;
+ pts[np].x = ix; pts[np++].y = (iy + rec->top+15)>>1;
+ pts[np].x = rec->right-15; pts[np++].y = pts[np-1].y;
+ pts[np].x = pts[np-1].x; pts[np++].y = rec->top+15;
+ if(id == 209) pts[np-1].y -= 7;
+ break;
+ }
+ if(np) o->oPolyline(pts, np);
+ o->oCircle(ix-2, iy-2, ix+2, iy+2);
+#ifdef _WINDOWS
+ o->oCircle(rec->left+13, rec->bottom-13, rec->left+17, rec->bottom-17);
+ o->oCircle(rec->right-13, rec->top+13, rec->right-17, rec->top+17);
+#else
+ o->oCircle(rec->left+13, rec->bottom-14, rec->left+17, rec->bottom-16);
+ o->oCircle(rec->right-14, rec->top+13, rec->right-16, rec->top+17);
+#endif
+ o->UpdateRect(rec, false);
+ break;
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Execute error bar style as owner drawn buttons for the error bar dialog
+// and in the scatterplot dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void OD_ErrBarTempl(int cmd, void *par, RECT *rec, anyOutput *o,
+ void *data, int id)
+{
+ LineDEF Line = {.1f, 1.0f, 0x0L, 0x0L};
+ FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
+ POINT pts[6];
+ int ix, iy;
+
+ switch(cmd) {
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ Line.color = cmd == OD_DRAWSELECTED ? 0x00000000L : 0x00d0d0d0L;
+ Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00d0d0d0L;
+ ix = (rec->left + rec->right)/2;
+ iy = (rec->top +rec->bottom)/2;
+ o->SetLine(&Line);
+ pts[0].x = pts[3].x = pts[4].x = rec->left;
+ pts[0].y = pts[1].y = pts[4].y = rec->top;
+ pts[1].x = pts[2].x = rec->right-1;
+ pts[2].y = pts[3].y = rec->bottom-1;
+ o->oPolyline(pts, 5);
+ Line.color = 0x00000000L;
+ o->SetLine(&Line);
+ o->SetFill(&Fill);
+ o->oRectangle(rec->left+3, rec->top+3, rec->right-3, rec->bottom-3);
+ switch(id) {
+ case 500:
+ pts[2].x = pts[3].x = ix;
+ pts[0].x = pts[4].x = ix-5; pts[1].x = pts[5].x = ix+5;
+ pts[0].y = pts[1].y = pts[2].y = rec->top +8;
+ pts[3].y = pts[4].y = pts[5].y = rec->bottom -8;
+ o->oSolidLine(pts); o->oSolidLine(pts+2); o->oSolidLine(pts+4);
+ break;
+ case 501:
+ case 502:
+ pts[2].x = pts[3].x = ix; pts[0].x = ix-5; pts[1].x = ix+5;
+ pts[0].y = pts[1].y = pts[2].y = (id == 502 ? rec->bottom -8 : rec->top +8);
+ pts[3].y = iy;
+ o->oSolidLine(pts); o->oSolidLine(pts+2);
+ break;
+ case 503:
+ pts[2].y = pts[3].y = iy;
+ pts[0].y = pts[4].y = iy-5; pts[1].y = pts[5].y = iy+5;
+ pts[0].x = pts[1].x = pts[2].x = rec->left +8;
+ pts[3].x = pts[4].x = pts[5].x = rec->right -8;
+ o->oSolidLine(pts); o->oSolidLine(pts+2); o->oSolidLine(pts+4);
+ break;
+ case 504:
+ case 505:
+ pts[2].y = pts[3].y = iy; pts[0].y = iy-5; pts[1].y = iy+5;
+ pts[0].x = pts[1].x = pts[2].x = (id == 505 ? rec->right -8 : rec->left +8);
+ pts[3].x = ix;
+ o->oSolidLine(pts); o->oSolidLine(pts+2);
+ break;
+ }
+ o->oCircle(ix-4, iy-4, ix+4, iy+4);
+ o->UpdateRect(rec, false);
+ break;
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Execute whisker style as owner drawn buttons
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void OD_WhiskerTempl(int cmd, void *par, RECT *rec, anyOutput *o,
+ void *data, int id)
+{
+ LineDEF Line = {.1f, 1.0f, 0x0L, 0x0L};
+ FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
+ POINT pts[6];
+ int ix, iy;
+
+ switch(cmd) {
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ Line.color = cmd == OD_DRAWSELECTED ? 0x00000000L : 0x00d0d0d0L;
+ Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00d0d0d0L;
+ ix = (rec->left + rec->right)/2;
+ iy = (rec->top +rec->bottom)/2;
+ o->SetLine(&Line);
+ pts[0].x = pts[3].x = pts[4].x = rec->left;
+ pts[0].y = pts[1].y = pts[4].y = rec->top;
+ pts[1].x = pts[2].x = rec->right-1;
+ pts[2].y = pts[3].y = rec->bottom-1;
+ o->oPolyline(pts, 5);
+ Line.color = 0x00000000L;
+ o->SetLine(&Line);
+ o->SetFill(&Fill);
+ o->oRectangle(rec->left+3, rec->top+3, rec->right-3, rec->bottom-3);
+ switch(id) {
+ case 500:
+ pts[2].x = pts[3].x = ix;
+ pts[0].x = pts[4].x = ix-5; pts[1].x = pts[5].x = ix+5;
+ pts[0].y = pts[1].y = pts[2].y = rec->top +8;
+ pts[3].y = pts[4].y = pts[5].y = rec->bottom -8;
+ o->oSolidLine(pts); o->oSolidLine(pts+2); o->oSolidLine(pts+4);
+ break;
+ case 501:
+ pts[0].x = pts[1].x = ix; pts[0].y = rec->bottom -8;
+ pts[1].y = rec->top +8; o->oSolidLine(pts);
+ break;
+ case 502:
+ pts[0].x = ix-5; pts[1].x = pts[2].x = ix; pts[3].x = ix +5;
+ pts[0].y = pts[1].y = rec->bottom-8; pts[2].y = pts[3].y = rec->top+8;
+ o->oPolyline(pts, 4);
+ break;
+ case 503:
+ pts[0].x = ix+5; pts[1].x = pts[2].x = ix; pts[3].x = ix -5;
+ pts[0].y = pts[1].y = rec->bottom-8; pts[2].y = pts[3].y = rec->top+8;
+ o->oPolyline(pts, 4);
+ break;
+ }
+ o->UpdateRect(rec, false);
+ break;
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Execute polar plot templates as owner drawn buttons
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void OD_PolarTempl(int cmd, void *par, RECT *rec, anyOutput *o,
+ void *data, int id)
+{
+ LineDEF Line = {.0f, 1.0f, 0x0L, 0x0L};
+ FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
+ FillDEF FillR = {FILL_NONE, 0x000000ffL, 1.0, 0L};
+ FillDEF FillG = {FILL_NONE, 0x0000ff00L, 1.0, 0L};
+ FillDEF FillB = {FILL_NONE, 0x00ff0000L, 1.0, 0L};
+ FillDEF FillY = {FILL_NONE, 0x0000ffffL, 1.0, 0L};
+ TextDEF td, otd;
+ POINT pts[12];
+ int ix, iy;
+
+ switch(cmd) {
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ Line.color = cmd == OD_DRAWSELECTED ? 0x00000000L : 0x00d0d0d0L;
+ Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00d0d0d0L;
+ ix = (rec->left + rec->right)/2;
+ iy = (rec->top +rec->bottom)/2;
+ o->SetLine(&Line);
+ pts[0].x = pts[3].x = pts[4].x = rec->left;
+ pts[0].y = pts[1].y = pts[4].y = rec->top;
+ pts[1].x = pts[2].x = rec->right-1;
+ pts[2].y = pts[3].y = rec->bottom-1;
+ o->oPolyline(pts, 5);
+ Line.color = 0x00000000L;
+ o->SetLine(&Line);
+ o->SetFill(&Fill);
+ o->oCircle(rec->left+3, rec->top+3, rec->right-3, rec->bottom-3);
+ switch(id) {
+ case 200:
+ case 201:
+ case 202:
+ if(id == 201 || id == 202) {
+ pts[0].x = rec->left+13; pts[0].y = rec->top+10;
+ pts[1].x = rec->left+15; pts[1].y = rec->top+25;
+ pts[2].x = rec->right-19; pts[2].y = rec->top+33;
+ pts[3].x = rec->right-11; pts[3].y = rec->top+13;
+ o->oPolyline(pts, 4);
+ o->SetFill(&FillG);
+ }
+ else o->SetFill(&FillR);
+ if(id == 200 || id == 201) {
+ o->oCircle(rec->left+10, rec->top+7, rec->left+16, rec->top+13);
+ o->oCircle(rec->left+12, rec->top+22, rec->left+18, rec->top+28);
+ o->oCircle(rec->right-22, rec->top+30, rec->right-16, rec->top+36);
+ o->oCircle(rec->right-14, rec->top+10, rec->right-8, rec->top+16);
+ }
+ break;
+ case 203:
+ pts[0].x = rec->left+7; pts[0].y = rec->top+13;
+ pts[1].x = rec->left+10; pts[1].y = rec->top+30;
+ pts[2].x = rec->right-19; pts[2].y = rec->top+33;
+ pts[3].x = rec->right-9; pts[3].y = rec->top+11;
+ pts[4].x = ix-4; pts[4].y =iy +3;
+ o->SetFill(&FillY);
+ o->oPolygon(pts, 5);
+ break;
+ case 204:
+ if(cmd == OD_DRAWNORMAL) FillG.color = 0x00d0d0d0L;
+ o->SetFill(&FillG);
+ o->oCircle(ix-6, rec->top+5, ix+6, iy+6);
+ memcpy(&td, &o->TxtSet, sizeof(TextDEF));
+ memcpy(&otd, &o->TxtSet, sizeof(TextDEF));
+ td.Align = TXA_HCENTER | TXA_VTOP;
+ td.Style = TXS_NORMAL;
+ td.Mode = TXM_TRANSPARENT;
+ td.fSize *= 0.8; td.iSize = 0;
+ td.ColTxt = 0x00ff0000L;
+ o->SetTextSpec(&td);
+ o->oTextOut(ix, iy+3, "y=f(x)", 0);
+ o->SetTextSpec(&otd);
+ }
+ o->UpdateRect(rec, false);
+ break;
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Execute templates for pie-charts as owner drawn buttons
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void OD_PieTempl(int cmd, void *par, RECT *rec, anyOutput *o,
+ void *data, int id)
+{
+ LineDEF Line = {.0, 1.0, 0x0L, 0x0L};
+ FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
+ FillDEF FillR = {FILL_NONE, 0x000000ffL, 1.0, 0L};
+ FillDEF FillG = {FILL_NONE, 0x0000ff00L, 1.0, 0L};
+ FillDEF FillB = {FILL_NONE, 0x00ff0000L, 1.0, 0L};
+ double angels1[]={90.0, 45.0, -45.0, 90.0};
+ double angels2[]={180, 157.5, 112.5, 0.0};
+ POINT pts[12];
+ int ix, iy;
+ double r, *ang = angels1;
+ segment *seg = 0L;
+ lfPOINT fc;
+
+ switch(cmd) {
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ Line.color = cmd == OD_DRAWSELECTED ? 0x00000000L : 0x00d0d0d0L;
+ Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00d0d0d0L;
+ ix = (rec->left + rec->right)/2;
+ iy = (rec->top +rec->bottom)/2;
+ o->SetLine(&Line);
+ pts[0].x = pts[3].x = pts[4].x = rec->left;
+ pts[0].y = pts[1].y = pts[4].y = rec->top;
+ pts[1].x = pts[2].x = rec->right-1;
+ pts[2].y = pts[3].y = rec->bottom-1;
+ o->oPolyline(pts, 5);
+ Line.color = 0x00000000L;
+ o->SetLine(&Line);
+ o->SetFill(&Fill);
+ o->oRectangle(rec->left+3, rec->top+3, rec->right-3, rec->bottom-3);
+ switch(id) {
+ case 401: case 411:
+ ang = angels2;
+ case 400: case 410:
+ fc.fx = o->fix2un((double)ix-1); fc.fy = o->fiy2un((double)iy);
+ r = o->fix2un((double)(rec->right -rec->left))/3;
+ seg = new segment(0L, 0L, &fc, 0.0, r, ang[0], ang[1]);
+ if(seg) {
+ if(id == 410 || id == 411) seg->SetSize(SIZE_RADIUS1, r*.7);
+ seg->Command(CMD_SEG_LINE, &Line, 0L);
+ seg->Command(CMD_SEG_FILL, &FillR, 0L);
+ seg->DoPlot(o);
+ seg->SetSize(SIZE_ANGLE1, ang[1]);
+ seg->SetSize(SIZE_ANGLE2, ang[2]);
+ seg->Command(CMD_SEG_FILL, &FillG, 0L);
+ seg->DoPlot(o);
+ seg->SetSize(SIZE_ANGLE1, ang[2]);
+ seg->SetSize(SIZE_ANGLE2, ang[3]);
+ seg->Command(CMD_SEG_FILL, &FillB, 0L);
+ seg->DoPlot(o);
+ delete seg;
+ }
+ break;
+ }
+ o->UpdateRect(rec, false);
+ break;
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Show a simple graph how 3D axes are organized as owner drawn button
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void OD_AxisDesc3D(int cmd, void *par, RECT *rec, anyOutput *o,
+ void *data, int id)
+{
+ POINT pts[5];
+
+ switch(cmd) {
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ pts[0].x = ((rec->left + rec->right)>>1)-15;
+ pts[0].y = ((rec->bottom + rec->top)>>1)+10;
+ pts[1].x = rec->left + 15; pts[1].y = rec->bottom-20;
+ o->oSolidLine(pts);
+ pts[2].x = pts[1].x +2; pts[2].y = pts[1].y -7;
+ o->oSolidLine(pts + 1);
+ pts[2].x = pts[1].x +6; pts[2].y = pts[1].y -2;
+ o->oSolidLine(pts + 1);
+ o->oTextOut(pts[1].x -2, pts[1].y -5, "z", 1);
+ pts[1].x = pts[0].x; pts[1].y = rec->top+20;
+ o->oSolidLine(pts);
+ pts[2].x = pts[1].x -4; pts[2].y = pts[1].y +6;
+ o->oSolidLine(pts + 1);
+ pts[2].x = pts[1].x +4;
+ o->oSolidLine(pts + 1);
+ o->oTextOut(pts[1].x + 4, pts[1].y - 18, "y", 1);
+ pts[1].x = rec->right-15; pts[1].y = rec->bottom -22;
+ o->oSolidLine(pts);
+ pts[2].x = pts[1].x -6; pts[2].y = pts[1].y +2;
+ o->oSolidLine(pts + 1);
+ pts[2].x = pts[1].x -4; pts[2].y = pts[1].y -5;
+ o->oSolidLine(pts + 1);
+ o->oTextOut(pts[1].x +9, pts[1].y -4, "x", 1);
+ o->UpdateRect(rec, false);
+ break;
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Execute axis breaks symbols as owner drawn button
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void OD_BreakTempl(int cmd, void *par, RECT *rec, anyOutput *o,
+ void *data, int id)
+{
+ LineDEF Line = {.1f, 1.0f, 0x0L, 0x0L};
+ FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
+ POINT pts[15];
+ int i, ix, iy;
+
+ switch(cmd) {
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ Line.color = cmd == OD_DRAWSELECTED ? 0x00000000L : 0x00d0d0d0L;
+ Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00d0d0d0L;
+ ix = (rec->left + rec->right)>>1;
+ iy = (rec->top +rec->bottom)>>1;
+ o->SetLine(&Line);
+ pts[0].x = pts[3].x = pts[4].x = rec->left;
+ pts[0].y = pts[1].y = pts[4].y = rec->top;
+ pts[1].x = pts[2].x = rec->right-1;
+ pts[2].y = pts[3].y = rec->bottom-1;
+ o->oPolyline(pts, 5);
+ Line.color = 0x00000000L;
+ o->SetLine(&Line);
+ o->SetFill(&Fill);
+ o->oRectangle(rec->left+3, rec->top+3, rec->right-3, rec->bottom-3);
+ pts[0].x = pts[1].x = ix;
+ pts[0].y = rec->top +5; pts[1].y = iy-3;
+ o->oSolidLine(pts);
+ pts[0].y = rec->bottom -7; pts[1].y = iy+3;
+ o->oSolidLine(pts);
+ switch(id) {
+ case 402:
+ pts[0].x = ix-7; pts[1].x = ix+7;
+ pts[0].y = iy; pts[1].y = iy-6;
+ o->oSolidLine(pts);
+ pts[0].y += 6; pts[1].y += 6;
+ o->oSolidLine(pts);
+ break;
+ case 403:
+ pts[0].x = ix-7; pts[1].x = ix+7;
+ pts[0].y = iy-3; pts[1].y = iy-3;
+ o->oSolidLine(pts);
+ pts[1].y += 6; o->oSolidLine(pts);
+ pts[0].y += 6; o->oSolidLine(pts);
+ break;
+ case 404:
+ for(i = 0; i < 15; i++) {
+ pts[i].x = ix +i -7;
+ pts[i].y = iy - 3 + (int)(sin((double)i*0.41887902)*2.5);
+ }
+ o->oPolyline(pts, 15);
+ for(i = 0; i < 15; i++) pts[i].y += 6;
+ o->oPolyline(pts, 15);
+ break;
+ }
+ o->UpdateRect(rec, false);
+ break;
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Execute plot selection templates as owner drawn button
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void UtilBarDraw(POINT *pts, int x, int y1, int y2, anyOutput *o)
+{
+ pts[1].x = pts[0].x = pts[4].x = x;
+ pts[0].y = y1; pts[1].y = y2;
+ pts[2].y = pts[1].y-1; pts[2].x = pts[3].x = pts[0].x-3;
+ pts[3].y = pts[0].y-1; pts[4].y = pts[0].y;
+ o->oPolygon(pts, 5);
+ pts[2].x += 5; pts[3].x += 5;
+ o->oPolygon(pts, 5);
+ pts[1].x -= 3; pts[1].y = pts[0].y-1;
+ pts[2].x = pts[0].x-2; pts[2].y = pts[0].y-2;
+ o->oPolygon(pts, 5);
+}
+
+void OD_PlotTempl(int cmd, void *par, RECT *rec, anyOutput *o,
+ void *data, int id)
+{
+ LineDEF Line = {.0, 1.0, 0x0L, 0x0L};
+ LineDEF rLine = {.0, 1.0, 0x00000080L, 0x0L};
+ LineDEF bLine = {.0, 1.0, 0x00e00000L, 0x0L};
+ LineDEF gLine = {.0, 1.0, 0x0000e000L, 0x0L};
+ FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
+ FillDEF FillR = {FILL_NONE, 0x000000ffL, 1.0, 0L};
+ FillDEF FillG = {FILL_NONE, 0x0000ff00L, 1.0, 0L};
+ FillDEF FillB = {FILL_NONE, 0x00ff0000L, 1.0, 0L};
+ FillDEF FillY = {FILL_NONE, 0x0000ffffL, 1.0, 0L};
+ TextDEF td, otd;
+ POINT pts[12];
+ int i, j, ix, iy;
+ double r;
+ segment *seg = 0L;
+ lfPOINT fc;
+
+ switch(cmd) {
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ ix = (rec->left + rec->right)>>1;
+ iy = (rec->top +rec->bottom)>>1;
+ switch(id) {
+ case 560: case 561: case 562: case 563: case 564: //3D axes
+ OD_AxisTempl3D(cmd, par, rec, o, data, 410+AxisTempl3D);
+ break;
+ default:
+ Line.color = cmd == OD_DRAWSELECTED ? 0x00000000L : 0x00d0d0d0L;
+ Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00d0d0d0L;
+ o->SetLine(&Line);
+ pts[0].x = pts[3].x = pts[4].x = rec->left;
+ pts[0].y = pts[1].y = pts[4].y = rec->top;
+ pts[1].x = pts[2].x = rec->right-1;
+ pts[2].y = pts[3].y = rec->bottom-1;
+ o->oPolyline(pts, 5);
+ Line.color = 0x00000000L;
+ o->SetLine(&Line);
+ o->SetFill(&Fill);
+ o->oRectangle(rec->left+3, rec->top+3, rec->right-3, rec->bottom-3);
+ break;
+ }
+ switch(id) {
+ case 500:
+ case 501:
+ fc.fx = o->fix2un((double)ix-1); fc.fy = o->fiy2un((double)iy);
+ r = o->fix2un((double)(rec->right -rec->left))/3;
+ seg = new segment(0L, 0L, &fc, 0.0, r, 90.0, 45.0);
+ if(seg) {
+ if(id == 501) seg->SetSize(SIZE_RADIUS1, r*.7f);
+ seg->Command(CMD_SEG_LINE, &Line, 0L);
+ seg->Command(CMD_SEG_FILL, &FillR, 0L);
+ seg->DoPlot(o);
+ seg->SetSize(SIZE_ANGLE1, 45.0f);
+ seg->SetSize(SIZE_ANGLE2, -45.0f);
+ seg->Command(CMD_SEG_FILL, &FillG, 0L);
+ seg->DoPlot(o);
+ seg->SetSize(SIZE_ANGLE1, -45.0f);
+ seg->SetSize(SIZE_ANGLE2, 90.0f);
+ seg->Command(CMD_SEG_FILL, &FillB, 0L);
+ seg->DoPlot(o);
+ delete seg;
+ }
+ break;
+ case 502:
+ pts[0].x = rec->right-8; pts[0].y = rec->top+8;
+ pts[1].x = ix+4; pts[1].y = iy+2;
+ pts[2].x = ix+8; pts[2].y = rec->bottom-11;
+ pts[3].x = ix; pts[3].y = iy+7;
+ pts[4].x = ix-6; pts[4].y = iy+13;
+ pts[5].x = ix-5; pts[5].y = iy+5;
+ pts[6].x = rec->left+10; pts[6].y = iy+2;
+ pts[7].x = ix-3; pts[7].y = iy-1;
+ pts[8].x = ix-3; pts[8].y = iy-10;
+ pts[9].x = ix+2; pts[9].y = iy-4;
+ pts[10].x = pts[0].x; pts[10].y = pts[0].y;
+ o->SetFill(&FillY);
+ o->oPolygon(pts, 11);
+ break;
+ case 503:
+ o->SetFill(&FillR);
+ o->oRectangle(rec->left+8, rec->top+30, rec->left+12, rec->bottom-3);
+ o->oRectangle(rec->left+15, rec->bottom-10, rec->left+19, rec->bottom-3);
+ o->oRectangle(rec->left+22, rec->top+10, rec->left+26, rec->bottom-3);
+ o->oRectangle(rec->left+29, rec->bottom-35, rec->left+33, rec->bottom-3);
+ o->oRectangle(rec->left+36, rec->top+30, rec->left+40, rec->bottom-3);
+ break;
+ case 504:
+ o->SetFill(&FillR);
+ o->oRectangle(rec->left+9, rec->top+30, rec->left+13, rec->bottom-3);
+ o->oRectangle(rec->right-20, rec->top+10, rec->right-16, rec->bottom-3);
+ o->SetFill(&FillG);
+ o->oRectangle(rec->left+13, rec->top+25, rec->left+17, rec->bottom-3);
+ o->oRectangle(rec->right-16, rec->top+15, rec->right-12, rec->bottom-3);
+ o->SetFill(&FillB);
+ o->oRectangle(rec->left+17, rec->top+35, rec->left+21, rec->bottom-3);
+ o->oRectangle(rec->right-12, rec->top+20, rec->right-8, rec->bottom-3);
+ break;
+ case 505:
+ o->SetFill(&FillY);
+ o->oRectangle(rec->left+15, rec->bottom-10, rec->left+19, rec->bottom-3);
+ o->oRectangle(rec->left+22, rec->top+15, rec->left+26, rec->bottom-3);
+ o->oRectangle(rec->left+29, rec->bottom-30, rec->left+33, rec->bottom-3);
+ o->oRectangle(rec->left+36, rec->bottom-12, rec->left+40, rec->bottom-3);
+ o->SetLine(&bLine);
+ pts[0].x = rec->left +9; pts[0].y = rec->bottom-5; pts[1].x = pts[0].x+1;
+ for(i = 0; i < (rec->right - rec->left - 18); i++) {
+ r = ((double)(i+rec->left-ix+7))/8.0;
+ pts[1].y = rec->bottom - iround(exp(-r*r)*35.0+5.0);
+ o->oSolidLine(pts);
+ pts[0].x++; pts[1].x++; pts[0].y = pts[1].y;
+ }
+ break;
+ case 520:
+ case 521:
+ if(id == 521) {
+ pts[0].x = rec->left+13; pts[0].y = rec->bottom-12;
+ pts[1].x = rec->left+20; pts[1].y = rec->top+18;
+ pts[2].x = rec->right-19; pts[2].y = rec->top+33;
+ pts[3].x = rec->right-11; pts[3].y = rec->top+13;
+ o->oPolyline(pts, 4);
+ o->SetFill(&FillG);
+ }
+ else o->SetFill(&FillR);
+ o->oCircle(rec->left+10, rec->bottom-15, rec->left+16, rec->bottom-9);
+ o->oCircle(rec->left+17, rec->top+15, rec->left+23, rec->top+21);
+ o->oCircle(rec->right-22, rec->top+30, rec->right-16, rec->top+36);
+ o->oCircle(rec->right-14, rec->top+10, rec->right-8, rec->top+16);
+ break;
+ case 522:
+ o->SetFill(&FillR);
+ o->oRectangle(rec->left+3, rec->top+8, rec->left+16, rec->top+16);
+ o->SetFill(&FillG);
+ o->oRectangle(rec->left+3, iy-4, rec->right-16, iy+4);
+ o->SetFill(&FillB);
+ o->oRectangle(rec->left+3, rec->bottom-8, rec->left+26, rec->bottom-16);
+ break;
+ case 523:
+ o->SetFill(&FillR);
+ o->oRectangle(rec->left+8, rec->top+30, rec->left+16, rec->bottom-3);
+ o->SetFill(&FillG);
+ o->oRectangle(ix-4, rec->top+10, ix+4, rec->bottom-3);
+ o->SetFill(&FillB);
+ o->oRectangle(rec->right-8, rec->top+20, rec->right-16, rec->bottom-3);
+ break;
+ case 524:
+ o->SetFill(&FillG);
+ o->oCircle(rec->left+10, rec->bottom-15, rec->left+16, rec->bottom-9);
+ o->oCircle(ix-9, iy-18, ix+9, iy);
+ o->oCircle(rec->right-7, rec->top+30, rec->right-17, rec->top+40);
+ break;
+ case 525:
+ pts[0].x = pts[1].x = rec->left +12;
+ pts[0].y = rec->top+20; pts[1].y = rec->top+40;
+ o->oPolyline(pts,2);
+ pts[0].x = pts[1].x = rec->right-12;
+ o->oPolyline(pts,2);
+ pts[0].x = pts[1].x = ix;
+ pts[0].y = rec->top+10; pts[1].y = rec->top+35;
+ o->oPolyline(pts,2);
+ o->SetFill(&FillY);
+ o->oRectangle(rec->left+8, rec->top+25, rec->left+16, rec->top+35);
+ o->oRectangle(ix-4, rec->top+13, ix+4, rec->top+28);
+ o->oRectangle(rec->right-8, rec->top+30, rec->right-16, rec->top+35);
+ break;
+ case 526:
+ pts[0].x = rec->left+13; pts[0].y = rec->bottom-12;
+ pts[1].x = rec->right-11; pts[1].y = rec->top+8;
+ o->oSolidLine(pts);
+ o->SetFill(&FillB);
+ o->oCircle(rec->left+10, rec->bottom-21, rec->left+16, rec->bottom-15);
+ o->oCircle(rec->left+17, rec->top+20, rec->left+23, rec->top+26);
+ o->oCircle(rec->right-22, rec->top+25, rec->right-16, rec->top+31);
+ o->oCircle(rec->right-14, rec->top+15, rec->right-8, rec->top+21);
+ o->oCircle(rec->right-22, rec->top+9, rec->right-16, rec->top+15);
+ break;
+ case 527:
+ o->oCircle(rec->left+8, rec->top+8, rec->right-8, rec->bottom-8);
+ o->oCircle(rec->left+16, rec->top+16, rec->right-16, rec->bottom-16);
+ pts[0].x = rec->left+6; pts[0].y = iy;
+ pts[1].x = rec->right-6; pts[1].y = iy;
+ o->oSolidLine(pts);
+ pts[0].x = ix; pts[0].y = rec->bottom-6;
+ pts[1].x = ix; pts[1].y = rec->top+6;
+ o->oSolidLine(pts); o->SetFill(&FillR);
+ o->oCircle(rec->left+13, rec->top+13, rec->left+19, rec->top+19);
+ o->oCircle(ix-7, iy+1, ix-1, iy+7);
+ o->oCircle(rec->right-19, rec->bottom-19, rec->right-13, rec->bottom-13);
+ o->oCircle(rec->right-19, rec->top+13, rec->right-13, rec->top+19);
+ break;
+ case 528:
+ o->SetFill(&FillY);
+ o->oRectangle(rec->left+8, iy-2, ix-2, iy+2);
+ o->oRectangle(ix-2, iy-15, ix+2, iy+15);
+ o->oRectangle(ix+2, iy-11, ix+6, iy+11);
+ o->oRectangle(ix+6, iy-5, rec->right-8, iy+5);
+ break;
+ case 529:
+ o->SetLine(&rLine);
+ pts[0].x = rec->left +9; pts[0].y = iy; pts[1].x = pts[0].x+1;
+ for(i = 0; i < (rec->right - rec->left - 18); i++) {
+ pts[1].y = iy-4 + iround(pow(20.0, 1.0+((double)-i)/30.0) * -sin(((double)i)));
+ o->oSolidLine(pts);
+ pts[0].x++; pts[1].x++; pts[0].y = pts[1].y;
+ }
+ memcpy(&td, &o->TxtSet, sizeof(TextDEF));
+ memcpy(&otd, &o->TxtSet, sizeof(TextDEF));
+ td.Align = TXA_HCENTER | TXA_VTOP;
+ td.Style = TXS_NORMAL;
+ td.Mode = TXM_TRANSPARENT;
+ td.ColTxt = 0x00c00000L;
+ o->SetTextSpec(&td);
+ o->oTextOut(ix, iy+4, "y=f(x)", 0);
+ o->SetTextSpec(&otd);
+ break;
+ case 530:
+ o->SetLine(&rLine);
+ pts[0].x = rec->left +9; pts[0].y = iy+13; pts[1].x = pts[0].x+1;
+ for(i = 0; i < (rec->right - rec->left - 18); i++) {
+ pts[1].y = iy+12 + iround(-log10(((double)i)/.4 + 1.0)*15.0);
+ o->oSolidLine(pts);
+ pts[0].x++; pts[1].x++; pts[0].y = pts[1].y;
+ }
+ o->SetLine(&Line); o->SetFill(&FillG);
+ o->oCircle(rec->left+8, rec->bottom-15, rec->left+14, rec->bottom-9);
+ o->oCircle(rec->left+11, iy-1, rec->left+17, iy+5);
+ o->oCircle(rec->left+17, rec->top+12, rec->left+23, rec->top+18);
+ o->oCircle(rec->right-22, rec->top+8, rec->right-16, rec->top+14);
+ o->oCircle(rec->right-14, rec->top+10, rec->right-8, rec->top+16);
+ memcpy(&td, &o->TxtSet, sizeof(TextDEF));
+ memcpy(&otd, &o->TxtSet, sizeof(TextDEF));
+ td.Align = TXA_HLEFT | TXA_VCENTER;
+ td.Style = TXS_BOLD; td.Mode = TXM_TRANSPARENT;
+ td.fSize = 7.0; td.iSize = 0;
+ td.ColTxt = cmd == OD_DRAWSELECTED ? 0x0000f0f0L : 0x00c00000;
+ o->SetTextSpec(&td);
+ o->oTextOut(ix-2, iy+3, "?", 0);
+ o->SetTextSpec(&otd);
+ break;
+ case 531:
+ o->SetLine(&rLine);
+ pts[0].x = rec->left +9; pts[0].y = iy;
+ pts[1].x = ix; pts[1].y = rec->top + 9;
+ pts[2].x = rec->right -9; pts[2].y = iy;
+ o->oPolyline(pts, 3, 0L);
+ o->SetLine(&gLine);
+ pts[0].y -= 15; pts[1].y = iy; pts[2].y -=7;
+ o->oPolyline(pts, 3, 0L);
+ o->SetLine(&bLine);
+ pts[0].y += 9; pts[1].y += 10; pts[2].y = pts[1].y;
+ o->oPolyline(pts, 3, 0L);
+ break;
+ case 540:
+ o->SetFill(&FillR);
+ o->oRectangle(rec->left+8, rec->bottom-8, rec->left+16, rec->bottom-3);
+ o->oRectangle(ix-4, rec->bottom-18, ix+4, rec->bottom-3);
+ o->oRectangle(rec->right-8, rec->bottom-12, rec->right-16, rec->bottom-3);
+ o->SetFill(&FillG);
+ o->oRectangle(rec->left+8, rec->bottom-13, rec->left+16, rec->bottom-8);
+ o->oRectangle(ix-4, rec->bottom-28, ix+4, rec->bottom-18);
+ o->oRectangle(rec->right-8, rec->bottom-22, rec->right-16, rec->bottom-12);
+ o->SetFill(&FillB);
+ o->oRectangle(rec->left+8, rec->bottom-18, rec->left+16, rec->bottom-13);
+ o->oRectangle(ix-4, rec->bottom-38, ix+4, rec->bottom-28);
+ o->oRectangle(rec->right-8, rec->bottom-27, rec->right-16, rec->bottom-22);
+ break;
+ case 541:
+ o->SetFill(&FillR);
+ pts[0].x = pts[1].x = pts[5].x = rec->left+8;
+ pts[0].y = pts[4].y =pts[5].y = rec->bottom-4;
+ pts[1].y = iy+5; pts[2].x = ix; pts[2].y = rec->bottom-5;
+ pts[3].x = pts[4].x = rec->right-8;
+ pts[3].y = rec->bottom-12;
+ o->oPolygon(pts, 6);
+ o->SetFill(&FillY);
+ for(i = 1; i < 6; i++) {
+ pts[i-1].x = pts[i].x; pts[i-1].y = pts[i].y;
+ }
+ pts[5].x = pts[0].x; pts[5].y = pts[0].y;
+ pts[4].x = pts[1].x; pts[4].y = pts[1].y-8;
+ pts[3].y = rec->bottom-20;
+ o->oPolygon(pts, 6);
+ o->SetFill(&FillG);
+ pts[1].y = pts[4].y; pts[2].y = pts[3].y;
+ pts[4].y -= 12; pts[3].y -= 3;
+ o->oPolygon(pts, 6);
+ break;
+ case 542:
+ Line.color = 0x00ff0000L;
+ o->SetLine(&Line);
+ pts[0].x = rec->left+6; pts[0].y = rec->bottom-6;
+ pts[1].x = rec->left+10; pts[1].y = rec->bottom-6;
+ pts[2].x = rec->left+12; pts[2].y = iy + 8;
+ pts[3].x = rec->left+14; pts[3].y = rec->bottom-6;
+ pts[4].x = rec->right-24; pts[4].y = rec->bottom-6;
+ pts[5].x = rec->right-22; pts[5].y = iy + 4;
+ pts[6].x = rec->right-20; pts[6].y = rec->bottom-6;
+ pts[7].x = rec->right-16; pts[7].y = rec->bottom-6;
+ for(i = 0; i < 4; i++){
+ o->oPolyline(pts, 8);
+ for(j = 0; j < 8; j++) {
+ pts[j].x += 4; pts[j].y -= 4;
+ }
+ pts[2].y -= 4; pts[5].y++;
+ }
+ break;
+ case 543:
+ OD_AxisTempl3D(cmd, par, rec, o, data, 411);
+ o->SetFill(&FillR);
+ UtilBarDraw(pts, ix-5, iy-2, rec->bottom-12, o);
+ UtilBarDraw(pts, ix, iy+3, rec->bottom-11, o);
+ UtilBarDraw(pts, ix+5, iy-5, rec->bottom-10, o);
+ UtilBarDraw(pts, ix+10, iy-4, rec->bottom-9, o);
+ o->SetFill(&FillG);
+ UtilBarDraw(pts, ix-10, iy+2, rec->bottom-9, o);
+ UtilBarDraw(pts, ix-5, iy+10, rec->bottom-8, o);
+ UtilBarDraw(pts, ix, iy+8, rec->bottom-7, o);
+ UtilBarDraw(pts, ix+5, iy, rec->bottom-6, o);
+ break;
+ case 544:
+ OD_AxisTempl3D(cmd, par, rec, o, data, 411);
+ for(i = 0; i < 6; i++){
+ switch(i) {
+ case 0:
+ o->SetFill(&FillY);
+ pts[0].x = ix-5; pts[0].y = iy+1;
+ pts[1].x = ix; pts[1].y = iy-10;
+ break;
+ case 1:
+ pts[0].x = pts[1].x; pts[0].y = pts[1].y;
+ pts[1].x = ix+5; pts[1].y = iy -6;
+ break;
+ case 2:
+ pts[0].x = pts[1].x; pts[0].y = pts[1].y;
+ pts[1].x = ix+10; pts[1].y = iy +4;
+ break;
+ case 3:
+ o->SetFill(&FillR);
+ pts[0].x = ix-10; pts[0].y = iy-10;
+ pts[1].x = ix-5; pts[1].y = iy+4;
+ break;
+ case 4:
+ pts[0].x = pts[1].x; pts[0].y = pts[1].y;
+ pts[1].x = ix; pts[1].y = iy +9;
+ break;
+ case 5:
+ pts[0].x = pts[1].x; pts[0].y = pts[1].y;
+ pts[1].x = ix+10; pts[1].y = iy +12;
+ break;
+ }
+ pts[2].x = pts[1].x -3; pts[2].y = pts[1].y + 2;
+ pts[3].x = pts[0].x -3; pts[3].y = pts[0].y + 2;
+ pts[4].x = pts[0].x; pts[4].y = pts[0].y;
+ o->oPolygon(pts, 5);
+ }
+ break;
+ case 560:
+ o->SetFill(&FillY);
+#ifdef _WINDOWS
+ o->oCircle(rec->right-13, rec->top+7, rec->right-19, rec->top+13);
+ o->oCircle(rec->right-11, iy-3, rec->right-17, iy+3);
+ o->oCircle(ix, iy+3, ix+6, iy+9);
+ o->oCircle(rec->left+12, iy+3, rec->left+18, iy+9);
+ o->oCircle(ix, rec->bottom-6, ix+6, rec->bottom-12);
+#else
+ o->oCircle(rec->right-15, rec->top+7, rec->right-19, rec->top+13);
+ o->oCircle(rec->right-13, iy-3, rec->right-17, iy+3);
+ o->oCircle(ix, iy+3, ix+6, iy+9);
+ o->oCircle(rec->left+12, iy+3, rec->left+18, iy+9);
+ o->oCircle(ix, rec->bottom-8, ix+6, rec->bottom-12);
+#endif
+ break;
+ case 561:
+ o->SetFill(&FillG);
+ UtilBarDraw(pts, ix+1, rec->top +12, rec->bottom-10, o);
+ UtilBarDraw(pts, rec->left+16, iy+8, rec->bottom-8, o);
+ UtilBarDraw(pts, rec->right-12, iy+12, rec->bottom-8, o);
+ break;
+ case 562:
+ o->SetLine(&bLine);
+ pts[0].x = rec->left+20; pts[0].y = rec->bottom-10;
+ pts[1].x = rec->right-10; pts[1].y = rec->bottom-16;
+ o->oSolidLine(pts);
+ pts[0].x = pts[1].x; pts[0].y = pts[1].y;
+ pts[1].x -= 8; pts[1].y -= 12;
+ o->oSolidLine(pts);
+ pts[0].x = pts[1].x; pts[0].y = pts[1].y;
+ pts[1].x -= 18; pts[1].y += 3;
+ o->oSolidLine(pts);
+ pts[0].x = pts[1].x; pts[0].y = pts[1].y;
+ pts[1].x += 15; pts[1].y += 4;
+ o->oSolidLine(pts);
+ break;
+ case 563:
+ o->SetFill(&FillG);
+ o->oCircle(rec->left+12, rec->bottom-19, rec->left+18, rec->bottom-13);
+ o->oCircle(ix, iy-10, ix+14, iy+4);
+ o->oCircle(ix, rec->top+34, ix+10, rec->top+44);
+ break;
+ case 564:
+ o->SetFill(&FillY);
+ pts[0].x = rec->left+10; pts[0].y = rec->bottom-14;
+ pts[1].x = pts[0].x; pts[1].y = rec->top +16;
+ pts[2].x = ix-6; pts[2].y = iy+4;
+ pts[3].x = pts[2].x; pts[3].y = rec->bottom -10;
+ pts[4].x = pts[0].x; pts[4].y = pts[0].y;
+ o->oPolygon(pts, 5, 0L);
+ pts[0].x = pts[2].x; pts[0].y = pts[2].y;
+ pts[1].x = pts[3].x; pts[1].y = pts[3].y;
+ pts[2].x = ix + 3; pts[2].y = pts[1].y -2;
+ pts[3].x = pts[2].x; pts[3].y = pts[0].y +1;
+ pts[4].x = pts[0].x; pts[4].y = pts[0].y;
+ o->oPolygon(pts, 5, 0L);
+ pts[0].x = pts[2].x; pts[0].y = pts[2].y;
+ pts[1].x = pts[3].x; pts[1].y = pts[3].y;
+ pts[2].x = ix + 10; pts[2].y = pts[1].y +9;
+ pts[3].x = pts[2].x; pts[3].y = pts[0].y +3;
+ pts[4].x = pts[0].x; pts[4].y = pts[0].y;
+ o->oPolygon(pts, 5, 0L);
+ break;
+ }
+ o->UpdateRect(rec, false);
+ break;
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Execute axis templates as owner drawn buttons
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void OD_AxisTempl(int cmd, void *par, RECT *rec, anyOutput *o,
+ void *data, int id)
+{
+ LineDEF Line = {0.0, 1.0, 0x0L, 0x0L};
+ LineDEF Grid = {0.0, 1.0, 0x00c0c0c0, 0x0L};
+ FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
+ POINT pts[5];
+ int i, ty, tx, sx;
+
+ switch(cmd) {
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ Line.color = cmd == OD_DRAWSELECTED ? 0x00000000L : 0x00d0d0d0L;
+ Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00d0d0d0L;
+ o->SetLine(&Line);
+ pts[0].x = pts[3].x = pts[4].x = rec->left;
+ pts[0].y = pts[1].y = pts[4].y = rec->top;
+ pts[1].x = pts[2].x = rec->right-1;
+ pts[2].y = pts[3].y = rec->bottom-1;
+ o->oPolyline(pts, 5);
+ Line.color = 0x00000000L;
+ o->SetLine(&Line);
+ o->SetFill(&Fill);
+ o->oRectangle(rec->left+3, rec->top+3, rec->right-3, rec->bottom-3);
+ tx = ty = 0;
+ switch(id) {
+ case 310:
+ o->oRectangle(rec->left+10, rec->top+6, rec->right-6, rec->bottom-10);
+ ty = rec->bottom -10; tx = rec->left+8;
+ break;
+ case 311:
+ o->oRectangle(rec->left+10, rec->top+6, rec->right-6, rec->bottom-10);
+ pts[0].x = rec->left+10; pts[1].x = rec->right-6;
+ pts[0].y = pts[1].y = rec->bottom-32;
+ o->oSolidLine(pts);
+ pts[0].y = rec->top+6; pts[1].y = rec->bottom-10;
+ pts[0].x = pts[1].x = rec->left + 32;
+ o->oSolidLine(pts);
+ ty = rec->bottom -31; tx = rec->left+30;
+ break;
+ case 312:
+ pts[0].x = rec->left+10; pts[1].x = rec->right-6;
+ pts[0].y = pts[1].y = rec->bottom-11;
+ o->oSolidLine(pts);
+ pts[0].y = rec->top+6; pts[1].y = rec->bottom-10;
+ pts[0].x = pts[1].x = rec->left + 10;
+ o->oSolidLine(pts);
+ ty = rec->bottom -10; tx = rec->left+8;
+ break;
+ case 313:
+ pts[0].x = rec->left+10; pts[1].x = rec->right-6;
+ pts[0].y = pts[1].y = rec->top + 9;
+ o->oSolidLine(pts);
+ pts[0].y = rec->top+10; pts[1].y = rec->bottom-10;
+ pts[0].x = pts[1].x = rec->left + 10;
+ o->oSolidLine(pts);
+ ty = rec->top+7; tx = rec->left+8;
+ break;
+ case 314:
+ pts[0].x = rec->left+10; pts[1].x = rec->right-6;
+ pts[0].y = pts[1].y = rec->bottom-11;
+ o->oSolidLine(pts);
+ pts[0].y = rec->top+6; pts[1].y = rec->bottom-10;
+ pts[0].x = pts[1].x = rec->left + 27;
+ o->oSolidLine(pts);
+ ty = rec->bottom -10; tx = rec->left+25;
+ break;
+ }
+ if(ODtickstyle & 0x300) {
+ o->SetLine(&Grid);
+ pts[0].y = rec->top+7; pts[1].y = rec->bottom-11;
+ if(id == 313) pts[0].y +=3;
+ if(ODtickstyle & 0x100) for(i = rec->left+16; i < rec->right-6; i+=12) {
+ pts[0].x = pts[1].x = i;
+ o->oSolidLine(pts);
+ }
+ pts[0].x = rec->left+11; pts[1].x = rec->right-7;
+ if(ODtickstyle & 0x200)
+ for(i = rec->bottom- (id == 313 ? 11 : 17); i > rec->top+6; i -=12) {
+ pts[0].y = pts[1].y = i;
+ o->oSolidLine(pts);
+ }
+ o->SetLine(&Line);
+ }
+ if(tx != ty) {
+ sx = 2;
+ switch(ODtickstyle & 0x03){
+ case 1:
+ if(id == 313) ty += 3;
+ else ty -= 3;
+ tx += 3;
+ break;
+ case 2:
+ if(id == 313) ty += 1;
+ else ty -= 2;
+ tx += 1;
+#ifdef _WINDOWS
+ sx = 3;
+#endif
+ break;
+ default:
+ break;
+ }
+ pts[0].y = ty; pts[1].y = ty+sx;
+ for(i = rec->left+10; i < rec->right-6; i+=6) {
+ pts[0].x = pts[1].x = i;
+ o->oSolidLine(pts);
+ }
+ pts[0].x = tx; pts[1].x = tx+sx;
+ for(i = rec->bottom-11; i > rec->top+6; i -=6) {
+ pts[0].y = pts[1].y = i;
+ o->oSolidLine(pts);
+ }
+ }
+ o->UpdateRect(rec, false);
+ break;
+ }
+
+}
+
+void OD_AxisTempl3D(int cmd, void *par, RECT *rec, anyOutput *o,
+ void *data, int id)
+{
+ LineDEF Line = {0.0, 1.0, 0x0L, 0x0L};
+ FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
+ POINT pts[5];
+ int x, y;
+
+ switch(cmd) {
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ Line.color = cmd == OD_DRAWSELECTED ? 0x00000000L : 0x00d0d0d0L;
+ Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00d0d0d0L;
+ o->SetLine(&Line);
+ pts[0].x = pts[3].x = pts[4].x = rec->left;
+ pts[0].y = pts[1].y = pts[4].y = rec->top;
+ pts[1].x = pts[2].x = rec->right-1;
+ pts[2].y = pts[3].y = rec->bottom-1;
+ o->oPolyline(pts, 5);
+ Line.color = 0x00000000L;
+ o->SetLine(&Line);
+ o->SetFill(&Fill);
+ o->oRectangle(rec->left+3, rec->top+3, rec->right-3, rec->bottom-3);
+ switch(id) {
+ case 410: case 411:
+ pts[0].x = rec->left+20; pts[0].y = rec->bottom-14;
+ pts[1].x = rec->left+10; pts[1].y = rec->bottom-10;
+ o->oSolidLine(pts);
+ pts[1].x = rec->right-10; pts[1].y = pts[0].y + 3;
+ o->oSolidLine(pts);
+ pts[1].x = pts[0].x; pts[1].y = rec->top+8;
+ o->oSolidLine(pts);
+ if(id == 411) {
+ pts[0].x = rec->left+10; pts[0].y = rec->top+12;
+ o->oSolidLine(pts);
+ pts[0].x = rec->right-10; pts[0].y = pts[1].y + 3;
+ o->oSolidLine(pts);
+ pts[1].x = pts[0].x; pts[1].y = rec->bottom-11;
+ o->oSolidLine(pts);
+ pts[0].x = rec->right-20; pts[0].y = rec->bottom-7;
+ o->oSolidLine(pts);
+ pts[1].x = rec->left+10; pts[1].y = rec->bottom-10;
+ o->oSolidLine(pts);
+ pts[0].x = rec->left+10; pts[0].y = rec->top+12;
+ o->oSolidLine(pts);
+ }
+ break;
+ case 412:
+ x = (rec->right+rec->left)>>1; y = (rec->top+rec->bottom)>>1;
+ pts[0].x = rec->left+14; pts[0].y = y+4;
+ pts[1].x = rec->right-14; pts[1].y = y-2;
+ o->oSolidLine(pts);
+ pts[1].y += 6; pts[0].y -= 6; pts[1].x +=4; pts[0].x -=4;
+ o->oSolidLine(pts);
+ pts[0].x = pts[1].x = x; pts[0].y = y-15; pts[1].y = y+15;
+ o->oSolidLine(pts);
+ }
+ o->UpdateRect(rec, false);
+ break;
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Execute axis templates for new axis as owner drawn buttons
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void OD_NewAxisTempl(int cmd, void *par, RECT *rec, anyOutput *o,
+ void *data, int id)
+{
+ LineDEF Line = {0.0, 1.0, 0x0L, 0x0L};
+ FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
+ POINT pts[5];
+ int i, ix, iy, step, d1, d2;
+
+ switch(cmd) {
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ Line.color = cmd == OD_DRAWSELECTED ? 0x00000000L : 0x00d0d0d0L;
+ Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00d0d0d0L;
+ o->SetLine(&Line);
+ ix = (rec->right + rec->left)>>1;
+ iy = (rec->bottom + rec->top)>>1;
+ pts[0].x = pts[3].x = pts[4].x = rec->left;
+ pts[0].y = pts[1].y = pts[4].y = rec->top;
+ pts[1].x = pts[2].x = rec->right-1;
+ pts[2].y = pts[3].y = rec->bottom-1;
+ o->oPolyline(pts, 5);
+ Line.color = 0x00000000L;
+ o->SetLine(&Line);
+ o->SetFill(&Fill);
+ o->oRectangle(rec->left+3, rec->top+3, rec->right-3, rec->bottom-3);
+ d1 = d2 = 0;
+ switch(id) {
+ case 201: d1 = -6; d2 = -2;
+ case 202: d2 -= 14;
+ case 203: d1 += 6; d2 += 3;
+ case 204:
+ d1 = d1 + ix -3; d2 = d2 + ix +4;
+ pts[0].x = pts[1].x = ix;
+ pts[0].y = rec->top +9; pts[1].y = rec->bottom -9;
+ step = ((pts[1].y - pts[0].y)/5)+1;
+ o->oSolidLine(pts);
+ pts[0].x = d1; pts[1].x = ix;
+ for(i = rec->top +11; i <= rec->bottom-9; i += step) {
+ pts[0].y = pts[1].y = i;
+ o->oSolidLine(pts);
+ o->oRectangle(d2, i-1, d2+4, i+1);
+ }
+ break;
+ case 205: d1 = 6; d2 = 3;
+ case 206: d2 += 10;
+ case 207: d1 -= 6; d2 -= 3;
+ case 208:
+ d1 = d1 + iy +3; d2 = d2 + iy - 4;
+ pts[0].y = pts[1].y = iy;
+ pts[0].x = rec->left +9; pts[1].x = rec->right -9;
+ step = ((pts[1].x - pts[0].x)/4)+1;
+ o->oSolidLine(pts);
+ pts[0].y = d1; pts[1].y = iy;
+ for(i = rec->left +11; i <= rec->right-9; i += step) {
+ pts[0].x = pts[1].x = i;
+ o->oSolidLine(pts);
+ o->oRectangle(i-1, d2, i+2, d2+2);
+ }
+ break;
+ }
+ o->UpdateRect(rec, false);
+ break;
+ }
+}
+
diff --git a/Output.cpp b/Output.cpp
new file mode 100755
index 0000000..54d6576
--- /dev/null
+++ b/Output.cpp
@@ -0,0 +1,1829 @@
+//Output.cpp, Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005 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 <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.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
+#include "rlplot.h"
+
+tag_Units Units[] = {{0, "mm", 1.0f}, {1, "cm", 10.0f}, {2, "inch", 25.4f},
+ };
+
+extern Default defs;
+extern GraphObj *CurrGO, *TrackGO; //Selected Graphic Objects
+extern Label *CurrLabel;
+extern Graph *CurrGraph;
+extern dragHandle *CurrHandle;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Output base class
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+anyOutput::anyOutput()
+{
+ units = defs.cUnits;
+ dBgCol = dFillCol = defs.Color(COL_BG);
+ xAxis.owner = yAxis.owner = zAxis.owner = (void *)this;
+ xAxis.flags = yAxis.flags = zAxis.flags = 0L;
+ xAxis.min = yAxis.min = zAxis.min = 0.0;
+ xAxis.max = yAxis.max = zAxis.max = 1.0;
+ xAxis.nBreaks = yAxis.nBreaks = zAxis.nBreaks = 0;
+ xAxis.breaks = yAxis.breaks = zAxis.breaks = 0L;
+ ddx = ddy = ddz = 1.0;
+ RLP.finc = 1.0f;
+ RLP.fp = 0.0f;
+ dPattern = 0xffffffffL; //impossible (invisible)line pattern to start with
+ dBgCol = defs.Color(COL_BG);
+ MrkMode = MRK_NONE; MrkRect = 0L;
+ VPorg.fx = VPorg.fy = 0.0; VPscale = 1.0;
+ MenuHeight = 0; cCursor = MC_ARROW;
+ rotM[0][0] = rotM[1][1] = rotM[2][2] = 1.0;
+ rotM[0][1] = rotM[0][2] = rotM[1][0] = rotM[1][2] = rotM[2][0] = rotM[2][1] = 0.0;
+ hasHistMenu = false; HistMenuSize = 0;
+ light_source.fx = light_source.fy = 0.0;
+}
+
+void
+anyOutput::SetRect(fRECT rec, int u, AxisDEF *x_ax, AxisDEF *y_ax)
+{
+ double spx, spy;
+
+ if (u >= 0 && u < NUM_UNITS) defs.cUnits = units = u;
+ else units = defs.cUnits;
+ spx = rec.Xmax - rec.Xmin; spy = rec.Ymin -rec.Ymax;
+ MrkMode = MRK_NONE;
+ Box1.Xmin = co2fix(rec.Xmin); Box1.Ymin = co2fiy(rec.Ymax);
+ Box1.Xmax = co2fix(rec.Xmax); Box1.Ymax = co2fiy(rec.Ymin);
+ if(!x_ax || !y_ax) return;
+ if(x_ax->flags & AXIS_DEFRECT) {
+ Box1.Xmin = co2fix(x_ax->loc[0].fx);
+ Box1.Xmax = co2fix(x_ax->loc[1].fx);
+ spx = x_ax->loc[1].fx - x_ax->loc[0].fx;
+ }
+ if(y_ax->flags & AXIS_DEFRECT) {
+ Box1.Ymin = co2fiy(y_ax->loc[0].fy);
+ Box1.Ymax = co2fiy(y_ax->loc[1].fy);
+ spy = y_ax->loc[1].fy - y_ax->loc[0].fy;
+ }
+ memcpy(&xAxis, x_ax, sizeof(AxisDEF));
+ memcpy(&yAxis, y_ax, sizeof(AxisDEF));
+ ddy = GetAxisFac(&yAxis, un2fiy(spy), 1);
+ ddx = GetAxisFac(&xAxis, un2fix(spx), 0);
+ xAxis.owner = yAxis.owner = this;
+}
+
+void
+anyOutput::SetSpace(fPOINT3D *cub1, fPOINT3D *cub2, int u, double *rot,
+ fPOINT3D *cent, AxisDEF *x_ax, AxisDEF *y_ax, AxisDEF *z_ax)
+{
+ double rotQ[6]; //rotation definition:
+ // unit vector x
+ // y
+ // z
+ // sin(phi)
+ // cos(phi)
+ // 1.0 -cos(phi)
+ double dp;
+
+ if (u >= 0 && u < NUM_UNITS) defs.cUnits = units = u;
+ else units = defs.cUnits;
+ MrkMode = MRK_NONE;
+ HideTextCursor();
+ memcpy(&xAxis, x_ax, sizeof(AxisDEF));
+ memcpy(&yAxis, y_ax, sizeof(AxisDEF));
+ memcpy(&zAxis, z_ax, sizeof(AxisDEF));
+ xAxis.owner = yAxis.owner = zAxis.owner = this;
+ //assume resolution equal in all directions: use un2fix() for
+ // all coordinates
+ Box1.Xmin = co2fix(cub1->fx); Box1.Ymin = co2fiy(cub2->fy);
+ Box1.Xmax = co2fix(cub2->fx); Box1.Ymax = co2fiy(cub1->fy);
+ Box1z.fx = un2fiz(cub1->fz); Box1z.fy = un2fiz(cub2->fz);
+ if(x_ax->flags & AXIS_DEFRECT) {
+ Box1.Xmin = co2fix(x_ax->loc[0].fx); Box1.Xmax = co2fix(x_ax->loc[1].fx);
+ }
+ if(y_ax->flags & AXIS_DEFRECT) {
+ Box1.Ymax = co2fiy(y_ax->loc[0].fy); Box1.Ymin = co2fiy(y_ax->loc[1].fy);
+ }
+ if(z_ax->flags & AXIS_DEFRECT) {
+ Box1z.fx = un2fiz(z_ax->loc[0].fz); Box1z.fy = un2fiz(z_ax->loc[1].fz);
+ }
+ ddx = GetAxisFac(&xAxis, Box1.Xmax-Box1.Xmin, 0);
+ ddy = GetAxisFac(&yAxis, Box1.Ymax-Box1.Ymin, 1);
+ ddz = GetAxisFac(&zAxis, Box1z.fy - Box1z.fx, 2);
+ rotC.fx = un2fix(cent->fx)+ VPorg.fx;
+ rotC.fy = un2fiy(cent->fy)+ VPorg.fy;
+ rotC.fz = un2fiz(cent->fz);
+ memcpy(rotQ, rot, sizeof(rotQ));
+ //normalize vector part of rotQ
+ dp = sqrt(rotQ[0]*rotQ[0] + rotQ[1]*rotQ[1] + rotQ[2]*rotQ[2]);
+ rotQ[0] /= dp; rotQ[1] /= dp; rotQ[2] /= dp;
+ dp = sqrt(rotQ[0]*rotQ[0] + rotQ[1]*rotQ[1] + rotQ[2]*rotQ[2]);
+ //set up rotation matrix from quaternion
+ //see: Graphic Gems, A.S. Glassner ed.; Academic Press Inc.
+ //M.E. Pique: Rotation Tools
+ // ISBN 0-12-286165-5, p. 466
+ rotM[0][0] = rotQ[5]*rotQ[0]*rotQ[0] + rotQ[4];
+ rotM[0][1] = rotQ[5]*rotQ[0]*rotQ[1] + rotQ[3]*rotQ[2];
+ rotM[0][2] = rotQ[5]*rotQ[0]*rotQ[2] - rotQ[3]*rotQ[1];
+ rotM[1][0] = rotQ[5]*rotQ[0]*rotQ[1] - rotQ[3]*rotQ[2];
+ rotM[1][1] = rotQ[5]*rotQ[1]*rotQ[1] + rotQ[4];
+ rotM[1][2] = rotQ[5]*rotQ[1]*rotQ[2] + rotQ[3]*rotQ[0];
+ rotM[2][0] = rotQ[5]*rotQ[0]*rotQ[2] + rotQ[3]*rotQ[1];
+ rotM[2][1] = rotQ[5]*rotQ[1]*rotQ[2] - rotQ[3]*rotQ[0];
+ rotM[2][2] = rotQ[5]*rotQ[2]*rotQ[2] + rotQ[4];
+}
+
+void
+anyOutput::LightSource(double x, double y)
+{
+ int i, j, m;
+ double angx, angy;
+ double a[3][3], b[3][3];
+
+ if(light_source.fx == 0.0 || light_source.fy == 0.0 ||
+ x != light_source.fx || y != light_source.fy) {
+ light_source.fx = x; light_source.fy = y;
+ angx = x * 0.017453292; angy = y * 0.017453292;
+ for (i = 0; i < 3; i++) for(j = 0; j < 3; j++) {
+ a[i][j] = b[i][j] = 0.0;
+ }
+ //first axis
+ a[0][0] = 1.0; a[1][1] = cos(angx); a[1][2] = -sin(angx);
+ a[2][1] = -a[1][2]; a[2][2] = a[1][1];
+ //second axis
+ b[0][0] = cos(angy); b[0][1] = -sin(angy); b[1][0] = -b[0][1];
+ b[1][1] = b[0][0]; b[2][2] = 1.0;
+ //combine the two rotations
+ for (i = 0; i < 3; i++) for(j = 0; j < 3; j++){
+ light_vec[i][j] = 0.0;
+ for(m = 0; m < 3; m++) light_vec[i][j] += (a[i][m] * b[m][j]);
+ }
+ }
+}
+
+DWORD
+anyOutput::VecColor(double *plane_vec, DWORD color1, DWORD color2)
+{
+ double v[3], vec[3], vlength;
+ int i, j;
+
+ //rotate vector towards the light source
+ if(!plane_vec) return color1;
+ v[0] = plane_vec[0]; v[1] = plane_vec[2]; v[2] = plane_vec[1];
+ for (i = 0; i < 3; i++) for(j = 0, vec[i] = 0.0; j < 3; j++)
+ vec[i] += (light_vec[i][j] * v[j]);
+ //normalize vec: both vector should have unit length but make sure
+ vlength = sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
+ if(vlength < 0.9) return color1;
+ vec[0] /= vlength; vec[1] /= vlength; vec[2] /= vlength;
+ //calc color
+ return IpolCol(color1, color2, fabs(vec[1]));
+}
+
+bool
+anyOutput::GetSize(RECT *rc)
+{
+ memcpy(rc, &DeskRect, sizeof(RECT));
+ return true;
+}
+
+double
+anyOutput::fx2fix(double x)
+{
+ double temp;
+
+ x = TransformValue(&xAxis, x, true);
+ temp = (x - xAxis.min)*ddx;
+ if(0 == (xAxis.flags & AXIS_INVERT)) return temp + Box1.Xmin;
+ return Box1.Xmax-temp;
+}
+
+double
+anyOutput::fy2fiy(double y)
+{
+ double temp;
+
+ y = TransformValue(&yAxis, y, true);
+ temp = (y - yAxis.min)*ddy;
+ if(AXIS_INVERT == (yAxis.flags & AXIS_INVERT)) return temp + Box1.Ymin;
+ return Box1.Ymax-temp;
+}
+
+double
+anyOutput::fz2fiz(double z)
+{
+ double temp;
+
+ z = TransformValue(&zAxis, z, true);
+ temp = (z - zAxis.min)*ddz;
+ if(0 == (zAxis.flags & AXIS_INVERT)) return temp + Box1z.fx;
+ return Box1z.fy-temp;
+}
+
+bool
+anyOutput::fp2fip(lfPOINT *fdp, lfPOINT *fip)
+{
+ double x, y, si, csi, temp;
+
+ if((xAxis.flags & AXIS_ANGULAR) && (yAxis.flags & AXIS_RADIAL)) {
+ x = 6.283185307 * TransformValue(&xAxis, fdp->fx + xAxis.Start, true)/(xAxis.max-xAxis.min);
+ si = sin(x); csi = cos(x);
+ y = TransformValue(&yAxis, fdp->fy, true);
+ temp = (y - yAxis.min)*ddy;
+ if(yAxis.flags & AXIS_INVERT) temp = Box1.Ymax - Box1.Ymin - temp;
+ fip->fx = ((Box1.Xmin + Box1.Xmax)/2.0) + csi * temp;
+ if(xAxis.flags & AXIS_INVERT) fip->fy = Box1.Ymax + si * temp;
+ else fip->fy = Box1.Ymax - si * temp;
+ fip->fy += disp_y;
+ return true;
+ }
+ else {
+ fip->fx = fx2fix(fdp->fx); fip->fy = fy2fiy(fdp->fy);
+ return true;
+ }
+ return false;
+}
+
+bool
+anyOutput::fvec2ivec(fPOINT3D *v, fPOINT3D *iv)
+{
+ double x, y, z;
+
+ if(!v || !iv) return false;
+ x = fx2fix(v->fx)-rotC.fx;
+ y = fy2fiy(v->fy)-rotC.fy;
+ z = fz2fiz(v->fz)-rotC.fz;
+ iv->fx = x * rotM[0][0] + y * rotM[0][1] + z * rotM[0][2] + rotC.fx;
+ iv->fy = x * rotM[1][0] + y * rotM[1][1] + z * rotM[1][2] + rotC.fy;
+ iv->fz = x * rotM[2][0] + y * rotM[2][1] + z * rotM[2][2] + rotC.fz;
+ iv->fx += disp_x; iv->fy += disp_y;
+ return true;
+}
+
+bool
+anyOutput::cvec2ivec(fPOINT3D *v, fPOINT3D *iv)
+{
+ double x, y, z;
+
+ if(!v || !iv) return false;
+ x = co2fix(v->fx)-rotC.fx;
+ y = co2fiy(v->fy)-rotC.fy;
+ z = un2fiz(v->fz)-rotC.fz;
+ iv->fx = x * rotM[0][0] + y * rotM[0][1] + z * rotM[0][2] + rotC.fx;
+ iv->fy = x * rotM[1][0] + y * rotM[1][1] + z * rotM[1][2] + rotC.fy;
+ iv->fz = x * rotM[2][0] + y * rotM[2][1] + z * rotM[2][2] + rotC.fz;
+ iv->fx += disp_x; iv->fy += disp_y;
+ return true;
+}
+
+bool
+anyOutput::uvec2ivec(fPOINT3D *v, fPOINT3D *iv)
+{
+ double x, y, z;
+
+ if(!v || !iv) return false;
+ x = un2fix(v->fx);
+ y = un2fiy(v->fy);
+ z = un2fiz(v->fz);
+ iv->fx = x * rotM[0][0] + y * rotM[0][1] + z * rotM[0][2];
+ iv->fy = x * rotM[1][0] + y * rotM[1][1] + z * rotM[1][2];
+ iv->fz = x * rotM[2][0] + y * rotM[2][1] + z * rotM[2][2];
+ return true;
+}
+
+double
+anyOutput::un2fix(double x)
+{
+ return (x * VPscale * hres*Units[units].convert/25.4);
+}
+
+double
+anyOutput::un2fiy(double y)
+{
+ return (y * VPscale * vres*Units[units].convert/25.4);
+}
+
+double
+anyOutput::un2fiz(double z)
+{
+ return (z * VPscale * hres*Units[units].convert/25.4);
+}
+
+double
+anyOutput::fix2un(double fix)
+{
+ return (fix/Units[units].convert*25.4/hres)/VPscale;
+}
+
+double
+anyOutput::fiy2un(double fiy)
+{
+ return (fiy/Units[units].convert*25.4/vres)/VPscale;
+}
+
+bool
+anyOutput::GetLine(LineDEF *lDef)
+{
+ if(lDef) {
+ lDef->width = LineWidth;
+ lDef->color = dLineCol;
+ lDef->pattern = dPattern;
+ return true;
+ }
+ return false;
+}
+
+
+bool
+anyOutput::SetTextSpec(TextDEF *set)
+{
+ memcpy(&TxtSet, set, sizeof(TextDEF));
+ TxtSet.text = 0L;
+ return true;
+}
+
+
+bool
+anyOutput::ShowMark(void *src, int Mode)
+{
+ GraphObj *go;
+
+ if(MrkMode != MRK_NONE) HideMark();
+ MrkMode = Mode; MrkRect = src;
+ switch (Mode) {
+ case MRK_INVERT:
+ return UpdateRect((RECT*)src, true);
+ case MRK_GODRAW: case MRK_SSB_DRAW:
+ go = (GraphObj *) src;
+ go->DoMark(this, true);
+ CurrGO = go;
+ if(CurrLabel && CurrLabel != CurrGO) {
+ HideTextCursor();
+ CurrLabel = 0L;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool
+anyOutput::HideMark()
+{
+ CurrGO = 0L;
+ switch(MrkMode) {
+ case MRK_NONE:
+ return true;
+ case MRK_INVERT:
+ MrkMode = MRK_NONE;
+ return UpdateRect((RECT*)MrkRect, false);
+ case MRK_GODRAW:
+ MrkMode = MRK_NONE; //inhibit reentrance
+ if(CurrGraph) {
+ if(CurrGraph->Command(CMD_HIDE_MARK, MrkRect, this)){
+ return true;
+ }
+ else CurrGraph->Command(CMD_REDRAW, 0L, this);
+ }
+ return true;
+ case MRK_SSB_DRAW:
+ MrkMode = MRK_NONE;
+ if (MrkRect) ((GraphObj*)MrkRect)->DoMark(this, false);
+ return true;
+ }
+ return false;
+}
+
+int
+anyOutput::CalcCursorPos(char *txt, POINT p, POINT *fit)
+{
+ int i, d, w, h, CurrPos;
+
+ d = TxtSet.iSize >>2;
+ if(!txt || !fit) return 0;
+ if (!(i = strlen(txt)))return 0;
+ //right justified text
+ if(TXA_HRIGHT == (TxtSet.Align & TXA_HRIGHT)){
+ if((p.x - fit->x) < d) return i;
+ for (CurrPos = i-1; CurrPos >= 0; CurrPos--) {
+ if(!oGetTextExtent(txt+CurrPos, i-CurrPos, &w, &h)) return 0;
+ if((w = p.x - w - d) <= fit->x) return CurrPos;
+ }
+ return 0;
+ }
+ //left justified text
+ else {
+ if((fit->x - p.x) < d) return 0;
+ for (CurrPos = i; CurrPos >= 0; CurrPos--) {
+ if(!oGetTextExtent(txt, CurrPos, &w, &h)) return 0;
+ if((w = p.x + w - d) <= fit->x) return CurrPos;
+ }
+ }
+ return 0;
+}
+
+bool
+anyOutput::TextCursor(char *txt, POINT p, POINT *fit, int *pos, int dx)
+{
+ int i, w, h, CurrPos;
+ RECT disp;
+
+ if(fit) CurrPos = CalcCursorPos(txt, p, fit);
+ //recalculate caret position
+ if(txt && pos && !fit){
+ if(TxtSet.Align & TXA_HRIGHT) { //right justfied text
+ if((i = strlen(txt)-(*pos))){
+ if(!oGetTextExtent(txt+(*pos), i, &w, &h)) return false;
+ w = p.x - w;
+ }
+ else w = p.x-1;
+ }
+ else { //left justified text
+ if(!(*pos)) w = 0;
+ else if(!oGetTextExtent(txt, *pos, &w, &h))return false;
+ w += p.x;
+ }
+ }
+ else if(!fit)return false;
+ //right justified text: search caret and cursor position
+ else if(txt && (TxtSet.Align & TXA_HRIGHT)){
+ i = strlen(txt);
+ if(i == CurrPos) w = 1;
+ else if(!oGetTextExtent(txt+CurrPos, i-CurrPos, &w, &h)) return false;
+ w = p.x - w;
+ }
+ //left justified text: search caret and cursor position
+ else if(txt && fit) {
+ if (!CurrPos) w = 0;
+ else if(!oGetTextExtent(txt, CurrPos, & w, &h)) return false;
+ w += p.x;
+ }
+ if(fit && pos) *pos = CurrPos;
+ disp.left = disp.right = w+dx;
+ disp.top = p.y;
+#ifdef _WINDOWS
+ disp.bottom = disp.top + TxtSet.iSize;
+#else
+ disp.bottom = disp.top + iround(TxtSet.iSize*1.25);
+#endif
+ ShowTextCursor(this, &disp, 0x0L);
+ return true;
+}
+
+//we need our own implementation of Bresenham's line drawing algorithm to draw
+// a line with variable pattern sizes.
+//Ref: P.S. Heckbert (1990) "Digital Line Drawing", in: Graphic Gems
+// (A.S. Glassner, ed.); Academic Press, Inc.,
+// ISBN 0-12-286165-5
+bool
+anyOutput::PatLine(POINT p1, POINT p2)
+{
+ int d, ax, ay, sx, sy, dx, dy;
+ double fInc2;
+ bool bPen;
+ POINT tr[2];
+
+ dx = p2.x - p1.x;
+ fInc2 = RLP.finc * 0.414213562; //increment by sqrt(2) if 45� slope
+ if ( p2.x < p1.x) { ax = (-dx)<<1; sx = -1; }
+ else { ax = dx <<1; sx = 1; }
+ dy = p2.y - p1.y;
+ if (p2.y < p1.y) { ay = (-dy)<<1; sy = -1; }
+ else { ay = dy<<1; sy = 1; }
+ tr[0].x = tr[1].x = p1.x; tr[0].y = tr[1].y = p1.y;
+ if(dPattern &(1 << ((int)RLP.fp))) bPen = false;
+ else bPen = true;
+ if (ax > ay) { // x dominant
+ d = ay - (ax >>1);
+ for ( ; ; ) {
+ RLP.fp += RLP.finc;
+ if(RLP.fp >= 32.0f) RLP.fp -= 32.0f;
+ if(bPen) {
+ if(tr[1].x == p2.x) return oSolidLine(tr);
+ if (d >= 0) {tr[1].y += sy; d -= ax; RLP.fp += fInc2;}
+ tr[1].x += sx;
+ if(dPattern &(1 << ((int)RLP.fp))) {
+ bPen = false;
+ oSolidLine(tr);
+ tr[0].x = tr[1].x; tr[0].y = tr[1].y;
+ }
+ }
+ else {
+ if(tr[0].x == p2.x) return true;
+ if (d >= 0) {tr[0].y += sy; d -= ax; RLP.fp += fInc2;}
+ tr[0].x += sx;
+ if(!(dPattern &(1 << ((int)RLP.fp)))) {
+ bPen = true;
+ tr[1].x = tr[0].x; tr[1].y = tr[0].y;
+ }
+ }
+ d += ay;
+ }
+ }
+ else { // y dominant
+ d = ax - (ay >>1);
+ for ( ; ; ) {
+ RLP.fp += RLP.finc;
+ if(RLP.fp >= 32.0f) RLP.fp -= 32.0f;
+ if (bPen){
+ if (tr[1].y == p2.y) return oSolidLine(tr);
+ if (d >= 0) {tr[1].x += sx; d -= ay; RLP.fp += fInc2;}
+ tr[1].y += sy;
+ if(dPattern &(1 << ((int)RLP.fp))) {
+ bPen = false;
+ oSolidLine(tr);
+ tr[0].x = tr[1].x; tr[0].y = tr[1].y;
+ }
+ }
+ else {
+ if (tr[0].y == p2.y) return true;
+ if (d >= 0) {tr[0].x += sx; d -= ay; RLP.fp += fInc2;}
+ tr[0].y += sy;
+ if(!(dPattern &(1 << ((int)RLP.fp)))) {
+ bPen = true;
+ tr[1].x = tr[0].x; tr[1].y = tr[0].y;
+ }
+ }
+ d += ax;
+ }
+ }
+}
+
+static int Helv_Char_Width [] = {
+ 0, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+ 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+ 15, 17, 20, 31, 31, 49, 37, 11, 18, 18, 21, 32, 15, 18, 15, 15,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 15, 15, 32, 32, 32, 31,
+ 56, 37, 37, 40, 40, 37, 34, 43, 40, 15, 28, 37, 31, 45, 40, 43,
+ 37, 43, 40, 37, 33, 40, 37, 54, 35, 35, 34, 15, 15, 15, 24, 31,
+ 18, 31, 31, 28, 31, 31, 15, 31, 31, 11, 13, 28, 11, 47, 31, 31,
+ 31, 31, 18, 28, 15, 31, 29, 39, 27, 27, 27, 18, 14, 18, 32, 41,
+ 31, 41, 12, 31, 18, 55, 31, 31, 18, 56, 37, 18, 55, 41, 34, 41,
+ 41, 12, 12, 18, 18, 19, 31, 55, 16, 55, 28, 18, 52, 41, 27, 37,
+ 15, 17, 31, 31, 31, 31, 14, 31, 18, 41, 20, 31, 32, 18, 41, 30,
+ 22, 30, 18, 18, 18, 32, 30, 15, 18, 18, 20, 31, 46, 46, 46, 34,
+ 37, 37, 37, 37, 37, 37, 55, 40, 37, 37, 37, 37, 15, 15, 15, 15,
+ 40, 40, 43, 43, 43, 43, 43, 32, 43, 40, 40, 40, 40, 37, 37, 34,
+ 31, 31, 31, 31, 31, 31, 49, 28, 31, 31, 31, 31, 15, 15, 15, 15,
+ 31, 31, 31, 31, 31, 31, 31, 30, 34, 31, 31, 31, 31, 28, 31, 28};
+
+/*
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 18, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 18, 18, 24, 42, 39, 66, 51, 18, 24, 24, 30, 42, 18, 45, 18, 21,
+ 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 18, 18, 45, 45, 45, 36,
+ 75, 51, 51, 54, 54, 48, 42, 57, 54, 24, 39, 54, 42, 63, 54, 54,
+ 48, 54, 51, 48, 48, 54, 51, 66, 51, 48, 45, 21, 21, 21, 36, 42,
+ 18, 39, 42, 36, 42, 39, 24, 42, 39, 18, 18, 36, 18, 60, 42, 39,
+ 42, 42, 27, 36, 24, 42, 39, 54, 36, 39, 36, 24, 18, 24, 42, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 39, 42, 39, 42, 18, 39, 24, 57, 27, 42, 45, 24, 57, 24,
+ 27, 42, 21, 21, 21, 42, 36, 18, 21, 21, 27, 42, 57, 57, 57, 36,
+ 51, 51, 51, 51, 51, 51, 69, 54, 48, 48, 48, 48, 24, 24, 24, 24,
+ 54, 54, 54, 54, 54, 54, 54, 42, 54, 54, 54, 54, 54, 48, 48, 45,
+ 39, 39, 39, 39, 39, 39, 63, 36, 39, 39, 39, 39, 18, 18, 18, 18,
+ 39, 42, 39, 39, 39, 39, 39, 42, 39, 42, 42, 42, 42, 39, 42, 39};
+*/
+static int Cour_Char_Width [] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 35, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35};
+
+
+
+bool
+anyOutput::oGetTextExtent(char *text, int cb, int *width, int *height)
+{
+ int *CharWidth;
+ int i, w;
+
+ switch (TxtSet.Font) {
+ case FONT_COURIER: CharWidth = Cour_Char_Width; break;
+ default: CharWidth = Helv_Char_Width; break;
+ }
+ if(!cb && text) cb = strlen(text);
+ for(i = w = 0; i < cb; i++) w += CharWidth[text[i]];
+ *width = (w * TxtSet.iSize)>>6;
+ *height = TxtSet.iSize;
+ return true;
+}
+
+bool
+anyOutput::oSphere(int cx, int cy, int r, POINT *pts, int cp, char *nam)
+{
+ FillDEF fd;
+ HatchOut *ho;
+ int i, j;
+
+ if(pts && cp) oPolygon(pts, cp, nam);
+ else oCircle(cx - r, cy - r, cx + r + 1, cy + r + 1, nam);
+ fd.color = dFillCol; fd.color2 = dFillCol2;
+ fd.hatch = 0L; fd.scale = 1.0;
+ fd.type = FILL_NONE;
+ if(ho = new HatchOut(this)) {
+ ho->SetFill(&fd);
+ ho->light_source.fx = light_source.fx;
+ ho->light_source.fy = light_source.fy;
+ for(i = 0; i < 3; i++) for (j = 0; j < 3; j++) {
+ ho->light_vec[i][j] = light_vec[i][j];
+ }
+ ho->oSphere(cx, cy, r, pts, cp, 0L);
+ delete(ho);
+ return true;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Process hatch patterns in an output class
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+enum {HO_NONE, HO_RECT, HO_CIRCLE, HO_ELLIPSE, HO_BIGELLYPSE,
+ HO_POLYGON};
+struct {
+ union {
+ struct {
+ RECT rec;
+ }rec;
+ struct {
+ POINT centre;
+ long sr;
+ }cir;
+ struct {
+ POINT centre;
+ int ix, iy;
+ unsigned long sab;
+ }ell;
+ struct {
+ POINT fo[2];
+ unsigned int rsab;
+ int a, b;
+ }bell;
+ struct {
+ POINT *pts;
+ int cp;
+ }plg;
+ };
+}HatchDef;
+
+HatchOut::HatchOut(anyOutput *Parent):anyOutput()
+{
+ ParInit = false;
+ ho = HO_NONE;
+ ht = FILL_COMBS;
+ out = Parent;
+ xbase = ybase = 1.5;
+ units = 0; //use mm for defaults
+ if(Parent) out->GetSize(&DeskRect);
+ else DeskRect.left = DeskRect.right = DeskRect.top = DeskRect.bottom = 0;
+ MyLineDef.width = 0.0f;
+ MyLineDef.patlength = 10.0f;
+ MyLineDef.color = 0x00ff0000L;
+ MyLineDef.pattern = 0x00000000L;
+}
+
+
+HatchOut::~HatchOut()
+{
+}
+
+bool
+HatchOut::SetFill(FillDEF *fill)
+{
+ if(!fill) return false;
+ ht = (fill->type & 0xff);
+ if(fill->hatch) memcpy(&MyLineDef, fill->hatch, sizeof(LineDEF));
+ //we assume that all operations are at a 1:1 pixel relation to the parent,
+ // but we use un2fix and un2fiy from the parent: correct for zoom ....
+ switch(out->units) {
+ case 0: //parent uses mm
+ xbase = out->un2fix(1.5); ybase = out->un2fiy(1.5);
+ break;
+ case 1: //parent uses cm
+ xbase = out->un2fix(0.15); ybase = out->un2fiy(0.15);
+ break;
+ case 2: //parent uses inches
+ xbase = out->un2fix(0.059); ybase = out->un2fiy(0.059);
+ break;
+ }
+ if(fill->scale >0.05f && fill->scale < 20.0) {
+ xbase *= fill->scale; ybase *= fill->scale;
+ }
+ dFillCol = fill->color;
+ dFillCol2 = fill->color2;
+ return true;
+}
+
+bool
+HatchOut::StartPage()
+{
+ if(out) out->GetSize(&DeskRect);
+ return true;
+}
+
+bool
+HatchOut::oCircle(int x1, int y1, int x2, int y2, char *nam)
+{
+ long tmp;
+
+ if(x1 < x2) { UseRect.left = x1; UseRect.right = x2; }
+ else { UseRect.left = x2; UseRect.right = x1; }
+ if(y1 < y2) { UseRect.top = y1; UseRect.bottom = y2; }
+ else { UseRect.top = y2; UseRect.bottom = y1; }
+ if((UseRect.right -UseRect.left)==(UseRect.bottom-UseRect.top)) {
+ HatchDef.cir.centre.x = (UseRect.right + UseRect.left)/2;
+ HatchDef.cir.centre.y = (UseRect.bottom + UseRect.top)/2;
+ tmp = (UseRect.right - UseRect.left)/2;
+ HatchDef.cir.sr = (long)tmp * (long)tmp-1;
+ if(HatchDef.cir.sr >9) HatchDef.cir.sr -= tmp; //stay inside circle
+ ho = HO_CIRCLE;
+ PrepareParent(false);
+ return DoHatch();
+ }
+ //for small ellipses use the centered equation
+ if((UseRect.right -UseRect.left) <512 && (UseRect.bottom-UseRect.top)<512) {
+ ho = HO_ELLIPSE;
+ HatchDef.ell.centre.x = (UseRect.right + UseRect.left)/2;
+ HatchDef.ell.centre.y = (UseRect.bottom + UseRect.top)/2;
+ HatchDef.ell.ix = tmp = (UseRect.right - UseRect.left)/2;
+ HatchDef.ell.sab = tmp * tmp;
+ HatchDef.ell.iy = tmp = (UseRect.bottom - UseRect.top)/2;
+ HatchDef.ell.sab *= (tmp * tmp);
+ PrepareParent(false);
+ return DoHatch();
+ }
+ //for bigger ellipses we use the focuses to describe the ellipse
+ // this reduces numerical problems
+ ho = HO_BIGELLYPSE;
+ HatchDef.bell.fo[0].x= HatchDef.bell.fo[1].x= (UseRect.right+UseRect.left)/2;
+ HatchDef.bell.fo[0].y= HatchDef.bell.fo[1].y= (UseRect.bottom+UseRect.top)/2;
+ if((UseRect.right -UseRect.left) >(UseRect.bottom-UseRect.top)){
+ HatchDef.bell.rsab = UseRect.right - UseRect.left;
+ HatchDef.bell.a = (UseRect.right - UseRect.left)/2;
+ HatchDef.bell.b = (UseRect.bottom - UseRect.top)/2;
+ tmp = isqr(HatchDef.bell.a*HatchDef.bell.a -
+ HatchDef.bell.b*HatchDef.bell.b);
+ HatchDef.bell.fo[0].x -= tmp;
+ HatchDef.bell.fo[1].x += tmp;
+ }
+ else {
+ HatchDef.bell.rsab = UseRect.bottom - UseRect.top;
+ HatchDef.bell.b = (UseRect.right - UseRect.left)/2;
+ HatchDef.bell.a = (UseRect.bottom - UseRect.top)/2;
+ tmp = isqr(HatchDef.bell.a*HatchDef.bell.a -
+ HatchDef.bell.b*HatchDef.bell.b);
+ HatchDef.bell.fo[0].y -= tmp;
+ HatchDef.bell.fo[1].y += tmp;
+ }
+ PrepareParent(false);
+ return DoHatch();
+}
+
+bool
+HatchOut::oSphere(int cx, int cy, int r, POINT *pts, int cp, char *nam)
+{
+ double v[3], vec[3];
+ int i, j;
+
+ ht = FILL_LIGHT3D;
+
+ v[0] = 0.0; v[1] = 1.0; v[2] = 0.0;
+ for (i = 0; i < 3; i++) for(j = 0, vec[i] = 0.0; j < 3; j++)
+ vec[i] += (light_vec[i][j] * v[j]);
+ circ_grad.cx = cx - iround(vec[0]*((double)r));
+ circ_grad.cy = cy - iround(vec[2]*((double)r));
+ circ_grad.r = r;
+ if(pts && cp) return oPolygon(pts, cp, nam);
+ return oCircle(cx - r, cy - r, cx + r + 1, cy + r + 1, nam);
+}
+
+bool
+HatchOut::oRectangle(int x1, int y1, int x2, int y2, char *nam)
+{
+ if(x1 < x2) {
+ HatchDef.rec.rec.left = UseRect.left = x1;
+ HatchDef.rec.rec.right = UseRect.right = x2-1;
+ }
+ else {
+ HatchDef.rec.rec.left = UseRect.left = x2;
+ HatchDef.rec.rec.right = UseRect.right = x1-1;
+ }
+ if(y1 < y2) {
+ HatchDef.rec.rec.top = UseRect.top = y1;
+ HatchDef.rec.rec.bottom = UseRect.bottom = y2-1;
+ }
+ else {
+ HatchDef.rec.rec.top = UseRect.top = y2;
+ HatchDef.rec.rec.bottom = UseRect.bottom = y1-1;
+ }
+ ho = HO_RECT;
+ PrepareParent(false);
+ return DoHatch();
+}
+
+bool
+HatchOut::oPolygon(POINT *pts, int cp, char *nam)
+{
+ int i;
+ POINT *p;
+
+ p = (POINT*)malloc((cp+2)*(sizeof(POINT)));
+ HatchDef.plg.pts = p;
+ if(!p || cp < 3)return false;
+ HatchDef.plg.pts[0].x = UseRect.left = UseRect.right = pts[0].x;
+ HatchDef.plg.pts[0].y = UseRect.top = UseRect.bottom = pts[0].y;
+ for(i = 1; i < cp; i++){
+ UseRect.left = UseRect.left < pts[i].x ? UseRect.left : pts[i].x;
+ UseRect.right = UseRect.right > pts[i].x ? UseRect.right : pts[i].x;
+ UseRect.top = UseRect.top < pts[i].y ? UseRect.top : pts[i].y;
+ UseRect.bottom = UseRect.bottom > pts[i].y ? UseRect.bottom : pts[i].y;
+ p[i].x = pts[i].x; p[i].y = pts[i].y;
+ }
+ i--;
+ if(p[i].x != pts[0].x || p[i].y != pts[0].y) {
+ i++;
+ p[i].x = pts[0].x; p[i].y = pts[0].y;
+ }
+ HatchDef.plg.cp = i+1;
+ ho= HO_POLYGON;
+ PrepareParent(false);
+ return DoHatch();
+}
+
+bool
+HatchOut::PrepareParent(bool Restore)
+{
+ if(Restore){
+ if(out && ParInit)out->SetLine(&ParLineDef);
+ }
+ else if(out) {
+ out->GetLine(&ParLineDef);
+ ParInit = out->SetLine(&MyLineDef);
+ }
+ return true;
+}
+
+bool
+HatchOut::DoHatch()
+{
+ MkPolyLine(NULL, NULL);
+ switch(ht){
+ case FILL_NONE: break;
+ case FILL_HLINES: Lines000(); break;
+ case FILL_VLINES: Lines090(); break;
+ case FILL_HVCROSS: Lines000(); Lines090(); break;
+ case FILL_DLINEU: Lines045(); break;
+ case FILL_DLINED: Lines315(); break;
+ case FILL_DCROSS: Lines045(); Lines315(); break;
+ case FILL_STIPPLE1: case FILL_STIPPLE2:
+ case FILL_STIPPLE3: case FILL_STIPPLE4:
+ case FILL_STIPPLE5: Stipple(ht); break;
+ case FILL_ZIGZAG: Zigzag(); break;
+ case FILL_COMBS: Combs(); break;
+ case FILL_BRICKH: BricksH(); break;
+ case FILL_BRICKV: BricksV(); break;
+ case FILL_BRICKDU: Bricks045(); break;
+ case FILL_BRICKDD: Bricks315(); break;
+ case FILL_TEXTURE1: Texture1(); break;
+ case FILL_TEXTURE2: Texture2(); break;
+ case FILL_WAVES1: Arcs(FILL_WAVES1); break;
+ case FILL_SCALES: Arcs(FILL_SCALES); break;
+ case FILL_SHINGLES: Arcs(FILL_SHINGLES); break;
+ case FILL_WAVES2: Waves2(); break;
+ case FILL_HERRING: Herringbone(); break;
+ case FILL_CIRCLES: Circles(); break;
+ case FILL_GRASS: Grass(); break;
+ case FILL_FOAM: Foam(); break;
+ case FILL_RECS: Recs(); break;
+ case FILL_LIGHT3D: CircGrad(); break;
+ }
+
+ //clean up
+ if(ho == HO_POLYGON) {
+ if(HatchDef.plg.pts) free(HatchDef.plg.pts);
+ HatchDef.plg.pts = NULL;
+ }
+ ho = HO_NONE;
+ MkPolyLine(NULL, out);
+ return PrepareParent(true);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// collect line segments to a polyline command
+#define MK_PL_MAX 1000
+bool
+HatchOut::MkPolyLine(POINT *p, anyOutput *o)
+{
+ static POINT pl[MK_PL_MAX];
+ static long npt = 0;
+
+ if(p && o) {
+ if(!npt) {
+ memcpy(pl, p, 2*sizeof(POINT));
+ npt = 2;
+ return true;
+ }
+ if(p[0].x != pl[npt-1].x || p[0].y != pl[npt-1].y) {
+ o->oPolyline(pl, npt);
+ memcpy(pl, p, 2*sizeof(POINT));
+ npt = 2;
+ return true;
+ }
+ AddToPolygon(&npt, pl, p+1);
+ if(npt > (MK_PL_MAX-1)) {
+ npt = 0;
+ return o->oPolyline(pl, MK_PL_MAX);
+ }
+ return true;
+ }
+ if(!p && !o) {
+ npt = 0;
+ return true;
+ }
+ if(!p && o && npt) {
+ o->oPolyline(pl, npt);
+ npt = 0;
+ return true;
+ }
+ return false;
+}
+
+//use Bresenham's algorithm to draw lines
+//Ref: P.S. Heckbert (1990) "Digital Line Drawing", in: Graphic Gems
+// (A.S. Glassner, ed.); Academic Press, Inc.,
+// ISBN 0-12-286165-5
+bool
+HatchOut::HatchLine(POINT p1, POINT p2)
+{
+ int d, ax, ay, sx, sy, dx, dy;
+ bool bPen;
+ POINT tr[2];
+
+ dx = p2.x - p1.x;
+ if ( p2.x < p1.x) { ax = (-dx)<<1; sx = -1; }
+ else { ax = dx <<1; sx = 1; }
+ dy = p2.y - p1.y;
+ if (p2.y < p1.y) { ay = (-dy)<<1; sy = -1; }
+ else { ay = dy<<1; sy = 1; }
+ tr[0].x = tr[1].x = p1.x; tr[0].y = tr[1].y = p1.y;
+ if(IsInside(p1)) bPen = true;
+ else bPen = false;
+ if (ax > ay) { // x dominant
+ d = ay - (ax >>1);
+ for ( ; ; ) {
+ if(bPen) {
+ if(tr[1].x == p2.x) return MkPolyLine(tr, out);
+ if (d >= 0) {tr[1].y += sy; d -= ax;}
+ tr[1].x += sx;
+ if(!IsInside(tr[1])) {
+ bPen = false;
+ MkPolyLine(tr, out);
+ tr[0].x = tr[1].x; tr[0].y = tr[1].y;
+ }
+ }
+ else {
+ if(tr[0].x == p2.x) return true;
+ if (d >= 0) {tr[0].y += sy; d -= ax;}
+ tr[0].x += sx;
+ if(IsInside(tr[0])){
+ bPen = true;
+ tr[1].x = tr[0].x; tr[1].y = tr[0].y;
+ }
+ }
+ d += ay;
+ }
+ }
+ else { // y dominant
+ d = ax - (ay >>1);
+ for ( ; ; ) {
+ if (bPen){
+ if (tr[1].y == p2.y) return MkPolyLine(tr, out);
+ if (d >= 0) {tr[1].x += sx; d -= ay;}
+ tr[1].y += sy;
+ if(!IsInside(tr[1])) {
+ bPen = false;
+ MkPolyLine(tr, out);
+ tr[0].x = tr[1].x; tr[0].y = tr[1].y;
+ }
+ }
+ else {
+ if (tr[0].y == p2.y) return true;
+ if (d >= 0) {tr[0].x += sx; d -= ay;}
+ tr[0].y += sy;
+ if(IsInside(tr[0])) {
+ bPen = true;
+ tr[1].x = tr[0].x; tr[1].y = tr[0].y;
+ }
+ }
+ d += ax;
+ }
+ }
+}
+
+//use circular Bresenham's algorithm to draw arcs
+//Ref: C. Montani, R. Scopigno (1990) "Speres-To-Voxel Conversion", in:
+// Graphic Gems (A.S. Glassner ed.) Academic Press, Inc.;
+// ISBN 0-12-288165-5
+bool
+HatchOut::HatchArc(int ix, int iy, int r, int qad, bool start)
+{
+ int x, y, q, di, de, lim;
+ bool bInside;
+ static POINT tr[2];
+
+ if(r < 1) r = 1;
+ if(start) {
+ tr[1].x = ix-r; tr[1].y = iy;
+ }
+ for(q = 0; q < qad; q++) {
+ x = lim = 0; y = r; di = 2*(1-r);
+ bInside = IsInside(tr[1]);
+ while (y >= lim){
+ if(di < 0) {
+ de = 2*di + 2*y -1;
+ if(de > 0) {
+ x++; y--; di += (2*x -2*y +2);
+ }
+ else {
+ x++; di += (2*x +1);
+ }
+ }
+ else {
+ de = 2*di -2*x -1;
+ if(de > 0) {
+ y--; di += (-2*y +1);
+ }
+ else {
+ x++; y--; di += (2*x -2*y +2);
+ }
+ }
+ tr[0].x = tr[1].x; tr[0].y = tr[1].y;
+ switch(q) {
+ case 0: tr[1].x = ix-y; tr[1].y = iy+x; break;
+ case 1: tr[1].x = ix+x; tr[1].y = iy+y; break;
+ case 2: tr[1].x = ix+y; tr[1].y = iy-x; break;
+ case 3: tr[1].x = ix-x; tr[1].y = iy-y; break;
+ }
+ if(IsInside(tr[1])){
+ if(bInside)MkPolyLine(tr, out);
+ bInside = true;
+ }
+ else {
+ if(bInside) MkPolyLine(0L, out);
+ bInside = false;
+ }
+ }
+ }
+ return true;
+}
+
+bool
+HatchOut::IsInside(POINT p)
+{
+ long tmp1, tmp2, tmp3, tmp4;
+
+ if(p.x < DeskRect.left || p.x > DeskRect.right || p.y < DeskRect.top
+ || p.y >DeskRect.bottom) return false;
+ switch(ho){
+ case HO_RECT:
+ if(p.x > HatchDef.rec.rec.left && p.x < HatchDef.rec.rec.right &&
+ p.y > HatchDef.rec.rec.top && p.y < HatchDef.rec.rec.bottom)
+ return true;
+ return false;
+ case HO_CIRCLE:
+ tmp1 = p.x-HatchDef.cir.centre.x;
+ tmp2 = p.y-HatchDef.cir.centre.y;
+ if((tmp1 * tmp1 + tmp2 * tmp2) < HatchDef.cir.sr)
+ return true;
+ return false;
+ case HO_ELLIPSE:
+ tmp1 = p.x-HatchDef.ell.centre.x;
+ tmp2 = p.y-HatchDef.ell.centre.y;
+ tmp3 = HatchDef.ell.iy;
+ tmp4 = HatchDef.ell.ix;
+ if((unsigned long)(tmp1 * tmp1 * tmp3 * tmp3 + tmp2 * tmp2 * tmp4 * tmp4) < HatchDef.ell.sab)
+ return true;
+ return false;
+ case HO_BIGELLYPSE:
+ tmp1 = HatchDef.bell.fo[0].x - p.x; tmp1 *= tmp1;
+ tmp2 = HatchDef.bell.fo[0].y - p.y; tmp2 *= tmp2;
+ tmp3 = HatchDef.bell.fo[1].x - p.x; tmp3 *= tmp3;
+ tmp4 = HatchDef.bell.fo[1].y - p.y; tmp4 *= tmp4;
+ return (isqr(tmp1+tmp2)+isqr(tmp3+tmp4)) < HatchDef.bell.rsab;
+ case HO_POLYGON:
+ return IsInPolygon(&p, HatchDef.plg.pts, HatchDef.plg.cp);
+ }
+ return false;
+}
+
+void
+HatchOut::Lines000()
+{
+ int y, yinc;
+ POINT Line[2];
+
+ if(2>(yinc = iround(ybase*.8)))yinc = 2;
+ Line[0].x = UseRect.left;
+ Line[1].x = UseRect.right;
+ for(y = UseRect.top; y < UseRect.bottom; y += yinc) {
+ Line[0].y = Line[1].y = y;
+ HatchLine(Line[0], Line[1]);
+ }
+}
+
+void
+HatchOut::Lines090()
+{
+ int x, xinc;
+ POINT Line[2];
+
+ if(2>(xinc = iround(xbase*.8)))xinc = 2;
+ Line[0].y = UseRect.top;
+ Line[1].y = UseRect.bottom;
+ for(x = UseRect.left; x < UseRect.right; x += xinc) {
+ Line[0].x = Line[1].x = x;
+ HatchLine(Line[0], Line[1]);
+ }
+}
+
+void
+HatchOut::Lines045()
+{
+ int x, y, y1, xinc, yinc;
+ POINT Line[2];
+
+ if(3>(xinc=iround(xbase*1.2)))xinc=3; if(3>(yinc=iround(ybase*1.2)))yinc=3;
+ Line[1].x = x = UseRect.right;
+ Line[0].y = Line[1].y = y = UseRect.bottom;
+ while(x > UseRect.left) {
+ Line[0].x = x = x-xinc;
+ if(y > UseRect.top) Line[1].y = y = y-yinc;
+ else Line[1].x -= xinc;
+ HatchLine(Line[0], Line[1]);
+ }
+ y1 = Line[0].y;
+ while(y1 > UseRect.top) {
+ Line[0].y = y1 = y1-yinc;
+ if(y > UseRect.top) Line[1].y = y = y-yinc;
+ else Line[1].x -= xinc;
+ HatchLine(Line[0], Line[1]);
+ }
+}
+
+void
+HatchOut::Lines315()
+{
+ int x, y, y1, xinc, yinc;
+ POINT Line[2];
+
+ if(3>(xinc=iround(xbase*1.2)))xinc= 3; if(3>(yinc=iround(ybase*1.2)))yinc= 3;
+ Line[1].x = x = UseRect.right;
+ Line[0].y = Line[1].y = y = UseRect.top;
+ while (x > UseRect.left) {
+ Line[0].x = x = x-xinc;
+ if(y < UseRect.bottom) Line[1].y = y = y+yinc;
+ else Line[1].x -= xinc;
+ HatchLine(Line[0], Line[1]);
+ }
+ y1 = Line[0].y;
+ while(y1 < UseRect.bottom) {
+ Line[0].y = y1 = y1+yinc;
+ if(y < UseRect.bottom) Line[1].y = y = y+yinc;
+ else Line[1].x -= xinc;
+ HatchLine(Line[0], Line[1]);
+ }
+}
+
+void
+HatchOut::Stipple(int type)
+{
+ int x, y, xinc, yinc, level, xspac, yspac;
+ POINT Line[2];
+
+ if(!(xinc = iround(xbase*0.48)))xinc = 1; if(!(yinc = iround(ybase*0.48)))yinc = 1;
+ if(!(xspac = iround(xbase*0.56)))xspac = 1; if(!(yspac = iround(ybase*0.56)))yspac = 1;
+ level = 0;
+ for(x = UseRect.left; x < UseRect.right; x += xspac*2) {
+ level &= 0x1;
+ for(y = UseRect.top; y < UseRect.bottom; y += yspac*4) {
+ if(type < FILL_STIPPLE3) {
+ Line[0].x = x;
+ Line[0].y = level? y+yinc+yspac*2 : y+yinc;
+ Line[1].x = Line[0].x+xinc; Line[1].y = Line[0].y-yinc;
+ if(type == FILL_STIPPLE1)HatchLine(Line[0], Line[1]);
+ Line[0].x = Line[1].x; Line[0].y = Line[1].y;
+ Line[1].x += xinc; Line[1].y += yinc;
+ if(type == FILL_STIPPLE1)HatchLine(Line[0], Line[1]);
+ Line[0].x = Line[1].x; Line[0].y = Line[1].y;
+ Line[1].x -= xinc; Line[1].y += yinc;
+ HatchLine(Line[0], Line[1]);
+ Line[0].x = Line[1].x; Line[0].y = Line[1].y;
+ Line[1].x -= xinc; Line[1].y -= yinc;
+ HatchLine(Line[0], Line[1]);
+ }
+ else if(type <= FILL_STIPPLE5) {
+ Line[0].x = x;
+ Line[0].y =Line[1].y = level? y+yinc+yspac*2 : y+yinc;
+ Line[1].x = Line[0].x+xinc*2;
+ if(type == FILL_STIPPLE3 || type == FILL_STIPPLE4)HatchLine(Line[0], Line[1]);
+ Line[0].x = Line[1].x = x+xinc;
+ Line[0].y = Line[1].y -yinc;
+ Line[1].y += yinc;
+ if(type == FILL_STIPPLE3 || type == FILL_STIPPLE5)HatchLine(Line[0], Line[1]);
+ }
+ }
+ level++;
+ }
+}
+
+void
+HatchOut::Zigzag()
+{
+ int yinc, ix, iy;
+ POINT Line[2];
+
+ if(3>(yinc = iround(ybase)))yinc=3;
+ if(2>(iy = iround(ybase*.8)))iy=2; if(2>(ix = iround(xbase*.8)))ix=2;
+ Line[0].x = Line[1].x = UseRect.left;
+ Line[0].y = Line[1].y = UseRect.top;
+ while(Line[0].y < UseRect.bottom +iy) {
+ while(Line[1].x < UseRect.right) {
+ Line[1].y -= iy; Line[1].x += ix;
+ HatchLine(Line[0], Line[1]);
+ Line[0].x = Line[1].x; Line[1].x += ix;
+ Line[0].y = Line[1].y; Line[1].y += iy;
+ HatchLine(Line[0], Line[1]);
+ Line[0].x = Line[1].x; Line[0].y = Line[1].y;
+ }
+ Line[0].x = Line[1].x = UseRect.left;
+ Line[0].y = Line[1].y += yinc;
+ }
+}
+
+void
+HatchOut::Combs()
+{
+ int x, y, xinc, yinc;
+ POINT Line[2], Next;
+
+ if(!(yinc = iround(ybase*.4)))yinc = 1;
+ if(2 >(xinc = iround(xbase*.69282))) xinc = 2; //exact yinc *sin(60�)*2
+ y = UseRect.top + yinc;
+ while(y < UseRect.bottom + yinc*2) {
+ Line[0].y = Line[1].y = y;
+ Line[0].x = Line[1].x = UseRect.left-xinc;
+ while(Line[1].x < UseRect.right && Line[1].y >= UseRect.top){
+ Line[1].y -= (yinc*2);
+ HatchLine(Line[0], Line[1]);
+ Line[0].x = Line[1].x; Line[1].x += xinc;
+ Line[0].y = Line[1].y; Line[1].y -= yinc;
+ HatchLine(Line[0], Line[1]);
+ Line[0].x = Line[1].x; Line[0].y = Line[1].y;
+ Line[1].x += xinc; Line[1].y += yinc;
+ HatchLine(Line[0], Line[1]);
+ Line[1].x -= xinc; Line[1].y -= yinc;
+ }
+ y += yinc*6;
+ }
+ Next.x = x = UseRect.left-xinc; Next.y = y;
+ while(x < UseRect.right) {
+ Line[0].y = Line[1].y = Next.y;
+ Line[0].x = Line[1].x = x;
+ while(Line[1].x < UseRect.right&& Line[1].y >= UseRect.top){
+ Line[1].y -= (yinc*2);
+ HatchLine(Line[0], Line[1]);
+ Line[0].x = Line[1].x; Line[1].x += xinc;
+ Line[0].y = Line[1].y; Line[1].y -= yinc;
+ HatchLine(Line[0], Line[1]);
+ Line[0].x = Line[1].x; Line[0].y = Line[1].y;
+ Line[1].x += xinc; Line[1].y += yinc;
+ HatchLine(Line[0], Line[1]);
+ Line[1].x -= xinc; Line[1].y -= yinc;
+ }
+ x += xinc*2;
+ }
+}
+
+void
+HatchOut::BricksH()
+{
+ int i, j, y, yinc, xinc;
+ POINT Line[2];
+
+ if(4>(xinc=iround(xbase*1.6)))xinc=4; if(2>(yinc=iround(ybase*0.8)))yinc=2;
+ for(y = UseRect.top, j = 0; y < UseRect.bottom; y += yinc, j++) {
+ Line[0].x = UseRect.left;
+ Line[1].x = UseRect.right;
+ Line[0].y = Line[1].y = y;
+ HatchLine(Line[0], Line[1]);
+ Line[0].y ++; Line[1].y += yinc;
+ for (i = (j&1)?UseRect.left:UseRect.left+xinc/2;i<UseRect.right;i+=xinc){
+ Line[0].x = Line[1].x = i;
+ HatchLine(Line[0], Line[1]);
+ }
+ }
+}
+
+void
+HatchOut::BricksV()
+{
+ int i, j, x, yinc, xinc;
+ POINT Line[2];
+
+ if(2>(xinc=iround(xbase*0.8)))xinc=2; if(4>(yinc=iround(ybase*1.6)))yinc=4;
+ for(x = UseRect.left, j= 0; x < UseRect.right; x += xinc, j++) {
+ Line[0].y = UseRect.top;
+ Line[1].y = UseRect.bottom;
+ Line[0].x = Line[1].x = x;
+ HatchLine(Line[0], Line[1]);
+ Line[0].x ++; Line[1].x += xinc;
+ for (i = (j&1)?UseRect.top:UseRect.top+yinc/2;i<UseRect.bottom;i+=yinc){
+ Line[0].y = Line[1].y = i;
+ HatchLine(Line[0], Line[1]);
+ }
+ }
+}
+
+void
+HatchOut::Bricks045()
+{
+ int xinc, yinc, bwx, bwy;
+ POINT Line[2];
+
+ if(2>(xinc=iround(xbase*.7)))xinc = 2; if(2>(yinc=iround(ybase*.7)))yinc = 2;
+ bwx = xinc *2; bwy = yinc *2;
+ Line[0].x = UseRect.left - xinc;
+ Line[0].y = UseRect.top;
+ while((Line[0].y < UseRect.bottom + bwy)) {
+ while(Line[0].x < UseRect.right) {
+ Line[1].x = Line[0].x + bwx;
+ Line[1].y = Line[0].y - bwy;
+ HatchLine(Line[0], Line[1]);
+ Line[0].x = Line[1].x;
+ Line[0].y = Line[1].y;
+ Line[1].x = Line[0].x + xinc;
+ Line[1].y = Line[0].y + yinc;
+ HatchLine(Line[0], Line[1]);
+ Line[0].y += bwy;
+ }
+ Line[0].y += bwy;
+ Line[0].x = UseRect.left - xinc;
+ }
+}
+
+void
+HatchOut::Bricks315()
+{
+ int xinc, yinc, bwx, bwy;
+ POINT Line[2];
+
+ if(2>(xinc=iround(xbase*.7)))xinc = 2; if(2>(yinc=iround(ybase*.7)))yinc = 2;
+ bwx = xinc *2; bwy = yinc *2;
+ Line[0].x = UseRect.left - xinc;
+ Line[0].y = UseRect.top -bwy;
+ while((Line[0].y < UseRect.bottom)) {
+ while(Line[0].x < UseRect.right) {
+ Line[1].x = Line[0].x + bwx;
+ Line[1].y = Line[0].y + bwy;
+ HatchLine(Line[0], Line[1]);
+ Line[0].x = Line[1].x;
+ Line[0].y = Line[1].y;
+ Line[1].x = Line[0].x + xinc;
+ Line[1].y = Line[0].y - yinc;
+ HatchLine(Line[0], Line[1]);
+ Line[0].y -= bwy;
+ }
+ Line[0].y += bwy;
+ Line[0].x = UseRect.left - xinc;
+ }
+}
+
+void
+HatchOut::Texture1()
+{
+ int j, xinc, yinc;
+ POINT Line[2];
+
+ if(!(xinc = iround(xbase*0.4)))xinc = 1; if(!(yinc = iround(ybase*0.4)))yinc = 1;
+ Line[0].x = UseRect.left - xinc;
+ Line[0].y = UseRect.top - yinc;
+ j = 0;
+ while((Line[0].y < UseRect.bottom)) {
+ while(Line[0].x < UseRect.right) {
+ Line[1].x = Line[0].x;
+ Line[1].y = Line[0].y + (yinc *2);
+ HatchLine(Line[0], Line[1]);
+ Line[0].x += xinc;
+ Line[0].y += yinc;
+ Line[1].x = Line[0].x + (xinc *2);
+ Line[1].y = Line[0].y;
+ HatchLine(Line[0], Line[1]);
+ Line[0].x += xinc*3;
+ Line[0].y -= yinc;
+ }
+ j++;
+ Line[0].y += yinc *2;
+ Line[0].x = UseRect.left - xinc;
+ if(j &0x01) Line[0].x += (xinc * 2);
+ }
+}
+
+
+void
+HatchOut::Texture2()
+{
+ int j, xinc, yinc;
+ POINT Line[2];
+
+ if(2>(xinc=iround(xbase*.6)))xinc= 2; if(2>(yinc=iround(ybase*.6)))yinc= 2;
+ Line[0].x = UseRect.left - xinc*2; Line[0].y = UseRect.top - yinc*2;
+ j = 0;
+ while((Line[0].y < UseRect.bottom)) {
+ while(Line[0].x < UseRect.right) {
+ Line[1].x = Line[0].x; Line[1].y = Line[0].y + (yinc *3);
+ HatchLine(Line[0], Line[1]);
+ Line[0].x += xinc; Line[1].x = Line[0].x;
+ HatchLine(Line[0], Line[1]);
+ Line[0].y += yinc; Line[1].x = Line[0].x + (xinc *3);
+ Line[1].y = Line[0].y;
+ HatchLine(Line[0], Line[1]);
+ Line[0].y += yinc; Line[1].y = Line[0].y;
+ HatchLine(Line[0], Line[1]);
+ Line[0].x += xinc*3; Line[0].y -= yinc*2;
+ }
+ j++;
+ Line[0].y += yinc *2; Line[0].x = UseRect.left - xinc*2;
+ if(j &0x01) Line[0].x += (xinc *2);
+ }
+}
+
+void
+HatchOut::Arcs(int type)
+{
+ int i, j, level, ix, iy;
+
+ if(type == FILL_SHINGLES) {
+ iy = iround(ybase*1.6); ix = iround(xbase*.8);
+ }
+ else {
+ iy = iround(ybase*.8); ix = iround(xbase*.8);
+ }
+ if(iy < 2) iy = 2; if(ix < 2) ix = 2;
+ UseRect.right += ix; UseRect.top -= 2*iy; UseRect.bottom += 2*iy;
+ for(i = UseRect.top, level = 0; i < UseRect.bottom; i+= iy, level++) {
+ if(type == FILL_WAVES1) {
+ HatchArc(UseRect.left, i, ix, 0, true);
+ for(j = UseRect.left; j < UseRect.right; j += ix*2) HatchArc(j, i, ix, 2, false);
+ i += iy/3;
+ }
+ else if(type == FILL_SCALES) {
+ HatchArc(UseRect.left, i, ix, 0, true);
+ for(j = UseRect.left; j < UseRect.right; j += ix*2)
+ HatchArc((level &1) ? j+ix:j, i, ix, 2, false);
+ i++;
+ }
+ else {
+ for(j = UseRect.left; j < UseRect.right; j += ix*2){
+ HatchArc((level &1) ? j+ix:j, i-1, ix, 0, true);
+ HatchArc((level &1) ? j+ix:j, i + iy/2, ix, 2, false);
+ }
+ i++;
+ }
+ }
+}
+
+void
+HatchOut::Waves2() //hatch using sine waves
+{
+ int i, j, y, ix, yinc, *pts;
+ POINT Line[2];
+ double dtmp;
+
+ if(3>(yinc = iround(ybase*.8)))yinc = 3; if(14>(ix = iround(xbase*2.5)))ix = 14;
+ if(!(pts = (int *)malloc(ix * sizeof(int))))return;
+ for(i = 0; i < ix; i++) {
+ dtmp = sin(6.283185307/((double)ix/(double)i));
+ pts[i] = dtmp > 0.0 ? iround(0.3*ybase*dtmp) : iround(0.3*ybase*dtmp);
+ }
+ for(y = UseRect.top; y <= UseRect.bottom + yinc; y += yinc){
+ Line[0].x = UseRect.left; Line[1].x = UseRect.left+1;
+ Line[0].y = y; Line[1].y = y+pts[1];
+ for(j = 2; Line[0].x < UseRect.right+1; j++) {
+ HatchLine(Line[0], Line[1]);
+ Line[0].x = Line[1].x; Line[1].x++;
+ Line[0].y = Line[1].y; Line[1].y = y + pts[j%ix];
+ }
+ }
+ free(pts);
+}
+
+void
+HatchOut::Herringbone()
+{
+ int ix1, ix2, iy1, iy2, y;
+ POINT Line[2];
+
+ if(2>(ix1 = iround(xbase*.6)))ix1 = 2; ix2 = ix1*4;
+ if(2>(iy1 = iround(ybase*.6)))iy1 = 2; iy2 = iy1*4;
+ for(y = UseRect.top; y <= UseRect.bottom + iy2; y += iy1*2) {
+ Line[0].x = UseRect.left-ix2; Line[1].x = Line[0].x + ix2;
+ Line[0].y = y; Line[1].y = Line[0].y - iy2;
+ do {
+ HatchLine(Line[0], Line[1]);
+ Line[0].x = Line[1].x - ix1; Line[1].x = Line[0].x + ix2;
+ Line[0].y = Line[1].y - iy1; Line[1].y = Line[0].y + iy2;
+ HatchLine(Line[0], Line[1]);
+ Line[0].x = Line[1].x - ix1; Line[1].x = Line[0].x + ix2;
+ Line[0].y = Line[1].y + iy1; Line[1].y = Line[0].y - iy2;
+ } while(Line[0].x <= UseRect.right);
+ }
+}
+
+void
+HatchOut::Circles()
+{
+ int x, y, r, level, xspac, yspac;
+
+ if(2 > (xspac = iround(+xbase*.8))) xspac = 2;
+ if(4 > (yspac = iround(ybase*1.38564))) yspac = 4;
+ if(1 > (r = iround(xbase*.4)))r = 1;
+ level = 0;
+ UseRect.bottom += yspac; UseRect.right += r;
+ for(x = UseRect.left; x < UseRect.right; x += xspac) {
+ level &= 0x1;
+ for(y = UseRect.top; y < UseRect.bottom; y += yspac*2) {
+ HatchArc(x, level? y+yspac : y, r, 4, true);
+ }
+ level++;
+ }
+}
+
+void
+HatchOut::Grass()
+{
+ int i, count, dh, dw;
+ double xsize, ysize;
+ long idum = -1;
+ POINT pts[2];
+
+ xsize = xbase *2.0; ysize = ybase*2.0;
+ if(xsize < 4.0) xsize = 4.0; if(ysize < 4.0) ysize = 4.0;
+ IncrementMinMaxRect(&UseRect, (int)xsize);
+ count = (UseRect.right -UseRect.left)*(UseRect.bottom-UseRect.top);
+ i = (int)(xsize*ysize*0.15); if(i) count /= i;
+ dh = UseRect.bottom-UseRect.top; dw = UseRect.right-UseRect.left;
+ for(i = 0; i < count; i++) {
+ pts[0].x = UseRect.left+(int)(dw*ran2(&idum));
+ pts[0].y = UseRect.top+(int)(dh*ran2(&idum));
+ pts[1].x = pts[0].x + (int)(ran2(&idum)*xsize);
+ pts[1].y = pts[0].y + (int)(ran2(&idum)*ysize);
+ if(pts[0].x != pts[1].x || pts[0].y != pts[1].y) HatchLine(pts[0], pts[1]);
+ }
+}
+
+void
+HatchOut::Foam()
+{
+ int i, count, dh, dw;
+ double xsize;
+ long idum = -1;
+
+ xsize = xbase *0.9;
+ if(xsize < 2.0) xsize = 2.0;
+ IncrementMinMaxRect(&UseRect, (int)xsize);
+ count = (UseRect.right -UseRect.left)*(UseRect.bottom-UseRect.top);
+ count /= (int)(xsize*xsize);
+ dh = UseRect.bottom-UseRect.top; dw = UseRect.right-UseRect.left;
+ for(i = 0; i < count; i++) {
+ HatchArc(UseRect.left+(int)(dw*ran2(&idum)), UseRect.top+(int)(dh*ran2(&idum)),
+ (int)(ran2(&idum)*ran2(&idum)*xsize +xsize*.2), 4, true);
+ }
+}
+
+void
+HatchOut::Recs()
+{
+ int i, count, dh, dw;
+ double xsize, ysize;
+ long idum = -1;
+ POINT Line[5];
+
+ xsize = xbase *2.8; ysize = ybase *2.8;
+ if(xsize < 4.0) xsize = 4.0; if(ysize < 4.0) ysize = 4.0;
+ IncrementMinMaxRect(&UseRect, (int)xsize);
+ count = (UseRect.right -UseRect.left)*(UseRect.bottom-UseRect.top);
+ i = (int)(floor(xsize*ysize*.4)); if(i) count /= i;
+ dh = UseRect.bottom-UseRect.top; dw = UseRect.right-UseRect.left;
+ for(i = 0; i < count; i++) {
+ Line[0].x = Line[3].x = Line[4].x = UseRect.left+(int)(dw*ran2(&idum));
+ Line[0].y = Line[1].y = Line[4].y = UseRect.top+(int)(dh*ran2(&idum));
+ Line[1].x = Line[2].x = Line[0].x + (int)(ran2(&idum)*xsize +xsize*.2);
+ Line[2].y = Line[3].y = Line[0].y + (int)(ran2(&idum)*ysize +ysize*.2);
+ HatchLine(Line[0], Line[1]); HatchLine(Line[1], Line[2]);
+ HatchLine(Line[2], Line[3]); HatchLine(Line[3], Line[4]);
+ }
+}
+
+void
+HatchOut::CircGrad()
+{
+ int i;
+ double f;
+ LineDEF ld = {0.0, 1.0, 0x0, 0x0};
+
+ for(i = 1; i < this->circ_grad.r; i++) {
+ f = (((double)i)/((double)circ_grad.r));
+ f = f*f;
+ ld.color = IpolCol(dFillCol, dFillCol2, f);
+ out->SetLine(&ld);
+ HatchArc(circ_grad.cx, circ_grad.cy, i, 4, true);
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// export to *.tif file (tag image file)
+// This code is based on information from the following book
+// G. Born, 'Referenzhandbuch Dateiformate',
+// Addison-Wesley ISBN 3-89319-815-6
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class ExportTif:public anyOutput {
+public:
+ ExportTif(GraphObj *g, char *FileName, DWORD flags, double res, double wi, double he);
+ ~ExportTif();
+ bool StartPage();
+ bool EndPage();
+
+private:
+ int w, h;
+ anyOutput *bmo;
+ char *name;
+ int oFile;
+};
+
+ExportTif::ExportTif(GraphObj *g, char *FileName, DWORD flags, double res, double wi, double he)
+{
+ hres = vres = res;
+ name = 0L; bmo = 0L;
+ DeskRect.left = DeskRect.top = 0;
+ DeskRect.right = DeskRect.bottom = 0x4fffffff;
+ dFillCol = 0xffffffffL;
+ if(g && FileName) {
+ w = un2ix(wi); h = un2iy(he);
+ if(bmo = NewBitmapClass(w, h, hres, vres)){
+ bmo->VPorg.fy = -co2fiy(g->GetSize(SIZE_GRECT_TOP));
+ bmo->VPorg.fx = -co2fix(g->GetSize(SIZE_GRECT_LEFT));
+ bmo->Erase(0x00ffffffL);
+ g->DoPlot(bmo);
+ }
+ name = strdup(FileName);
+ }
+ oFile = 0;
+}
+
+ExportTif::~ExportTif()
+{
+ if(name) free(name);
+ if(bmo) DelBitmapClass(bmo);
+}
+
+bool
+ExportTif::StartPage()
+{
+ unsigned char header[] = {
+ 0x49, 0x49, //intel byte order
+ 0x2a, 0x00, //version 4.2
+ 0x08, 0x00, 0x00, 0x00, //the image file directory just follows
+ 0x0f, 0x00, //number of tags in IFD
+ 0xfe, 0x00, 0x04, 0x00, 0x01, 0x00, //new subfile tag
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x04, 0x00, 0x01, 0x00, //image width tag (pixels)
+ 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x04, 0x00, 0x01, 0x00, //image height tag (pixels)
+ 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
+ 0x02, 0x01, 0x03, 0x00, 0x01, 0x00, //BitsPerSample tag
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, // ...8 bits per sample
+ 0x03, 0x01, 0x03, 0x00, 0x01, 0x00, //compression tag
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // ...no compression
+ 0x06, 0x01, 0x03, 0x00, 0x01, 0x00, //photometric interpretation
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, // ...its RGB
+ 0x11, 0x01, 0x04, 0x00, 0x01, 0x00, //strip (image) offset
+ 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, // ... number of strips and offset to data
+ 0x12, 0x01, 0x03, 0x00, 0x01, 0x00, //orientation tag
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // ...its top/left
+ 0x15, 0x01, 0x03, 0x00, 0x01, 0x00, //samples per pixel
+ 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // ... 3 samples (colors) for RGB
+ 0x17, 0x01, 0x04, 0x00, 0x01, 0x00, //strip byte count
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1a, 0x01, 0x05, 0x00, 0x01, 0x00, //horizontal resolution
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x1b, 0x01, 0x05, 0x00, 0x01, 0x00, //vertical resolution
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x1c, 0x01, 0x03, 0x00, 0x01, 0x00, //planar configuration
+ 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, // ... one layer
+ 0x28, 0x01, 0x03, 0x00, 0x01, 0x00, //resolution units
+ 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, // ... dots per inch
+ 0x31, 0x01, 0x02, 0x00, 0x01, 0x00, //Software
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 // ... RLPlot ...
+ };
+ DWORD res_info[4] = {iround(hres), 0x01, iround(vres), 0x01};
+ char prog_name[20];
+
+
+ if(name && bmo) {
+ if(-1 ==(oFile = open(name, O_RDWR | O_BINARY | O_CREAT | O_TRUNC,
+ S_IWRITE | S_IREAD))) {
+ ErrorBox("Could not open output file");
+ return false;
+ }
+ *((int*)(header+30))= w; *((int*)(header+42))= h;
+ *((DWORD*)(header+126)) = (DWORD)(w * h * 3);
+ *((int*)(header+90)) = sizeof(header) + sizeof(res_info) + 20;
+ *((int*)(header+138)) = sizeof(header);
+ *((int*)(header+150)) = sizeof(header)+8;
+ *((int*)(header+186)) = sizeof(header)+16;
+ sprintf(prog_name, "RLPlot %s", SZ_VERSION);
+ write(oFile, &header, sizeof(header));
+ write(oFile, &res_info, sizeof(res_info));
+ write(oFile, &res_info, 20);
+ return true;
+ }
+ return false;
+}
+
+bool
+ExportTif::EndPage()
+{
+ int i, j, c;
+ DWORD pix;
+ unsigned char *pix_data, *cpix = (unsigned char*)&pix;
+
+ if(bmo && (pix_data = (unsigned char*)malloc(3072))){
+ for(i = c = 0; i < h; i++) {
+ for(j = 0; j < w; j++) {
+ bmo->oGetPix(j, i, &pix); pix_data[c++] = cpix[0];
+ pix_data[c++] = cpix[1]; pix_data[c++] = cpix[2];
+ if(c >= 3072) {
+ write(oFile, pix_data, 3072);
+ c = 0;
+ }
+ }
+ }
+ write(oFile, pix_data, c);
+ free(pix_data);
+ }
+ oFile = close(oFile);
+ return true;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Entry point to export graph to tag image file
+void DoExportTif(GraphObj *g, char *FileName, DWORD flags)
+{
+ ExportTif *ex;
+ double res, width, height;
+
+ if(!g || !FileName) return;
+ res = 98.0;
+ width = g->GetSize(SIZE_GRECT_RIGHT) - g->GetSize(SIZE_GRECT_LEFT);
+ height = g->GetSize(SIZE_GRECT_BOTTOM) - g->GetSize(SIZE_GRECT_TOP);
+ if(GetBitmapRes(&res, &width, &height, "Export Tag Image File")){
+ ex = new ExportTif(g, FileName, flags, res, width, height);
+ if(ex->StartPage()) ex->EndPage();
+ delete(ex);
+ }
+}
diff --git a/PlotObs.cpp b/PlotObs.cpp
new file mode 100755
index 0000000..30c873a
--- /dev/null
+++ b/PlotObs.cpp
@@ -0,0 +1,4427 @@
+//PlotObs.cpp, Copyright (c) 2001, 2002, 2003, 2004, 2005 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
+//
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// This modules contains code for the differnt Plot objects. Plots are
+// graphic objects containing more objects, which represent the data.
+// Several Plots may be contained in a Graph: Plots are the different layers
+// of a Graph.
+// Most part of this module has been moved here from rlplot.cpp of
+// earlier versions.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#include "rlplot.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+extern char TmpTxt[];
+extern Default defs;
+extern int cPlots;
+extern GraphObj *CurrGO, *TrackGO; //Selected Graphic Objects
+extern Axis **CurrAxes; //axes of current graph
+extern UndoObj Undo;
+
+int AxisTempl3D = 0;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Plot::Plot(GraphObj *par, DataObj *d):GraphObj(par, d)
+{
+ Id = GO_PLOT;
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ sprintf(TmpTxt, "Plot %d", ++cPlots);
+ name = strdup(TmpTxt);
+ use_xaxis = use_yaxis = 0;
+ hidden = 0;
+}
+
+double
+Plot::GetSize(int select)
+{
+ switch(select){
+ case SIZE_MINE: return 0.0;
+ //The Bounds values must be returned by every plot:
+ // they are necessary for scaling !
+ case SIZE_BOUNDS_XMIN:
+ return parent ? parent->GetSize(SIZE_BOUNDS_XMIN) : Bounds.Xmin;
+ case SIZE_BOUNDS_XMAX:
+ return parent ? parent->GetSize(SIZE_BOUNDS_XMAX) : Bounds.Xmax;
+ case SIZE_BOUNDS_YMIN:
+ return parent ? parent->GetSize(SIZE_BOUNDS_YMIN) : Bounds.Ymin;
+ case SIZE_BOUNDS_YMAX:
+ return parent ? parent->GetSize(SIZE_BOUNDS_YMAX) : Bounds.Ymax;
+ case SIZE_BARMINX:
+ case SIZE_BARMINY:
+ return 1.0f;
+ default:
+ if(parent) return parent->GetSize(select);
+ else return defs.GetSize(select);
+ }
+}
+
+DWORD
+Plot::GetColor(int select)
+{
+ if(parent) return parent->GetColor(select);
+ else return defs.Color(select);
+}
+
+void
+Plot::CheckBounds(double x, double y)
+{
+ if(x < Bounds.Xmin) Bounds.Xmin = x; if(x > Bounds.Xmax) Bounds.Xmax = x;
+ if(y < Bounds.Ymin) Bounds.Ymin = y; if(y > Bounds.Ymax) Bounds.Ymax = y;
+}
+
+bool
+Plot::UseAxis(int idx)
+{
+ double dx, dy;
+
+ if(CurrAxes && CurrAxes[idx]) {
+ dx = fabs(CurrAxes[idx]->GetSize(SIZE_XPOS+1) -
+ CurrAxes[idx]->GetSize(SIZE_XPOS));
+ dy = fabs(CurrAxes[idx]->GetSize(SIZE_YPOS+1) -
+ CurrAxes[idx]->GetSize(SIZE_YPOS));
+ if(dx > dy && idx != use_xaxis) {
+ Undo.ValInt(parent, &use_xaxis, 0L);
+ use_xaxis = idx; return true;
+ }
+ else if(idx != use_yaxis) {
+ Undo.ValInt(parent, &use_yaxis, 0L);
+ use_yaxis = idx; return true;
+ }
+ }
+ return false;
+}
+
+void
+Plot::ApplyAxes(anyOutput *o)
+{
+ AxisDEF x_axis, y_axis;
+ double dsp;
+ fRECT CurrRect;
+
+ if(!o || !CurrAxes || !parent) return;
+ memcpy(&x_axis, &o->xAxis, sizeof(AxisDEF));
+ memcpy(&y_axis, &o->yAxis, sizeof(AxisDEF));
+ CurrRect.Xmin = (dsp = parent->GetSize(SIZE_GRECT_LEFT)) +
+ parent->GetSize(SIZE_DRECT_LEFT);
+ CurrRect.Xmax = dsp + parent->GetSize(SIZE_DRECT_RIGHT);
+ if(use_xaxis && CurrAxes[use_xaxis]) {
+ memcpy(&x_axis, CurrAxes[use_xaxis]->axis, sizeof(AxisDEF));
+ if(x_axis.flags & AXIS_DEFRECT) {
+ x_axis.loc[0].fx += dsp; x_axis.loc[1].fx += dsp;
+ }
+ }
+ else use_xaxis = 0;
+ CurrRect.Ymin = (dsp = parent->GetSize(SIZE_GRECT_TOP)) +
+ parent->GetSize(SIZE_DRECT_BOTTOM);
+ CurrRect.Ymax = dsp + parent->GetSize(SIZE_DRECT_TOP);
+ if(use_yaxis && CurrAxes[use_yaxis]) {
+ memcpy(&y_axis, CurrAxes[use_yaxis]->axis, sizeof(AxisDEF));
+ if(y_axis.flags & AXIS_DEFRECT) {
+ y_axis.loc[0].fy += dsp; y_axis.loc[1].fy += dsp;
+ }
+ }
+ else use_yaxis = 0;
+ o->SetRect(CurrRect, o->units, &x_axis, &y_axis);
+}
+
+void
+Plot::CheckBounds3D(double x, double y, double z)
+{
+ if(x < xBounds.fx) xBounds.fx = x; if(x > xBounds.fy) xBounds.fy = x;
+ if(y < yBounds.fx) yBounds.fx = y; if(y > yBounds.fy) yBounds.fy = y;
+ if(z < zBounds.fx) zBounds.fx = z; if(z > zBounds.fy) zBounds.fy = z;
+ CheckBounds(x, y);
+}
+
+bool
+Plot::SavVarObs(GraphObj **gol, long ngo, DWORD flags)
+{
+ int i;
+ void *ptr;
+
+ if(!gol || !ngo) return false;
+ SavVarInit(150 * ngo);
+ for(i = 0; i < ngo; i++)
+ if(gol[i]) gol[i]->FileIO(SAVE_VARS);
+ ptr = SavVarFetch();
+ Undo.SavVarBlock(this, &ptr, flags);
+ return true;
+}
+
+DataObj *
+Plot::CreaCumData(char *xr, char *yr, int mode, double base)
+{
+ char **yranges;
+ int i, j, nc, nr, ir, ic;
+ double value, old_val;
+ DataObj *CumData = 0L;
+ AccRange *ax = 0L, *ay = 0L;
+
+ if(!xr || !yr || !mode || !data) return 0L;
+ if(!(CumData = new DataObj()))return 0L;
+ if(!(ax = new AccRange(xr))) {
+ delete CumData; return 0L;
+ }
+ nr = ax->CountItems();
+ if(!(yranges = split(yr, '&', &nc))){
+ delete CumData; delete ax; return 0L;
+ }
+ if(CumData->Init(mode == 1 || mode == 2 ? nr : nr * 2, nc+2)){
+ // set x values as first column
+ for(i = 0, ax->GetFirst(&ic, &ir); ax->GetNext(&ic, &ir); i++) {
+ if(data->GetValue(ir, ic, &value)) CumData->SetValue(i, 0, value);
+ CumData->SetValue(i, 1, base);
+ }
+ if(mode == 3 || mode == 4) for(i = 1; i <= nr; i++) { //complete polygon data
+ if(CumData->GetValue(nr-i, 0, &value)) CumData->SetValue(i-1+nr, 0, value);
+ }
+ //process all y-ranges
+ for (j = 2; j <= (nc+1); j++) if(ay = new AccRange(yranges[j-2])){
+ for(i = 0; i < nr; i++) {
+ if(CumData->GetValue(i, j-1, &value)) CumData->SetValue(i, j, value);
+ }
+ for(i = 0, ay->GetFirst(&ic, &ir); ay->GetNext(&ic, &ir) && i < nr; i++) {
+ if(data->GetValue(ir, ic, &value) && CumData->GetValue(i, j, &old_val)){
+ switch (mode) {
+ case 1: case 3: value += old_val; break;
+ case 2: case 4: value = old_val -value; break;
+ }
+ CumData->SetValue(i, j, value);
+ }
+ }
+ if(mode == 3 || mode == 4) for(i = 1; i <= nr; i++) {
+ //complete polygon data
+ if(CumData->GetValue(nr-i, j-1, &value)) CumData->SetValue(i-1+nr, j, value);
+ }
+ delete ay; ay = 0L;
+ }
+ }
+
+
+
+ for(i = 0; i < nc; i++) if(yranges[i]) free(yranges[i]);
+ if(ax) delete ax; if(ay) delete ay;
+ free(yranges);
+ return CumData;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// PlotScatt handles most XY-Plots: its a Plot-Class
+PlotScatt::PlotScatt(GraphObj *par, DataObj *d, DWORD presel):Plot(par, d)
+{
+ FileIO(INIT_VARS);
+ DefSel = presel;
+ Id = GO_PLOTSCATT;
+ if (!d) {
+ if(parent && parent->Command(CMD_DELOBJ, this, NULL)) return;
+ ErrorBox("Attempt to create plot\nwithout any data.");
+ return;
+ }
+}
+
+PlotScatt::PlotScatt(GraphObj *par, DataObj *d, int cBars, Bar **bars):Plot(par, d)
+{
+ int i;
+
+ FileIO(INIT_VARS);
+ if(cBars && bars) {
+ if((Bars = (Bar**)calloc(cBars, sizeof(Bar*)))) {
+ nPoints = cBars;
+ for(i = 0; i < cBars; i++) {
+ if((Bars[i] = bars[i])) Bars[i]->parent = this;
+ bars[i] = 0L;
+ }
+ }
+ }
+ Id = GO_PLOTSCATT;
+}
+
+PlotScatt::PlotScatt(GraphObj *par, DataObj *d, int nPts, Symbol **sym, DataLine *lin):
+ Plot(par, d)
+{
+ int i;
+
+ FileIO(INIT_VARS);
+ nPoints = nPts;
+ if(Symbols = sym) for(i = 0; i < nPts; i++) if(Symbols[i]) Symbols[i]->parent = this;
+ if(TheLine = lin) TheLine->parent = this;
+ Id = GO_PLOTSCATT;
+}
+
+PlotScatt::PlotScatt(int src):Plot(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+PlotScatt::~PlotScatt()
+{
+ ForEach(FE_FLUSH, 0L, 0L);
+ Undo.InvalidGO(this);
+}
+
+double
+PlotScatt::GetSize(int select)
+{
+ int i;
+ double ft1, ft2;
+
+ switch(select){
+ case SIZE_BARMINX:
+ if(BarDist.fx >= 0.0001) return BarDist.fx;
+ if((!Bars) | (nPoints < 2)) return 1.0f;
+ ft1 = fabs(Bars[1]->GetSize(SIZE_XPOS) - Bars[0]->GetSize(SIZE_XPOS));
+ for(i = 2; i < nPoints; i++) {
+ if(Bars[i] && Bars[i-1]) {
+ ft2 = fabs(Bars[i]->GetSize(SIZE_XPOS) - Bars[i-1]->GetSize(SIZE_XPOS));
+ if(ft2 < ft1 || ft1 < 0.0001f) ft1 = ft2;
+ }
+ }
+ return BarDist.fx = ft1 > 0.0001 ? ft1 : 1.0;
+ case SIZE_BARMINY:
+ if(BarDist.fy >= 0.0001) return BarDist.fy;
+ if((!Bars) | (nPoints < 2)) return 1.0f;
+ ft1 = fabs(Bars[1]->GetSize(SIZE_YPOS) - Bars[0]->GetSize(SIZE_YPOS));
+ for(i = 2; i < nPoints; i++) {
+ if(Bars[i] && Bars[i-1]) {
+ ft2 = fabs(Bars[i]->GetSize(SIZE_YPOS) - Bars[i-1]->GetSize(SIZE_YPOS));
+ if(ft2 < ft1 || ft1 < 0.0001f) ft1 = ft2;
+ }
+ }
+ return BarDist.fy = ft1 > 0.0001 ? ft1 : 1.0;
+ default:
+ return Plot::GetSize(select);
+ }
+}
+
+bool
+PlotScatt::SetSize(int select, double value)
+{
+ int i;
+
+ switch(select & 0xfff){
+ case SIZE_BARMINX:
+ BarDist.fx = value;
+ return true;
+ case SIZE_BARMINY:
+ BarDist.fy = value;
+ return true;
+ case SIZE_SYMBOL: case SIZE_SYM_LINE:
+ if(Symbols) for(i = 0; i < nPoints; i++)
+ if(Symbols[i]) Symbols[i]->SetSize(select, value);
+ return true;
+ case SIZE_ERRBAR: case SIZE_ERRBAR_LINE:
+ if(Errors) for(i = 0; i < nPoints; i++)
+ if(Errors[i]) Errors[i]->SetSize(select, value);
+ return true;
+ case SIZE_BAR_LINE: case SIZE_BAR: case SIZE_XBASE: case SIZE_YBASE:
+ if(Bars) for(i = 0; i < nPoints; i++)
+ if(Bars[i]) Bars[i]->SetSize(select, value);
+ return true;
+ case SIZE_ARROW_LINE: case SIZE_ARROW_CAPWIDTH: case SIZE_ARROW_CAPLENGTH:
+ if(Arrows) for(i = 0; i < nPoints; i++)
+ if(Arrows[i]) Arrows[i]->SetSize(select, value);
+ return true;
+ }
+ return false;
+}
+
+bool
+PlotScatt::SetColor(int select, DWORD col)
+{
+ int i;
+ GraphObj **go = 0L;
+
+ switch(select) {
+ case COL_SYM_LINE:
+ case COL_SYM_FILL: go = (GraphObj**)Symbols; break;
+ case COL_ERROR_LINE: go = (GraphObj**)Errors; break;
+ case COL_BAR_LINE:
+ case COL_BAR_FILL: go = (GraphObj**)Bars; break;
+ case COL_ARROW: go = (GraphObj**)Arrows; break;
+ default: return false;
+ }
+ if(go) for(i = 0; i < nPoints; i++)
+ if(go[i]) go[i]->SetColor(select, col);
+ return true;
+}
+
+void
+PlotScatt::DoPlot(anyOutput *o)
+{
+ if(!parent) return;
+ parent->Command(CMD_REG_AXISPLOT, (void*)this, o);
+ if(use_xaxis || use_yaxis) {
+ ApplyAxes(o);
+ ForEach(FE_PLOT, 0L, o);
+ parent->Command(CMD_AXIS, 0L, o);
+ }
+ else {
+ ForEach(FE_PLOT, 0L, o);
+ }
+ dirty = false;
+}
+
+bool
+PlotScatt::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i;
+
+ switch (cmd) {
+ case CMD_MOUSE_EVENT:
+ if(hidden) return false;
+ if(!CurrGO && ((MouseEvent*)tmpl)->Action == MOUSE_LBUP)
+ return ForEach(cmd, tmpl, o);
+ return false;
+ case CMD_LEGEND:
+ if(((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+ if(Bars) for (i = 0; i < nPoints; i++)
+ if(Bars[i]) Bars[i]->Command(cmd, tmpl, o);
+ if(Symbols) {
+ if(TheLine && TheLine->Id == GO_DATALINE) {
+ for (i = 0; i < nPoints && i < 100; i++)
+ if(Symbols[i]) ((Legend*)tmpl)->HasSym(&TheLine->LineDef, Symbols[i]);
+ }
+ else {
+ for (i = 0; i < nPoints && i < 100; i++)
+ if(Symbols[i]) ((Legend*)tmpl)->HasSym(0L, Symbols[i]);
+ }
+ if(TheLine && TheLine->Id == GO_DATAPOLYGON) TheLine->Command(cmd, tmpl, o);
+ }
+ else if(TheLine) TheLine->Command(cmd, tmpl, o);
+ break;
+ case CMD_MRK_DIRTY:
+ dirty = true;
+ case CMD_SETSCROLL: case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ return false;
+ case CMD_USEAXIS:
+ return UseAxis(*((int*)tmpl));
+ case CMD_FLUSH:
+ return ForEach(FE_FLUSH, 0L, 0L);
+ case CMD_AUTOSCALE:
+ if(hidden) return false;
+ if(dirty){
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL;
+ Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ }
+ else{
+ if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH &&
+ Bounds.Xmax > Bounds.Xmin && Bounds.Ymax > Bounds.Ymin) {
+ ((Plot*)parent)->CheckBounds(Bounds.Xmin, Bounds.Ymin);
+ ((Plot*)parent)->CheckBounds(Bounds.Xmax, Bounds.Ymax);
+ return true;
+ }
+ }
+ dirty = false;
+ case CMD_UPDATE:
+ if(cmd == CMD_UPDATE){
+ Undo.ObjConf(this, UNDO_CONTINUE);
+ dirty = true;
+ }
+ case CMD_SET_DATAOBJ:
+ if(cmd == CMD_SET_DATAOBJ) {
+ Id = GO_PLOTSCATT;
+ data = (DataObj *)tmpl;
+ }
+ ForEach(cmd, tmpl, o);
+ if(cmd == CMD_AUTOSCALE && parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH
+ && Bounds.Xmax > Bounds.Xmin && Bounds.Ymax > Bounds.Ymin) {
+ ((Plot*)parent)->CheckBounds(Bounds.Xmin, Bounds.Ymin);
+ ((Plot*)parent)->CheckBounds(Bounds.Xmax, Bounds.Ymax);
+ }
+ return true;
+ case CMD_HIDE_MARK:
+ return ForEach(cmd, tmpl, o);
+ case CMD_MUTATE: case CMD_REPL_GO:
+ dirty = true;
+ return ForEach(cmd == CMD_REPL_GO ? FE_REPLGO : FE_MUTATE, tmpl, o);
+ case CMD_SYMTEXT: case CMD_SYMTEXT_UNDO: case CMD_SYM_RANGETEXT:
+ case CMD_SYMTEXTDEF: case CMD_SYM_TYPE:
+ if(Symbols) for(i = 0; i < nPoints; i++)
+ if(Symbols[i]) Symbols[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_DL_LINE: case CMD_DL_TYPE:
+ if(DropLines) for(i = 0; i < nPoints; i++)
+ if(DropLines[i]) DropLines[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_ERR_TYPE:
+ if(Errors) for(i = 0; i < nPoints; i++)
+ if(Errors[i]) Errors[i]->type = *((int*)tmpl);
+ return true;
+ case CMD_BAR_TYPE: case CMD_BAR_FILL:
+ if(Bars) for(i = 0; i < nPoints; i++) {
+ if(Bars[i]) Bars[i]->Command(cmd, tmpl, o);
+ }
+ return true;
+ case CMD_ARROW_TYPE: case CMD_ARROW_ORG:
+ if(Arrows) for(i = 0; i < nPoints; i++) {
+ if(Arrows[i]) Arrows[i]->Command(cmd, tmpl, o);
+ }
+ return true;
+ case CMD_DELOBJ:
+ dirty = true;
+ if(parent && tmpl && o) return ForEach(FE_DELOBJ, tmpl, o);
+ break;
+ case CMD_SAVE_SYMBOLS:
+ return SavVarObs((GraphObj **)Symbols, nPoints, 0L);
+ case CMD_SAVE_BARS:
+ return SavVarObs((GraphObj **)Bars, nPoints, 0L);
+ case CMD_SAVE_ERRS:
+ return SavVarObs((GraphObj **)Errors, nPoints, 0L);
+ case CMD_SAVE_ARROWS:
+ return SavVarObs((GraphObj **)Arrows, nPoints, 0L);
+ case CMD_SAVE_DROPLINES:
+ return SavVarObs((GraphObj **)DropLines, nPoints, 0L);
+ }
+ return false;
+}
+
+bool
+PlotScatt::ForEach(int cmd, void *tmp, anyOutput *o)
+{
+ int i, j;
+ GraphObj **obs[] = {(GraphObj**)Symbols, (GraphObj**)Errors, (GraphObj**)Arrows,
+ (GraphObj**)DropLines, (GraphObj**)Labels, (GraphObj**)Bars};
+ GraphObj ***go = 0L;
+ GraphObj **tmpPlots;
+ bool bRedraw, bFound;
+
+ switch(cmd) {
+ case FE_MUTATE:
+ case FE_REPLGO:
+ if((tmpPlots = (GraphObj **)tmp) && tmpPlots[0] && tmpPlots[1]) {
+ for(j = 0; j < 6; j++){
+ if(obs[j]) for(i = 0; i < nPoints; i++){
+ if(obs[j][i] && obs[j][i] == tmpPlots[0]) {
+ if(cmd == FE_REPLGO) return ReplaceGO(&obs[j][i], tmpPlots);
+ else {
+ Undo.MutateGO(&obs[j][i], tmpPlots[1], 0L, o);
+ return true;
+ }
+ }
+ }
+ }
+ if(TheLine == tmpPlots[0]){
+ if(cmd == FE_REPLGO) return ReplaceGO((GraphObj**)&TheLine, tmpPlots);
+ else {
+ Undo.MutateGO((GraphObj**)&TheLine, tmpPlots[1], 0L, o);
+ return true;
+ }
+ }
+ }
+ return false;
+ case FE_PARENT:
+ for(j = 0; j < 6; j++){
+ if(obs[j]) for(i = 0; i < nPoints; i++){
+ if(obs[j][i]) obs[j][i]->parent = this;
+ }
+ }
+ if(TheLine) TheLine->parent = this;
+ return true;
+ case CMD_UPDATE:
+ case CMD_SET_DATAOBJ:
+ case CMD_AUTOSCALE:
+ for(j = 0; j < 6; j++){
+ if(obs[j]) for(i = 0; i < nPoints; i++){
+ if(obs[j][i]) obs[j][i]->Command(cmd, tmp, o);
+ }
+ }
+ if(TheLine) TheLine->Command(cmd, tmp, o);
+ return true;
+ case FE_PLOT:
+ if(TheLine) TheLine->DoPlot(o);
+ for(j = 5; j >= 0; j--){
+ if(obs[j]) for(i = 0; i < nPoints; i++){
+ if(obs[j][i]) obs[j][i]->DoPlot(o);
+ }
+ }
+ return true;
+ case FE_FLUSH:
+ for(j = 0; j < 6; j++){
+ if(obs[j]) {
+ for(i = 0; i < nPoints; i++) if(obs[j][i]) DeleteGO(obs[j][i]);
+ free(obs[j]); obs[j] = 0L;
+ }
+ }
+ if(ErrRange) free(ErrRange); if(yRange) free(yRange);
+ if(xRange) free(xRange); if(LbRange) free(LbRange);
+ ErrRange = yRange = xRange = LbRange = 0L;
+ if(TheLine) DeleteGO(TheLine);
+ Bars = 0L; Symbols = 0L; Errors = 0L;
+ Arrows = 0L; DropLines = 0L; Labels = 0L; TheLine = 0L;
+ return true;
+ case FE_DELOBJ:
+ if(!o) return false;
+ for(j = 0, bRedraw = false, go = 0L; j < 6 && !bRedraw; j++) {
+ if(obs[j]) for(i = 0; i < nPoints; i++){
+ if(obs[j][i]){
+ if(tmp == (void*)obs[j][i]) {
+ o->MrkMode = MRK_NONE;
+ o->MouseCursor(MC_WAIT, true);
+ Undo.DeleteGO(&obs[j][i], 0L, o);
+ switch(j) {
+ case 0: go = (GraphObj***)&Symbols; break;
+ case 1: go = (GraphObj***)&Errors; break;
+ case 2: go = (GraphObj***)&Arrows; break;
+ case 3: go = (GraphObj***)&DropLines; break;
+ case 4: go = (GraphObj***)&Labels; break;
+ case 5: go = (GraphObj***)&Bars; break;
+ }
+ bRedraw = true;
+ break;
+ }
+ }
+ }
+ }
+ if(!bRedraw && TheLine && tmp == (void *) TheLine) {
+ o->MrkMode = MRK_NONE;
+ Undo.DeleteGO((GraphObj**)(&TheLine), 0L, o);
+ bRedraw = true;
+ }
+ if(bRedraw && go) for(i = j = 0; i < nPoints; i++) if(go[0][i]) j++;
+ if(!j) Undo.DropMemory(this, (void**)go, UNDO_CONTINUE);
+ if(bRedraw && dirty) Command(CMD_AUTOSCALE, 0L, o);
+ if(!Bars && !Symbols && !Errors && !Arrows && !TheLine && !DropLines
+ && !Labels) parent->Command(CMD_DELOBJ_CONT, this, o);
+ else if(bRedraw) parent->Command(CMD_REDRAW, NULL, o);
+ return bRedraw;
+ case CMD_HIDE_MARK:
+ if(!o || !tmp) return false;
+ if(bFound =(tmp == (void*)TheLine)) TheLine->DoMark(o, false);
+ else for(j = 5; j >= 0 && !bFound; j--){
+ if(obs[j]) for(i = 0; i < nPoints && !bFound; i++){
+ if(bFound = (tmp == (void*)obs[j][i])) obs[j][i]->DoMark(o, false);
+ else if(obs[j][i] && obs[j][i]->Id == GO_MLABEL &&
+ obs[j][i]->Command(cmd, tmp, o)) return true;
+ }
+ }
+ return bFound;
+ default: //pass command to all objects
+ for(j = 0; j < 6; j++){
+ if(obs[j]) for(i = 0; i < nPoints; i++){
+ if(obs[j][i]) if(obs[j][i]->Command(cmd, tmp, o)) return true;
+ }
+ }
+ if(TheLine) return (TheLine->Command(cmd, tmp, o));
+ return false;
+ }
+ return false;
+}
+
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// BarChart is based on scatterplot
+BarChart::BarChart(GraphObj *par, DataObj *d):PlotScatt(par, d, 0L)
+{
+ Id = GO_BARCHART;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Frequenc distribution: bar chart with function
+FreqDist::FreqDist(GraphObj *par, DataObj *d):Plot(par, d)
+{
+ FileIO(INIT_VARS);
+ Id = GO_FREQDIST;
+}
+
+FreqDist::FreqDist(int src):Plot(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+FreqDist::~FreqDist()
+{
+ int i;
+
+ if(curr_data) delete(curr_data); curr_data = 0L;
+ if(ssRef) free(ssRef); ssRef = 0L;
+ if(plots) {
+ for(i = 0; i < nPlots; i++) if(plots[i]) DeleteGO(plots[i]);
+ free(plots); plots=0L;
+ }
+}
+
+void
+FreqDist::DoPlot(anyOutput *o)
+{
+ int i;
+
+ if(!plots || !o || !data || !parent) return;
+ parent->Command(CMD_REG_AXISPLOT, (void*)this, o);
+ if(use_xaxis || use_yaxis) ApplyAxes(o);
+ for(i = 0; i < nPlots; i++) {
+ if(plots[i]) {
+ if(plots[i]->Id >= GO_PLOT && plots[i]->Id < GO_GRAPH){
+ if(((Plot*)plots[i])->hidden == 0) plots[i]->DoPlot(o);
+ }
+ else plots[i]->DoPlot(o);
+ }
+ }
+ if(use_xaxis || use_yaxis) parent->Command(CMD_AXIS, 0L, o);
+}
+
+bool
+FreqDist::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i;
+
+ switch (cmd) {
+ case CMD_MOUSE_EVENT:
+ if(hidden || ((MouseEvent*)tmpl)->Action != MOUSE_LBUP || CurrGO) return false;
+ case CMD_LEGEND:
+ if(plots) for(i = 0; i < nPlots; i++) {
+ if(plots[i]){
+ if(plots[i]->Id >= GO_PLOT && plots[i]->Id < GO_GRAPH){
+ if(((Plot*)plots[i])->hidden == 0) plots[i]->Command(cmd, tmpl, o);
+ }
+ else plots[i]->Command(cmd, tmpl, o);
+ }
+ }
+ return false;
+ case CMD_HIDE_MARK:
+ if(plots) for(i = 0; i < nPlots; i++) if(plots[i]){
+ if(tmpl == (void*)plots[i]) {
+ plots[i]->DoMark(o, false);
+ return true;
+ }
+ else if(plots[i]->Command(cmd, tmpl, o)) return true;
+ }
+ return false;
+ case CMD_DELOBJ:
+ if(plots && tmpl && parent) for(i = 0; i < nPlots; i++) if(plots[i]){
+ if(tmpl == (void*)plots[i]) {
+ DeleteGO(plots[i]); plots[i]=0L;
+ if(i == 1) type=0;
+ parent->Command(CMD_REDRAW, 0L, o);
+ return true;
+ }
+ }
+ return false;
+ case CMD_UPDATE:
+ if(data && parent && plots) {
+ ProcData(0);
+ if(!curr_data) return false;
+ for(i = 0; i < nPlots; i++) if(plots[i]) {
+ plots[i]->Command(CMD_SET_DATAOBJ, curr_data, o);
+ plots[i]->Command(CMD_UPDATE, 0L, o);
+ }
+ }
+ return false;
+ case CMD_SET_DATAOBJ:
+ Id = GO_FREQDIST;
+ data = (DataObj *)tmpl;
+ return true;
+ case CMD_MRK_DIRTY:
+ dirty = true;
+ case CMD_SETSCROLL: case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ return false;
+ case CMD_USEAXIS:
+ return UseAxis(*((int*)tmpl));
+ case CMD_AUTOSCALE:
+ if(hidden) return false;
+ if(dirty){
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL;
+ Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ }
+ else{
+ if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH &&
+ Bounds.Xmax > Bounds.Xmin && Bounds.Ymax > Bounds.Ymin) {
+ ((Plot*)parent)->CheckBounds(Bounds.Xmin, Bounds.Ymin);
+ ((Plot*)parent)->CheckBounds(Bounds.Xmax, Bounds.Ymax);
+ return true;
+ }
+ }
+ dirty = false;
+ if(plots) for(i = 0; i < nPlots; i++) {
+ if(plots[i]){
+ if(plots[i]->Id >= GO_PLOT && plots[i]->Id < GO_GRAPH){
+ if(((Plot*)plots[i])->hidden == 0) plots[i]->Command(cmd, tmpl, o);
+ }
+ else plots[i]->Command(cmd, tmpl, o);
+ }
+ }
+ if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH &&
+ Bounds.Xmax > Bounds.Xmin && Bounds.Ymax > Bounds.Ymin) {
+ ((Plot*)parent)->CheckBounds(Bounds.Xmin, Bounds.Ymin);
+ ((Plot*)parent)->CheckBounds(Bounds.Xmax, Bounds.Ymax);
+ return true;
+ case CMD_DROP_GRAPH:
+ if(tmpl && plots && nPlots >1) {
+ if(plots[1]) DeleteGO(plots[1]);
+ plots[1] = (GraphObj*)tmpl; dirty = true; plots[1]->parent = this;
+ plots[1]->Command(CMD_SET_DATAOBJ, curr_data, o);
+ Command(CMD_AUTOSCALE, 0L, o);
+ return true;
+ }
+ return false;
+ }
+ }
+ return false;
+}
+
+void
+FreqDist::ProcData(int sel)
+{
+ AccRange *ar;
+ int nv, i, j, r, c, ncl, *f_data, cb;
+ double min = HUGE_VAL, max = -HUGE_VAL, sum, mean, sd, tmp, d, *s_data;
+ Bar **bars = 0L;
+ char *fo;
+
+ if(!parent || !data || !ssRef || !plots) return;
+ if(curr_data) delete(curr_data);
+ if((curr_data = new DataObj()) && (ar = new AccRange(ssRef))) {
+ nv = ar->CountItems(); ar->GetFirst(&c, &r);
+ if(!(s_data = (double*)malloc(nv * sizeof(double)))) {
+ delete(ar); return;
+ }
+ for(sum = 0.0, nv = 0; ar->GetNext(&c, &r); ) if(data->GetValue(r, c, &tmp)) {
+ sum+=tmp; s_data[nv++] = tmp;
+ }
+ mean = sum / ((double)nv); delete(ar);
+ for(sum = 0.0, j = 0; j < nv; j++){
+ if(s_data[j] > max) max = s_data[j]; if(s_data[j] < min) min = s_data[j];
+ sum += ((d = (s_data[j] - mean)) * d);
+ }
+ sd = sqrt(sum/((double)nv));
+ step = fabs(step);
+ if(sel == -1) {
+ start = min; step = (max - min)/(step != 0.0 ? step : 7.0);
+ }
+ else if(sel == -2) {
+ min = start;
+ }
+ ncl = (int)(floor((max-start)/step));
+ if(plots[0] && (max > (Bounds.Xmax+step/2.0) || min < (Bounds.Xmin-step/2.0))) {
+ DeleteGO(plots[0]); plots[0] = 0L;
+ }
+ if(!plots[0])bars = (Bar**)calloc(ncl, sizeof(Bar*));
+ f_data = (int*)calloc(ncl+1, sizeof(int));
+ for(i = 0; i < nv; i++) {
+ j = (int)(floor((s_data[i] - start)/step));
+ if(j >= 0 && j < ncl) f_data[j]++;
+ else if(s_data[i] == max) f_data[j-1]++;
+ }
+ if(f_data[ncl]) ncl++;
+ curr_data->Init(ncl, 2);
+ for(i = 0; i< ncl; i++) {
+ curr_data->SetValue(i, 0, tmp = start + i * step + step * .5);
+ curr_data->SetValue(i, 1, (double)f_data[i]);
+ if(bars) {
+ bars[i] = new Bar(this, 0L, tmp, (double)f_data[i], BAR_VERTB | BAR_RELWIDTH, 0, i, 1, i);
+ }
+ }
+ free(s_data); free(f_data);
+ if(bars && (plots[0] = new PlotScatt(this, data, ncl, bars))){
+ plots[0]->Command(CMD_BAR_FILL, &BarFill, 0L);
+ plots[0]->SetColor(COL_BAR_LINE, BarLine.color);
+ plots[0]->SetSize(SIZE_BAR_LINE, BarLine.width);
+ }
+ if(plots[0]){
+ plots[0]->Command(CMD_SET_DATAOBJ, curr_data, 0L);
+ plots[0]->Command(CMD_AUTOSCALE, 0L, 0L);
+ }
+ if(type && (fo = (char*)malloc(1000))) {
+ cb = sprintf(fo, "[1=Function]\n");
+ cb += sprintf(fo+cb,"x1= %g\n", min);
+ cb += sprintf(fo+cb,"x2= %g\n", max);
+ cb += sprintf(fo+cb,"xstep= %g\n", (max-min)/100.0);
+ cb += sprintf(fo+cb,"Line= 0.4 6 0x000000ff 0x0\n");
+
+ cb += sprintf(fo+cb,"f_xy=\"A=%g; SD=%g; M=%g\\n", nv*step, sd, mean);
+ cb += sprintf(fo+cb,"ex=(x-M)/SD; ex=-0.5*ex*ex\\n");
+ cb += sprintf(fo+cb,"y=(A/(SD*2.5066283))*exp(ex)\\n\"\n");
+
+ OpenGraph(this, 0L, (unsigned char *)fo);
+ free(fo);
+ }
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Regression line and symbols
+Regression::Regression(GraphObj *par, DataObj *d):Plot(par, d)
+{
+ FileIO(INIT_VARS);
+ Id = GO_REGRESSION;
+}
+
+Regression::Regression(int src):Plot(0L, 0L)
+{
+ int i;
+
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ //now set parent in all children
+ if(rLine) rLine->parent = this;
+ if(sde) sde->parent = this;
+ if(Symbols)
+ for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->parent = this;
+ }
+}
+
+Regression::~Regression()
+{
+ Command(CMD_FLUSH, 0L, 0L);
+ Undo.InvalidGO(this);
+}
+
+double
+Regression::GetSize(int select)
+{
+ return Plot::GetSize(select);
+}
+
+bool
+Regression::SetSize(int select, double value)
+{
+ int i;
+
+ switch(select & 0xfff){
+ case SIZE_SYMBOL:
+ case SIZE_SYM_LINE:
+ if(Symbols) for(i = 0; i < nPoints; i++)
+ if(Symbols[i]) Symbols[i]->SetSize(select, value);
+ return true;
+ }
+ return false;
+}
+
+bool
+Regression::SetColor(int select, DWORD col)
+{
+ int i;
+ switch(select) {
+ case COL_SYM_LINE:
+ case COL_SYM_FILL:
+ if(Symbols) for(i = 0; i < nPoints; i++)
+ if(Symbols[i]) Symbols[i]->SetColor(select, col);
+ return true;
+ }
+ return false;
+}
+
+void
+Regression::DoPlot(anyOutput *o)
+{
+ int i;
+
+
+ parent->Command(CMD_REG_AXISPLOT, (void*)this, o);
+ if(use_xaxis || use_yaxis) ApplyAxes(o);
+ if(sde){
+ if(rLine && sde->Command(CMD_DROP_OBJECT, rLine, o)) rLine = 0L;
+ sde->DoPlot(o);
+ }
+ if(rLine) rLine->DoPlot(o);
+ if(Symbols) for(i = 0; i < nPoints; i++)
+ if(Symbols[i]) Symbols[i]->DoPlot(o);
+ if(use_xaxis || use_yaxis) parent->Command(CMD_AXIS, 0L, o);
+ dirty = false;
+}
+
+bool
+Regression::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i, j;
+ static MouseEvent *mev;
+ bool bEmpty,bRedraw = false;
+ LineDEF *ld;
+
+ switch (cmd) {
+ case CMD_MOUSE_EVENT:
+ if(hidden) return false;
+ mev = (MouseEvent *) tmpl;
+ switch(mev->Action) {
+ case MOUSE_LBUP:
+ if(Symbols) for (i = nPoints-1; i >= 0; i--)
+ if(Symbols[i] && Symbols[i]->Command(cmd, tmpl, o))return true;
+ if(rLine && rLine->Command(cmd, tmpl, o)) return true;
+ if(sde && sde->Command(cmd, tmpl, o)) return true;
+ break;
+ }
+ break;
+ case CMD_LEGEND:
+ if(tmpl && ((GraphObj*)tmpl)->Id == GO_LEGEND && rLine && rLine->Id == GO_REGLINE) {
+ ld = rLine->GetLine();
+ if(Symbols) {
+ for (i = 0; i < nPoints && i < 100; i++)
+ if(Symbols[i]) ((Legend*)tmpl)->HasSym(ld, Symbols[i]);
+ }
+ else ((Legend*)tmpl)->HasFill(ld, 0L);
+ return true;
+ }
+ return false;
+ case CMD_MRK_DIRTY:
+ if(rLine || sde) Recalc();
+ dirty = true;
+ case CMD_SETSCROLL:
+ case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ return false;
+ case CMD_USEAXIS:
+ UseAxis(*((int*)tmpl));
+ return true;
+ case CMD_DROP_OBJECT:
+ if(tmpl && ((GraphObj*)tmpl)->Id == GO_REGLINE && !rLine) {
+ rLine = (RegLine *)tmpl;
+ rLine->parent = this;
+ return true;
+ }
+ break;
+ case CMD_FLUSH:
+ if(yRange) free(yRange); if(xRange) free(xRange);
+ yRange = xRange = 0L;
+ if(rLine) DeleteGO(rLine);
+ if(sde) DeleteGO(sde);
+ rLine = 0L; sde = 0L;
+ if(Symbols) for (i = nPoints-1; i >= 0; i--)
+ if(Symbols[i]) DeleteGO(Symbols[i]);
+ if(Symbols) free(Symbols);
+ Symbols = 0L;
+ return true;
+ case CMD_AUTOSCALE:
+ if(dirty){
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL;
+ Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ }
+ else return true;
+ dirty = false;
+ case CMD_SET_DATAOBJ:
+ if(cmd == CMD_SET_DATAOBJ) {
+ Id = GO_REGRESSION;
+ data = (DataObj *)tmpl;
+ }
+ if(rLine) rLine->Command(cmd, tmpl, o);
+ if(Symbols) for (i = 0; i < nPoints; i++)
+ if(Symbols[i]) Symbols[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_SYMTEXT: case CMD_SYM_RANGETEXT:
+ case CMD_SYMTEXTDEF: case CMD_SYM_TYPE:
+ if(Symbols) for(i = 0; i < nPoints; i++)
+ if(Symbols[i]) Symbols[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_HIDE_MARK:
+ return false;
+ case CMD_SAVE_SYMBOLS:
+ return SavVarObs((GraphObj **)Symbols, nPoints, 0L);
+ case CMD_UPDATE:
+ if(Symbols) {
+ Undo.ObjConf(this, UNDO_CONTINUE);
+ for(i = 0; i < nPoints; i++)
+ if(Symbols[i]) Symbols[i]->Command(cmd, tmpl, o);
+ if(rLine || sde) Recalc();
+ return true;
+ }
+ return false;
+ case CMD_DELOBJ:
+ if(!parent || !o) return false;
+ dirty = bEmpty = bRedraw = false;
+ if(Symbols) for(i = 0; i < nPoints; i++)
+ if(Symbols[i] && (void*)Symbols[i] == tmpl) {
+ bRedraw = true;
+ o->HideMark();
+ Undo.DeleteGO((GraphObj**)(&Symbols[i]), 0L, o);
+ for(j = 0, bEmpty = true; j < nPoints; j++) {
+ if(Symbols[j]) {
+ bEmpty = false;
+ break;
+ }
+ }
+ if(!bEmpty && dirty) Command(CMD_AUTOSCALE, 0L, o);
+ break;
+ }
+ if(rLine && (void*)rLine == tmpl) {
+ Undo.DeleteGO((GraphObj**)(&rLine), 0L, o);
+ if(!Symbols && !sde) parent->Command(CMD_DELOBJ_CONT, this, o);
+ else bRedraw = true;
+ }
+ if(sde && (void*)sde == tmpl) {
+ sde->Command(CMD_RMU, 0L, 0L);
+ Undo.DeleteGO((GraphObj**)(&sde), 0L, o);
+ if(!Symbols && !rLine) parent->Command(CMD_DELOBJ_CONT, this, o);
+ else bRedraw = true;
+ }
+ if(bEmpty && Symbols) {
+ Undo.DropMemory(this, (void**)(&Symbols), UNDO_CONTINUE);
+ bRedraw = false;
+ if(!rLine && !sde) parent->Command(CMD_DELOBJ_CONT, this, o);
+ else bRedraw = true;
+ }
+ if(bRedraw)parent->Command(CMD_REDRAW, 0L, o);
+ return bRedraw;
+ }
+ return false;
+}
+
+void
+Regression::Recalc()
+{
+ int i, j;
+ long n;
+ bool dValid;
+ lfPOINT *val;
+
+ if(nPoints <2 || !Symbols ||
+ !(val = (lfPOINT*)calloc(nPoints, sizeof(lfPOINT)))) return;
+ for(i = 0, n = 0; i < nPoints; i++){
+ if(Symbols[i] && Symbols[i]->Id == GO_SYMBOL) {
+ val[j = (int)n].fx = Symbols[i]->GetSize(SIZE_XPOS);
+ val[j].fy = Symbols[i]->GetSize(SIZE_YPOS);
+ dValid = true;
+ switch(type & 0x700) {
+ case 0x100: //logarithmic x
+ if(dValid = val[j].fx > defs.min4log) val[j].fx = log10(val[j].fx);
+ break;
+ case 0x200: //reciprocal x
+ if(dValid = fabs(val[j].fx) >defs.min4log) val[j].fx = 1.0/val[j].fx;
+ break;
+ case 0x300: //square root x
+ if(dValid = fabs(val[j].fx) >defs.min4log) val[j].fx = sqrt(val[j].fx);
+ break;
+ }
+ if(dValid) switch(type & 0x7000) {
+ case 0x1000: //logarithmic y
+ if(dValid = val[j].fy > defs.min4log) val[j].fy = log10(val[j].fy);
+ break;
+ case 0x2000: //reciprocal y
+ if(dValid = fabs(val[j].fy) >defs.min4log) val[j].fy = 1.0/val[j].fy;
+ break;
+ case 0x3000: //square root y
+ if(dValid = fabs(val[j].fy) >defs.min4log) val[j].fy = sqrt(val[j].fy);
+ break;
+ }
+ if(dValid) n++;
+ }
+ }
+ if(sde && sde->Id == GO_SDELLIPSE) sde->Recalc(val, n);
+ if(rLine && rLine->Id == GO_REGLINE) rLine->Recalc(val, n);
+ free(val);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// BubblePlot is a Plot-Class
+BubblePlot::BubblePlot(GraphObj *par, DataObj *d):Plot(par, d)
+{
+ FileIO(INIT_VARS);
+ Id = GO_BUBBLEPLOT;
+ if (!d && parent) parent->Command(CMD_DELOBJ, this, NULL);
+}
+
+BubblePlot::BubblePlot(int src):Plot(0L, 0L)
+{
+ long i;
+
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ BubbleFill.hatch = &BubbleFillLine;
+ if(Bubbles)for(i = 0; i< nPoints; i++) {
+ if(Bubbles[i])Bubbles[i]->parent = this;
+ }
+ }
+}
+
+BubblePlot::~BubblePlot()
+{
+ int i;
+
+ if(Bubbles) {
+ for(i = 0; i < nPoints; i++) if(Bubbles[i]) DeleteGO(Bubbles[i]);
+ free (Bubbles);
+ }
+ Undo.InvalidGO(this);
+}
+
+DWORD
+BubblePlot::GetColor(int select)
+{
+ switch(select) {
+ case COL_BUBBLE_FILL: return BubbleFill.color;
+ case COL_BUBBLE_LINE: return BubbleLine.color;
+ case COL_BUBBLE_FILLLINE: return BubbleFillLine.color;
+ default:
+ return Plot::GetColor(select);
+ }
+}
+
+void
+BubblePlot::DoPlot(anyOutput *o)
+{
+ int i;
+
+ parent->Command(CMD_REG_AXISPLOT, (void*)this, o);
+ if(use_xaxis || use_yaxis) {
+ ApplyAxes(o);
+ if(Bubbles) for(i = 0; i < nPoints; i++)
+ if(Bubbles[i]) Bubbles[i]->DoPlot(o);
+ parent->Command(CMD_AXIS, 0L, o);
+ }
+ else {
+ if(Bubbles) for(i = 0; i < nPoints; i++)
+ if(Bubbles[i]) Bubbles[i]->DoPlot(o);
+ }
+ dirty = false;
+}
+
+bool
+BubblePlot::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i;
+ static MouseEvent *mev;
+ GraphObj **tmpPlots;
+
+ switch (cmd) {
+ case CMD_MOUSE_EVENT:
+ if(hidden) return false;
+ mev = (MouseEvent *) tmpl;
+ switch(mev->Action) {
+ case MOUSE_LBUP:
+ //select objects invers to plot order
+ if(Bubbles && !CurrGO) for(i = nPoints-1; i >=0; i--)
+ if(Bubbles[i]) if(Bubbles[i]->Command(cmd, tmpl, o))break;
+ break;
+ }
+ break;
+ case CMD_REPL_GO:
+ if((tmpPlots = (GraphObj **)tmpl) && tmpPlots[0] && tmpPlots[1] && Bubbles) {
+ for(i = 0; i < nPoints; i++) if(Bubbles[i] && Bubbles[i] == tmpPlots[0]) {
+ return ReplaceGO((GraphObj**)&Bubbles[i], tmpPlots);
+ }
+ }
+ return false;
+ case CMD_MRK_DIRTY:
+ dirty = true;
+ case CMD_SETSCROLL:
+ case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ return false;
+ case CMD_USEAXIS:
+ UseAxis(*((int*)tmpl));
+ return true;
+ case CMD_SET_DATAOBJ:
+ Id = GO_BUBBLEPLOT;
+ data = (DataObj *)tmpl;
+ case CMD_UPDATE:
+ if(cmd == CMD_UPDATE) Undo.ObjConf(this, UNDO_CONTINUE);
+ case CMD_BUBBLE_ATTRIB:
+ case CMD_BUBBLE_TYPE:
+ case CMD_BUBBLE_FILL:
+ case CMD_BUBBLE_LINE:
+ if(Bubbles) for(i = 0; i < nPoints; i++)
+ if(Bubbles[i]) Bubbles[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_DELOBJ:
+ if(Bubbles && parent) for(i = 0; i < nPoints; i++) {
+ o->HideMark();
+ if(Bubbles[i] && tmpl == (void *)Bubbles[i]) {
+ Undo.DeleteGO((GraphObj**)(&Bubbles[i]), 0L, o);
+ parent->Command(CMD_REDRAW, 0L, o);
+ return true;
+ }
+ }
+ break;
+ case CMD_SAVE_SYMBOLS:
+ return SavVarObs((GraphObj **)Bubbles, nPoints, 0L);
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// PolarPlot is a Plot-Class
+PolarPlot::PolarPlot(GraphObj *par, DataObj *d):Plot(par, d)
+{
+ FileIO(INIT_VARS);
+ Id = GO_POLARPLOT;
+ if (!d && parent) parent->Command(CMD_DELOBJ, this, NULL);
+}
+
+PolarPlot::PolarPlot(int src):Plot(0L, 0L)
+{
+ int i;
+
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ Fill.hatch = &FillLine;
+ //now set parent in all children
+ if(Plots)
+ for(i = 0; i < nPlots; i++) if(Plots[i]) Plots[i]->parent = this;
+ if(Axes)
+ for(i = 0; i < nAxes; i++) if(Axes[i]) Axes[i]->parent = this;
+ }
+}
+
+PolarPlot::~PolarPlot()
+{
+ int i;
+
+ if(Plots){
+ for(i = 0; i < nPlots; i++) if(Plots[i]) DeleteGO(Plots[i]);
+ free(Plots); Plots = 0L;
+ }
+ if(Axes){
+ for(i = 0; i < nAxes; i++) if(Axes[i]) DeleteGO(Axes[i]);
+ free(Axes); Axes = 0L;
+ }
+ Undo.InvalidGO(this);
+}
+
+double
+PolarPlot::GetSize(int select)
+{
+ switch(select) {
+ case SIZE_BOUNDS_XMIN: return Bounds.Xmin;
+ case SIZE_BOUNDS_XMAX: return Bounds.Xmax;
+ case SIZE_BOUNDS_YMIN: return Bounds.Ymin;
+ case SIZE_BOUNDS_YMAX: return Bounds.Ymax;
+ case SIZE_BOUNDS_LEFT: return (Axes && Axes[0])?(((Axis*)Axes[0])->GetAxis())->min:0.0;
+ case SIZE_BOUNDS_RIGHT: return (Axes && Axes[0])?(((Axis*)Axes[0])->GetAxis())->max:0.0;
+ case SIZE_BOUNDS_TOP: return (Axes && Axes[1])?(((Axis*)Axes[1])->GetAxis())->max:0.0;
+ case SIZE_BOUNDS_BOTTOM: return (Axes && Axes[1])?(((Axis*)Axes[1])->GetAxis())->min:0.0;
+ case SIZE_YAXISX:
+ if(!CurrDisp) return 0.0;
+ if((((Axis*)Axes[1])->GetAxis())->flags & AXIS_X_DATA)
+ return CurrDisp->fx2fix((((Axis*)Axes[1])->GetAxis())->loc[0].fx);
+ else return CurrDisp->co2fix((((Axis*)Axes[1])->GetAxis())->loc[0].fx);
+ case SIZE_XAXISY:
+ if(!CurrDisp) return 0.0;
+ if((((Axis*)Axes[0])->GetAxis())->flags & AXIS_Y_DATA)
+ return CurrDisp->fy2fiy((((Axis*)Axes[0])->GetAxis())->loc[0].fy);
+ else return CurrDisp->co2fiy((((Axis*)Axes[0])->GetAxis())->loc[0].fy);
+ case SIZE_XCENTER: return (((Axis*)Axes[0])->GetAxis())->Center.fx;
+ case SIZE_YCENTER: return (((Axis*)Axes[0])->GetAxis())->Center.fy;
+ default:
+ if(parent) return parent->GetSize(select);
+ }
+ return defs.GetSize(select);
+}
+
+void
+PolarPlot::DoPlot(anyOutput *o)
+{
+ int i;
+
+ if(o) CurrDisp = o;
+ else return;
+ if(!parent) return;
+ CurrRect.Xmin = CurrRect.Xmax = (((Axis*)Axes[1])->GetAxis())->Center.fx +
+ parent->GetSize(SIZE_GRECT_LEFT);
+ CurrRect.Xmin -= (((Axis*)Axes[0])->GetAxis())->Radius;
+ CurrRect.Xmax += (((Axis*)Axes[0])->GetAxis())->Radius;
+ CurrRect.Ymin = CurrRect.Ymax = (((Axis*)Axes[0])->GetAxis())->Center.fy +
+ parent->GetSize(SIZE_GRECT_TOP);
+ CurrRect.Ymin -= (((Axis*)Axes[0])->GetAxis())->Radius;
+ CurrRect.Ymax += (((Axis*)Axes[0])->GetAxis())->Radius;
+ (((Axis*)Axes[0])->GetAxis())->Start = ((((Axis*)Axes[0])->GetAxis())->flags & AXIS_INVERT) ? -offs : offs;
+ o->SetRect(CurrRect, defs.cUnits, ((Axis*)Axes[0])->GetAxis(), ((Axis*)Axes[1])->GetAxis());
+ o->SetFill(&Fill);
+ if(Axes) for(i = 0; i < nAxes; i++) {
+ if(i == 1) {
+ if(!(type & 0x01) && Axes[i]) Axes[i]->DoPlot(o);
+ }
+ else if(Axes[i]) Axes[i]->DoPlot(o);
+ }
+ if(Plots) for(i = 0; i < nPlots; i++) if(Plots[i]) {
+ if(Plots[i]->Id >= GO_PLOT && Plots[i]->Id < GO_GRAPH) {
+ if(((Plot*)Plots[i])->hidden == 0) Plots[i]->DoPlot(o);
+ }
+ else Plots[i]->DoPlot(o);
+ }
+ rDims.left = o->co2ix(CurrRect.Xmin); rDims.right = o->co2ix(CurrRect.Xmax);
+ rDims.top = o->co2iy(CurrRect.Ymin); rDims.bottom = o->co2iy(CurrRect.Ymax);
+ if(parent) parent->Command(CMD_AXIS, 0L, o);
+}
+
+bool
+PolarPlot::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ GraphObj **tmpPlots;
+ int i;
+ AxisDEF *ad0, *ad1;
+ double tmp;
+
+ switch (cmd) {
+ case CMD_CONFIG:
+ Config();
+ return true;
+ case CMD_SET_DATAOBJ:
+ Id = GO_POLARPLOT;
+ data = (DataObj *)tmpl;
+ case CMD_UPDATE:
+ if(Axes) for(i = 0; i< nAxes; i++) if(Axes[i]) Axes[i]->Command(cmd, tmpl, o);
+ case CMD_LEGEND:
+ if(Plots) for(i = 0; i < nPlots; i++) if(Plots[i]) Plots[i]->Command(cmd, tmpl, o);
+ return false;
+ case CMD_OBJTREE:
+ if(!tmpl) return false;
+ if(Plots) for(i = 0; i < nPlots; i++) if(Plots[i])
+ ((ObjTree*)tmpl)->Command(CMD_UPDATE, Plots[i], 0L);
+ return true;
+ case CMD_HIDE_MARK:
+ if(!tmpl || !o) return false;
+ //do all axes
+ if(Axes)for(i = nAxes-1; i>=0; i--) {
+ if(tmpl == (void*)Axes[i]){
+ Axes[i]->DoMark(CurrDisp, false); return true;
+ }
+ else if(Axes[i]->Id == GO_AXIS) {
+ if(Axes[i]->Command(cmd, tmpl, o)) return true;
+ }
+ }
+ //do all plots
+ if(Plots)for(i = nPlots-1; i>=0; i--) {
+ if(tmpl == (void*)Plots[i]){
+ Plots[i]->DoMark(CurrDisp, false); return true;
+ }
+ else if(Plots[i] && (Plots[i]->Id == GO_MLABEL || Plots[i]->Id == GO_LEGEND ||
+ (Plots[i]->Id >= GO_PLOT && Plots[i]->Id < GO_GRAPH))) {
+ if(Plots[i]->Command(cmd, tmpl, o)) return true;
+ }
+ }
+ return false;
+ case CMD_MOUSE_EVENT:
+ if(hidden) return false;
+ if(o) switch(((MouseEvent*)tmpl)->Action) {
+ case MOUSE_LBUP:
+ if(Axes) for(i = 0; i< nAxes; i++) if(Axes[i])
+ if(Axes[i]->Command(cmd, tmpl, o))return true;
+ if(Plots) for(i = 0; i < nPlots; i++) if(Plots[i])
+ Plots[i]->Command(cmd, tmpl, o);
+ if(!CurrGO && IsInRect(&rDims, ((MouseEvent*)tmpl)->x, ((MouseEvent*)tmpl)->y)){
+ CurrGO = this;
+ o->ShowMark(&rDims, MRK_INVERT);
+ return true;
+ }
+ break;
+ }
+ return false;
+ case CMD_REPL_GO:
+ if(!(tmpPlots = (GraphObj **)tmpl) || !tmpPlots[0] || !tmpPlots[1]) return false;
+ if(Axes) for(i = 0; i < nAxes; i++) if(Axes[i] && Axes[i] == tmpPlots[0]){
+ return ReplaceGO(&Axes[i], tmpPlots);
+ }
+ break;
+ case CMD_SETSCROLL:
+ case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ return false;
+ case CMD_DELOBJ_CONT:
+ case CMD_DELOBJ:
+ if(Plots && nPlots) for(i = 0; i < nPlots; i++) if(tmpl == (void*)Plots[i]) {
+ Undo.DeleteGO((GraphObj**)(&Plots[i]), cmd == CMD_DELOBJ_CONT ? UNDO_CONTINUE : 0L, o);
+ if(parent)parent->Command(CMD_REDRAW, NULL, o);
+ return true;
+ }
+ if(Axes && nAxes > 1 && (tmpl == (void*)Axes[0] || tmpl == (void*)Axes[1]))
+ InfoBox("Axes required for scaling\ncannot be deleted.");
+ break;
+ case CMD_AXIS: //axis changed: reconstruct corresponding axis
+ if(Axes && nAxes >1 && tmpl && Axes[0] && Axes[1]) {
+ ad0 = ((Axis*)Axes[0])->GetAxis(); ad1 = ((Axis*)Axes[1])->GetAxis();
+ if(tmpl == Axes[0]) {
+ CheckNewFloat(&ad1->loc[1].fy, ad1->loc[1].fy, ad0->Center.fy, this, UNDO_CONTINUE);
+ tmp = ad1->loc[1].fy - ad0->Radius;
+ CheckNewFloat(&ad1->loc[0].fy, ad1->loc[0].fy, tmp, this, UNDO_CONTINUE);
+ }
+ if(tmpl == Axes[1]) {
+ CheckNewFloat(&ad0->Center.fy, ad0->Center.fy, ad1->loc[1].fy, this, UNDO_CONTINUE);
+ tmp = fabs(ad1->loc[1].fy - ad1->loc[0].fy);
+ CheckNewFloat(&ad0->Radius, ad0->Radius, tmp, this, UNDO_CONTINUE);
+ }
+ }
+ break;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// BoxPlot is a Plot-Class
+BoxPlot::BoxPlot(GraphObj *par, DataObj *d):Plot(par, d)
+{
+ FileIO(INIT_VARS);
+ Id = GO_BOXPLOT;
+ if (!d && parent) parent->Command(CMD_DELOBJ, this, NULL);
+}
+
+BoxPlot::BoxPlot(int src):Plot(0L, 0L)
+{
+ int i;
+
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ //now set parent in all children
+ if(Boxes)
+ for(i = 0; i < nPoints; i++) if(Boxes[i]) Boxes[i]->parent = this;
+ if(Whiskers)
+ for(i = 0; i < nPoints; i++) if(Whiskers[i]) Whiskers[i]->parent = this;
+ if(Symbols)
+ for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->parent = this;
+ if(TheLine) TheLine->parent = this;
+ }
+}
+
+BoxPlot::BoxPlot(GraphObj *par, DataObj *dt, int mode, int c1, int c2, int c3):Plot(par, dt)
+{
+ int i, nr;
+ lfPOINT fp;
+
+ FileIO(INIT_VARS); Id = GO_BOXPLOT; fp.fx = fp.fy = 0.0;
+ if(data && data->GetSize(&i, &nr)) {
+ nPoints = nr;
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL;
+ Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ if(Boxes = (Box**)calloc(nr, sizeof(Box*))) for(i = 0; i < nr; i++) {
+ if(mode == 1) Boxes[i] = new Box(this, data, fp, fp, 0, c1, i, c2, i, c1, i, c3, i);
+ else Boxes[i] = new Box(this, data, fp, fp, 0, c2, i, c1, i, c3, i, c1, i);
+ if(Boxes[i]) Boxes[i]->Command(CMD_AUTOSCALE, 0L, 0L);
+ }
+ }
+ BoxDist.fx = BoxDist.fy = GetSize(mode == 2 ? SIZE_BOXMINY : SIZE_BOXMINX);
+}
+
+BoxPlot::~BoxPlot()
+{
+ int i;
+
+ if(Whiskers) {
+ for(i = 0; i < nPoints; i++) if(Whiskers[i]) delete(Whiskers[i]);
+ free (Whiskers);
+ }
+ if(Boxes) {
+ for(i = 0; i < nPoints; i++) if(Boxes[i]) delete(Boxes[i]);
+ free (Boxes);
+ }
+ if(Symbols) {
+ for(i = 0; i < nPoints; i++) if(Symbols[i]) delete(Symbols[i]);
+ free (Symbols);
+ }
+ if(TheLine) delete(TheLine);
+ Undo.InvalidGO(this);
+}
+
+double
+BoxPlot::GetSize(int select)
+{
+ int i;
+ double ft1, ft2;
+
+ switch(select){
+ case SIZE_BOXMINX:
+ if(BoxDist.fx >= 0.0001) return BoxDist.fx;
+ if((!Boxes) | (nPoints < 2)) return 1.0;
+ ft1 = ft2 = 1.0;
+ if(Boxes[0] && Boxes[1]) ft1 = fabs(Boxes[1]->GetSize(SIZE_XPOS) -
+ Boxes[0]->GetSize(SIZE_XPOS));
+ else return 1.0;
+ for(i = 2; i < nPoints; i++) {
+ if(Boxes[i] && Boxes[i-1]) ft2 = fabs(Boxes[i]->
+ GetSize(SIZE_XPOS) - Boxes[i-1]->GetSize(SIZE_XPOS));
+ if(ft2 < ft1 || ft1 < 0.0001) ft1 = ft2;
+ }
+ return BoxDist.fx = ft1 > 0.0001 ? ft1 : 1.0;
+ case SIZE_BOXMINY:
+ if(BoxDist.fy >= 0.0001) return BoxDist.fy;
+ if((!Boxes) | (nPoints < 2)) return 1.0f;
+ ft1 = ft2 = 1.0f;
+ if(Boxes[0] && Boxes[1]) ft1 = fabs(Boxes[1]->GetSize(SIZE_YPOS) -
+ Boxes[0]->GetSize(SIZE_YPOS));
+ else return 1.0f;
+ for(i = 2; i < nPoints; i++) {
+ if(Boxes[i] && Boxes[i-1]) ft2 = fabs(Boxes[i]->
+ GetSize(SIZE_YPOS) - Boxes[i-1]->GetSize(SIZE_YPOS));
+ if(ft2 < ft1 || ft1 < 0.0001f) ft1 = ft2;
+ }
+ return BoxDist.fy = ft1 > 0.0001 ? ft1 : 1.0f;
+ default:
+ return Plot::GetSize(select);
+ }
+}
+
+bool
+BoxPlot::SetSize(int select, double value)
+{
+ int i;
+
+ switch(select & 0xfff){
+ case SIZE_SYMBOL:
+ case SIZE_SYM_LINE:
+ if(Symbols) for(i = 0; i < nPoints; i++)
+ if(Symbols[i]) Symbols[i]->SetSize(select, value);
+ return true;
+ case SIZE_WHISKER:
+ case SIZE_WHISKER_LINE:
+ if(Whiskers) for(i = 0; i < nPoints; i++)
+ if(Whiskers[i]) Whiskers[i]->SetSize(select, value);
+ return true;
+ case SIZE_BOX:
+ case SIZE_BOX_LINE:
+ if(Boxes) for(i = 0; i < nPoints; i++)
+ if(Boxes[i]) Boxes[i]->SetSize(select, value);
+ return true;
+ }
+ return false;
+}
+
+bool
+BoxPlot::SetColor(int select, DWORD col)
+{
+ int i;
+
+ switch(select) {
+ case COL_SYM_LINE:
+ case COL_SYM_FILL:
+ if(Symbols) for(i = 0; i < nPoints; i++)
+ if(Symbols[i]) Symbols[i]->SetColor(select, col);
+ return true;
+ case COL_WHISKER:
+ if(Whiskers) for(i = 0; i < nPoints; i++)
+ if(Whiskers[i]) Whiskers[i]->SetColor(select, col);
+ return true;
+ case COL_BOX_LINE:
+ if(Boxes) for(i = 0; i < nPoints; i++)
+ if(Boxes[i]) Boxes[i]->SetColor(select, col);
+ return true;
+ default:
+ return false;
+ }
+}
+
+void
+BoxPlot::DoPlot(anyOutput *o)
+{
+ int i;
+
+ if(!parent) return;
+ parent->Command(CMD_REG_AXISPLOT, (void*)this, o);
+ if(use_xaxis || use_yaxis) ApplyAxes(o);
+ if(TheLine) TheLine->DoPlot(o);
+ if(Whiskers)
+ for(i = 0; i < nPoints; i++) if(Whiskers[i]) Whiskers[i]->DoPlot(o);
+ if(Boxes)
+ for(i = 0; i < nPoints; i++) if(Boxes[i]) Boxes[i]->DoPlot(o);
+ if(Symbols)
+ for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->DoPlot(o);
+ dirty = false;
+ if(use_xaxis || use_yaxis)parent->Command(CMD_AXIS, 0L, o);
+}
+
+bool
+BoxPlot::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i, j;
+ bool bRedraw;
+ MouseEvent *mev;
+ GraphObj **obs[] = {(GraphObj**)Boxes, (GraphObj**)Whiskers, (GraphObj**)Symbols};
+ GraphObj ***go;
+
+ switch (cmd) {
+ case CMD_MOUSE_EVENT:
+ if(hidden) return false;
+ mev = (MouseEvent *) tmpl;
+ switch(mev->Action) {
+ case MOUSE_LBUP:
+ for(j = 2; j >= 0 && !CurrGO; j--) { //invers to plot order
+ if(obs[j]) for (i = nPoints-1; i >= 0; i--)
+ if(obs[j][i]) if(obs[j][i]->Command(cmd, tmpl, o))break;
+ }
+ if(TheLine && !CurrGO) TheLine->Command(cmd, tmpl, o);
+ break;
+ }
+ break;
+ case CMD_LEGEND:
+ if(Boxes) for (i = 0; i < nPoints; i++)
+ if(Boxes[i]) Boxes[i]->Command(cmd, tmpl, o);
+ break;
+ case CMD_SET_DATAOBJ:
+ Id = GO_BOXPLOT; data = (DataObj *)tmpl; dirty = true;
+ case CMD_AUTOSCALE:
+ if(cmd == CMD_AUTOSCALE){
+ if(hidden) return false;
+ if(dirty) {
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL;
+ Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ }
+ else{
+ if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH &&
+ Bounds.Xmax > Bounds.Xmin && Bounds.Ymax > Bounds.Ymin) {
+ ((Plot*)parent)->CheckBounds(Bounds.Xmin, Bounds.Ymin);
+ ((Plot*)parent)->CheckBounds(Bounds.Xmax, Bounds.Ymax);
+ return true;
+ }
+ }
+ dirty = false;
+ }
+ case CMD_UPDATE:
+ if(cmd == CMD_UPDATE) Undo.ObjConf(this, UNDO_CONTINUE);
+ for(j = 0; j < 3; j++) {
+ if(obs[j]) for (i = 0; i < nPoints; i++)
+ if(obs[j][i]) obs[j][i]->Command(cmd, tmpl, o);
+ }
+ if(TheLine) TheLine->Command(cmd, tmpl, o);
+ if(cmd == CMD_AUTOSCALE && parent && parent->Id > GO_PLOT && parent->Id < GO_GRAPH
+ && Bounds.Xmax > Bounds.Xmin && Bounds.Ymax > Bounds.Ymin){
+ ((Plot*)parent)->CheckBounds(Bounds.Xmin, Bounds.Ymin);
+ ((Plot*)parent)->CheckBounds(Bounds.Xmax, Bounds.Ymax);
+ }
+ return true;
+ case CMD_USEAXIS:
+ UseAxis(*((int*)tmpl));
+ return true;
+ case CMD_MRK_DIRTY:
+ dirty = true;
+ case CMD_SETSCROLL:
+ case CMD_REDRAW:
+ if(parent)return parent->Command(cmd, tmpl, o);
+ return false;
+ case CMD_DELOBJ:
+ if(!parent || !o) return false;
+ for(j = 0, bRedraw = false, go = 0L; j < 3 && !bRedraw; j++) {
+ if(obs[j]) for(i = 0; i < nPoints; i++)
+ if(obs[j][i] && tmpl == (void*)obs[j][i]) {
+ o->HideMark();
+ Undo.DeleteGO(&obs[j][i], 0L, o);
+ switch(j) {
+ case 0: go = (GraphObj***)&Boxes; break;
+ case 1: go = (GraphObj***)&Whiskers; break;
+ case 2: go = (GraphObj***)&Symbols; break;
+ }
+ bRedraw = true;
+ break;
+ }
+ }
+ if(!bRedraw && TheLine && tmpl == (void *) TheLine) {
+ o->HideMark();
+ Undo.DeleteGO((GraphObj**)(&TheLine), 0L, o);
+ bRedraw = true;
+ }
+ if(bRedraw && go) for(i = j = 0; i < nPoints; i++) if(go[0][i]) j++;
+ if(!j) Undo.DropMemory(this, (void**)go, UNDO_CONTINUE);
+ if(!Boxes && !Whiskers && !Symbols && !TheLine)
+ parent->Command(CMD_DELOBJ_CONT, this, o);
+ else if(bRedraw) parent->Command(CMD_REDRAW, NULL, o);
+ return bRedraw;
+ case CMD_SYMTEXT:
+ case CMD_SYM_RANGETEXT:
+ case CMD_SYMTEXTDEF:
+ case CMD_SYM_TYPE:
+ if(Symbols) for(i = 0; i < nPoints; i++)
+ if(Symbols[i]) Symbols[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_SAVE_SYMBOLS:
+ return SavVarObs((GraphObj **)Symbols, nPoints, 0L);
+ case CMD_SAVE_BARS:
+ return SavVarObs((GraphObj **)Boxes, nPoints, 0L);
+ case CMD_SAVE_BARS_CONT:
+ return SavVarObs((GraphObj **)Boxes, nPoints, UNDO_CONTINUE);
+ case CMD_SAVE_ERRS:
+ return SavVarObs((GraphObj **)Whiskers, nPoints, 0L);
+ case CMD_BOX_TYPE:
+ BoxDist.fy = BoxDist.fx = 0.0;
+ case CMD_BOX_FILL:
+ if(Boxes) for (i = 0; i < nPoints; i++)
+ if(Boxes[i]) Boxes[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_WHISKER_STYLE:
+ if(Whiskers) for (i = 0; i < nPoints; i++)
+ if(Whiskers[i]) Whiskers[i]->Command(cmd, tmpl, o);
+ return true;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Density distribution plot
+DensDisp::DensDisp(GraphObj *par, DataObj *d):Plot(par, d)
+{
+ FileIO(INIT_VARS);
+ Id = GO_DENSDISP;
+ if (!d && parent) parent->Command(CMD_DELOBJ, this, NULL);
+}
+
+DensDisp::DensDisp(int src):Plot(0L, 0L)
+{
+ int i;
+
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ //now set parent in all children
+ if(Boxes)
+ for(i = 0; i < nPoints; i++) if(Boxes[i]) Boxes[i]->parent = this;
+ }
+}
+
+DensDisp::~DensDisp()
+{
+ int i;
+
+ if(Boxes) {
+ for(i = 0; i < nPoints; i++) if(Boxes[i]) DeleteGO(Boxes[i]);
+ free (Boxes);
+ }
+ if(yRange) free(yRange); if(xRange) free(xRange);
+ yRange = xRange = 0L;
+ Undo.InvalidGO(this);
+}
+
+bool
+DensDisp::SetSize(int select, double value)
+{
+ int i;
+
+ switch(select & 0xfff){
+ case SIZE_BOX_LINE:
+ if(Boxes) for(i = 0; i < nPoints; i++)
+ if(Boxes[i]) Boxes[i]->SetSize(select, value);
+ return true;
+ }
+ return false;
+}
+
+bool
+DensDisp::SetColor(int select, DWORD col)
+{
+ int i;
+
+ switch(select) {
+ case COL_BOX_LINE:
+ if(Boxes) for(i = 0; i < nPoints; i++)
+ if(Boxes[i]) Boxes[i]->SetColor(select, col);
+ return true;
+ default:
+ return false;
+ }
+}
+
+void
+DensDisp::DoPlot(anyOutput *o)
+{
+ int i;
+
+ if(!parent) return;
+ parent->Command(CMD_REG_AXISPLOT, (void*)this, o);
+ if(use_xaxis || use_yaxis) {
+ ApplyAxes(o);
+ if(Boxes) for(i = 0; i < nPoints; i++)
+ if(Boxes[i]) Boxes[i]->DoPlot(o);
+ parent->Command(CMD_AXIS, 0L, o);
+ }
+ else {
+ if(Boxes) for(i = 0; i < nPoints; i++)
+ if(Boxes[i]) Boxes[i]->DoPlot(o);
+ }
+ dirty = false;
+}
+
+bool
+DensDisp::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i;
+ MouseEvent *mev;
+
+ switch (cmd) {
+ case CMD_MRK_DIRTY:
+ dirty = true;
+ case CMD_SETSCROLL:
+ case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ return false;
+ case CMD_USEAXIS:
+ UseAxis(*((int*)tmpl));
+ return true;
+ case CMD_MOUSE_EVENT:
+ if(hidden) return false;
+ mev = (MouseEvent *) tmpl;
+ switch(mev->Action) {
+ case MOUSE_LBUP:
+ for(i = nPoints-1; i >= 0 && !CurrGO; i--) {
+ if(Boxes[i] && Boxes[i]->Command(cmd, tmpl, o))return true;
+ }
+ break;
+ }
+ break;
+ case CMD_SET_DATAOBJ:
+ for(i = 0; i < nPoints; i++) if(Boxes[i]) Boxes[i]->Command(cmd, tmpl, o);
+ Id = GO_DENSDISP;
+ data = (DataObj *)tmpl;
+ return true;
+ case CMD_DELOBJ:
+ if(!parent || !o) return false;
+ for(i = 0; i < nPoints; i++) {
+ if(Boxes[i] && tmpl == (void*)Boxes[i]){
+ o->HideMark();
+ Undo.DeleteGO((GraphObj**)(&Boxes[i]), 0L, o);
+ return parent->Command(CMD_REDRAW, NULL, o);
+ }
+ }
+ break;
+ case CMD_AUTOSCALE:
+ if(dirty){
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL;
+ Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ }
+ else return true;
+ dirty = false;
+ case CMD_BOX_TYPE:
+ case CMD_BOX_FILL:
+ if(Boxes) for (i = 0; i < nPoints; i++)
+ if(Boxes[i]) Boxes[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_UPDATE:
+ Undo.ObjConf(this, UNDO_CONTINUE);
+ DoUpdate();
+ return true;
+ }
+ return false;
+}
+
+void
+DensDisp::DoUpdate()
+{
+ AccRange *rX, *rY;
+ int i, j, k, l, ic, n;
+ double v, w;
+ lfPOINT fp1, fp2;
+
+ if(xRange && yRange && (rX = new AccRange(xRange)) && (rY = new AccRange(yRange))) {
+ if((n=rX->CountItems()) == rY->CountItems()) {
+ if(Boxes) {
+ for(i = 0; i < nPoints; i++) if(Boxes[i]) DeleteGO(Boxes[i]);
+ free (Boxes);
+ }
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ Boxes = (Box**)calloc(nPoints = n, sizeof(Box*));
+ rX->GetFirst(&i, &j); rY->GetFirst(&k, &l);
+ rX->GetNext(&i, &j); rY->GetNext(&k, &l);
+ for(ic = 0; ic < n && !data->GetValue(j, i, &v); ic++) {
+ rX->GetNext(&i, &j); rY->GetNext(&k, &l);
+ }
+ rX->GetNext(&i, &j); rY->GetNext(&k, &l);
+ if(type & 0x10){ //vertical ?
+ fp2.fx = 0; fp2.fy = v;
+ }
+ else {
+ fp2.fx = v; fp2.fy = 0.0;
+ }
+ ic = 0;
+ do {
+ if(data->GetValue(j, i, &v) && data->GetValue(l, k, &w)){
+ memcpy(&fp1, &fp2, sizeof(lfPOINT));
+ if(type & 0x10) {
+ CheckBounds(w, fp1.fy); CheckBounds(-w, v);
+ fp2.fy = v;
+ switch(type & 0x3) {
+ case 1: fp1.fx = fp2.fx = w/2.0; break;
+ case 2: fp1.fx = fp2.fx = -w/2.0; break;
+ default: fp2.fx = 0.0; break;
+ }
+ }
+ else {
+ CheckBounds(fp1.fx, w); CheckBounds(v, -w);
+ fp2.fx = v;
+ switch(type & 0x3) {
+ case 1: fp1.fy = fp2.fy = w/2.0; break;
+ case 2: fp1.fy = fp2.fy = -w/2.0; break;
+ default: fp2.fy = 0.0; break;
+ }
+ }
+ if(Boxes[ic] = new Box(this, data, fp1, fp2, BAR_WIDTHDATA))
+ Boxes[ic]->SetSize(SIZE_BOX, (type &0x03) ? w/2.0 : w);
+ }
+ ic++;
+ }while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l));
+ SetSize(SIZE_BOX_LINE, DefLine.width);
+ SetColor(COL_BOX_LINE, DefLine.color);
+ Command(CMD_BOX_FILL, (void*)&DefFill, 0L);
+ }
+ else InfoBox("Error updating Plot!");
+ delete(rX); delete(rY);
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Stacked bars consist of several box-plots
+StackBar::StackBar(GraphObj *par, DataObj *d):Plot(par, d)
+{
+ FileIO(INIT_VARS);
+ Id = GO_STACKBAR;
+ if (!d && parent) parent->Command(CMD_DELOBJ, this, NULL);
+}
+
+StackBar::StackBar(int src):Plot(0L, 0L)
+{
+ int i;
+
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ //now set parent in all children
+ if(Boxes) for(i = 0; i < numPlots; i++)
+ if(Boxes[i]) Boxes[i]->parent = this;
+ if(xyPlots) for(i = 0; i < numXY; i++)
+ if(xyPlots[i]) xyPlots[i]->parent = this;
+ if(Polygons) for(i = 0; i < numPG; i++)
+ if(Polygons[i]) Polygons[i]->parent = this;
+ if(Lines) for(i = 0; i < numPL; i++)
+ if(Lines[i]) Lines[i]->parent = this;
+ }
+}
+
+StackBar::~StackBar()
+{
+ int i;
+
+ if(Boxes){
+ for(i = 0; i < numPlots; i++) if(Boxes[i]) DeleteGO(Boxes[i]);
+ free(Boxes);
+ }
+ if(xyPlots){
+ for(i = 0; i < numXY; i++) if(xyPlots[i]) DeleteGO(xyPlots[i]);
+ free(xyPlots);
+ }
+ if(Polygons) {
+ for(i = 0; i < numPG; i++) if(Polygons[i]) DeleteGO(Polygons[i]);
+ free(Polygons);
+ }
+ if(Lines) {
+ for(i = 0; i < numPL; i++) if(Lines[i]) DeleteGO(Lines[i]);
+ free(Lines);
+ }
+ if(ssXrange) free(ssXrange); if(ssYrange) free(ssYrange);
+ if(CumData) delete CumData; CumData = 0L;
+ Undo.InvalidGO(this);
+}
+
+bool
+StackBar::SetSize(int select, double value)
+{
+ int i;
+
+ switch(select & 0xfff){
+ case SIZE_BAR:
+ if(xyPlots) for(i = 0; i < numXY; i++)
+ if(xyPlots[i]) xyPlots[i]->SetSize(select, value);
+ return true;
+ case SIZE_BOX:
+ case SIZE_BOX_LINE:
+ if(Boxes) for(i = 0; i < numPlots; i++)
+ if(Boxes[i]) Boxes[i]->SetSize(select, value);
+ return true;
+ }
+ return false;
+}
+
+void
+StackBar::DoPlot(anyOutput *o)
+{
+ int i;
+ double dx, dy;
+ fRECT oldREC;
+
+ if(!o || !parent) return;
+ parent->Command(CMD_REG_AXISPLOT, (void*)this, o);
+ if(use_xaxis || use_yaxis) ApplyAxes(o);
+ dx = o->un2fix(dspm.fx); dy = o->un2fiy(dspm.fy);
+ memcpy(&oldREC, &o->Box1, sizeof(fRECT));
+ if(Boxes) for(i = 0; i < numPlots; i++) if(Boxes[i]) {
+ if(Boxes[i]->Id >= GO_PLOT && Boxes[i]->Id < GO_GRAPH) {
+ if(((Plot*)Boxes[i])->hidden == 0) Boxes[i]->DoPlot(o);
+ }
+ else Boxes[i]->DoPlot(o);
+ }
+ if(xyPlots) for(i = 0; i < numXY; i++) if(xyPlots[i]) {
+ if(xyPlots[i]->Id >= GO_PLOT && xyPlots[i]->Id < GO_GRAPH) {
+ if(((Plot*)xyPlots[i])->hidden == 0) xyPlots[i]->DoPlot(o);
+ }
+ else xyPlots[i]->DoPlot(o);
+ }
+ if(Polygons) for(i = 0; i < numPG; i++)
+ if(Polygons[i]) Polygons[i]->DoPlot(o);
+ if(Lines) for(i = numPL-1; i >= 0; i--){
+ o->Box1.Xmin = oldREC.Xmin + dx*i;
+ o->Box1.Ymin = oldREC.Ymin + dy*i;
+ o->Box1.Xmax = oldREC.Xmax + dx*i;
+ o->Box1.Ymax = oldREC.Ymax + dy*i;
+ if(Lines[i]) Lines[i]->DoPlot(o);
+ }
+ dirty = false;
+ memcpy(&o->Box1, &oldREC, sizeof(fRECT));
+ if(use_xaxis || use_yaxis) parent->Command(CMD_AXIS, 0L, o);
+}
+
+bool
+StackBar::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i;
+ static MouseEvent *mev;
+
+ switch (cmd) {
+ case CMD_MOUSE_EVENT:
+ if(hidden) return false;
+ mev = (MouseEvent *) tmpl;
+ switch(mev->Action) {
+ case MOUSE_LBUP:
+ if(Boxes && !CurrGO) for(i = 0; i < numPlots; i++)
+ if(Boxes[i] && Boxes[i]->Command(cmd, tmpl, o))return true;
+ if(xyPlots && !CurrGO) for(i = 0; i < numXY; i++)
+ if(xyPlots[i] && xyPlots[i]->Command(cmd, tmpl, o))return true;
+ if(Polygons && !CurrGO) for(i = 0; i < numPG; i++)
+ if(Polygons[i] && Polygons[i]->Command(cmd, tmpl, o))return true;
+ if(Lines && !CurrGO) for(i = 0; i < numPL; i++)
+ if(Lines[i] && Lines[i]->Command(cmd, tmpl, o))return true;
+ break;
+ }
+ break;
+ case CMD_HIDE_MARK:
+ if(!tmpl) return false;
+ if(Boxes && !CurrGO) for(i = 0; i < numPlots; i++)
+ if(Boxes[i] && Boxes[i]->Command(cmd, tmpl, o))return true;
+ if(xyPlots && !CurrGO) for(i = 0; i < numXY; i++)
+ if(xyPlots[i] && xyPlots[i]->Command(cmd, tmpl, o))return true;
+ if(Polygons && !CurrGO) for(i = 0; i < numPG; i++)
+ if(Polygons[i] && Polygons[i] == tmpl){
+ Polygons[i]->DoMark(o, false);
+ return true;
+ }
+ if(Lines && !CurrGO) for(i = 0; i < numPL; i++)
+ if(Lines[i] && Lines[i] == tmpl){
+ Lines[i]->DoMark(o, false);
+ return true;
+ }
+ break;
+ case CMD_OBJTREE:
+ if(!tmpl) return false;
+ if(Boxes) for(i = 0; i < numPlots; i++) if(Boxes[i])
+ ((ObjTree*)tmpl)->Command(CMD_UPDATE, Boxes[i], 0L);
+ if(xyPlots) for(i = 0; i < numXY; i++) if(xyPlots[i])
+ ((ObjTree*)tmpl)->Command(CMD_UPDATE, xyPlots[i], 0L);
+ return true;
+ case CMD_LEGEND:
+ if(Boxes) for (i = 0; i < numPlots; i++)
+ if(Boxes[i]) Boxes[i]->Command(cmd, tmpl, o);
+ if(Polygons) for (i = numPG-1; i >= 0; i--)
+ if(Polygons[i]) Polygons[i]->Command(cmd, tmpl, o);
+ break;
+ case CMD_USEAXIS:
+ UseAxis(*((int*)tmpl));
+ return true;
+ case CMD_MRK_DIRTY:
+ dirty = true;
+ case CMD_SETSCROLL: case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ return false;
+ case CMD_BAR_TYPE:
+ if(xyPlots) for(i = 0; i < numXY; i++)
+ if(xyPlots[i]) xyPlots[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_SAVE_BARS: case CMD_SAVE_BARS_CONT:
+ if(Boxes) for(i = 0; i < numPlots; i++)
+ if(Boxes[i])Boxes[i]->Command(CMD_SAVE_BARS_CONT, tmpl, o);
+ return true;
+ case CMD_SET_DATAOBJ:
+ Id = GO_STACKBAR;
+ if(data == tmpl) return true;
+ data = (DataObj *)tmpl;
+ case CMD_AUTOSCALE: case CMD_UPDATE:
+ if(cmd == CMD_UPDATE) Undo.ObjConf(this, UNDO_CONTINUE);
+ if(cmd == CMD_AUTOSCALE) {
+ if(hidden) return false;
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL;
+ Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ dirty = false;
+ }
+ if(cum_data_mode){
+ if(CumData) delete CumData;
+ CumData = CreaCumData(ssXrange, ssYrange, cum_data_mode, StartVal);
+ if(cmd == CMD_SET_DATAOBJ) tmpl = CumData;
+ if(cmd == CMD_UPDATE && CumData) {
+ if(Polygons) for(i = 0; i < numPG; i++)
+ if(Polygons[i]) Polygons[i]->Command(CMD_SET_DATAOBJ, CumData, o);
+ if(Lines) for(i = 0; i < numPL; i++)
+ if(Lines[i]) Lines[i]->Command(CMD_SET_DATAOBJ, CumData, o);
+ if(xyPlots) for(i = 0; i < numXY; i++)
+ if(xyPlots[i]) xyPlots[i]->Command(CMD_SET_DATAOBJ, CumData, o);
+ if(Boxes) for (i = 0; i < numPlots; i++)
+ if(Boxes[i]) Boxes[i]->Command(CMD_SET_DATAOBJ, CumData, o);
+ }
+ }
+ if(Polygons) for(i = 0; i < numPG; i++)
+ if(Polygons[i]) Polygons[i]->Command(cmd, tmpl, o);
+ if(Lines) for(i = 0; i < numPL; i++)
+ if(Lines[i]) Lines[i]->Command(cmd, tmpl, o);
+ if(xyPlots) for(i = 0; i < numXY; i++)
+ if(xyPlots[i]) {
+ if(cmd == CMD_AUTOSCALE && xyPlots[i]->Id >= GO_PLOT && xyPlots[i]->Id < GO_GRAPH) {
+ if(((Plot*)xyPlots[i])->hidden == 0) xyPlots[i]->Command(cmd, tmpl, o);
+ }
+ else xyPlots[i]->Command(cmd, tmpl, o);
+ }
+ case CMD_BOX_TYPE:
+ if(Boxes) for (i = 0; i < numPlots; i++)
+ if(Boxes[i]) Boxes[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_DELOBJ:
+ if(o) o->HideMark();
+ if(!tmpl || !parent) return false;
+ if(Polygons) for(i = 0; i < numPG; i++) if(Polygons[i] == tmpl) {
+ Undo.DeleteGO((GraphObj**)(&Polygons[i]), 0L, o);
+ return parent->Command(CMD_REDRAW, 0L, o);
+ }
+ if(Lines) for(i = 0; i < numPL; i++) if(Lines[i] == tmpl) {
+ Undo.DeleteGO((GraphObj**)(&Lines[i]), 0L, o);
+ return parent->Command(CMD_REDRAW, 0L, o);
+ }
+ if(xyPlots) for(i = 0; i < numXY; i++){
+ if(xyPlots[i] == tmpl) {
+ Undo.DeleteGO((GraphObj**)(&xyPlots[i]), 0L, o);
+ return parent->Command(CMD_REDRAW, 0L, o);
+ }
+ else if(xyPlots[i] && xyPlots[i]->Command(cmd, tmpl, o)) return true;
+ }
+ if(Boxes) for(i = 0; i < numPlots; i++){
+ if(Boxes[i] == tmpl) {
+ Undo.DeleteGO((GraphObj**)(&Boxes[i]), 0L, o);
+ return parent->Command(CMD_REDRAW, 0L, o);
+ }
+ else if(Boxes[i] && Boxes[i]->Command(cmd, tmpl, o)) return true;
+ }
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Stacked polygons is based on stacked bar
+StackPG::StackPG(GraphObj *par, DataObj *d):StackBar(par, d)
+{
+ Id = GO_STACKPG;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// waterfall plot is based on stacked bar
+Waterfall::Waterfall(GraphObj *par, DataObj *d):StackBar(par, d)
+{
+ Id = GO_WATERFALL;
+ dspm.fx = dspm.fy = 0.0;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// multi data line plot is based on stacked bar
+MultiLines::MultiLines(GraphObj *par, DataObj *d):StackBar(par, d)
+{
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// simple pie chart
+PieChart::PieChart(GraphObj *par, DataObj *d):Plot(par, d)
+{
+ FileIO(INIT_VARS);
+ Id = GO_PIECHART;
+ if (!d && parent) parent->Command(CMD_DELOBJ, this, NULL);
+}
+
+PieChart::PieChart(int src):Plot(0L, 0L)
+{
+ int i;
+
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ //now set parent in children
+ if(Segments)
+ for(i = 0; i < nPts; i++) if(Segments[i]) Segments[i]->parent = this;
+ }
+}
+
+PieChart::~PieChart()
+{
+ int i;
+
+ if(Segments) {
+ for(i = 0; i < nPts; i++) if(Segments[i]) DeleteGO(Segments[i]);
+ free(Segments); Segments = 0L;
+ }
+ if(ssRefA) free(ssRefA); if(ssRefR) free(ssRefR);
+ ssRefA = ssRefR = 0L;
+ Undo.InvalidGO(this);
+}
+
+bool
+PieChart::SetSize(int select, double value)
+{
+ int i;
+
+ switch(select & 0xfff) {
+ case SIZE_XPOS:
+ case SIZE_YPOS:
+ case SIZE_RADIUS1:
+ case SIZE_RADIUS2:
+ if(Segments) for(i = 0; i < nPts; i++) {
+ if(Segments[i]) Segments[i]->SetSize(select, value);
+ }
+ return true;
+ default:
+ return false;
+ }
+ return true;
+}
+
+void
+PieChart::DoPlot(anyOutput *o)
+{
+ int i;
+
+ if(Segments) for(i = 0; i < nPts; i++) if(Segments[i]) Segments[i]->DoPlot(o);
+}
+
+bool
+PieChart::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i;
+ MouseEvent *mev;
+
+ switch (cmd) {
+ case CMD_MOUSE_EVENT:
+ if(hidden) return false;
+ mev = (MouseEvent *) tmpl;
+ switch(mev->Action) {
+ case MOUSE_LBUP:
+ //select objects invers to plot order
+ if(Segments && !CurrGO) for(i = nPts-1; i>=0; i--)
+ if(Segments[i]) if(Segments[i]->Command(cmd, tmpl, o))break;
+ break;
+ }
+ break;
+ case CMD_SETSCROLL: case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ return false;
+ case CMD_UPDATE:
+ DoUpdate();
+ return true;
+ case CMD_SET_DATAOBJ:
+ Id = GO_PIECHART;
+ data = (DataObj *)tmpl;
+ case CMD_SHIFT_OUT: case CMD_SEG_FILL: case CMD_SEG_LINE:
+ case CMD_SEG_MOVEABLE: case CMD_LEGEND:
+ if(Segments) for(i = 0; i < nPts; i++)
+ if(Segments[i]) Segments[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_DELOBJ:
+ o->HideMark();
+ if(Segments && parent) for(i = 0; i < nPts; i++) {
+ if(Segments[i] && tmpl == (void *)Segments[i]) {
+ Undo.DeleteGO((GraphObj**)(&Segments[i]), 0L, o);
+ parent->Command(CMD_REDRAW, NULL, o);
+ return true;
+ }
+ }
+ break;
+ case CMD_SAVE_SYMBOLS:
+ return SavVarObs((GraphObj **)Segments, nPts, 0L);
+ }
+ return false;
+}
+
+void
+PieChart::DoUpdate()
+{
+ AccRange *rY = 0L, *rR = 0L;
+ double sum, fv, dang1, dang2;
+ int i, ix, iy, rix, riy;
+
+ if(ssRefA && (rY = new AccRange(ssRefA))) {
+ Undo.ObjConf(this, UNDO_CONTINUE);
+ if(ssRefR) rR = new AccRange(ssRefR);
+ rY->GetFirst(&ix, &iy); rY->GetNext(&ix, &iy);
+ for(i = 0, sum = 0.0; i < nPts; i++){
+ if(data->GetValue(iy, ix, &fv)) sum += fv;
+ rY->GetNext(&ix, &iy);
+ }
+ sum /= CtDef.fy;
+ dang1 = dang2 = CtDef.fx;
+ rY->GetFirst(&ix, &iy); rY->GetNext(&ix, &iy);
+ if(rR) {
+ rR->GetFirst(&rix, &riy); rR->GetNext(&rix, &riy);
+ }
+ for(i = 0; i < nPts; i++){
+ if(data->GetValue(iy, ix, &fv)) {
+ dang2 -= (double)fv / sum;
+ if(dang2 < 0.0) dang2 += 360.0;
+ if(Segments[i]) {
+ Segments[i]->SetSize(SIZE_ANGLE1, dang1);
+ Segments[i]->SetSize(SIZE_ANGLE2, dang2);
+ if(rR && data->GetValue(riy, rix, &fv)){
+ fv *= FacRad;
+ Segments[i]->SetSize(SIZE_RADIUS2, fv);
+ }
+ }
+ dang1 = dang2;
+ }
+ rY->GetNext(&ix, &iy);
+ if(rR) rR->GetNext(&rix, &riy);
+ }
+ }
+ if(rY) delete rY; if(rR) delete rR;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// ring chart is based on piechart
+RingChart::RingChart(GraphObj *par, DataObj *d):PieChart(par, d)
+{
+ Id = GO_RINGCHART;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// a GoGroup contains objects NOT referring to data (e.g. drawing objects)
+GoGroup::GoGroup(GraphObj *par, DataObj *d):Plot(par, d)
+{
+ Objects = 0L;
+ nObs = 0;
+ fPos.fx = fPos.fy = 0.0;
+ Id = GO_GROUP;
+}
+
+GoGroup::GoGroup(int src):Plot(0L, 0L)
+{
+ int i;
+
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ //now set parent in children
+ if(Objects)
+ for(i = 0; i < nObs; i++) if(Objects[i]) Objects[i]->parent = this;
+ }
+}
+
+GoGroup::~GoGroup()
+{
+ int i;
+
+ if(Objects && nObs) {
+ for(i = 0; i < nObs; i++) if(Objects[i]) DeleteGO(Objects[i]);
+ free(Objects);
+ }
+ Undo.InvalidGO(this);
+}
+
+double
+GoGroup::GetSize(int select)
+{
+ if(parent) switch(select){
+ case SIZE_GRECT_TOP:
+ case SIZE_GRECT_BOTTOM:
+ return parent->GetSize(select)-fPos.fy;
+ case SIZE_GRECT_LEFT:
+ case SIZE_GRECT_RIGHT:
+ return parent->GetSize(select)-fPos.fx;
+ case SIZE_XPOS:
+ return fPos.fx;
+ case SIZE_YPOS:
+ return fPos.fy;
+ }
+ return 0.0f;
+}
+
+void
+GoGroup::DoPlot(anyOutput *o)
+{
+ int i;
+ double dx, dy;
+
+ dx = o->un2fix(fPos.fx + (parent ? parent->GetSize(SIZE_GRECT_LEFT) : 0.0));
+ dy = o->un2fiy(fPos.fy + (parent ? parent->GetSize(SIZE_GRECT_TOP) : 0.0));
+ o->VPorg.fx += dx; o->VPorg.fy += dy;
+ for(i = 0; i < nObs; i++) if(Objects[i]) Objects[i]->DoPlot(o);
+ o->VPorg.fx -= dx; o->VPorg.fy -= dy;
+}
+
+bool
+GoGroup::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ GraphObj **tmp_go;
+ MouseEvent *mev;
+ int i;
+
+ switch(cmd) {
+ case CMD_MOUSE_EVENT:
+ if(hidden) return false;
+ mev = (MouseEvent *) tmpl;
+ switch(mev->Action) {
+ case MOUSE_LBUP:
+ //select objects invers to plot order
+ if(Objects && !CurrGO) for(i = nObs-1; i>=0; i--)
+ if(Objects[i]) if(Objects[i]->Command(cmd, tmpl, o))break;
+ break;
+ }
+ break;
+ case CMD_SET_DATAOBJ:
+ Id = GO_GROUP;
+ if(Objects) for(i = 0; i < nObs; i++)
+ if(Objects[i]) Objects[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_DROP_OBJECT:
+ if(!Objects || nObs<1) {
+ if((Objects = (GraphObj **)calloc(1, sizeof(GraphObj*)))){
+ Objects[0] = (GraphObj *)tmpl;
+ nObs = 1;
+ return true;
+ }
+ }
+ else if((tmp_go = (GraphObj **)realloc(Objects, (nObs+1)*sizeof(GraphObj*)))) {
+ Objects = tmp_go;
+ Objects[nObs++] = (GraphObj *)tmpl;
+ return true;
+ }
+ break;
+ case CMD_SETSCROLL:
+ case CMD_REDRAW:
+ if(parent) return parent->Command(CMD_REDRAW, tmpl, o);
+ return false;
+ case CMD_DELOBJ:
+ if(Objects && parent) for(i = 0; i < nObs; i++) {
+ o->HideMark();
+ if(Objects[i] && tmpl == (void *)Objects[i]) {
+ Undo.DeleteGO((GraphObj**)(&Objects[i]), 0L, o);
+ parent->Command(CMD_REDRAW, NULL, o);
+ return true;
+ }
+ }
+ break;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// star chart
+StarChart::StarChart(GraphObj *par, DataObj *d):GoGroup(par, d)
+{
+ Id = GO_STARCHART;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// three dimensional scatterplot
+Scatt3D::Scatt3D(GraphObj *par, DataObj *d, DWORD flags):Plot(par, d)
+{
+ FileIO(INIT_VARS);
+ c_flags = flags;
+ Id = GO_SCATT3D;
+}
+
+Scatt3D::Scatt3D(GraphObj *par, DataObj *d, Brick **cols, long nob):Plot(par, d)
+{
+ int i;
+
+ FileIO(INIT_VARS);
+ c_flags = 0L; Id = GO_SCATT3D;
+ Columns = cols; nColumns = nob;
+ if(Columns) for(i = 0; i < nColumns; i++) if(Columns[i]) Columns[i]->parent=this;
+}
+
+Scatt3D::Scatt3D(GraphObj *par, DataObj *d, Sphere **ba, long nob):Plot(par, d)
+{
+ int i;
+
+ FileIO(INIT_VARS);
+ c_flags = 0L; Id = GO_SCATT3D;
+ Balls = ba; nBalls = nob;
+ if(Balls) for(i = 0; i < nBalls; i++) if(Balls[i]) Balls[i]->parent=this;
+}
+
+Scatt3D::Scatt3D(int src):Plot(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+Scatt3D::~Scatt3D()
+{
+ long i;
+
+ if(ssRefX) free(ssRefX); if(ssRefY) free(ssRefY);
+ if(ssRefZ) free(ssRefZ); ssRefX = ssRefY = ssRefZ = 0L;
+ Undo.InvalidGO(this);
+ if(Balls) {
+ for(i = 0; i < nBalls; i++) if(Balls[i]) DeleteGO(Balls[i]);
+ free(Balls); Balls = 0L;
+ }
+ if(Columns) {
+ for(i = 0; i < nColumns; i++) if(Columns[i]) DeleteGO(Columns[i]);
+ free(Columns); Columns = 0L;
+ }
+ if(DropLines) {
+ for(i = 0; i < nDropLines; i++) if(DropLines[i]) DeleteGO(DropLines[i]);
+ free(DropLines); DropLines = 0L;
+ }
+ if(Arrows) {
+ for(i = 0; i < nArrows; i++) if(Arrows[i]) DeleteGO(Arrows[i]);
+ free(Arrows); Arrows = 0L;
+ }
+ if(Line) {
+ DeleteGO(Line); Line = 0L;
+ }
+ if(rib) {
+ DeleteGO(rib); rib = 0L;
+ }
+}
+
+double
+Scatt3D::GetSize(int select)
+{
+ if(parent) return parent->GetSize(select);
+ return 0.0;
+}
+
+bool
+Scatt3D::SetSize(int select, double value)
+{
+ int i;
+
+ switch(select & 0xfff) {
+ case SIZE_SYM_LINE:
+ case SIZE_SYMBOL:
+ if(Balls) for (i=0; i < nBalls; i++)
+ if(Balls[i]) Balls[i]->SetSize(select, value);
+ return true;
+ case SIZE_BAR_BASE: case SIZE_BAR_LINE: case SIZE_BAR:
+ case SIZE_BAR_DEPTH:
+ if(Columns) for (i=0; i < nColumns; i++)
+ if(Columns[i]) Columns[i]->SetSize(select, value);
+ return true;
+ case SIZE_ARROW_LINE: case SIZE_ARROW_CAPWIDTH:
+ case SIZE_ARROW_CAPLENGTH:
+ if(Arrows) for (i=0; i < nArrows; i++)
+ if(Arrows[i]) Arrows[i]->SetSize(select, value);
+ return true;
+ }
+ return false;
+}
+
+bool
+Scatt3D::SetColor(int select, DWORD col)
+{
+ int i;
+
+ switch(select) {
+ case COL_SYM_LINE: case COL_SYM_FILL:
+ if(Balls) for (i=0; i < nBalls; i++)
+ if(Balls[i]) Balls[i]->SetColor(select, col);
+ return true;
+ case COL_BAR_LINE: case COL_BAR_FILL:
+ if(Columns) for (i=0; i < nColumns; i++)
+ if(Columns[i]) Columns[i]->SetColor(select, col);
+ return true;
+ case COL_ARROW:
+ if(Arrows) for (i=0; i < nArrows; i++)
+ if(Arrows[i]) Arrows[i]->SetColor(select, col);
+ return true;
+ }
+ return false;
+}
+
+void
+Scatt3D::DoPlot(anyOutput *o)
+{
+ long i;
+ RECT rc;
+
+ if(!o) return;
+ o->GetSize(&rc);
+ rDims.left = rc.right; rDims.right = rc.left;
+ rDims.top = rc.bottom; rDims.bottom = rc.top;
+ if(Balls) {
+ for(i = 0; i < nBalls; i++){
+ if(Balls[i]){
+ Balls[i]->DoPlot(o);
+ UpdateMinMaxRect(&rDims, Balls[i]->rDims.right, Balls[i]->rDims.top);
+ UpdateMinMaxRect(&rDims, Balls[i]->rDims.left, Balls[i]->rDims.bottom);
+ }
+ }
+ }
+ if(Columns) {
+ for(i = 0; i < nColumns; i++){
+ if(Columns[i]){
+ Columns[i]->DoPlot(o);
+ UpdateMinMaxRect(&rDims, Columns[i]->rDims.right, Columns[i]->rDims.top);
+ UpdateMinMaxRect(&rDims, Columns[i]->rDims.left, Columns[i]->rDims.bottom);
+ }
+ }
+ }
+ if(DropLines) {
+ for(i = 0; i < nDropLines; i++){
+ if(DropLines[i]){
+ DropLines[i]->DoPlot(o);
+ UpdateMinMaxRect(&rDims, DropLines[i]->rDims.right, DropLines[i]->rDims.top);
+ UpdateMinMaxRect(&rDims, DropLines[i]->rDims.left, DropLines[i]->rDims.bottom);
+ }
+ }
+ }
+ if(Arrows) {
+ for(i = 0; i < nArrows; i++){
+ if(Arrows[i]){
+ Arrows[i]->DoPlot(o);
+ UpdateMinMaxRect(&rDims, Arrows[i]->rDims.right, Arrows[i]->rDims.top);
+ UpdateMinMaxRect(&rDims, Arrows[i]->rDims.left, Arrows[i]->rDims.bottom);
+ }
+ }
+ }
+ if(Line) {
+ Line->DoPlot(o);
+ UpdateMinMaxRect(&rDims, Line->rDims.right, Line->rDims.top);
+ UpdateMinMaxRect(&rDims, Line->rDims.left, Line->rDims.bottom);
+ }
+ if(rib) {
+ rib->DoPlot(o);
+ UpdateMinMaxRect(&rDims, rib->rDims.right, rib->rDims.top);
+ UpdateMinMaxRect(&rDims, rib->rDims.left, rib->rDims.bottom);
+ }
+ dirty = false;
+}
+
+bool
+Scatt3D::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i;
+ MouseEvent *mev;
+
+ switch (cmd) {
+ case CMD_HIDE_MARK:
+ if(!o || !tmpl) return false;
+ if(rib && rib->Command(cmd, tmpl, o)) return true;
+ if(Line && (void*) Line == tmpl){
+ Line->DoMark(o, false); return true;
+ }
+ if(Columns) for(i = 0; i < nColumns; i++) {
+ if(Columns[i] && (void*)Columns[i] == tmpl) {
+ Columns[i]->DoMark(o, false); return true;
+ }
+ }
+ if(DropLines) for(i = 0; i < nDropLines; i++) {
+ if(DropLines[i] && (void*)DropLines[i] == tmpl) {
+ DropLines[i]->DoMark(o, false); return true;
+ }
+ }
+ return false;
+ case CMD_MOUSE_EVENT:
+ if(hidden) return false;
+ mev = (MouseEvent *) tmpl;
+ switch(mev->Action) {
+ case MOUSE_LBUP:
+ if(Balls && !CurrGO) for(i = 0; i < nBalls; i++)
+ if(Balls[i]) if(Balls[i]->Command(cmd, tmpl, o))return true;
+ if(Columns && !CurrGO) for(i = 0; i < nColumns; i++)
+ if(Columns[i]) if(Columns[i]->Command(cmd, tmpl, o))return true;
+ if(DropLines && !CurrGO) for(i = 0; i < nDropLines; i++)
+ if(DropLines[i]) if(DropLines[i]->Command(cmd, tmpl, o))return true;
+ if(Arrows && !CurrGO) for(i = 0; i < nArrows; i++)
+ if(Arrows[i]) if(Arrows[i]->Command(cmd, tmpl, o))return true;
+ if(Line && !CurrGO) if(Line->Command(cmd, tmpl, o)) return true;
+ if(rib && !CurrGO) if(rib->Command(cmd, tmpl, o)) return true;
+ break;
+ }
+ break;
+ case CMD_MRK_DIRTY:
+ dirty = true;
+ case CMD_SET_GO3D: case CMD_SETSCROLL: case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ case CMD_DL_LINE: case CMD_DL_TYPE:
+ if(DropLines) for(i = 0; i < nDropLines; i++)
+ if(DropLines[i]) DropLines[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_ARROW_TYPE: case CMD_ARROW_ORG3D:
+ if(Arrows) for(i = 0; i < nArrows; i++)
+ if(Arrows[i]) Arrows[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_LEGEND:
+ if(!tmpl) return false;
+ if(Balls) {
+ if(Line && Line->Id == GO_LINE3D) {
+ for (i = 0; i < nBalls && i < 100; i++)
+ if(Balls[i]) ((Legend*)tmpl)->HasSym(&Line->Line, Balls[i]);
+ }
+ else {
+ for (i = 0; i < nBalls && i < 100; i++)
+ if(Balls[i]) ((Legend*)tmpl)->HasSym(0L, Balls[i]);
+ }
+ }
+ else if(Line) Line->Command(cmd, tmpl, o);
+ if(Columns) for(i = 0; i < nColumns; i++)
+ if(Columns[i]) Columns[i]->Command(cmd, tmpl, o);
+ if(rib) rib->Command(cmd, tmpl, o);
+ return true;
+ case CMD_SET_DATAOBJ:
+ Id = GO_SCATT3D;
+ data = (DataObj *)tmpl;
+ case CMD_UPDATE:
+ if(cmd == CMD_UPDATE) Undo.ObjConf(this, UNDO_CONTINUE);
+ if(Balls) for(i = 0; i < nBalls; i++)
+ if(Balls[i]) Balls[i]->Command(cmd, tmpl, o);
+ if(Columns) for(i = 0; i < nColumns; i++)
+ if(Columns[i]) Columns[i]->Command(cmd, tmpl, o);
+ if(DropLines) for(i = 0; i < nDropLines; i++)
+ if(DropLines[i]) DropLines[i]->Command(cmd, tmpl, o);
+ if(Arrows) for(i = 0; i < nArrows; i++)
+ if(Arrows[i]) Arrows[i]->Command(cmd, tmpl, o);
+ if(Line) Line->Command(cmd, tmpl, o);
+ if(rib) rib->Command(cmd, tmpl, o);
+ return true;
+ case CMD_AUTOSCALE:
+ if(dirty) {
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
+ xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
+ if(Balls) for(i = 0; i < nBalls; i++)
+ if(Balls[i]) Balls[i]->Command(cmd, tmpl, o);
+ if(Columns) for(i = 0; i < nColumns; i++)
+ if(Columns[i]) Columns[i]->Command(cmd, tmpl, o);
+ if(DropLines) for(i = 0; i < nDropLines; i++)
+ if(DropLines[i]) DropLines[i]->Command(cmd, tmpl, o);
+ if(Arrows) for(i = 0; i < nArrows; i++)
+ if(Arrows[i]) Arrows[i]->Command(cmd, tmpl, o);
+ if(Line) Line->Command(cmd, tmpl, o);
+ if(rib) rib->Command(cmd, tmpl, o);
+ }
+ if(parent && parent->Id > GO_PLOT && parent->Id < GO_GRAPH &&
+ xBounds.fx <= xBounds.fy && yBounds.fx <= yBounds.fy && zBounds.fx <= zBounds.fy){
+ ((Plot*)parent)->CheckBounds3D(xBounds.fx, yBounds.fx, zBounds.fx);
+ ((Plot*)parent)->CheckBounds3D(xBounds.fy, yBounds.fy, zBounds.fy);
+ }
+ dirty = false;
+ return true;
+ case CMD_DELOBJ:
+ if(o) o->HideMark();
+ if(!tmpl || !parent) return false;
+ if(rib && rib->Command(cmd, tmpl, o)) return true;
+ if(Balls) for(i = 0; i < nBalls; i++) if(Balls[i] == tmpl) {
+ Undo.DeleteGO((GraphObj**)(&Balls[i]), 0L, o);
+ return parent->Command(CMD_REDRAW, 0L, o);
+ }
+ if(Columns) for(i = 0; i < nColumns; i++) if(Columns[i] == tmpl) {
+ Undo.DeleteGO((GraphObj**)(&Columns[i]), 0L, o);
+ return parent->Command(CMD_REDRAW, 0L, o);
+ }
+ if(DropLines) for(i = 0; i < nDropLines; i++) if(DropLines[i] == tmpl) {
+ Undo.DeleteGO((GraphObj**)(&DropLines[i]), 0L, o);
+ return parent->Command(CMD_REDRAW, 0L, o);
+ }
+ if(Arrows) for(i = 0; i < nArrows; i++) if(Arrows[i] == tmpl) {
+ Undo.DeleteGO((GraphObj**)(&Arrows[i]), 0L, o);
+ return parent->Command(CMD_REDRAW, 0L, o);
+ }
+ if(Line && Line == tmpl) {
+ Undo.DeleteGO((GraphObj**)(&Line), 0L, o);
+ return parent->Command(CMD_REDRAW, 0L, o);
+ }
+ if(rib && rib == tmpl) {
+ Undo.DeleteGO((GraphObj**)(&rib), 0L, o);
+ return parent->Command(CMD_REDRAW, 0L, o);
+ }
+ case CMD_SYM_FILL:
+ if(Balls) for(i= 0; i < nBalls; i++) if(Balls[i])Balls[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_BAR_FILL:
+ if(Columns) for(i= 0; i < nColumns; i++) if(Columns[i])Columns[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_SAVE_SYMBOLS:
+ return SavVarObs((GraphObj **)Balls, nBalls, 0L);
+ case CMD_SAVE_BARS:
+ return SavVarObs((GraphObj **)Columns, nColumns, 0L);
+ case CMD_SAVE_ARROWS:
+ return SavVarObs((GraphObj **)Arrows, nArrows, 0L);
+ case CMD_SAVE_DROPLINES:
+ return SavVarObs((GraphObj **)DropLines, nDropLines, 0L);
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// three dimensional ribbon based on list of Plane3D objects
+Ribbon::Ribbon(GraphObj *par, DataObj *d, double z, double width, char *xr, char *yr)
+ :Plot(par, d)
+{
+ FileIO(INIT_VARS); Id = GO_RIBBON; type = 1;
+ if(xr) ssRefX = strdup(xr); if(yr) ssRefY = strdup(yr);
+ z_value = z; z_width = width;
+}
+
+Ribbon::Ribbon(GraphObj *par, DataObj *d, char *xr, char *yr, char *zr)
+ :Plot(par, d)
+{
+ FileIO(INIT_VARS); Id = GO_RIBBON; type = 2;
+ if(xr) ssRefX = strdup(xr); if(yr) ssRefY = strdup(yr);
+ if(zr) ssRefZ = strdup(zr);
+}
+
+Ribbon::Ribbon(int src):Plot(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+Ribbon::~Ribbon()
+{
+ int i;
+
+ if(ssRefX) free(ssRefX); if(ssRefY) free(ssRefY);
+ if(ssRefZ) free(ssRefZ); ssRefX = ssRefY = ssRefZ = 0L;
+ Undo.InvalidGO(this);
+ if(planes) {
+ for(i = 0; i < nPlanes; i++) if(planes[i]) DeleteGO(planes[i]);
+ free(planes); planes = 0L;
+ }
+ if(values) free(values); values = 0L; nVal = 0;
+}
+
+double
+Ribbon::GetSize(int select)
+{
+ switch(select) {
+ case SIZE_CELLWIDTH: return relwidth;
+ case SIZE_ZPOS: return z_value;
+ }
+ return 0.0;
+}
+
+bool
+Ribbon::SetSize(int select, double value)
+{
+ int i;
+
+ switch(select) {
+ case SIZE_SYM_LINE:
+ if(planes) for (i=0; i < nPlanes; i++)
+ if(planes[i]) planes[i]->SetSize(select, value);
+ return true;
+ case SIZE_CELLWIDTH:
+ if(value != relwidth) {
+ //assume planes saved already by CMD_SAVE_SYMBOLS
+ Undo.ValFloat(this, &relwidth, UNDO_CONTINUE);
+ relwidth = value;
+ if(planes) UpdateObs(false);
+ }
+ return true;
+ case SIZE_ZPOS:
+ if(value != z_value) {
+ //assume planes saved already by CMD_SAVE_SYMBOLS
+ Undo.ValFloat(this, &z_value, UNDO_CONTINUE);
+ z_value = value;
+ if(planes) UpdateObs(false);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool
+Ribbon::SetColor(int select, DWORD col)
+{
+ int i;
+
+ switch(select) {
+ case COL_POLYLINE:
+ Line.color = col;
+ case COL_POLYGON:
+ if(select == COL_POLYGON) Fill.color = col;
+ if(planes) for (i=0; i < nPlanes; i++)
+ if(planes[i]) planes[i]->SetColor(select, col);
+ return true;
+ }
+ return false;
+}
+
+void
+Ribbon::DoPlot(anyOutput *o)
+{
+ int i;
+
+ if(!planes) CreateObs();
+ if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->DoPlot(o);
+ dirty = false;
+}
+
+bool
+Ribbon::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i;
+ MouseEvent *mev;
+
+ switch (cmd) {
+ case CMD_MOUSE_EVENT:
+ if(hidden) return false;
+ mev = (MouseEvent *) tmpl;
+ switch(mev->Action) {
+ case MOUSE_LBUP:
+ if(planes && !CurrGO) for(i = 0; i < nPlanes; i++)
+ if(planes[i]) if(planes[i]->Command(cmd, tmpl, o)) return true;
+ break;
+ }
+ break;
+ case CMD_MRK_DIRTY:
+ dirty = true;
+ case CMD_SET_GO3D: case CMD_SETSCROLL: case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ case CMD_SET_DATAOBJ:
+ Id = GO_RIBBON;
+ data = (DataObj *)tmpl;
+ if(planes) for(i = 0; i < nPlanes; i++)
+ if(planes[i]) planes[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_UPDATE:
+ SavVarObs((GraphObj **)planes, nPlanes, UNDO_CONTINUE);
+ Undo.DataMem(this, (void**)&values, nVal * sizeof(fPOINT3D), &nVal, UNDO_CONTINUE);
+ UpdateObs(dirty = true);
+ if(parent) parent->Command(CMD_MRK_DIRTY, tmpl, o);
+ return true;
+ case CMD_AUTOSCALE:
+ if(!planes) CreateObs();
+ if(dirty) {
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
+ xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
+ if(planes) for(i = 0; i < nPlanes; i++)
+ if(planes[i]) planes[i]->Command(cmd, tmpl, o);
+ }
+ if(parent && parent->Id > GO_PLOT && parent->Id < GO_GRAPH &&
+ xBounds.fx <= xBounds.fy && yBounds.fx <= yBounds.fy && zBounds.fx <= zBounds.fy){
+ ((Plot*)parent)->CheckBounds3D(xBounds.fx, yBounds.fx, zBounds.fx);
+ ((Plot*)parent)->CheckBounds3D(xBounds.fy, yBounds.fy, zBounds.fy);
+ }
+ return true;
+ case CMD_DELOBJ:
+ if(!tmpl || !parent) return false;
+ if(planes) for(i = 0; i < nPlanes; i++) if(planes[i] == tmpl) {
+ Undo.DeleteGO((GraphObj**)(&planes[i]), 0L, o);
+ return parent->Command(CMD_REDRAW, 0L, o);
+ }
+ return false;
+ case CMD_SYM_FILL: case CMD_LEGEND:
+ if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_SAVE_SYMBOLS:
+ return SavVarObs((GraphObj **)planes, nPlanes, 0L);
+ }
+ return false;
+}
+
+void
+Ribbon::CreateObs()
+{
+ int i, rx, cx, ry, cy, rz, cz;
+ double fx, fy, fz, tmp;
+ fPOINT3D pg[5];
+ AccRange *rX, *rY, *rZ;
+
+ if(planes || !data) return;
+ rX = rY = rZ = 0L;
+ switch(type) {
+ case 1:
+ if(!ssRefX || !ssRefY) return;
+ if(z_width == 0.0) z_width = 1.0; if(relwidth == 0.0) relwidth = 0.6;
+ if((rX = new AccRange(ssRefX)) && (rY = new AccRange(ssRefY))) {
+ tmp = relwidth*z_width/2.0;
+ if(!(values = (fPOINT3D*)calloc(i = rX->CountItems(), sizeof(fPOINT3D)))){
+ delete rX; delete rY; return;
+ }
+ if(!(planes = (Plane3D**)calloc(i-1, sizeof(Plane3D*)))){
+ free(values); values = 0L; delete rX; delete rY; return;
+ }
+ for(i = 0, rX->GetFirst(&cx, &rx), rY->GetFirst(&cy, &ry);
+ rX->GetNext(&cx, &rx) && rY->GetNext(&cy, &ry); i++) {
+ if(data->GetValue(rx, cx, &fx) && data->GetValue(ry, cy, &fy)) {
+ values[i].fx = fx; values[i].fy = fy; values[i].fz = z_value;
+ pg[3].fx = pg[2].fx = fx; pg[3].fy = pg[2].fy = fy;
+ pg[2].fz = z_value - tmp; pg[3].fz = z_value +tmp;
+ if(i) {
+ pg[4].fx = pg[0].fx; pg[4].fy = pg[0].fy; pg[4].fz = pg[0].fz;
+ planes[i-1] = new Plane3D(this, data, pg, 5);
+ if(planes[i-1]) planes[i-1]->Command(CMD_PG_FILL, &Fill, 0L);
+ }
+ pg[0].fx = pg[3].fx; pg[0].fy = pg[3].fy; pg[0].fz = pg[3].fz;
+ pg[1].fx = pg[2].fx; pg[1].fy = pg[2].fy; pg[1].fz = pg[2].fz;
+ }
+ }
+ nPlanes = i-1; nVal = i;
+ }
+ break;
+ case 2:
+ if(!ssRefX || !ssRefY || !ssRefZ) return;
+ if((rX = new AccRange(ssRefX)) && (rY = new AccRange(ssRefY)) && (rZ = new AccRange(ssRefZ))) {
+ if(!(values = (fPOINT3D*)calloc(i = rX->CountItems(), sizeof(fPOINT3D)))){
+ delete rX; delete rY; delete rZ; return;
+ }
+ if(!(planes = (Plane3D**)calloc(i-1, sizeof(Plane3D*)))){
+ free(values); values = 0L; delete rX; delete rY; delete rZ; return;
+ }
+ for(i = 0, rX->GetFirst(&cx, &rx), rY->GetFirst(&cy, &ry), rZ->GetFirst(&cz, &rz);
+ rX->GetNext(&cx, &rx) && rY->GetNext(&cy, &ry) && rZ->GetNext(&cz, &rz); i++) {
+ if(data->GetValue(rx, cx, &fx) && data->GetValue(ry, cy, &fy) &&
+ data->GetValue(rz, cz, &fz)) {
+ values[i].fx = fx; values[i].fy = fy; values[i].fz = fz;
+ pg[3].fx = pg[2].fx = fx; pg[2].fz = pg[3].fz = fz;
+ pg[3].fy = 0.0; pg[2].fy = fy;
+ if(i) {
+ pg[4].fx = pg[0].fx; pg[4].fy = pg[0].fy; pg[4].fz = pg[0].fz;
+ planes[i-1] = new Plane3D(this, data, pg, 5);
+ if(planes[i-1]) planes[i-1]->Command(CMD_PG_FILL, &Fill, 0L);
+ }
+ pg[0].fx = pg[3].fx; pg[0].fy = pg[3].fy; pg[0].fz = pg[3].fz;
+ pg[1].fx = pg[2].fx; pg[1].fy = pg[2].fy; pg[1].fz = pg[2].fz;
+ }
+ }
+ nPlanes = i-1; nVal = i;
+ }
+ break;
+ }
+ if(rX) delete rX; if(rY) delete rY; if(rZ) delete rZ;
+}
+
+void
+Ribbon::UpdateObs(bool bNewData)
+{
+ int i, j, k, rx, cx, ry, cy, rz, cz;
+ double fx, fy, fz, tmp, da1, da2;
+ AccRange *rX, *rY, *rZ;
+ int sel_id[] = {SIZE_XPOS, SIZE_YPOS, SIZE_ZPOS};
+
+ if(!planes || !values) return;
+ rX = rY = rZ = 0L;
+ switch(type) {
+ case 1:
+ if(!ssRefX || !ssRefY || !data) return;
+ if(z_width == 0.0) z_width = 1.0; if(relwidth == 0.0) relwidth = 0.6;
+ if((rX = new AccRange(ssRefX)) && (rY = new AccRange(ssRefY))) {
+ tmp = relwidth*z_width/2.0;
+ for(i = 0, rX->GetFirst(&cx, &rx), rY->GetFirst(&cy, &ry);
+ rX->GetNext(&cx, &rx) && rY->GetNext(&cy, &ry) && i < nVal; i++) {
+ if(data->GetValue(rx, cx, &fx) && data->GetValue(ry, cy, &fy)) {
+ if(bNewData) {
+ values[i].fx = fx; values[i].fy = fy; values[i].fz = z_value;
+ }
+ else {
+ fx = values[i].fx; fy = values[i].fy; values[i].fz = z_value;
+ }
+ if(i && planes[i-1]) {
+ for(j = 0; j < 3; j++){
+ for(k = 0; k <5; k++) {
+ switch (j) {
+ case 0:
+ da1 = values[i-1].fx; da2 = values[i].fx;
+ break;
+ case 1:
+ da1 = values[i-1].fy; da2 = values[i].fy;
+ break;
+ case 2:
+ if(k != 1 && k != 2) da1 = da2 = (values[i].fz + tmp);
+ else da1 = da2 = (values[i].fz - tmp);
+ break;
+ }
+ planes[i-1]->SetSize(sel_id[j]+k, (k != 2 && k != 3) ? da1 : da2);
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+ case 2:
+ if(!ssRefX || !ssRefY || !ssRefZ || !data) return;
+ if((rX = new AccRange(ssRefX)) && (rY = new AccRange(ssRefY)) && (rZ = new AccRange(ssRefZ))) {
+ for(i = 0, rX->GetFirst(&cx, &rx), rY->GetFirst(&cy, &ry), rZ->GetFirst(&cz, &rz);
+ rX->GetNext(&cx, &rx) && rY->GetNext(&cy, &ry) && rZ->GetNext(&cz, &rz) && i < nVal; i++) {
+ if(data->GetValue(rx, cx, &fx) && data->GetValue(ry, cy, &fy) && data->GetValue(rz, cz, &fz)) {
+ values[i].fx = fx; values[i].fy = fy; values[i].fz = fz;
+ if(i && planes[i-1]) {
+ planes[i-1]->SetSize(SIZE_XPOS, values[i-1].fx); planes[i-1]->SetSize(SIZE_XPOS+3, fx);
+ planes[i-1]->SetSize(SIZE_XPOS+1, values[i-1].fx); planes[i-1]->SetSize(SIZE_XPOS+2, fx);
+ planes[i-1]->SetSize(SIZE_XPOS+4, values[i-1].fx);
+ planes[i-1]->SetSize(SIZE_YPOS+1, values[i-1].fy); planes[i-1]->SetSize(SIZE_YPOS+2, fy);
+ planes[i-1]->SetSize(SIZE_ZPOS, values[i-1].fz); planes[i-1]->SetSize(SIZE_ZPOS+3, fz);
+ planes[i-1]->SetSize(SIZE_ZPOS+1, values[i-1].fz); planes[i-1]->SetSize(SIZE_ZPOS+2, fz);
+ planes[i-1]->SetSize(SIZE_ZPOS+4, values[i-1].fz);
+ }
+ }
+ }
+ }
+ break;
+ }
+ if(rX) delete rX; if(rY) delete rY; if(rZ) delete rZ;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// draw a 3dimensional grid
+Grid3D::Grid3D(GraphObj *par, DataObj *d)
+ :Plot(par, d)
+{
+ FileIO(INIT_VARS); Id = GO_GRID3D;
+}
+
+Grid3D::Grid3D(int src):Plot(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+Grid3D::~Grid3D()
+{
+ int i;
+
+ Undo.InvalidGO(this);
+ if(lines) {
+ for(i = 0; i < nLines; i++) if(lines[i]) DeleteGO(lines[i]);
+ free(lines); lines = 0L;
+ }
+ nLines = 0;
+}
+
+void
+Grid3D::DoPlot(anyOutput *o)
+{
+ int i;
+
+ if(!lines) CreateObs();
+ if(lines) for(i = 0; i < nLines; i++) if(lines[i]) lines[i]->DoPlot(o);
+ dirty = false;
+}
+
+bool
+Grid3D::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i;
+ MouseEvent *mev;
+
+ switch (cmd) {
+ case CMD_MOUSE_EVENT:
+ if(hidden) return false;
+ mev = (MouseEvent *) tmpl;
+ switch(mev->Action) {
+ case MOUSE_LBUP:
+ if(lines && !CurrGO) for(i = 0; i < nLines; i++)
+ if(lines[i]) if(lines[i]->Command(cmd, tmpl, o)) return true;
+ break;
+ }
+ break;
+ case CMD_SET_LINE:
+ if(tmpl && lines) {
+ SavVarObs((GraphObj**)lines, nLines, 0L);
+ memcpy(&Line, tmpl, sizeof(LineDEF));
+ if(lines) for(i = 0; i < nLines; i++)
+ if(lines[i]) lines[i]->Command(cmd, tmpl, o);
+ }
+ break;
+ case CMD_MRK_DIRTY:
+ dirty = true;
+ case CMD_SET_GO3D: case CMD_SETSCROLL: case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ case CMD_SET_DATAOBJ:
+ Id = GO_GRID3D;
+ data = (DataObj *)tmpl;
+ if(lines) for(i = 0; i < nLines; i++)
+ if(lines[i]) lines[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_UPDATE:
+ InfoBox("Don't know how to update Grid");
+ return true;
+ case CMD_AUTOSCALE:
+ if(!lines) CreateObs();
+ if(dirty) {
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
+ xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
+ if(lines) for(i = 0; i < nLines; i++)
+ if(lines[i]) lines[i]->Command(cmd, tmpl, o);
+ }
+ if(parent && parent->Id > GO_PLOT && parent->Id < GO_GRAPH &&
+ xBounds.fx <= xBounds.fy && yBounds.fx <= yBounds.fy && zBounds.fx <= zBounds.fy){
+ ((Plot*)parent)->CheckBounds3D(xBounds.fx, yBounds.fx, zBounds.fx);
+ ((Plot*)parent)->CheckBounds3D(xBounds.fy, yBounds.fy, zBounds.fy);
+ }
+ return true;
+ case CMD_DELOBJ:
+ if(!tmpl || !parent) return false;
+ if(lines) for(i = 0; i < nLines; i++) if(lines[i] == tmpl) {
+ Undo.DeleteGO((GraphObj**)(&lines[i]), 0L, o);
+ return parent->Command(CMD_REDRAW, 0L, o);
+ }
+ }
+ return false;
+}
+
+void
+Grid3D::CreateObs()
+{
+ int i, ir, ic, idx, w, h;
+ fPOINT3D *vec;
+
+ if(!parent || !data || lines) return;
+ if(!(vec = (fPOINT3D*)malloc(sizeof(fPOINT3D) * 2))) return;
+ data->GetSize(&w, &h);
+ if(0 >= (nLines = 2 * w * h - w - h)) return;
+ if(!(lines =(Line3D**)calloc(nLines, sizeof(Line3D*)))) return;
+ vec[0].fx = start.fx; data->GetValue(0, 0, &vec[0].fy);
+ for(ic = 1, idx = 0; ic <= w; ic++) {
+ vec[0].fz = start.fz;
+ data->GetValue(0, ic-1, &vec[0].fy);
+ for(ir = 1; ir <= h; ir++){
+ if(ic < w && data->GetValue(ir-1, ic, &vec[1].fy)) {
+ vec[1].fx = vec[0].fx + step.fx; vec[1].fz = vec[0].fz;
+ lines[idx++] = new Line3D(this, 0L, vec, 2);
+ }
+ if(ir < h && data->GetValue(ir, ic-1, &vec[1].fy)) {
+ vec[1].fx = vec[0].fx; vec[1].fz = vec[0].fz + step.fz;
+ lines[idx++] = new Line3D(this, 0L, vec, 2);
+ }
+ vec[0].fz += step.fz; vec[0].fy = vec[1].fy;
+ }
+ vec[0].fx += step.fx;
+ }
+ for(i = 0; i < nLines; i++) if(lines[i]) lines[i]->Command(CMD_SET_LINE, &Line, 0L);
+ free(vec);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// define minima and maxima rectangle to be used by graph
+Limits::Limits(int src):Plot(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+Limits::~Limits()
+{
+}
+
+double
+Limits::GetSize(int select)
+{
+ return 0.0;
+}
+
+bool
+Limits::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ switch (cmd) {
+ case CMD_SET_DATAOBJ:
+ Id = GO_LIMITS;
+ data = (DataObj *)tmpl;
+ return true;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Calculate and display a user defined function
+Function::Function(GraphObj *par, DataObj *d):Plot(par, d)
+{
+ FileIO(INIT_VARS);
+ if(parent && parent->Id == GO_POLARPLOT) {
+ x1 = 0.0; x2 = 360.0; xstep = 0.5;
+ cmdxy = strdup("sin(pi*x/30)+1.1");
+ }
+ else {
+ x1 = 0.0; x2 = 100.0; xstep = 0.5;
+ cmdxy = strdup("sin(x)/x");
+ }
+ Id = GO_FUNCTION;
+}
+
+Function::Function(int src):Plot(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+Function::~Function()
+{
+ if(cmdxy) free(cmdxy); cmdxy = 0L;
+ if(param) free(param); param = 0L;
+ if(dl) DeleteGO(dl); dl = 0L;
+}
+
+bool
+Function::SetSize(int select, double value)
+{
+ switch(select & 0xfff){
+ case SIZE_MIN_X: x1 = value; return true;
+ case SIZE_MAX_X: x2 = value; return true;
+ case SIZE_XSTEP: xstep=value; return true;
+ }
+ return false;
+}
+
+void
+Function::DoPlot(anyOutput *o)
+{
+ if(!dl && cmdxy && cmdxy[0]) Update(o, 0);
+ dirty = false;
+ if(dl && o) {
+ dl->Command(CMD_SET_LINE, &Line, o);
+ dl->DoPlot(o);
+ }
+}
+
+bool
+Function::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ switch (cmd) {
+ case CMD_LEGEND: case CMD_MOUSE_EVENT:
+ if(hidden) return false;
+ if(dl) return dl->Command(cmd, tmpl, o);
+ break;
+ case CMD_HIDE_MARK:
+ if(dl && tmpl == dl) {
+ dl->DoMark(o, false);
+ return true;
+ }
+ return false;
+ case CMD_DELOBJ:
+ if(parent && tmpl && tmpl == dl) return parent->Command(CMD_DELOBJ, this, o);
+ break;
+ case CMD_MRK_DIRTY:
+ if(parent) parent->Command(cmd, tmpl, o);
+ return dirty = true;
+ case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ case CMD_SET_LINE:
+ if(tmpl) memcpy(&Line, tmpl, sizeof(LineDEF));
+ break;
+ case CMD_SET_DATAOBJ:
+ if(dl) dl->Command(cmd, tmpl, o);
+ Id = GO_FUNCTION;
+ data = (DataObj *)tmpl;
+ return true;
+ case CMD_SETPARAM:
+ if(tmpl) {
+ if(param) free(param);
+ param = strdup((char*)tmpl);
+ }
+ dirty = true;
+ return true;
+ case CMD_SETFUNC:
+ if(tmpl) {
+ if(cmdxy) free(cmdxy);
+ cmdxy = strdup((char*)tmpl);
+ }
+ dirty = true;
+ return true;
+ case CMD_UPDATE:
+ return Update(o, UNDO_CONTINUE);
+ case CMD_AUTOSCALE:
+ if(!dl) return Update(o, 0L);
+ if(dirty) {
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL;
+ Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
+ xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
+ if(dl) dl->Command(cmd, tmpl, o);
+ dirty = false;
+ }
+ if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH
+ && Bounds.Xmax > Bounds.Xmin && Bounds.Ymax > Bounds.Ymin) {
+ ((Plot*)parent)->CheckBounds(Bounds.Xmin, Bounds.Ymin);
+ ((Plot*)parent)->CheckBounds(Bounds.Xmax, Bounds.Ymax);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool
+Function::Update(anyOutput *o, DWORD flags)
+{
+ lfPOINT *xydata;
+ long ndata;
+
+ if(!parent || !cmdxy) return false;
+ if(parent->Id != GO_FITFUNC && dl) Undo.DeleteGO((GraphObj**)&dl, flags, o);
+ do_xyfunc(data, x1, x2, xstep, cmdxy, &xydata, &ndata, param);
+ if(xydata && ndata >1) {
+ if(!dl) dl = new DataLine(this, data, xydata, ndata);
+ else dl->LineData(xydata, ndata);
+ dirty = true;
+ Command(CMD_AUTOSCALE, 0L, 0L);
+ return true;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Calculate and display a user defined function
+FitFunc::FitFunc(GraphObj *par, DataObj *d):Plot(par, d)
+{
+ int width, height;
+
+ FileIO(INIT_VARS);
+ x1 = 0.0; x2 = 100.0; xstep = 0.5; dl = 0L;
+ cmdxy = strdup("a+b*x^c");
+ parxy = strdup("a=1; b=1; c=0.1;");
+ data->GetSize(&width, &height);
+ if(!ssXref) {
+ sprintf(TmpTxt, "a1:a%d", height);
+ ssXref = strdup(TmpTxt);
+ }
+ if(!ssYref) {
+ sprintf(TmpTxt, "b1:b%d", height);
+ ssYref = strdup(TmpTxt);
+ }
+ Id = GO_FITFUNC;
+}
+
+
+FitFunc::FitFunc(int src):Plot(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+
+FitFunc::~FitFunc()
+{
+ int i;
+
+ if(Symbols) {
+ for(i = 0; i< nPoints; i++) if(Symbols[i]) DeleteGO(Symbols[i]);
+ free(Symbols);
+ }
+ if(cmdxy) free(cmdxy); cmdxy = 0L;
+ if(parxy) free(parxy); parxy = 0L;
+ if(ssXref) free(ssXref); ssXref = 0L;
+ if(ssYref) free(ssYref); ssYref = 0L;
+ if(dl) DeleteGO(dl); dl = 0L;
+ Undo.InvalidGO(this);
+}
+
+bool
+FitFunc::SetSize(int select, double value)
+{
+ int i;
+
+ switch(select & 0xfff){
+ case SIZE_SYMBOL:
+ case SIZE_SYM_LINE:
+ if(Symbols) for(i = 0; i < nPoints; i++)
+ if(Symbols[i]) Symbols[i]->SetSize(select, value);
+ return true;
+ }
+ return false;
+}
+
+bool
+FitFunc::SetColor(int select, DWORD col)
+{
+ int i;
+
+ switch(select) {
+ case COL_SYM_LINE:
+ case COL_SYM_FILL:
+ if(Symbols) for(i = 0; i < nPoints; i++)
+ if(Symbols[i]) Symbols[i]->SetColor(select, col);
+ return true;
+ }
+ return false;
+}
+
+void
+FitFunc::DoPlot(anyOutput *o)
+{
+ int i;
+
+ if(!data || x1 >= x2) return;
+ dirty = false;
+ if(xstep <= 0.0) xstep = (x2-x1)/100.0;
+ if(!dl) dl = new Function(this, data);
+ if(dl && o){
+ dl->SetSize(SIZE_MIN_X, x1); dl->SetSize(SIZE_MAX_X, x2);
+ dl->SetSize(SIZE_XSTEP, xstep); dl->Command(CMD_SETFUNC, cmdxy, 0L);
+ dl->Command(CMD_SETPARAM, parxy, 0L); dl->Command(CMD_SET_LINE, &Line, 0L);
+ dl->Update(o, 0L); dl->DoPlot(o);
+ }
+ if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->DoPlot(o);
+}
+
+bool
+FitFunc::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i;
+ MouseEvent *mev;
+ LineDEF *ld;
+
+ switch(cmd) {
+ case CMD_LEGEND:
+ if(tmpl && ((GraphObj*)tmpl)->Id == GO_LEGEND && dl && dl->Id == GO_FUNCTION) {
+ ld = dl->GetLine();
+ if(Symbols) {
+ for (i = 0; i < nPoints && i < 100; i++)
+ if(Symbols[i]) ((Legend*)tmpl)->HasSym(ld, Symbols[i]);
+ }
+ else ((Legend*)tmpl)->HasFill(ld, 0L);
+ return true;
+ }
+ return false;
+ case CMD_HIDE_MARK:
+ if(dl) return dl->Command(cmd, tmpl, o);
+ return false;
+ case CMD_MOUSE_EVENT:
+ if(hidden) return false;
+ mev = (MouseEvent *) tmpl;
+ switch(mev->Action) {
+ case MOUSE_LBUP:
+ //select objects invers to plot order
+ if(Symbols && !CurrGO) for(i = nPoints-1; i >=0; i--)
+ if(Symbols[i] && Symbols[i]->Command(cmd, tmpl, o))return true;
+ break;
+ }
+ if(dl) return dl->Command(cmd, tmpl, o);
+ return false;
+ case CMD_AUTOSCALE:
+ if(dirty) {
+ if(!dl) if(!(dl = new Function(this, data))) return false;
+ dl->SetSize(SIZE_MIN_X, x1); dl->SetSize(SIZE_MAX_X, x2);
+ dl->SetSize(SIZE_XSTEP, xstep); dl->Command(CMD_SETFUNC, cmdxy, 0L);
+ dl->Command(CMD_SETPARAM, parxy, 0L); dl->Update(o, 0L);
+ memcpy(&Bounds, &dl->Bounds, sizeof(fRECT));
+ if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i])Symbols[i]->Command(cmd, tmpl, o);
+ dirty = false;
+ }
+ return true;
+ case CMD_UPDATE:
+ Undo.ObjConf(this, UNDO_CONTINUE);
+ if(Symbols) for(i = 0; i < nPoints; i++)
+ if(Symbols[i]) Symbols[i]->Command(cmd, tmpl, o);
+ do_fitfunc(data, ssXref, ssYref, 0L, &parxy, cmdxy, conv, maxiter, &chi2);
+ dirty = true;
+ if(parent) parent->Command(CMD_MRK_DIRTY, 0L, o);
+ return true;
+ case CMD_DELOBJ:
+ if(parent && tmpl && tmpl == dl) return parent->Command(CMD_DELOBJ, this, o);
+ else if(dl) return dl->Command(cmd, tmpl, o);
+ break;
+ case CMD_MRK_DIRTY:
+ dirty = true;
+ case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ case CMD_SET_DATAOBJ:
+ if(dl) dl->Command(cmd, tmpl, o);
+ if(Symbols) for(i = 0; i < nPoints; i++)
+ if(Symbols[i]) Symbols[i]->Command(cmd, tmpl, o);
+ Id = GO_FITFUNC;
+ data = (DataObj *)tmpl;
+ return true;
+ case CMD_SYMTEXT: case CMD_SYMTEXT_UNDO: case CMD_SYM_RANGETEXT:
+ case CMD_SYMTEXTDEF: case CMD_SYM_TYPE:
+ if(Symbols) for(i = 0; i < nPoints; i++)
+ if(Symbols[i]) Symbols[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_SAVE_SYMBOLS:
+ return SavVarObs((GraphObj **)Symbols, nPoints, 0L);
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// three dimensional graph
+Plot3D::Plot3D(GraphObj *par, DataObj *d, DWORD flags):Plot(par, d)
+{
+ RotDef = (double*)malloc(6 *sizeof(double));
+ FileIO(INIT_VARS);
+ Id = GO_PLOT3D;
+ crea_flags = flags;
+ xBounds.fx = yBounds.fx = zBounds.fx = Bounds.Xmin = Bounds.Ymin = HUGE_VAL;
+ xBounds.fy = yBounds.fy = zBounds.fy = Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+}
+
+Plot3D::Plot3D(int src):Plot(0L, 0L)
+{
+ int i;
+
+ RotDef = (double*)malloc(6 *sizeof(double));
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ //now set parent in all children
+ if(Axes) for(i = 0; i < nAxes; i++)
+ if(Axes[i]) Axes[i]->parent = this;
+ if(plots) for(i = 0; i < nPlots; i++)
+ if(plots[i]) plots[i]->parent = this;
+ }
+}
+
+Plot3D::~Plot3D()
+{
+ int i;
+
+ if(plots) {
+ for(i = 0; i < nPlots; i++) if(plots[i]) DeleteGO(plots[i]);
+ free(plots);
+ }
+ if(Axes) {
+ for(i = 0; i < nAxes; i++) if(Axes[i]) DeleteGO(Axes[i]);
+ free(Axes);
+ }
+ plots = 0L; nPlots = nAxes = 0;
+ if(drag) DeleteGO(drag); drag = 0L;
+ if(dispObs) free(dispObs); dispObs = 0L;
+ free(RotDef);
+ Undo.InvalidGO(this);
+}
+
+double
+Plot3D::GetSize(int select)
+{
+ AxisDEF *ax;
+
+ switch(select){
+ //The Bounds values must be returned by every plot:
+ // they are necessary for scaling !
+ case SIZE_BOUNDS_XMIN:
+ if(Axes && nAxes >2 && Axes[0] && (ax = Axes[0]->GetAxis()))
+ return (ax->flags & AXIS_INVERT) ? ax->max : ax->min;
+ return 0.0;
+ case SIZE_BOUNDS_XMAX:
+ if(Axes && nAxes >2 && Axes[0] && (ax = Axes[0]->GetAxis()))
+ return (ax->flags & AXIS_INVERT) ? ax->min : ax->max;
+ return 0.0;
+ case SIZE_BOUNDS_YMIN:
+ if(Axes && nAxes >2 && Axes[1] && (ax = Axes[1]->GetAxis()))
+ return (ax->flags & AXIS_INVERT) ? ax->max : ax->min;
+ return 0.0;
+ case SIZE_BOUNDS_YMAX:
+ if(Axes && nAxes >2 && Axes[1] && (ax = Axes[1]->GetAxis()))
+ return (ax->flags & AXIS_INVERT) ? ax->min : ax->max;
+ return 0.0;
+ case SIZE_BOUNDS_ZMIN:
+ if(Axes && nAxes >2 && Axes[2] && (ax = Axes[2]->GetAxis()))
+ return (ax->flags & AXIS_INVERT) ? ax->max : ax->min;
+ return 0.0;
+ case SIZE_BOUNDS_ZMAX:
+ if(Axes && nAxes >2 && Axes[2] && (ax = Axes[2]->GetAxis()))
+ return (ax->flags & AXIS_INVERT) ? ax->min : ax->max;
+ return 0.0;
+ case SIZE_XPOS: case SIZE_XPOS+4: return cu1.fx;
+ case SIZE_XPOS+1: case SIZE_XPOS+5: return cu2.fx;
+ case SIZE_XPOS+2: case SIZE_XPOS+6: return cu2.fx;
+ case SIZE_XPOS+3: case SIZE_XPOS+7: return cu1.fx;
+ case SIZE_YPOS: case SIZE_YPOS+1: case SIZE_YPOS+2:
+ case SIZE_YPOS+3: return cu1.fy;
+ case SIZE_YPOS+4: case SIZE_YPOS+5: case SIZE_YPOS+6:
+ case SIZE_YPOS+7: return cu2.fy;
+ case SIZE_ZPOS: case SIZE_ZPOS+1: case SIZE_ZPOS+4:
+ case SIZE_ZPOS+5: return cu1.fz;
+ case SIZE_ZPOS+2: case SIZE_ZPOS+3: case SIZE_ZPOS+6:
+ case SIZE_ZPOS+7: return cu2.fz;
+ case SIZE_XCENTER: return rotC.fx;
+ case SIZE_YCENTER: return rotC.fy;
+ case SIZE_ZCENTER: return rotC.fz;
+ default:
+ if(parent) return parent->GetSize(select);
+ else return defs.GetSize(select);
+ }
+}
+
+bool
+Plot3D::SetColor(int select, DWORD col)
+{
+ int i;
+
+ switch(select & 0xfff) {
+ case COL_AXIS:
+ if(Axes) for(i = 0; i< nAxes; i++) if(Axes[i]) Axes[i]->SetColor(select, col);
+ return true;
+ }
+ return false;
+}
+
+void
+Plot3D::DoPlot(anyOutput *o)
+{
+ long i, j, fo;
+
+ nObs = 0;
+ if(!parent || !o) return;
+ o->MouseCursor(MC_WAIT, true);
+ if(dirty) DoAutoscale();
+ o->LightSource(8.0, -16.0);
+ cu1.fx = cub1.fx; cu1.fy = cub1.fy; cu1.fz = cub1.fz;
+ cu2.fx = cub2.fx; cu2.fy = cub2.fy; cu2.fz = cub2.fz;
+ rc.fx = rotC.fx; rc.fy = rotC.fy; rc.fz = rotC.fz;
+ if(Axes && nAxes >2) {
+ o->SetSpace(&cu1, &cu2, defs.cUnits, RotDef, &rc, Axes[0]->GetAxis(),
+ Axes[1]->GetAxis(), Axes[2]->GetAxis());
+ for(i = 0; i< nAxes; i++) if(Axes[i]) Axes[i]->DoPlot(o);
+ if(plots) for(i = 0; i < nPlots; i++) if(plots[i]){
+ if(plots[i]->Id >= GO_PLOT && plots[i]->Id < GO_GRAPH) {
+ if(((Plot*)plots[i])->hidden == 0) plots[i]->DoPlot(o);
+ }
+ else plots[i]->DoPlot(o);
+ if(i) {
+ UpdateMinMaxRect(&rDims, plots[i]->rDims.right, plots[i]->rDims.top);
+ UpdateMinMaxRect(&rDims, plots[i]->rDims.left, plots[i]->rDims.bottom);
+ }
+ else memcpy(&rDims, &plots[i]->rDims, sizeof(RECT));
+ }
+ for(i = 0; i< nAxes; i++) if(Axes[i]){
+ UpdateMinMaxRect(&rDims, Axes[i]->rDims.right, Axes[i]->rDims.top);
+ UpdateMinMaxRect(&rDims, Axes[i]->rDims.left, Axes[i]->rDims.bottom);
+ }
+ }
+ for(i = j = 1; i < nObs; i++) if(dispObs[i] && dispObs[i]->go)
+ dispObs[j++] = dispObs[i];
+ nObs = j;
+ SortObj();
+ if(nObs && dispObs){
+ for (i = fo = 1; i <= nObs; i++){
+ while(dispObs[fo]->Zmax < dispObs[i]->Zmin && fo < (nObs-1)) fo++;
+ for(j = fo; j <= nObs; j++) {
+ if(dispObs[j]->go->Id != GO_LINESEG && i != j) switch(dispObs[i]->go->Id) {
+ case GO_LINESEG:
+ case GO_SPHERE:
+ case GO_PLANE:
+ dispObs[i]->go->Command(CMD_CLIP, dispObs[j]->go, o);
+ break;
+ }
+ //the following line, if included, reduces time but clipping
+ // is not complete because of CMD_DRAW_LATER
+// if(dispObs[j]->Zmin > dispObs[i]->Zmax) break;
+ }
+ }
+ for (i = 1; i <= nObs; i++) dispObs[i]->go->Command(CMD_REDRAW, 0L, o);
+ }
+ dirty = false;
+ o->MouseCursor(MC_ARROW, true);
+}
+
+void
+Plot3D::DoMark(anyOutput *o, bool mark)
+{
+ RECT upd;
+
+ if(!drag) drag = new Drag3D(this);
+ if(mark && drag) drag->DoPlot(o);
+ else {
+ memcpy(&upd, &rDims, sizeof(RECT));
+ IncrementMinMaxRect(&upd, 6);
+ o->UpdateRect(&upd, false);
+ }
+}
+
+bool
+Plot3D::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i;
+ GraphObj **tmpPlots;
+
+ switch (cmd) {
+ case CMD_MOUSE_EVENT:
+ if(hidden || ((MouseEvent*)tmpl)->Action != MOUSE_LBUP || CurrGO) return false;
+ if(dispObs) for (i = nObs; i > 0; i--) {
+ if(dispObs[i]) dispObs[i]->go->Command(cmd, tmpl, o);
+ if(CurrGO) return true;
+ }
+ if(IsInRect(&rDims, ((MouseEvent*)tmpl)->x, ((MouseEvent*)tmpl)->y)) {
+ o->ShowMark(CurrGO = this, MRK_GODRAW);
+ return true;
+ }
+ break;
+ case CMD_HIDE_MARK:
+ if(!tmpl) return false;
+ //do all axes
+ if(Axes)for(i = nAxes-1; i>=0; i--) {
+ if(tmpl == (void*)Axes[i]){
+ Axes[i]->DoMark(o, false);
+ return true;
+ }
+ else if(Axes[i]->Id == GO_AXIS) {
+ if(Axes[i]->Command(cmd, tmpl, o)) return true;
+ }
+ }
+ //do all plots
+ if(plots)for(i = nPlots-1; i>=0; i--) {
+ if(tmpl == (void*)plots[i]){
+ plots[i]->DoMark(o, false);
+ return true;
+ }
+ else if(plots[i]->Id == GO_MLABEL || (plots[i]->Id >= GO_PLOT && plots[i]->Id < GO_GRAPH)) {
+ if(plots[i]->Command(cmd, tmpl, o)) return true;
+ }
+ }
+ return false;
+ case CMD_OBJTREE:
+ if(!tmpl || !plots) return false;
+ for(i = 0; i < nPlots; i++) if(plots[i])
+ ((ObjTree*)tmpl)->Command(CMD_UPDATE, plots[i], 0L);
+ return true;
+ case CMD_REPL_GO:
+ if(!(tmpPlots = (GraphObj **)tmpl) || !tmpPlots[0] || !tmpPlots[1]) return false;
+ if(plots) for(i = 0; i < nPlots; i++) if(plots[i] && plots[i] == tmpPlots[0]){
+ return dirty = ReplaceGO((GraphObj**)&plots[i], tmpPlots);
+ }
+ return false;
+ case CMD_MRK_DIRTY:
+ return dirty = true;
+ case CMD_ADDAXIS:
+ InfoBox("Add axis to 3D graph:\n\nThis feature is not yet implemented!");
+ return false;
+ case CMD_SET_GO3D:
+ return AcceptObj((GraphObj *)tmpl);
+ case CMD_SETSCROLL:
+ case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ case CMD_SHIFTLEFT:
+ return Rotate(-0.017452406, 0.0, 0.0, o, true);
+ case CMD_SHIFTRIGHT:
+ return Rotate(0.017452406, 0.0, 0.0, o, true);
+ case CMD_SHIFTUP:
+ return Rotate(0.0, 0.017452406, 0.0, o, true);
+ case CMD_SHIFTDOWN:
+ return Rotate(0.0, -0.017452406, 0.0, o, true);
+ case CMD_CURRIGHT:
+ return Rotate(0.087155742, 0.0, 0.0, o, true);
+ case CMD_CURRLEFT:
+ return Rotate(-0.087155742, 0.0, 0.0, o, true);
+ case CMD_CURRUP:
+ return Rotate(0.0, 0.087155742, 0.0, o, true);
+ case CMD_CURRDOWN:
+ return Rotate(0.0, -0.087155742, 0.0, o, true);
+ case CMD_ADDCHAR:
+ if(tmpl && *((int*)tmpl) == 'r') return Rotate(0.0, 0.0, 0.087155742, o, true);
+ if(tmpl && *((int*)tmpl) == 'l') return Rotate(0.0, 0.0, -0.087155742, o, true);
+ if(tmpl && *((int*)tmpl) == 'R') return Rotate(0.0, 0.0, 0.017452406, o, true);
+ if(tmpl && *((int*)tmpl) == 'L') return Rotate(0.0, 0.0, -0.017452406, o, true);
+ return false;
+ case CMD_LEGEND:
+ if(plots) for(i = 0; i < nPlots; i++)
+ if(plots[i]) plots[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_SET_DATAOBJ:
+ Id = GO_PLOT3D;
+ data = (DataObj *)tmpl;
+ case CMD_UPDATE:
+ if(plots) for(i = 0; i < nPlots; i++)
+ if(plots[i]) plots[i]->Command(cmd, tmpl, o);
+ if(Axes) for(i = 0; i < nAxes; i++)
+ if(Axes[i]) Axes[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_DELOBJ:
+ if(o) o->HideMark();
+ if(!tmpl || !parent) return false;
+ if(plots) for(i = 0; i < nPlots; i++) if(plots[i] == tmpl) {
+ Undo.DeleteGO((GraphObj**)(&plots[i]), 0L, o);
+ return parent->Command(CMD_REDRAW, 0L, o);
+ }
+ return true;
+ case CMD_MOVE:
+ if(CurrGO && CurrGO->Id == GO_DRAGHANDLE) {
+ CalcRotation(((lfPOINT*)tmpl)[0].fx, ((lfPOINT*)tmpl)[0].fy, o, true);
+ if(parent) return parent->Command(CMD_REDRAW, 0L, 0L);
+ }
+ return true;
+ case CMD_AUTOSCALE:
+ if(dirty) {
+ DoAutoscale();
+ dirty = false;
+ }
+ return true;
+ case CMD_DROP_PLOT:
+ if(!parent || !tmpl || ((GraphObj*)tmpl)->Id < GO_PLOT) return false;
+ if(!nPlots) {
+ plots = (GraphObj**)calloc(2, sizeof(GraphObj*));
+ if(plots) {
+ nPlots = 1; plots[0] = (Plot *)tmpl;
+ plots[0]->parent = this; CreateAxes();
+ return dirty = parent->Command(CMD_REDRAW, 0L, 0L);
+ }
+ }
+ else {
+ ((Plot *)tmpl)->parent = this;
+ tmpPlots = (GraphObj**)memdup(plots, sizeof(GraphObj*) * (nPlots+2), 0);
+ Undo.ListGOmoved(plots, tmpPlots, nPlots);
+ Undo.SetGO(this, &tmpPlots[nPlots++], (Plot *)tmpl, 0L);
+ free(plots); plots = tmpPlots;
+ return dirty = parent->Command(CMD_REDRAW, 0L, 0L);
+ }
+ return false;
+ case CMD_ADDPLOT:
+ return AddPlot(0x0);
+ }
+ return false;
+}
+
+void *
+Plot3D::ObjThere(int x, int y)
+{
+ if(drag) return drag->ObjThere(x, y);
+ return 0L;
+}
+
+void
+Plot3D::Track(POINT *p, anyOutput *o)
+{
+ fPOINT3D v, iv;
+ POINT pts[5];
+ RECT upd_rc;
+
+ CalcRotation(((lfPOINT*)p)->fx, ((lfPOINT*)p)->fy, o, false);
+ memcpy(&upd_rc, &rDims, sizeof(RECT));
+ IncrementMinMaxRect(&rDims, 3);
+ o->UpdateRect(&upd_rc, false);
+ memcpy(&v, &cu2, sizeof(fPOINT3D));
+ o->cvec2ivec(&v, &iv);
+ pts[0].x = iround(iv.fx); pts[0].y = iround(iv.fy);
+ UpdateMinMaxRect(&rDims, pts[0].x, pts[0].y);
+ v.fx = cu1.fx; o->cvec2ivec(&v, &iv);
+ pts[1].x = iround(iv.fx); pts[1].y = iround(iv.fy);
+ UpdateMinMaxRect(&rDims, pts[1].x, pts[1].y);
+ v.fy = cu1.fy; o->cvec2ivec(&v, &iv);
+ pts[2].x = iround(iv.fx); pts[2].y = iround(iv.fy);
+ UpdateMinMaxRect(&rDims, pts[2].x, pts[2].y);
+ v.fz = cu1.fz; o->cvec2ivec(&v, &iv);
+ pts[3].x = iround(iv.fx); pts[3].y = iround(iv.fy);
+ UpdateMinMaxRect(&rDims, pts[3].x, pts[3].y);
+ v.fy = cu2.fy; o->cvec2ivec(&v, &iv);
+ pts[4].x = iround(iv.fx); pts[4].y = iround(iv.fy);
+ UpdateMinMaxRect(&rDims, pts[4].x, pts[4].y);
+ o->ShowLine(pts, 5, 0x000000ff);
+ v.fz = cu2.fz; o->cvec2ivec(&v, &iv);
+ pts[0].x = iround(iv.fx); pts[0].y = iround(iv.fy);
+ v.fz = cu1.fz; o->cvec2ivec(&v, &iv);
+ pts[1].x = iround(iv.fx); pts[1].y = iround(iv.fy);
+ v.fx = cu2.fx; o->cvec2ivec(&v, &iv);
+ pts[2].x = iround(iv.fx); pts[2].y = iround(iv.fy);
+ v.fz = cu2.fz; o->cvec2ivec(&v, &iv);
+ pts[3].x = iround(iv.fx); pts[3].y = iround(iv.fy);
+ v.fy = cu1.fy; o->cvec2ivec(&v, &iv);
+ pts[4].x = iround(iv.fx); pts[4].y = iround(iv.fy);
+ o->ShowLine(pts, 5, 0x000000ff);
+ v.fy = cu2.fy; v.fz = cu1.fz; o->cvec2ivec(&v, &iv);
+ pts[0].x = iround(iv.fx); pts[0].y = iround(iv.fy);
+ v.fy = cu1.fy; o->cvec2ivec(&v, &iv);
+ pts[1].x = iround(iv.fx); pts[1].y = iround(iv.fy);
+ v.fx = cu1.fx; o->cvec2ivec(&v, &iv);
+ pts[2].x = iround(iv.fx); pts[2].y = iround(iv.fy);
+ o->ShowLine(pts, 3, 0x000000ff);
+ v.fz = cu2.fz; o->cvec2ivec(&v, &iv);
+ pts[0].x = iround(iv.fx); pts[0].y = iround(iv.fy);
+ v.fx = cu2.fx; o->cvec2ivec(&v, &iv);
+ pts[1].x = iround(iv.fx); pts[1].y = iround(iv.fy);
+ v.fz = cu1.fz; o->cvec2ivec(&v, &iv);
+ pts[2].x = iround(iv.fx); pts[2].y = iround(iv.fy);
+ o->ShowLine(pts, 3, 0x000000ff);
+}
+
+void
+Plot3D::CreateAxes()
+{
+ typedef struct {
+ double x1, y1, z1, x2, y2, z2;
+ DWORD flags;
+ int a_type, t_type;
+ double lb_x, lb_y, tlb_x, tlb_y;
+ int txa;
+ }Axis3Ddef;
+ AxisDEF tmp_axis;
+ double ts = defs.GetSize(SIZE_AXIS_TICKS);
+ int i;
+ if(Axes || !parent)return;
+ TextDEF tlbdef = {parent->GetColor(COL_AXIS), 0x00ffffffL, defs.GetSize(SIZE_TICK_LABELS),
+ 0.0, 0.0, 0, TXA_HLEFT | TXA_VCENTER, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, 0L};
+ Axis3Ddef *at = 0L;
+ Axis3Ddef at1[] = {
+ {cub1.fx, cub1.fy, 0.0, cub2.fx, cub1.fy, 0.0,
+ AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_AUTOSCALE | AXIS_NEGTICKS, 1, 3,
+ 0.0, NiceValue((ts+defs.GetSize(SIZE_AXIS_TICKS))*2.0), 0.0,
+ NiceValue(ts * 2.0), TXA_HCENTER | TXA_VTOP},
+ {cub1.fx, cub1.fy, 0.0, cub1.fx, cub2.fy, 0.0,
+ AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_AUTOSCALE | AXIS_NEGTICKS, 2, 2,
+ -NiceValue((ts+defs.GetSize(SIZE_AXIS_TICKS))*3.0), 0.0,
+ -NiceValue(ts * 2.0), 0.0, TXA_HRIGHT | TXA_VCENTER},
+ {cub1.fx, cub1.fy, 0.0, cub1.fx, cub1.fy, cub2.fz,
+ AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_AUTOSCALE | AXIS_NEGTICKS, 3, 2,
+ -NiceValue((ts+defs.GetSize(SIZE_AXIS_TICKS))*3.0), 0.0,
+ -NiceValue(ts * 2.0), 0.0, TXA_HRIGHT | TXA_VCENTER}};
+ Axis3Ddef at2[] = {
+ {at1[0].x1, at1[0].y1, at1[2].z2, at1[0].x2, at1[0].y2, at1[2].z2,
+ AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_AUTOSCALE | AXIS_NEGTICKS, 1, 3,
+ 0.0, at1[0].lb_y, 0.0, at1[0].tlb_y, TXA_HCENTER | TXA_VTOP},
+ {at1[0].x2, at1[1].y1, 0.0, at1[0].x2, at1[1].y2, 0.0,
+ AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_AUTOSCALE | AXIS_POSTICKS, 2, 2,
+ -at1[1].lb_x, 0.0, -at1[1].tlb_x, 0.0, TXA_HLEFT | TXA_VCENTER},
+ {at1[0].x2, at1[0].y1, 0.0, at1[0].x2, at1[0].y1, at1[2].z2,
+ AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_AUTOSCALE | AXIS_POSTICKS, 3, 2,
+ -at1[2].lb_x, 0.0, -at1[2].tlb_x, 0.0, TXA_HLEFT | TXA_VCENTER},
+ {at1[0].x1, at1[0].y1, 0.0, at1[0].x2, at1[0].y2, 0.0,
+ AXIS_3D, 1, 3, 0.0, at1[0].lb_y, 0.0, at1[0].tlb_y, TXA_HCENTER | TXA_VCENTER},
+ {at1[0].x1, at1[1].y2, 0.0, at1[0].x2, at1[1].y2, 0.0,
+ AXIS_3D, 1, 3, 0.0, at1[0].lb_y, 0.0, at1[0].tlb_y, TXA_HCENTER | TXA_VCENTER},
+ {at1[0].x1, at1[1].y1, 0.0, at1[0].x1, at1[1].y2, 0.0,
+ AXIS_3D, 2, 2, at1[1].lb_x, 0.0, at1[1].tlb_x, 0.0, TXA_HCENTER | TXA_VCENTER},
+ {at1[0].x1, at1[1].y1, at1[2].z2, at1[0].x1, at1[1].y2, at1[2].z2,
+ AXIS_3D, 2, 2, at1[1].lb_x, 0.0, at1[1].tlb_x, 0.0, TXA_HCENTER | TXA_VCENTER},
+ {at1[0].x1, at1[0].y1, 0.0, at1[0].x1, at1[0].y1, at1[2].z2,
+ AXIS_3D, 3, 2, at1[2].lb_x, 0.0, at1[2].tlb_x, 0.0, TXA_HCENTER | TXA_VCENTER},
+ {at1[0].x1, at1[1].y2, 0.0, at1[0].x1, at1[1].y2, at1[2].z2,
+ AXIS_3D, 3, 2, at1[2].lb_x, 0.0, at1[2].tlb_x, 0.0}, TXA_HCENTER | TXA_VCENTER};
+ Axis3Ddef at3[] = {
+ {at1[0].x1, (at1[1].y1+at1[1].y2)/2.0, at1[2].z2/2.0, at1[0].x2,
+ (at1[1].y1+at1[1].y2)/2.0, at1[2].z2/2.0,
+ AXIS_3D | AXIS_AUTOTICK | AXIS_AUTOSCALE | AXIS_NEGTICKS, 1, 3,
+ 0.0, at1[0].lb_y, 0.0, at1[0].tlb_y, TXA_HCENTER | TXA_VTOP},
+ {(at1[0].x1 + at1[0].x2)/2.0, at1[1].y1, at1[2].z2/2.0,
+ (at1[0].x1 + at1[0].x2)/2.0, at1[1].y2, at1[2].z2/2.0,
+ AXIS_3D | AXIS_AUTOTICK | AXIS_AUTOSCALE | AXIS_POSTICKS, 2, 2,
+ -at1[1].lb_x, 0.0, -at1[1].tlb_x, 0.0, TXA_HLEFT | TXA_VCENTER},
+ {(at1[0].x1 + at1[0].x2)/2.0, (at1[1].y1+at1[1].y2)/2.0, 0.0,
+ (at1[0].x1 + at1[0].x2)/2.0, (at1[1].y1+at1[1].y2)/2.0, at1[2].z2,
+ AXIS_3D | AXIS_AUTOTICK | AXIS_AUTOSCALE | AXIS_POSTICKS, 3, 2,
+ -at1[2].lb_x, 0.0, -at1[2].tlb_x, 0.0, TXA_HLEFT | TXA_VCENTER}};
+
+ tmp_axis.min = 0.0; tmp_axis.max = 100.0;
+ tmp_axis.Start = 0.0; tmp_axis.Step = 20.0;
+ tmp_axis.Center.fx = tmp_axis.Center.fy = 0.0;
+ tmp_axis.Radius = 0.0; tmp_axis.nBreaks = 0;
+ tmp_axis.breaks = 0L; tmp_axis.owner = 0L;
+ switch(AxisTempl3D){
+ case 0: at = at1; nAxes = 3; break;
+ case 1: at = at2; nAxes = 9; break;
+ case 2: at = at3; nAxes = 3; break;
+ }
+ if(!(Axes = (Axis**)calloc(nAxes, sizeof(Axis *))))return;
+ if(at && nAxes) for(i = 0; i < nAxes; i++) {
+ tmp_axis.loc[0].fx = at[i].x1; tmp_axis.loc[0].fy = at[i].y1;
+ tmp_axis.loc[0].fz = at[i].z1; tmp_axis.loc[1].fx = at[i].x2;
+ tmp_axis.loc[1].fy = at[i].y2; tmp_axis.loc[1].fz = at[i].z2;
+ tlbdef.Align = at[i].txa;
+ if((Axes[i] = new Axis(this, data, &tmp_axis, at[i].flags))){
+ Axes[i]->type = at[i].a_type;
+ Axes[i]->SetSize(SIZE_LB_YDIST, at[i].lb_y);
+ Axes[i]->SetSize(SIZE_LB_XDIST, at[i].lb_x);
+ Axes[i]->SetSize(SIZE_TLB_YDIST, at[i].tlb_y);
+ Axes[i]->SetSize(SIZE_TLB_XDIST, at[i].tlb_x);
+ Axes[i]->Command(CMD_TICK_TYPE, &at[i].t_type, 0L);
+ Axes[i]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+ }
+ }
+}
+
+void
+Plot3D::DoAutoscale()
+{
+ int i;
+ AxisDEF *ad;
+
+ if(!plots) return;
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
+ xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
+ for(i = 0; i < nPlots; i++) if(plots[i]) plots[i]->Command(CMD_AUTOSCALE, 0L, 0L);
+ if(xBounds.fx <= xBounds.fy && yBounds.fx <= yBounds.fy && zBounds.fx <= zBounds.fy){
+ if(Axes)for(i = 0; i < 3; i++) if(Axes[i]){
+ ad = Axes[i]->axis;
+ if(ad->flags & AXIS_AUTOSCALE) {
+ switch(i) {
+ case 0:
+ if(xBounds.fx == xBounds.fy) {
+ xBounds.fx -= 1.0; xBounds.fy += 1.0;
+ }
+ ad->min = xBounds.fx; ad->max = xBounds.fy; break;
+ case 1:
+ if(yBounds.fx == yBounds.fy) {
+ yBounds.fx -= 1.0; yBounds.fy += 1.0;
+ }
+ ad->min = yBounds.fx; ad->max = yBounds.fy; break;
+ case 2:
+ if(zBounds.fx == zBounds.fy) {
+ zBounds.fx -= 1.0; zBounds.fy += 1.0;
+ }
+ ad->min = zBounds.fx; ad->max = zBounds.fy; break;
+ }
+ NiceAxis(ad, 4);
+ if(ad->min <= 0.0 && ((ad->flags & 0xf000) == AXIS_LOG ||
+ (ad->flags & 0xf000) == AXIS_RECI)) {
+ ad->min = base4log(ad, i);
+ }
+ Axes[i]->Command(CMD_AUTOSCALE, ad, 0L);
+ }
+ }
+ }
+}
+
+//Implement some kind of virtual trackball
+//see: J. Hultquist: A Virtual Trackball
+//Graphic Gems, A.S. Glassner ed.; Academic Press Inc.
+//ISBN 0-12-286165-5, pp. 462-463
+void
+Plot3D::CalcRotation(double dx, double dy, anyOutput *o, bool accept)
+{
+ fPOINT3D V0, V1, A;
+ double R, R2, si, dp, NewRot[6];
+ double rotM[3][3], newM[3][3]; //rotation matrices
+
+ if(!CurrGO || CurrGO->Id != GO_DRAGHANDLE || CurrGO->type < DH_18 ||
+ CurrGO->type > DH_88) return;
+ //get coordinates for last accepted rotation
+ V0.fx = GetSize(SIZE_XPOS + CurrGO->type - DH_18);
+ V0.fy = GetSize(SIZE_YPOS + CurrGO->type - DH_18);
+ V0.fz = GetSize(SIZE_ZPOS + CurrGO->type - DH_18);
+ //revert to last matrix
+ o->SetSpace(&cu1, &cu2, defs.cUnits, RotDef, &rc, Axes[0]->GetAxis(),
+ Axes[1]->GetAxis(), Axes[2]->GetAxis());
+ o->cvec2ivec(&V0, &V1);
+ memcpy(&V0, &V1, sizeof(fPOINT3D));
+ V1.fx += o->un2fix(dx); V1.fy += o->un2fiy(dy);
+ V0.fx -= o->rotC.fx; V0.fy -= o->rotC.fy; V0.fz -= o->rotC.fz;
+ V1.fx -= o->rotC.fx; V1.fy -= o->rotC.fy; V1.fz -= o->rotC.fz;
+ R = sqrt(R2 = V0.fx * V0.fx + V0.fy * V0.fy + V0.fz * V0.fz);
+ R2 -= (V1.fx * V1.fx + V1.fy * V1.fy);
+ if (R2 <= 1.0) return;
+ V1.fz = V1.fz > 0.0 ? sqrt(R2) : -sqrt(R2);
+ V0.fx /= R; V0.fy /= R; V0.fz /= R;
+ V1.fx /= R; V1.fy /= R; V1.fz /= R;
+ A.fx = (V1.fy * V0.fz) - (V1.fz * V0.fy);
+ A.fy = (V1.fz * V0.fx) - (V1.fx * V0.fz);
+ A.fz = (V1.fx * V0.fy) - (V1.fy * V0.fx);
+
+ si = sqrt(A.fx * A.fx + A.fy * A.fy + A.fz * A.fz);
+ if(si > 0.001) {
+ NewRot[0] = A.fx; NewRot[1] = A.fy; NewRot[2] = A.fz;
+ NewRot[3] = si; NewRot[4] = sqrt(1.0-si*si); NewRot[5] = 1.0-NewRot[4];
+ //normalize vector part of NewRot
+ dp = sqrt(NewRot[0]*NewRot[0] + NewRot[1]*NewRot[1] + NewRot[2]*NewRot[2]);
+ NewRot[0] /= dp; NewRot[1] /= dp; NewRot[2] /= dp;
+ //set up rotation matrix from quaternion
+ //see: Graphic Gems, A.S. Glassner ed.; Academic Press Inc.
+ //M.E. Pique: Rotation Tools
+ // ISBN 0-12-286165-5, p.466
+ rotM[0][0] = NewRot[5]*NewRot[0]*NewRot[0] + NewRot[4];
+ rotM[0][1] = NewRot[5]*NewRot[0]*NewRot[1] + NewRot[3]*NewRot[2];
+ rotM[0][2] = NewRot[5]*NewRot[0]*NewRot[2] - NewRot[3]*NewRot[1];
+ rotM[1][0] = NewRot[5]*NewRot[0]*NewRot[1] - NewRot[3]*NewRot[2];
+ rotM[1][1] = NewRot[5]*NewRot[1]*NewRot[1] + NewRot[4];
+ rotM[1][2] = NewRot[5]*NewRot[1]*NewRot[2] + NewRot[3]*NewRot[0];
+ rotM[2][0] = NewRot[5]*NewRot[0]*NewRot[2] + NewRot[3]*NewRot[1];
+ rotM[2][1] = NewRot[5]*NewRot[1]*NewRot[2] - NewRot[3]*NewRot[0];
+ rotM[2][2] = NewRot[5]*NewRot[2]*NewRot[2] + NewRot[4];
+ //rotate rotation matrix
+ if(MatMul(o->rotM, rotM, newM)) memcpy(&o->rotM, &newM, sizeof(newM));
+ }
+ if(accept) {
+ //create new quaternion in RotDef from rotation matrix of output class
+ Undo.RotDef(this, &RotDef, 0L);
+ RotDef[4] = (o->rotM[0][0] + o->rotM[1][1] + o->rotM[2][2] -1)/2.0;
+ RotDef[3] = sqrt(1.0-RotDef[4]*RotDef[4]);
+ RotDef[0] = (o->rotM[1][2] - o->rotM[2][1])/(2.0 * RotDef[3]);
+ RotDef[1] = (o->rotM[2][0] - o->rotM[0][2])/(2.0 * RotDef[3]);
+ RotDef[2] = (o->rotM[0][1] - o->rotM[1][0])/(2.0 * RotDef[3]);
+ RotDef[5] = 1.0-RotDef[4];
+ }
+}
+
+bool
+Plot3D::AcceptObj(GraphObj *go)
+{
+ if(!dispObs && !(dispObs = (obj_desc**)
+ calloc(nmaxObs = 1024, sizeof(obj_desc*))))return false;
+ else if((nObs+1) >= nmaxObs) dispObs = (obj_desc**)
+ realloc(dispObs, (nmaxObs = nmaxObs +1024) * sizeof(obj_desc*));
+ if(dispObs[++nObs] = (obj_desc*)calloc(1, sizeof(obj_desc))){
+ dispObs[nObs]->Zmin = go->GetSize(SIZE_MIN_Z);
+ dispObs[nObs]->Zmax = go->GetSize(SIZE_MAX_Z);
+ dispObs[nObs]->go = go;
+ }
+ return true;
+}
+
+//Execute a heap sort before drawing the objects
+//W.H. pres, B.P. Flannery, S.A. Teukolsky, W.T. Vetterling (1988/1989)
+//Numerical Recipes in C, Cambridge University Press, ISBN 0-521-35465-X
+// p. 245
+void
+Plot3D::SortObj()
+{
+ int l, j, ir, i;
+ obj_desc *rra;
+
+ if(nObs < 2) return;
+ l=(nObs >> 1)+1; ir = nObs;
+ for( ; ; ){
+ if(l > 1) rra = dispObs[--l];
+ else {
+ rra = dispObs[ir];
+ dispObs[ir] = dispObs[1];
+ if(--ir == 1) {
+ dispObs[1] = rra;
+ return;
+ }
+ }
+ i = l; j = l << 1;
+ while(j <= ir) {
+ if(j < ir && dispObs[j]->Zmin < dispObs[j+1]->Zmin) ++j;
+ if(rra->Zmin < dispObs[j]->Zmin) {
+ dispObs[i] = dispObs[j];
+ j += (i = j);
+ }
+ else j = ir + 1;
+ }
+ dispObs[i] = rra;
+ }
+}
+
+bool
+Plot3D::Rotate(double dx, double dy, double dz, anyOutput *o, bool accept)
+{
+ int i;
+ double si, NewRot[6];
+ double rotM[3][3], newM[3][3]; //rotation matrices
+ bool bRet = true;
+
+ for(i = 0; i < 3; i++) {
+ switch (i){
+ case 0:
+ if(dx > 0.0) {
+ NewRot[0] = -o->rotM[1][0]; NewRot[1] = -o->rotM[1][1];
+ NewRot[2] = -o->rotM[1][2];
+ NewRot[3] = si = dx;
+ }
+ else {
+ NewRot[0] = o->rotM[1][0]; NewRot[1] = o->rotM[1][1];
+ NewRot[2] = o->rotM[1][2];
+ NewRot[3] = si = -dx;
+ }
+ break;
+ case 1:
+ if(dy > 0.0) {
+ NewRot[0] = -o->rotM[0][0]; NewRot[1] = -o->rotM[0][1];
+ NewRot[2] = -o->rotM[0][2];
+ NewRot[3] = si = dy;
+ }
+ else {
+ NewRot[0] = o->rotM[0][0]; NewRot[1] = o->rotM[0][1];
+ NewRot[2] = o->rotM[0][2];
+ NewRot[3] = si = -dy;
+ }
+ break;
+ case 2:
+ if(dz > 0.0) {
+ NewRot[0] = -o->rotM[2][0]; NewRot[1] = -o->rotM[2][1];
+ NewRot[2] = -o->rotM[2][2];
+ NewRot[3] = si = dz;
+ }
+ else {
+ NewRot[0] = o->rotM[2][0]; NewRot[1] = o->rotM[2][1];
+ NewRot[2] = o->rotM[2][2];
+ NewRot[3] = si = -dz;
+ }
+ break;
+ }
+ if(si > 0.0) {
+ NewRot[4] = sqrt(1.0-si*si); NewRot[5] = 1.0-NewRot[4];
+ //set up rotation matrix from quaternion
+ //see: Graphic Gems, A.S. Glassner ed.; Academic Press Inc.
+ //M.E. Pique: Rotation Tools
+ // ISBN 0-12-286165-5, p.466
+ rotM[0][0] = NewRot[5]*NewRot[0]*NewRot[0] + NewRot[4];
+ rotM[0][1] = NewRot[5]*NewRot[0]*NewRot[1] + NewRot[3]*NewRot[2];
+ rotM[0][2] = NewRot[5]*NewRot[0]*NewRot[2] - NewRot[3]*NewRot[1];
+ rotM[1][0] = NewRot[5]*NewRot[0]*NewRot[1] - NewRot[3]*NewRot[2];
+ rotM[1][1] = NewRot[5]*NewRot[1]*NewRot[1] + NewRot[4];
+ rotM[1][2] = NewRot[5]*NewRot[1]*NewRot[2] + NewRot[3]*NewRot[0];
+ rotM[2][0] = NewRot[5]*NewRot[0]*NewRot[2] + NewRot[3]*NewRot[1];
+ rotM[2][1] = NewRot[5]*NewRot[1]*NewRot[2] - NewRot[3]*NewRot[0];
+ rotM[2][2] = NewRot[5]*NewRot[2]*NewRot[2] + NewRot[4];
+ if(MatMul(o->rotM, rotM, newM)) memcpy(&o->rotM, &newM, sizeof(newM));
+ else accept = bRet = false;
+ }
+ }
+ if(accept && bRet) {
+ //create new quaternion in RotDef from rotation matrix of output class
+ Undo.RotDef(this, &RotDef, 0L);
+ RotDef[4] = (o->rotM[0][0] + o->rotM[1][1] + o->rotM[2][2] -1)/2.0;
+ RotDef[3] = sqrt(1.0-RotDef[4]*RotDef[4]);
+ RotDef[0] = (o->rotM[1][2] - o->rotM[2][1])/(2.0 * RotDef[3]);
+ RotDef[1] = (o->rotM[2][0] - o->rotM[0][2])/(2.0 * RotDef[3]);
+ RotDef[2] = (o->rotM[0][1] - o->rotM[1][0])/(2.0 * RotDef[3]);
+ RotDef[5] = 1.0-RotDef[4];
+ if(parent)return parent->Command(CMD_REDRAW, 0L, o);
+ }
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// use Plot3D to create a 2.5 dimensional chart
+Chart25D::Chart25D(GraphObj *par, DataObj *d, DWORD flags)
+ :Plot3D(par, d, flags)
+{
+ dspm.fx = dspm.fy = dspm.fz = 1.0;
+}
+
+Chart25D::~Chart25D()
+{
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// use Plot3D to create a 2.5 dimensional ribbon chart
+Ribbon25D::Ribbon25D(GraphObj *par, DataObj *d, DWORD flags)
+ :Plot3D(par, d, flags)
+{
+ dspm.fx = dspm.fy = dspm.fz = 1.0;
+}
+
+Ribbon25D::~Ribbon25D()
+{
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// use Plot3D to create a 3 dimensional bubble plot
+BubblePlot3D::BubblePlot3D(GraphObj *par, DataObj *d)
+ :Plot3D(par, d, 0x0L)
+{
+}
+
+BubblePlot3D::~BubblePlot3D()
+{
+}
diff --git a/PropertyDlg.cpp b/PropertyDlg.cpp
new file mode 100755
index 0000000..c6f160f
--- /dev/null
+++ b/PropertyDlg.cpp
@@ -0,0 +1,7777 @@
+//PropertyDlg.cpp, Copyright (c) 2001, 2002, 2003, 2004, 2005 R.Lackner
+//Property dialogs for graphic objects
+//
+// 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 "TheDialog.h"
+
+extern tag_Units Units[];
+extern char TmpTxt[];
+extern TextDEF DlgText;
+extern Default defs;
+extern int dlgtxtheight;
+extern Axis **CurrAxes;
+extern UndoObj Undo;
+extern int AxisTempl3D;
+
+int ODtickstyle;
+
+//prototypes: WinSpec.cpp
+void *CreateDlgWnd(char *title, int x, int y, int width, int height, tag_DlgObj *d, DWORD flags);
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Symbol properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Symbol::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 45, 10, "Size & Color"};
+ TabSHEET tab2 = {110, 130, 10, "Edit"};
+ TabSHEET tab3 = {68, 110, 10, "Text Prop."};
+ TabSHEET tab4 = {45, 68, 10, "Text"};
+ Symbol *PrevSym = 0L;
+ char text1[40], text2[100];
+ int syms[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, SYM_TEXT};
+ DlgInfo SymDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to SYMBOL", 145, 10, 60, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 145, 25, 60, 12},
+ {3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 145, 40, 60, 12},
+ {4, 500, 5, CHECKED | ISPARENT, GROUP, NULL, 138, 40, 55, 12},
+ {5, 6, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 130, 70},
+ {6, 7, 300, ISPARENT, SHEET, &tab2, 5, 10, 130, 70},
+ {7, 8, 200, TOUCHEXIT | ISPARENT, SHEET, &tab3, 5, 10, 130, 70},
+ {8, 401, 250, TOUCHEXIT | ISPARENT, SHEET, &tab4, 5, 10, 130, 70},
+ {100, 101, 0, 0x0L, RTEXT, (void*)"size", 5, 25, 45, 8},
+ {101, 102, 0, TOUCHEXIT, INCDECVAL1, &size, 55, 25, 32, 10},
+ {102, 103, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 89, 25, 20, 8},
+ {103, 104, 0, 0x0L, RTEXT, (void*)"line width", 5, 37, 45, 8},
+ {104, 105, 0, TOUCHEXIT, INCDECVAL1, &SymLine.width, 55, 37, 32, 10},
+ {105, 106, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 89, 37, 20, 8},
+ {106, 107, 0, 0x0L, RTEXT, (void*)"line color", 5, 49, 45, 8},
+ {107, 108, 0, TOUCHEXIT | OWNDIALOG, COLBUTTON, (void *)SymLine.color, 55, 49, 25, 10},
+ {108, 109, 0, 0x0L, RTEXT, (void*)"fill color" , 5, 61, 45, 8},
+ {109, 0, 0, TOUCHEXIT | OWNDIALOG, COLBUTTON, (void *)SymFill.color, 55, 61, 25, 10},
+ {200, 204, 201, CHECKED | ISPARENT, GROUPBOX, (void*)" font ", 12, 28, 50, 45},
+ {201, 202, 0, TOUCHEXIT, RADIO1, (void*)"Helvetica", 15, 35, 45, 8},
+ {202, 203, 0, TOUCHEXIT, RADIO1, (void*)"Times", 15, 45, 45, 8},
+ {203, 0, 0, TOUCHEXIT, RADIO1, (void*)"Courier", 15, 55, 45, 8},
+ {204, 0, 205, CHECKED | ISPARENT, GROUPBOX, (void*)" style ", 72, 28, 57, 45},
+ {205, 206, 0, TOUCHEXIT, CHECKBOX, (void*)"bold", 75, 35, 25, 8},
+ {206, 207, 0, TOUCHEXIT, CHECKBOX, (void*)"italic", 75, 45, 25, 8},
+ {207, 0, 0, TOUCHEXIT, CHECKBOX, (void*)"underlined", 75, 55, 25, 8},
+ {250, 251, 0, TOUCHEXIT | CHECKED, RADIO1, (void*)"fixed text:", 10, 30, 45, 8},
+ {251, 252, 0, 0x0L, EDTEXT, text1, 60, 30, 45, 10},
+ {252, 253, 0, TOUCHEXIT, RADIO1, (void*)"from spreadsheet range:", 10, 45, 60, 8},
+ {253, 0, 0, 0x0L, EDTEXT, text2, 20, 55, 100, 10},
+ {300, 301, 0, 0x0L, RTEXT, (void*)"x-value", 5, 30, 45, 8},
+ {301, 302, 0, 0x0L, EDVAL1, &fPos.fx, 55, 30, 45, 10},
+ {302, 303, 0, 0x0L, RTEXT, (void*)"y-value", 5, 50, 45, 8},
+ {303, 0, 0, 0x0L, EDVAL1, &fPos.fy, 55, 50, 45, 10},
+ {401, 402, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[0], 15, 85, 10, 10},
+ {402, 403, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[1], 25, 85, 10, 10},
+ {403, 404, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[2], 35, 85, 10, 10},
+ {404, 405, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[3], 45, 85, 10, 10},
+ {405, 406, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[4], 55, 85, 10, 10},
+ {406, 407, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[5], 65, 85, 10, 10},
+ {407, 408, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[6], 75, 85, 10, 10},
+ {408, 409, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[7], 85, 85, 10, 10},
+ {409, 410, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[8], 95, 85, 10, 10},
+ {410, 411, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[9], 105, 85, 10, 10},
+ {411, 412, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[10], 115, 85, 10, 10},
+ {412, 413, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[11], 15, 95, 10, 10},
+ {413, 414, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[12], 25, 95, 10, 10},
+ {414, 415, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[13], 35, 95, 10, 10},
+ {415, 416, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[14], 45, 95, 10, 10},
+ {416, 0, 0, TOUCHEXIT, SYMRADIO, (void*)&syms[15], 55, 95, 40, 10},
+ {500, 0, 0, LASTOBJ | TOUCHEXIT, SYMBUTT, (void*)&PrevSym, 155, 65, 40, 40}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, tmpType, width, height;
+ DWORD tmpCol, undo_flags = 0L;
+ double tmpVal, o_size, n_size, o_lwidth, n_lwidth;
+ TextDEF textdef;
+ lfPOINT o_pos, n_pos;
+
+ if(!parent) return false;
+ if(!Command(CMD_GETTEXT, (void*)text1, 0L)) sprintf(text1, "text");
+ if(data && data->GetSize(&width, &height)) sprintf(text2, "b1:b%d", height);
+ else sprintf(text2, "(not available)");
+ if((PrevSym = new Symbol(0L, data, 0.0f, 0.0f, type))){
+ PrevSym->SetColor(COL_SYM_LINE, SymLine.color);
+ PrevSym->SetColor(COL_SYM_FILL, SymFill.color);
+ PrevSym->SetSize(SIZE_SYMBOL, size);
+ PrevSym->SetSize(SIZE_SYM_LINE, SymLine.width);
+ PrevSym->Command(CMD_SETTEXT, (void*)text1, 0L);
+ PrevSym->Command(CMD_GETTEXTDEF, &textdef, 0L);
+ PrevSym->Command(CMD_SET_DATAOBJ, (void*)data, 0L);
+ if(Command(CMD_GETTEXTDEF, &textdef, 0L))
+ PrevSym->Command(CMD_SETTEXTDEF, &textdef, 0L);
+ PrevSym->idx = idx;
+ }
+ if(PrevSym && (Dlg = new DlgRoot(SymDlg))) {
+ Dlg->TextFont(201, FONT_HELVETICA);
+ Dlg->TextFont(202, FONT_TIMES);
+ Dlg->TextFont(203, FONT_COURIER);
+ Dlg->TextStyle(205, TXS_BOLD);
+ Dlg->TextStyle(206, TXS_ITALIC);
+ Dlg->TextStyle(207, TXS_UNDERLINE);
+ if(type == SYM_TEXT) Dlg->SetCheck(416, 0L, true);
+ else Dlg->SetCheck(401+type, 0L, true);
+ switch(textdef.Font) {
+ case FONT_TIMES: Dlg->SetCheck(202, 0L, true); break;
+ case FONT_COURIER: Dlg->SetCheck(203, 0L, true); break;
+ default: Dlg->SetCheck(201, 0L, true); break;
+ }
+ if(textdef.Style & TXS_BOLD) Dlg->SetCheck(205, 0L, true);
+ if(textdef.Style & TXS_ITALIC) Dlg->SetCheck(206, 0L, true);
+ if(textdef.Style & TXS_UNDERLINE) Dlg->SetCheck(207, 0L, true);
+ }
+ else return false;
+ if(parent->name) sprintf(TmpTxt, "Symbol of %s", parent->name);
+ else strcpy(TmpTxt, "Symbol properties");
+ if(!(hDlg = CreateDlgWnd(TmpTxt, 50, 50, 430, 260, Dlg, 0x0L)))return false;
+ tmpCol = 0x00c0c0c0L; o_size = size; o_lwidth = SymLine.width;
+ Dlg->GetValue(101, &o_size); Dlg->GetValue(104, &o_lwidth);
+ n_size = o_size; n_lwidth = o_lwidth;
+ o_pos.fx = fPos.fx; o_pos.fy = fPos.fy;
+ if(Dlg->GetValue(301, &tmpVal)) o_pos.fx = tmpVal; n_pos.fx = o_pos.fx;
+ if(Dlg->GetValue(303, &tmpVal)) o_pos.fy = tmpVal; n_pos.fy = o_pos.fy;
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 2:
+ case 1:
+ if(PrevSym->type == SYM_TEXT && Dlg->GetCheck(250)){
+ Dlg->GetText(251, text1);
+ if(PrevSym->Command(CMD_GETTEXT, (void *)text2, 0L) && strcmp(text1, text2)) {
+ PrevSym->Command(CMD_SETTEXT, (void *)text1, 0L);
+ Dlg->DoPlot(NULL);
+ res = -1;
+ }
+ }
+ else if(PrevSym->type == SYM_TEXT && Dlg->GetCheck(252)) {
+ if(Dlg->GetCheck(252) && Dlg->GetText(253, text2))
+ PrevSym->Command(CMD_RANGETEXT, &text2, 0L);
+ }
+ Dlg->GetValue(101, &n_size); Dlg->GetValue(104, &n_lwidth);
+ break;
+ case 7: //the text sheets
+ case 8:
+ Dlg->SetCheck(416, 0L, true);
+ if(PrevSym->type != SYM_TEXT) {
+ PrevSym->type = SYM_TEXT;
+ Dlg->DoPlot(NULL);
+ }
+ res = -1;
+ break;
+ case 201: case 202: case 203: //fonts and styles
+ case 205: case 206: case 207:
+ if(PrevSym->Command(CMD_GETTEXTDEF, &textdef, 0L)) {
+ if(Dlg->GetCheck(202)) textdef.Font = FONT_TIMES;
+ else if(Dlg->GetCheck(203)) textdef.Font = FONT_COURIER;
+ else textdef.Font = FONT_HELVETICA;
+ textdef.Style = TXS_NORMAL;
+ if(Dlg->GetCheck(205)) textdef.Style |= TXS_BOLD;
+ if(Dlg->GetCheck(206)) textdef.Style |= TXS_ITALIC;
+ if(Dlg->GetCheck(207)) textdef.Style |= TXS_UNDERLINE;
+ PrevSym->Command(CMD_SETTEXTDEF, &textdef, 0L);
+ Dlg->DoPlot(NULL);
+ }
+ res = -1;
+ break;
+ case 252: //use spreadsheet text
+ if(!data) Dlg->SetCheck(250, 0L, true);
+ case 250: //use fixed text
+ if(Dlg->GetCheck(250) && Dlg->GetText(251,text1))PrevSym->Command(CMD_SETTEXT, text1, 0L);
+ else if(Dlg->GetCheck(252) && Dlg->GetText(253, text2))
+ PrevSym->Command(CMD_RANGETEXT, text2, 0L);
+ Dlg->DoPlot(NULL);
+ res = -1;
+ break;
+ case 401: case 402: case 403: case 404: //symbol selection
+ case 405: case 406: case 407: case 408:
+ case 409: case 410: case 411: case 412:
+ case 413: case 414: case 415:
+ tmpType = res - 401;
+ case 416: //text symbol
+ if(res == 416) tmpType = SYM_TEXT;
+ PrevSym->type = tmpType;
+ case 107: //line color button
+ if(res == 107 && Dlg->GetColor(107, &tmpCol))
+ PrevSym->SetColor(COL_SYM_LINE, tmpCol);
+ case 109: //fill color button
+ if(res == 109 && Dlg->GetColor(109, &tmpCol))
+ PrevSym->SetColor(COL_SYM_FILL, tmpCol);
+ case 101: //symbol size changed
+ case 104: //line width changed
+ case 500: //preview button
+ if(Dlg->GetValue(101, &tmpVal)) PrevSym->SetSize(SIZE_SYMBOL, tmpVal);
+ if(Dlg->GetValue(104, &tmpVal)) PrevSym->SetSize(SIZE_SYM_LINE, tmpVal);
+ if(PrevSym->type == SYM_TEXT) {
+ if(Dlg->GetCheck(250) && Dlg->GetText(251,text1))PrevSym->Command(CMD_SETTEXT, text1, 0L);
+ else if(Dlg->GetCheck(252) && Dlg->GetText(253, text2))
+ PrevSym->Command(CMD_RANGETEXT, text2, 0L);
+ }
+ Dlg->DoPlot(NULL);
+ res = -1;
+ break;
+ }
+ }while (res < 0);
+ switch (res) {
+ case 1: //accept values for symbol
+ undo_flags = CheckNewFloat(&size, o_size, n_size, parent, undo_flags);
+ undo_flags = CheckNewFloat(&SymLine.width, o_lwidth, n_lwidth, parent, undo_flags);
+ if(Dlg->GetValue(301, &tmpVal)) n_pos.fx = tmpVal;
+ if(Dlg->GetValue(303, &tmpVal)) n_pos.fy = tmpVal;
+ undo_flags = CheckNewLFPoint(&fPos, &o_pos, &n_pos, parent, undo_flags);
+ if(Dlg->GetColor(107, &tmpCol)) undo_flags =
+ CheckNewDword(&SymLine.color, SymLine.color, tmpCol, parent, undo_flags);
+ if(Dlg->GetColor(109, &tmpCol)) undo_flags =
+ CheckNewDword(&SymFill.color, SymFill.color, tmpCol, parent, undo_flags);
+ undo_flags = CheckNewInt(&type, type, PrevSym->type, parent, undo_flags);
+ if(type == SYM_TEXT && PrevSym->Command(CMD_GETTEXTDEF, &textdef, 0L)){
+ if(SymTxt && cmpTextDEF(SymTxt, &textdef)){
+ Undo.TextDef(parent, SymTxt, undo_flags); undo_flags |= UNDO_CONTINUE;
+ }
+ if(PrevSym->Command(CMD_GETTEXT, text1, 0L)) Command(CMD_SETTEXT, text1, 0L);
+ Command(CMD_SETTEXTDEF, &textdef, 0L);
+ }
+ break;
+ case 2: //accept values for all symbols of plot
+ parent->Command(CMD_SAVE_SYMBOLS, 0L, 0L);
+ parent->SetSize(SIZE_SYMBOL, n_size);
+ parent->SetSize(SIZE_SYM_LINE, n_lwidth);
+ if(Dlg->GetColor(107, &tmpCol)) parent->SetColor(COL_SYM_LINE, tmpCol);
+ if(Dlg->GetColor(109, &tmpCol)) parent->SetColor(COL_SYM_FILL, tmpCol);
+ parent->Command(CMD_SYM_TYPE, (void*)(& PrevSym->type), 0L);
+ if(PrevSym->type == SYM_TEXT) {
+ if(Dlg->GetCheck(250) && PrevSym->Command(CMD_GETTEXT, text1, 0L))
+ parent->Command(CMD_SYMTEXT_UNDO, text1, 0L);
+ else if(Dlg->GetCheck(252) && Dlg->GetText(253, text2))
+ parent->Command(CMD_SYM_RANGETEXT, text2, 0L);
+ if(PrevSym->Command(CMD_GETTEXTDEF, &textdef, 0L))
+ parent->Command(CMD_SYMTEXTDEF, &textdef, 0L);
+ }
+ break;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ delete PrevSym;
+ return true;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Bubble properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Bubble::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 50, 10, "Shape & Color"};
+ TabSHEET tab2 = {50, 90, 10, "Scaling"};
+ TabSHEET tab3 = {90, 120, 10, "Edit"};
+ int syms[] = {SYM_CIRCLE, SYM_RECT, SYM_TRIAU, SYM_TRIAD};
+ DlgInfo BubDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to BUBBLE", 130, 10, 60, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 130, 25, 60, 12},
+ {3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 40, 60, 12},
+ {4, 0, 5, CHECKED | ISPARENT, GROUP, NULL, 138, 40, 55, 12},
+ {5, 6, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 120, 100},
+ {6, 7, 200, ISPARENT, SHEET, &tab2, 5, 10, 120, 100},
+ {7, 0, 300, ISPARENT, SHEET, &tab3, 5, 10, 120, 100},
+ {100, 109, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 18, 57, 90, 50},
+ {109, 110, 0, 0x0L, SYMRADIO, (void *)&syms[0], 30, 30, 20, 20},
+ {110, 111, 0, 0x0L, SYMRADIO, (void *)&syms[1], 50, 30, 20, 20},
+ {111, 112, 0, 0x0L, SYMRADIO, (void *)&syms[2], 70, 30, 20, 20},
+ {112, 0, 0, 0x0L, SYMRADIO, (void *)&syms[3], 90, 30, 20, 20},
+ {200, 201, 0, 0x0L, LTEXT, (void*)"Sizes are given as", 10, 30, 110, 8},
+ {201, 202, 210, ISPARENT | CHECKED, GROUP, NULL, 0, 0, 0, 0},
+ {202, 203, 0, 0x0L, LTEXT, (void*)"Proportionality (relative to circle)", 10, 64, 110, 8},
+ {203, 0, 220, ISPARENT | CHECKED, GROUP, NULL, 0, 0, 0, 0},
+ {210, 211, 0, 0x0L, RADIO1, (void *) Units[defs.cUnits].display, 40, 38, 45, 8},
+ {211, 212, 0, 0x0L, RADIO1, (void*)"scaling with X axis", 40, 46, 45, 8},
+ {212, 0, 0, 0x0L, RADIO1, (void*)"scaling with Y axis", 40, 54, 45, 8},
+ {220, 221, 0, 0x0L, RADIO1, (void*)"diameter", 40, 72, 45, 8},
+ {221, 222, 0, 0x0L, RADIO1, (void*)"circumference", 40, 80, 45, 8},
+ {222, 0, 0, 0x0L, RADIO1, (void*)"area", 40, 88, 45, 8},
+ {300, 301, 0, 0x0L, RTEXT, (void*)"x-value", 10, 40, 45, 8},
+ {301, 302, 0, 0x0L, EDVAL1, &fPos.fx, 60, 40, 35, 10},
+ {302, 303, 0, 0x0L, RTEXT, (void*)"y-value", 10, 60, 45, 8},
+ {303, 304, 0, 0x0L, EDVAL1, &fPos.fy, 60, 60, 35, 10},
+ {304, 305, 0, 0x0L, RTEXT, (void*)"size", 10, 80, 45, 8},
+ {305, 0, 0, LASTOBJ, EDVAL1, &fs, 60, 80, 35, 10}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, tmpType;
+ lfPOINT o_pos, n_pos;
+ LineDEF newLine, newFillLine;
+ FillDEF newFill;
+ DWORD undo_flags = 0L;
+ double o_size, n_size;
+ bool bRet = false;
+
+ if(!parent) return false;
+ OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&BubbleLine, 0);
+ OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&BubbleFill, 0);
+ Dlg = new DlgRoot(BubDlg);
+ switch(type & 0x00f) {
+ case BUBBLE_SQUARE: Dlg->SetCheck(110, 0L, true); break;
+ case BUBBLE_UPTRIA: Dlg->SetCheck(111, 0L, true); break;
+ case BUBBLE_DOWNTRIA: Dlg->SetCheck(112, 0L, true); break;
+ default: Dlg->SetCheck(109, 0L, true); break;
+ }
+ switch(type & 0x0f0) {
+ case BUBBLE_XAXIS: Dlg->SetCheck(211, 0L, true); break;
+ case BUBBLE_YAXIS: Dlg->SetCheck(212, 0L, true); break;
+ default: Dlg->SetCheck(210, 0L, true); break;
+ }
+ switch(type & 0xf00) {
+ case BUBBLE_CIRCUM: Dlg->SetCheck(221, 0L, true); break;
+ case BUBBLE_AREA: Dlg->SetCheck(222, 0L, true); break;
+ default: Dlg->SetCheck(220, 0L, true); break;
+ }
+ if(!Dlg->GetValue(301, &o_pos.fx)) o_pos.fx = fPos.fx;
+ if(!Dlg->GetValue(303, &o_pos.fy)) o_pos.fy = fPos.fy;
+ if(!Dlg->GetValue(305, &o_size)) o_size = fs;
+ n_pos.fx = o_pos.fx; n_pos.fy = o_pos.fy; n_size = o_size;
+ if(parent->name) sprintf(TmpTxt, "Bubble of %s", parent->name);
+ else strcpy(TmpTxt, "Bubble properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 390, 260, Dlg, 0x0L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 1: //accept for current bubble only
+ case 2: //accept for plot
+ OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
+ OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&newFill, 0);
+ memcpy(&newFillLine, &BubbleFillLine, sizeof(LineDEF));
+ if(newFill.hatch) memcpy(&newFillLine, newFill.hatch, sizeof(LineDEF));
+ if(Dlg->GetCheck(110)) tmpType = BUBBLE_SQUARE;
+ else if(Dlg->GetCheck(111)) tmpType = BUBBLE_UPTRIA;
+ else if(Dlg->GetCheck(112)) tmpType = BUBBLE_DOWNTRIA;
+ else tmpType = BUBBLE_CIRCLE;
+ if(Dlg->GetCheck(211)) tmpType |= BUBBLE_XAXIS;
+ else if(Dlg->GetCheck(212)) tmpType |= BUBBLE_YAXIS;
+ if(Dlg->GetCheck(221)) tmpType |= BUBBLE_CIRCUM;
+ else if(Dlg->GetCheck(222)) tmpType |= BUBBLE_AREA;
+ break;
+ }
+ }while (res < 0);
+ switch (res) {
+ case 1: //new setting for current bubble only
+ Dlg->GetValue(301, &n_pos.fx); Dlg->GetValue(303, &n_pos.fy);
+ undo_flags = CheckNewLFPoint(&fPos, &o_pos, &n_pos, parent, undo_flags);
+ undo_flags = CheckNewInt(&type, type, tmpType, parent, undo_flags);
+ Dlg->GetValue(305, &n_size);
+ undo_flags = CheckNewFloat(&fs, o_size, n_size, parent, undo_flags);
+ if(cmpLineDEF(&BubbleLine, &newLine)) {
+ Undo.Line(parent, &BubbleLine, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&BubbleLine, &newLine, sizeof(LineDEF));
+ }
+ if(newFill.type && cmpLineDEF(&BubbleFillLine, &newFillLine)) {
+ Undo.Line(parent, &BubbleFillLine, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&BubbleFillLine, &newFillLine, sizeof(LineDEF));
+ }
+ if(cmpFillDEF(&BubbleFill, &newFill)) {
+ Undo.Fill(parent, &BubbleFill, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&BubbleFill, &newFill, sizeof(FillDEF));
+ }
+ BubbleFill.hatch = &BubbleFillLine;
+ if(undo_flags & UNDO_CONTINUE) bRet = true;
+ break;
+ case 2: //accept settings for plot
+ parent->Command(CMD_SAVE_SYMBOLS, 0L, 0L);
+ parent->Command(CMD_BUBBLE_TYPE, (void*)(& tmpType), 0L);
+ parent->Command(CMD_BUBBLE_ATTRIB, (void*)(& tmpType), 0L);
+ parent->Command(CMD_BUBBLE_FILL, (void*)&newFill, 0L);
+ parent->Command(CMD_BUBBLE_LINE, (void*)&newLine, 0L);
+ bRet = true;
+ break;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Bar properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Bar::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 50, 10, "Size & Color"};
+ TabSHEET tab2 = {50, 90, 10, "Baseline"};
+ TabSHEET tab3 = {90, 120, 10, "Edit"};
+ char sTxt1[20], sTxt2[20];
+ DlgInfo BarDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to BAR", 130, 10, 55, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 130, 25, 55, 12},
+ {3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 40, 55, 12},
+ {4, 0, 5, CHECKED | ISPARENT, GROUP, NULL, 138, 40, 55, 12},
+ {5, 6, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 120, 120},
+ {6, 7, 200, ISPARENT, SHEET, &tab2, 5, 10, 120, 120},
+ {7, 0, 300, ISPARENT, SHEET, &tab3, 5, 10, 120, 120},
+ {100, 109, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 18, 30, 90, 50},
+ {109, 110, 0, 0x0L, LTEXT, (void*)"bar width:", 10, 80, 45, 8},
+ {110, 111, 0, 0x0L, RADIO1, (void*)" fixed", 20, 92, 25, 8},
+ {111, 112, 0, 0x0L, EDTEXT, &sTxt1[1], 60, 92, 25, 10},
+ {112, 113, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 87, 92, 20, 8},
+ {113, 114, 0, 0x0L, RADIO1, (void*)" relative", 20, 104, 25, 8},
+ {114, 115, 0, 0x0L, EDTEXT, &sTxt2[1], 60, 104, 25, 10},
+ {115, 0, 0, 0x0L, LTEXT, (void*)"%", 87, 104, 10, 8},
+ {200, 201, 0, TOUCHEXIT, RADIO2, (void*)"vertical bars", 20, 30, 45, 8},
+ {201, 205, 202, CHECKED | ISPARENT, GROUP, NULL, 0, 0, 0, 0},
+ {202, 203, 0, TOUCHEXIT, RADIO1, (void*)"bottom baseline", 30, 40, 35, 8},
+ {203, 204, 0, TOUCHEXIT, RADIO1, (void*)"top", 30, 48, 35, 8},
+ {204, 0, 0, TOUCHEXIT, RADIO1, (void*)"user y =", 30, 56, 35, 8},
+ {205, 206, 0, 0x0L, EDVAL1, &BarBase.fy, 65, 56, 35, 10},
+ {206, 207, 0, TOUCHEXIT, RADIO2, (void*)"horizontal bars", 20, 70, 45, 8},
+ {207, 211, 208, CHECKED | ISPARENT, GROUP, NULL, 0, 0, 0, 0},
+ {208, 209, 0, TOUCHEXIT, RADIO1, (void*)"left baseline", 30, 80, 35, 8},
+ {209, 210, 0, TOUCHEXIT, RADIO1, (void*)"right", 30, 88, 35, 8},
+ {210, 0, 0, TOUCHEXIT, RADIO1, (void*)"user x =", 30, 96, 35, 8},
+ {211, 212, 0, 0x0L, EDVAL1, &BarBase.fx, 65, 96, 35, 10},
+ {212, 0, 0, 0x0L, CHECKBOX, (void*)"bars centered across baseline", 20, 113, 50, 8},
+ {300, 301, 0, 0x0L, RTEXT, (void*)"x-value", 10, 50, 45, 8},
+ {301, 302, 0, 0x0L, EDVAL1, &fPos.fx, 60, 50, 40, 10},
+ {302, 303, 0, 0x0L, RTEXT, (void*)"y-value", 10, 75, 45, 8},
+ {303, 0, 0, LASTOBJ, EDVAL1, &fPos.fy, 60, 75, 40, 10}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ double n_size;
+ int res, tmpType = type;
+ bool bRet = false;
+ LineDEF newLine, newFillLine;
+ FillDEF newFill;
+ DWORD undo_flags = 0L;
+ lfPOINT o_bl, n_bl, o_pos, n_pos;
+
+ if(!parent) return false;
+ OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&BarLine, 0);
+ OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&BarFill, 0);
+ if(type & BAR_RELWIDTH) {
+ WriteNatFloatToBuff(sTxt2, size);
+ WriteNatFloatToBuff(sTxt1, defs.GetSize(SIZE_BAR));
+ }
+ else {
+ WriteNatFloatToBuff(sTxt1, size);
+ strcpy(sTxt2, " 50");
+ }
+ Dlg = new DlgRoot(BarDlg);
+ switch (type & 0xff) {
+ case BAR_VERTB: case BAR_VERTT: case BAR_VERTU:
+ Dlg->SetCheck(200, 0L, true);
+ Dlg->SetCheck(208, 0L, true);
+ switch(type & 0xff) {
+ case BAR_VERTT: Dlg->SetCheck(203, 0L, true); break;
+ case BAR_VERTU: Dlg->SetCheck(204, 0L, true); break;
+ default: Dlg->SetCheck(202, 0L, true); break;
+ }
+ break;
+ case BAR_HORL: case BAR_HORR: case BAR_HORU:
+ Dlg->SetCheck(206, 0L, true);
+ Dlg->SetCheck(202, 0L, true);
+ switch(type & 0xff) {
+ case BAR_HORR: Dlg->SetCheck(209, 0L, true); break;
+ case BAR_HORU: Dlg->SetCheck(210, 0L, true); break;
+ default: Dlg->SetCheck(208, 0L, true); break;
+ }
+ break;
+ }
+ if(type & BAR_RELWIDTH) Dlg->SetCheck(113, 0L, true);
+ else Dlg->SetCheck(110, 0L, true);
+ if(type & BAR_CENTERED) Dlg->SetCheck(212, 0L, true);
+ if(parent && parent->name) sprintf(TmpTxt, "Bar of %s", parent->name);
+ else strcpy(TmpTxt, "Bar properties");
+ if(!Dlg->GetValue(211, &o_bl.fx)) o_bl.fx = BarBase.fx;
+ if(!Dlg->GetValue(205, &o_bl.fy)) o_bl.fy = BarBase.fy;
+ if(!Dlg->GetValue(301, &o_pos.fx)) o_pos.fx = fPos.fx;
+ if(!Dlg->GetValue(303, &o_pos.fy)) o_pos.fy = fPos.fy;
+ n_bl.fx = o_bl.fx; n_bl.fy = o_bl.fy;
+ n_pos.fx = o_pos.fx; n_pos.fy = o_pos.fy;
+ n_size = size;
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 390, 296, Dlg, 0x0L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 202: case 203: case 204:
+ Dlg->SetCheck(200, NULL, true);
+ tmpType = res == 202 ? BAR_VERTB : res == 203 ? BAR_VERTT : BAR_VERTU;
+ res = -1; //continue on radiobutton
+ break;
+ case 208: case 209: case 210:
+ Dlg->SetCheck(206, NULL, true);
+ tmpType = res == 208 ? BAR_HORL : res == 209 ? BAR_HORR : BAR_HORU;
+ res = -1; //continue on radiobutton
+ break;
+ case 200: //group of vertical bars
+ if(Dlg->GetCheck(203)) tmpType = BAR_VERTT;
+ else if(Dlg->GetCheck(204)) tmpType = BAR_VERTU;
+ else tmpType = BAR_VERTB;
+ res = -1;
+ break;
+ case 206: //group of horizontal bars
+ if(Dlg->GetCheck(209)) tmpType = BAR_HORR;
+ else if(Dlg->GetCheck(210)) tmpType = BAR_HORU;
+ else tmpType = BAR_HORL;
+ res = -1;
+ break;
+ case 1:
+ case 2:
+ OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
+ OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&newFill, 0);
+ memcpy(&newFillLine, &HatchLine, sizeof(LineDEF));
+ if(newFill.hatch) memcpy(&newFillLine, newFill.hatch, sizeof(LineDEF));
+ if(Dlg->GetCheck(113)) {
+ tmpType |= BAR_RELWIDTH; Dlg->GetValue(114, &n_size);
+ }
+ else {
+ tmpType &= ~BAR_RELWIDTH; Dlg->GetValue(111, &n_size);
+ }
+ if(Dlg->GetCheck(212))tmpType |= BAR_CENTERED;
+ else tmpType &= ~BAR_CENTERED;
+ Dlg->GetValue(211, &n_bl.fx); Dlg->GetValue(205, &n_bl.fy);
+ Dlg->GetValue(301, &n_pos.fx); Dlg->GetValue(303, &n_pos.fy);
+ break;
+ }
+ }while (res < 0);
+ switch (res) {
+ case 1: //new setting for current bar only
+ undo_flags = CheckNewInt(&type, type, tmpType, parent, undo_flags);
+ undo_flags = CheckNewLFPoint(&BarBase, &o_bl, &n_bl, parent, undo_flags);
+ undo_flags = CheckNewLFPoint(&fPos, &o_pos, &n_pos, parent, undo_flags);
+ if(undo_flags & UNDO_CONTINUE) parent->Command(CMD_MRK_DIRTY, 0L, 0L);
+ undo_flags = CheckNewFloat(&size, size, n_size, parent, undo_flags);
+ if(cmpLineDEF(&BarLine, &newLine)) {
+ Undo.Line(parent, &BarLine, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&BarLine, &newLine, sizeof(LineDEF));
+ }
+ if(newFill.type && cmpLineDEF(&HatchLine, &newFillLine)) {
+ Undo.Line(parent, &HatchLine, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&HatchLine, &newFillLine, sizeof(LineDEF));
+ }
+ if(cmpFillDEF(&BarFill, &newFill)) {
+ Undo.Fill(parent, &BarFill, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&BarFill, &newFill, sizeof(FillDEF));
+ }
+ BarFill.hatch = &HatchLine;
+ if(undo_flags & UNDO_CONTINUE) bRet = true;
+ break;
+ case 2: //new settings to all bars of plot
+ parent->Command(CMD_SAVE_BARS, 0L, 0L);
+ if(parent->Id == GO_PLOTSCATT && parent->parent
+ && parent->parent->Id == GO_STACKBAR){
+ parent->parent->SetSize(SIZE_BAR, n_size);
+ parent->parent->Command(CMD_BAR_TYPE, (void *)(& tmpType), 0L);
+ }
+ else {
+ parent->SetSize(SIZE_BAR, n_size);
+ parent->Command(CMD_BAR_TYPE, (void *)(& tmpType), 0L);
+ }
+ parent->SetColor(COL_BAR_LINE, newLine.color);
+ parent->SetSize(SIZE_BAR_LINE, newLine.width);
+ parent->SetSize(SIZE_YBASE, n_bl.fy);
+ parent->SetSize(SIZE_XBASE, n_bl.fx);
+ parent->Command(CMD_MRK_DIRTY, 0L, 0L);
+ parent->Command(CMD_BAR_TYPE, (void *)(& tmpType), 0L);
+ parent->Command(CMD_BAR_FILL, (void *)&newFill, 0L);
+ bRet = true;
+ break;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Data line properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+DataLine::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 40, 10, "Line"};
+ TabSHEET tab2 = {40, 80, 10, "Style"};
+ DlgInfo LineDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 150, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 150, 25, 45, 12},
+ {3, 0, 4, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
+ {4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 139, 120},
+ {5, 0, 200, ISPARENT, SHEET, &tab2, 5, 10, 139, 120},
+ {100, 0, 0, NOSELECT, ODBUTTON, (void*)OD_linedef, 10, 38, 130, 100},
+ {200, 201, 0, 0x0L, LTEXT, (void*)"select style:", 10, 38, 130, 100},
+ {201, 202, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_LineStyleTempl), 12, 50, 25, 25},
+ {202, 203, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_LineStyleTempl), 37, 50, 25, 25},
+ {203, 204, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_LineStyleTempl), 62, 50, 25, 25},
+ {204, 205, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_LineStyleTempl), 87, 50, 25, 25},
+ {205, 206, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_LineStyleTempl), 112, 50, 25, 25},
+ {206, 207, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_LineStyleTempl), 37, 75, 25, 25},
+ {207, 208, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_LineStyleTempl), 62, 75, 25, 25},
+ {208, 209, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_LineStyleTempl), 87, 75, 25, 25},
+ {209, 0, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_LineStyleTempl), 112, 75, 25, 25},
+ {800, 0, 0, LASTOBJ, NONE, 0L, 0, 0, 0, 0}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, tmpType = type;
+ DWORD undo_flags = 0L;
+ LineDEF newLine;
+ bool bRet = false;
+
+ if(!parent) return false;
+ if(parent->Id == GO_FUNCTION) return parent->PropertyDlg();
+ OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
+ if(!(Dlg = new DlgRoot(LineDlg)))return false;
+ Dlg->SetCheck(201 + (type & 0x7), 0L, true);
+ if(parent && parent->name) sprintf(TmpTxt, "Line of %s", parent->name);
+ else strcpy(TmpTxt, "Line properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 410, 300, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 201: case 202: case 203: case 204: case 205:
+ case 206: case 207: case 208: case 209:
+ tmpType &= ~0x0f;
+ tmpType |= (res-201);
+ res = -1;
+ break;
+ }
+ }while (res < 0);
+ if(res == 1){ //OK pressed
+ OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
+ if(cmpLineDEF(&LineDef, &newLine)) {
+ Undo.Line(parent, &LineDef, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&LineDef, &newLine, sizeof(LineDEF));
+ }
+ undo_flags = CheckNewInt(&type, type, tmpType, parent, undo_flags);
+ if(undo_flags & UNDO_CONTINUE) bRet = true;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Data polygon properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+DataPolygon::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 40, 10, "Polygon"};
+ DlgInfo LineDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 102, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 102, 25, 45, 12},
+ {3, 0, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 90, 75},
+ {100, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)OD_filldef, 8, 30, 90, 50}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ LineDEF newLine, newFillLine;
+ FillDEF newFill;
+ DWORD undo_flags = 0L;
+ int res;
+ bool bRet = false;
+
+ OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
+ OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&pgFill, 0);
+ Dlg = new DlgRoot(LineDlg);
+ if(parent && parent->name) sprintf(TmpTxt, "Polygon of %s", parent->name);
+ else strcpy(TmpTxt, "Polygon properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 310, 204, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ }while (res < 0);
+ if(res == 1){ //OK pressed
+ OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
+ OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&newFill, 0);
+ memcpy(&newFillLine, &pgFillLine, sizeof(LineDEF));
+ if(newFill.hatch) memcpy(&newFillLine, newFill.hatch, sizeof(LineDEF));
+ if(cmpLineDEF(&LineDef, &newLine)) {
+ Undo.Line(parent, &LineDef, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&LineDef, &newLine, sizeof(LineDEF));
+ }
+ if(newFill.type && cmpLineDEF(&pgFillLine, &newFillLine)) {
+ Undo.Line(parent, &pgFillLine, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&pgFillLine, &newFillLine, sizeof(LineDEF));
+ }
+ if(cmpFillDEF(&pgFill, &newFill)) {
+ Undo.Fill(parent, &pgFill, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&pgFill, &newFill, sizeof(FillDEF));
+ }
+ pgFill.hatch = &pgFillLine;
+ if(undo_flags & UNDO_CONTINUE) bRet = true;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Regression line properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+RegLine::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 30, 10, "Line"};
+ TabSHEET tab2 = {30, 60, 10, "Model"};
+ TabSHEET tab3 = {60, 95, 10, "Clipping"};
+ char text1[40], text2[40], text3[40], text4[40], text5[40];
+ DlgInfo LineDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 155, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 155, 25, 45, 12},
+ {3, 0, 4, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
+ {4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 144, 130},
+ {5, 6, 200, ISPARENT, SHEET, &tab2, 5, 10, 144, 130},
+ {6, 0, 300, ISPARENT, SHEET, &tab3, 5, 10, 144, 130},
+ {100, 0, 0, NOSELECT, ODBUTTON, (void*)OD_linedef, 12, 38, 130, 100},
+ {200, 201, 0, TOUCHEXIT, RADIO1, (void*)"y dependent on x", 15, 25, 130, 8},
+ {201, 202, 0, 0x0L, LTEXT, (void*)text1, 25, 33, 120, 8},
+ {202, 203, 0, TOUCHEXIT, RADIO1, (void*)"x dependent on y", 15, 45, 130, 8},
+ {203, 204, 0, 0x0L, LTEXT, (void*)text2, 25, 53, 120, 8},
+ {204, 205, 0, TOUCHEXIT, RADIO1, (void*)"mixed model", 15, 65, 130, 8},
+ {205, 206, 0, 0x0L, LTEXT, (void*)text3, 25, 73, 120, 8},
+ {206, 207, 0, TOUCHEXIT, RADIO1, (void*)"zero crossing (x = 0, y = 0)", 15, 85, 130, 8},
+ {207, 208, 0, 0x0L, LTEXT, (void*)text4, 25, 93, 120, 8},
+ {208, 209, 0, TOUCHEXIT, RADIO1, (void*)"set manually", 15, 105, 130, 8},
+ {209, 210, 0, 0x0L, LTEXT, (void*)text5, 25, 113, 60, 8},
+ {210, 211, 0, 0x0L, RTEXT, (void*)"a =", 92, 113, 10, 8},
+ {211, 212, 0, 0x0L, EDVAL1, &l5.fx, 104, 113, 40, 10},
+ {212, 213, 0, 0x0L, RTEXT, (void*)"b =", 92, 125, 10, 8},
+ {213, 0, 0, 0x0L, EDVAL1, &l5.fy, 104, 125, 40, 10},
+ {300, 301, 0, 0x0L, LTEXT, (void*)"Line length is limited by", 15, 30, 100, 8},
+ {301, 302, 0, TOUCHEXIT, RADIO1, (void*)"data minima and maxima", 15, 45, 100, 8},
+ {302, 303, 0, TOUCHEXIT, RADIO1, (void*)"frame rectangle", 15, 60, 100, 8},
+ {303, 304, 0, TOUCHEXIT, RADIO1, (void*)"user defined values", 15, 75, 100, 8},
+ {304, 305, 0, 0x0L, RTEXT, (void*)"x", 10, 89, 15, 8},
+ {305, 306, 0, 0x0L, EDVAL1, &uclip.Xmin, 27, 89, 40, 10},
+ {306, 307, 0, 0x0L, LTEXT, (void*)"-", 70, 89, 5, 8},
+ {307, 308, 0, 0x0L, EDVAL1, &uclip.Xmax, 76, 89, 40, 10},
+ {308, 309, 0, 0x0L, LTEXT, (void*)"[data]", 119, 89, 15, 8},
+ {309, 310, 0, 0x0L, RTEXT, (void*)"y", 10, 101, 15, 8},
+ {310, 311, 0, 0x0L, EDVAL1, &uclip.Ymin, 27, 101, 40, 10},
+ {311, 312, 0, 0x0L, LTEXT, (void*)"-", 70, 101, 5, 8},
+ {312, 313, 0, 0x0L, EDVAL1, &uclip.Ymax, 76, 101, 40, 10},
+ {313, 0, 0, LASTOBJ, LTEXT, (void*)"[data]", 119, 101, 15, 8}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, tmpType;
+ bool bRet = false;
+ LineDEF newLine;
+ DWORD undo_flags = 0L;
+ lfPOINT o_l5, n_l5;
+ fRECT o_clip, n_clip;
+ char *tx, *ty;
+
+ OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
+ switch(type &0x700) {
+ case 0x100: tx = "log(x)"; break;
+ case 0x200: tx = "(1/x)"; break;
+ case 0x300: tx = "sqrt(x)"; break;
+ default: tx = "x"; break;
+ }
+ switch(type &0x7000) {
+ case 0x1000: ty = "log(y)"; break;
+ case 0x2000: ty = "(1/y)"; break;
+ case 0x3000: ty = "sqrt(y)"; break;
+ default: ty = "y"; break;
+ }
+ sprintf(text1, "%s = %.3lf + %.3lf * %s (n = %ld)", ty, l1.fx, l1.fy, tx, nPoints);
+ sprintf(text2, "%s = %.3lf + %.3lf * %s", ty, l2.fx, l2.fy, tx);
+ sprintf(text3, "%s = %.3lf + %.3lf * %s", ty, l3.fx, l3.fy, tx);
+ sprintf(text4, "%s = %.3lf + %.3lf * %s", ty, l4.fx, l4.fy, tx);
+ sprintf(text5, "%s = a + b * %s", ty, tx);
+ if(!(Dlg = new DlgRoot(LineDlg))) return false;
+ Dlg->Activate(211, false); Dlg->Activate(213, false);
+ switch(type & 0x07) {
+ case 1: Dlg->SetCheck(202, 0L, true); break;
+ case 2: Dlg->SetCheck(204, 0L, true); break;
+ case 3: Dlg->SetCheck(206, 0L, true); break;
+ case 4:
+ Dlg->SetCheck(208, 0L, true);
+ Dlg->Activate(211, true); Dlg->Activate(213, true);
+ break;
+ default: Dlg->SetCheck(200, 0L, true); break;
+ }
+ switch(type & 0x70) {
+ case 0x10: Dlg->SetCheck(302, 0L, true); break;
+ case 0x20: Dlg->SetCheck(303, 0L, true); break;
+ default: Dlg->SetCheck(301, 0L, true); break;
+ }
+ if(0x20 == (type & 0x70)) {
+ Dlg->Activate(305, true); Dlg->Activate(307, true);
+ Dlg->Activate(310, true); Dlg->Activate(312, true);
+ }
+ else {
+ Dlg->Activate(305, false); Dlg->Activate(307, false);
+ Dlg->Activate(310, false); Dlg->Activate(312, false);
+ }
+ if(!Dlg->GetValue(211, &o_l5.fx)) o_l5.fx = l5.fx;
+ if(!Dlg->GetValue(213, &o_l5.fy)) o_l5.fy = l5.fy;
+ n_l5.fx = o_l5.fx; n_l5.fy = o_l5.fy;
+ if(!Dlg->GetValue(305, &o_clip.Xmin)) o_clip.Xmin = uclip.Xmin;
+ if(!Dlg->GetValue(307, &o_clip.Xmax)) o_clip.Xmax = uclip.Xmax;
+ if(!Dlg->GetValue(310, &o_clip.Ymin)) o_clip.Ymin = uclip.Ymin;
+ if(!Dlg->GetValue(312, &o_clip.Ymax)) o_clip.Ymax = uclip.Ymax;
+ memcpy(&n_clip, &o_clip, sizeof(fRECT));
+ if(parent && parent->name) {
+ sprintf(TmpTxt, "Regression line of %s", parent->name);
+ }
+ else strcpy(TmpTxt, "Regression line properties");
+ hDlg = CreateDlgWnd(cp ? TmpTxt :
+ (char*)"Linear regression analysis step 2/2", 50, 50, 420, 320, Dlg, 0x0L);
+ if(!cp) Dlg->SetCheck(5, 0L, true);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 200: case 202: case 204: case 206:
+ Dlg->Activate(211, false); Dlg->Activate(213, false);
+ res = -1;
+ break;
+ case 208:
+ Dlg->Activate(211, true); Dlg->Activate(213, true);
+ res = -1;
+ break;
+ case 301: case 302:
+ Dlg->Activate(305, false); Dlg->Activate(307, false);
+ Dlg->Activate(310, false); Dlg->Activate(312, false);
+ res = -1;
+ break;
+ case 303:
+ Dlg->Activate(305, true); Dlg->Activate(307, true);
+ Dlg->Activate(310, true); Dlg->Activate(312, true);
+ res = -1;
+ break;
+ }
+ }while (res < 0);
+ if(res == 1){ //OK pressed
+ OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
+ if(cmpLineDEF(&LineDef, &newLine)) {
+ Undo.Line(parent, &LineDef, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&LineDef, &newLine, sizeof(LineDEF));
+ }
+ tmpType = type & (~0x77);
+ if(Dlg->GetCheck(202)) tmpType |= 1;
+ else if(Dlg->GetCheck(204)) tmpType |= 2;
+ else if(Dlg->GetCheck(206)) tmpType |= 3;
+ else if(Dlg->GetCheck(208)) tmpType |= 4;
+ if(Dlg->GetCheck(302)) tmpType |= 0x10;
+ else if(Dlg->GetCheck(303)) tmpType |= 0x20;
+ undo_flags = CheckNewInt(&type, type, tmpType, parent, undo_flags);
+ Dlg->GetValue(211, &n_l5.fx); Dlg->GetValue(213, &n_l5.fy);
+ undo_flags = CheckNewLFPoint(&l5, &o_l5, &n_l5, parent, undo_flags);
+ Dlg->GetValue(305, &n_clip.Xmin); Dlg->GetValue(307, &n_clip.Xmax);
+ Dlg->GetValue(310, &n_clip.Ymin); Dlg->GetValue(312, &n_clip.Ymax);
+ undo_flags = CheckNewFloat(&uclip.Xmin, o_clip.Xmin, n_clip.Xmin, parent, undo_flags);
+ undo_flags = CheckNewFloat(&uclip.Xmax, o_clip.Xmax, n_clip.Xmax, parent, undo_flags);
+ undo_flags = CheckNewFloat(&uclip.Ymin, o_clip.Ymin, n_clip.Ymin, parent, undo_flags);
+ undo_flags = CheckNewFloat(&uclip.Ymax, o_clip.Ymax, n_clip.Ymax, parent, undo_flags);
+ if(!cp || (undo_flags & UNDO_CONTINUE)) bRet = true;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// SDellipse properties
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+SDellipse::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 40, 10, "Line"};
+ TabSHEET tab2 = {40, 80, 10, "Details"};
+ DlgInfo ellDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 150, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 150, 25, 45, 12},
+ {3, 0, 4, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
+ {4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 139, 120},
+ {5, 0, 200, ISPARENT, SHEET, &tab2, 5, 10, 139, 120},
+ {100, 0, 0, NOSELECT, ODBUTTON, (void*)OD_linedef, 10, 38, 130, 100},
+ {200, 201, 0, 0x0L, CHECKBOX, (void*)" show regression line", 20, 30, 80, 9},
+ {201, 0, 250, CHECKED, GROUPBOX, (void*)" ellipse ", 10, 55, 129, 70},
+ {250, 251, 0, 0x0L, LTEXT, (void*)"center (means of data)", 25, 60, 60, 8},
+ {251, 252, 0, 0x0L, RTEXT, (void*)"x =", 20, 70, 60, 8},
+ {252, 253, 0, 0x0L, LTEXT, 0L, 82, 70, 30, 8},
+ {253, 254, 0, 0x0L, RTEXT, (void*)"y =", 20, 78, 60, 8},
+ {254, 255, 0, 0x0L, LTEXT, 0L, 82, 78, 30, 8},
+ {255, 256, 0, 0x0L, LTEXT, (void*)"standard deviation (SD)", 25, 90, 60, 8},
+ {256, 257, 0, 0x0L, RTEXT, (void*)"major axis =", 20, 100, 60, 8},
+ {257, 258, 0, 0x0L, LTEXT, 0L, 82, 100, 30, 8},
+ {258, 259, 0, 0x0L, RTEXT, (void*)"minor axis =", 20, 108, 60, 8},
+ {259, 0, 0, LASTOBJ, LTEXT, 0L, 82, 108, 30, 8}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, tmpType;
+ LineDEF newLine;
+ bool bRet = false;
+ DWORD undo_flags = 0L;
+
+ if(!parent) return false;
+ OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
+ if(!(Dlg = new DlgRoot(ellDlg))) return false;
+ if(!(type & 0x10000)) Dlg->SetCheck(200, 0L, true);
+ WriteNatFloatToBuff(TmpTxt, mx); Dlg->SetText(252, TmpTxt+1);
+ WriteNatFloatToBuff(TmpTxt, my); Dlg->SetText(254, TmpTxt+1);
+ strcpy(TmpTxt, "+/-");
+ WriteNatFloatToBuff(TmpTxt+3, sd1); Dlg->SetText(259, TmpTxt);
+ WriteNatFloatToBuff(TmpTxt+3, sd2); Dlg->SetText(257, TmpTxt);
+ tmpType = type;
+ if(parent && parent->name) sprintf(TmpTxt, "SD ellipse of %s", parent->name);
+ else strcpy(TmpTxt, "SD ellipse properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 410, 300, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ }while (res < 0);
+ if(res == 1){ //OK pressed
+ OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
+ if(cmpLineDEF(&LineDef, &newLine)) {
+ Undo.Line(parent, &LineDef, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&LineDef, &newLine, sizeof(LineDEF));
+ }
+ if(Dlg->GetCheck(200)) tmpType &= ~0x10000;
+ else tmpType |= 0x10000;
+ undo_flags = CheckNewInt(&type, type, tmpType, parent, undo_flags);
+ if(undo_flags & UNDO_CONTINUE) bRet = true;
+ }
+ CloseDlgWnd(hDlg); delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Normal error bars properties
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+ErrorBar::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 38, 10, "Error Bar"};
+ TabSHEET tab2 = {38, 65, 10, "Type"};
+ TabSHEET tab3 = {65, 90, 10, "Edit"};
+ DlgInfo ErrDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to ERROR", 100, 10, 57, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 100, 25, 57, 12},
+ {3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 100, 40, 57, 12},
+ {4, 0, 5, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
+ {5, 6, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 90, 100},
+ {6, 7, 200, ISPARENT, SHEET, &tab2, 5, 10, 90, 100},
+ {7, 0, 300, ISPARENT, SHEET, &tab3, 5, 10, 90, 100},
+ {100, 101, 0, 0x0L, RTEXT, (void*)"cap width", 15, 40, 28, 8},
+ {101, 102, 0, 0x0L, EDVAL1, &SizeBar, 46, 40, 25, 10},
+ {102, 103, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 73, 40, 20, 8},
+ {103, 104, 0, 0x0L, RTEXT, (void*)"line width", 15, 55, 28, 8},
+ {104, 105, 0, 0x0L, EDVAL1, &ErrLine.width, 46, 55, 25, 10},
+ {105, 106, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 73, 55, 20, 8},
+ {106, 107, 0, 0x0L, RTEXT, (void*)"line color", 15, 70, 28, 8},
+ {107, 0, 0, OWNDIALOG, COLBUTTON, (void *)ErrLine.color, 46, 70, 25, 10},
+ {200, 0, 500, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {300, 301, 0, 0x0L, RTEXT, (void*)"x-value", 15, 40, 28, 8},
+ {301, 302, 0, 0x0L, EDVAL1, &fPos.fx, 46, 40, 35, 10},
+ {302, 303, 0, 0x0L, RTEXT, (void*)"y-value", 15, 55, 28, 8},
+ {303, 304, 0, 0x0L, EDVAL1, &fPos.fy, 46, 55, 35, 10},
+ {304, 305, 0, 0x0L, RTEXT, (void*)"error", 15, 70, 28, 8},
+ {305, 0, 0, 0x0L, EDVAL1, &ferr, 46, 70, 35, 10},
+ {500, 501, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 12, 40, 25, 25},
+ {501, 502, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 37, 40, 25, 25},
+ {502, 503, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 62, 40, 25, 25},
+ {503, 504, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 12, 65, 25, 25},
+ {504, 505, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 37, 65, 25, 25},
+ {505, 0, 0, LASTOBJ | TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 62, 65, 25, 25}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, tmpType = type;
+ double n_sb, o_sb, n_lw, o_lw, n_err, o_err;
+ lfPOINT n_pos, o_pos;
+ DWORD n_col, undo_flags = 0L;
+ bool bRet = false;
+
+ if(!parent) return false;
+ if(!(Dlg = new DlgRoot(ErrDlg)))return false;
+ Dlg->SetCheck(500 + (type & 0x7), 0L, true);
+ if(!(Dlg->GetValue(101, &o_sb))) o_sb = SizeBar;
+ if(!(Dlg->GetValue(104, &o_lw))) o_lw = ErrLine.width;
+ if(!(Dlg->GetValue(305, &o_err))) o_err = ferr;
+ if(!(Dlg->GetValue(301, &o_pos.fx))) o_pos.fx = fPos.fx;
+ if(!(Dlg->GetValue(303, &o_pos.fy))) o_pos.fy = fPos.fy;
+ n_sb = o_sb; n_lw = o_lw; n_err = o_err; n_pos.fx = o_pos.fx; n_pos.fy = o_pos.fy;
+ if(parent && parent->name) sprintf(TmpTxt, "Error bar of %s", parent->name);
+ else strcpy(TmpTxt, "Error properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 328, 260, Dlg, 0x0L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 500: case 501: case 502:
+ case 503: case 504: case 505:
+ tmpType = res-500;
+ res = -1;
+ break;
+ case 1: //accept for this object
+ case 2: // or all objects of plot
+ Dlg->GetValue(101, &n_sb); Dlg->GetValue(104, &n_lw);
+ Dlg->GetColor(107, &n_col); Dlg->GetValue(305, &n_err);
+ Dlg->GetValue(301, &n_pos.fx); Dlg->GetValue(303, &n_pos.fy);
+ break;
+ }
+ }while (res <0);
+ switch (res) {
+ case 1: //new setting for current error bar only
+ undo_flags = CheckNewFloat(&SizeBar, o_sb, n_sb, parent, undo_flags);
+ undo_flags = CheckNewFloat(&ErrLine.width, o_lw, n_lw, parent, undo_flags);
+ undo_flags = CheckNewDword(&ErrLine.color, ErrLine.color, n_col, parent, undo_flags);
+ undo_flags = CheckNewInt(&type, type, tmpType, parent, undo_flags);
+ undo_flags = CheckNewFloat(&ferr, o_err, n_err, parent, undo_flags);
+ undo_flags = CheckNewLFPoint(&fPos, &o_pos, &n_pos, parent, undo_flags);
+ if(undo_flags & UNDO_CONTINUE) bRet = true;
+ break;
+ case 2: //new settings to all error bars of plot
+ parent->Command(CMD_SAVE_ERRS, 0L, 0L);
+ parent->SetSize(SIZE_ERRBAR, n_sb);
+ parent->SetSize(SIZE_ERRBAR_LINE, n_lw);
+ parent->SetColor(COL_ERROR_LINE, n_col);
+ if(type != tmpType) parent->Command(CMD_MRK_DIRTY, 0L, 0L);
+ bRet = parent->Command(CMD_ERR_TYPE, (void*)(& tmpType), 0L);
+ break;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Arrow properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Arrow::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 29, 10, "Arrow"};
+ TabSHEET tab2 = {29, 59, 10, "Type"};
+ TabSHEET tab3 = {59, 90, 10, "Edit"};
+ DlgInfo ArrowDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, type & ARROW_UNITS ?
+ (void*)"OK" : (void*)"Apply to ARROW", 100, 10, 57, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 100, 25, 57, 12},
+ {3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 100,
+ type & ARROW_UNITS ? 25 : 40, 57, 12},
+ {4, 50, 5, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
+ {5, 6, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 90, 100},
+ {6, 7, 200, ISPARENT, SHEET, &tab2, 5, 10, 90, 100},
+ {7, 0, 300, ISPARENT, SHEET, &tab3, 5, 10, 90, 100},
+ {50, 0, 600, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
+ {100, 101, 0, 0x0L, RTEXT, (void*)"cap width", 15, 40, 28, 8},
+ {101, 102, 0, 0x0L, EDVAL1, &cw, 46, 40, 25, 10},
+ {102, 103, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 73, 40, 20, 8},
+ {103, 104, 0, 0x0L, RTEXT, (void*)"length", 15, 52, 28, 8},
+ {104, 105, 0, 0x0L, EDVAL1, &cl, 46, 52, 25, 10},
+ {105, 106, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 73, 52, 20, 8},
+ {106, 107, 0, 0x0L, RTEXT, (void*)"line width", 15, 70, 28, 8},
+ {107, 108, 0, 0x0L, EDVAL1, &LineDef.width, 46, 70, 25, 10},
+ {108, 109, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 73, 70, 20, 8},
+ {109, 110, 0, 0x0L, RTEXT, (void*)"color", 15, 82, 28, 8},
+ {110, 0, 0, OWNDIALOG, COLBUTTON, (void *)LineDef.color, 46, 82, 25, 10},
+ {200, 201, 0, TOUCHEXIT, RADIO1, (void*)"line only", 15, 40, 60, 8},
+ {201, 202, 0, TOUCHEXIT, RADIO1, (void*)"arrow with lines", 15, 55, 60, 8},
+ {202, 0, 0, TOUCHEXIT, RADIO1, (void*)"filled arrow", 15, 70, 60, 8},
+ {300, 301, 0, 0x0L, RTEXT, (void*)"x-value", 10, 30, 28, 8},
+ {301, 302, 0, 0x0L, EDVAL1, &pos2.fx, 46, 30, 35, 10},
+ {302, 303, 0, 0x0L, RTEXT, (void*)"y-value", 10, 42, 28, 8},
+ {303, 304, 0, 0x0L, EDVAL1, &pos2.fy, 46, 42, 35, 10},
+ {304, 305, 0, 0x0L, RTEXT, (void*)"origin x", 10, 60, 28, 8},
+ {305, 306, 0, 0x0L, EDVAL1, &pos1.fx, 46, 60, 35, 10},
+ {306, 307, 0, 0x0L, RTEXT, (void*)" y", 10, 72, 28, 8},
+ {307, 308, 0, 0x0L, EDVAL1, &pos1.fy, 46, 72, 35, 10},
+ {308, 309, 0, 0x0L, CHECKBOX, (void*)"set common origin to", 16, 85, 70, 8},
+ {309, 0, 0, 0x0L, LTEXT, (void*)"all arrows of plot", 25, 93, 65, 8},
+ {600, 601, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 108, 67, 15, 15},
+ {601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 134, 67, 15, 15},
+ {602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 134, 82, 15, 15},
+ {603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 108, 82, 15, 15}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ lfPOINT o_pos1, o_pos2, n_pos1, n_pos2;
+ double o_cw, o_cl, n_cw, n_cl, o_lw, n_lw;
+ int res, tmptype = type, undo_level = *Undo.pcb;
+ bool bRet = false;
+ DWORD o_col, n_col, undo_flags = 0L;
+
+ if(!parent) return false;
+ if(!(Dlg = new DlgRoot(ArrowDlg))) return false;
+ Dlg->GetValue(301, &o_pos2.fx); Dlg->GetValue(303, &o_pos2.fy);
+ Dlg->GetValue(305, &o_pos1.fx); Dlg->GetValue(307, &o_pos1.fy);
+ Dlg->GetValue(101, &o_cw); Dlg->GetValue(104, &o_cl);
+ Dlg->GetValue(107, &o_lw); Dlg->GetColor(110, &o_col);
+ if(parent->Id == GO_GRAPH || parent->Id == GO_PAGE) Dlg->ShowItem(50, true);
+ switch(type & 0xff) {
+ case ARROW_LINE: Dlg->SetCheck(201, 0L, true); break;
+ case ARROW_TRIANGLE: Dlg->SetCheck(202, 0L, true); break;
+ default: Dlg->SetCheck(200, 0L, true); break;
+ }
+ if(tmptype & ARROW_UNITS){
+ Dlg->ShowItem(2, false);
+ Dlg->ShowItem(308, false); Dlg->ShowItem(309, false);
+ }
+ if(parent && parent->name) sprintf(TmpTxt, "Arrow of %s", parent->name);
+ else strcpy(TmpTxt, "Arrow properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 328, 260, Dlg, 0x0L);
+ do {
+ LoopDlgWnd();
+ res = ExecDrawOrderButt(parent, this, Dlg->GetResult());
+ switch (res) {
+ case 200: tmptype = ARROW_NOCAP; res = -1; break;
+ case 201: tmptype = ARROW_LINE; res = -1; break;
+ case 202: tmptype = ARROW_TRIANGLE; res = -1; break;
+ case 1: case 2:
+ Dlg->GetValue(301, &n_pos2.fx); Dlg->GetValue(303, &n_pos2.fy);
+ Dlg->GetValue(305, &n_pos1.fx); Dlg->GetValue(307, &n_pos1.fy);
+ Dlg->GetValue(101, &n_cw); Dlg->GetValue(104, &n_cl);
+ Dlg->GetValue(107, &n_lw); Dlg->GetColor(110, &n_col);
+ break;
+ }
+ }while (res <0);
+ switch (res) {
+ case 1: //new setting for current arrow
+ if(n_pos1.fx != o_pos1.fx || n_pos1.fy != o_pos1.fy ||
+ n_pos2.fx != o_pos2.fx || n_pos2.fy != o_pos2.fy){
+ Command(CMD_SAVEPOS, 0L, 0L); undo_flags |= UNDO_CONTINUE;
+ memcpy(&pos1, &n_pos1, sizeof(lfPOINT)); memcpy(&pos2, &n_pos2, sizeof(lfPOINT));
+ if(!(type & ARROW_UNITS)) parent->Command(CMD_MRK_DIRTY, 0L, 0L);
+ }
+ if((type & 0xff) != (tmptype & 0xff)){
+ Undo.ValInt(this, &type, undo_flags);
+ type &= ~0xff; type |= (tmptype & 0xff); undo_flags |= UNDO_CONTINUE;
+ }
+ undo_flags = CheckNewFloat(&cw, o_cw, n_cw, this, undo_flags);
+ undo_flags = CheckNewFloat(&cl, o_cl, n_cl, this, undo_flags);
+ undo_flags = CheckNewFloat(&LineDef.width, o_lw, n_lw, this, undo_flags);
+ undo_flags = CheckNewDword(&LineDef.color, o_col, n_col, this, undo_flags);
+ if(undo_flags & UNDO_CONTINUE) bModified = true;
+ bRet = true;
+ break;
+ case 2: //new settings to all arrows of plot
+ if(parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+ parent->Command(CMD_SAVE_ARROWS, 0L, 0L);
+ if(Dlg->GetCheck(308)) parent->Command(CMD_ARROW_ORG, &n_pos1, 0L);
+ parent->SetSize(SIZE_ARROW_LINE, n_lw);
+ parent->SetSize(SIZE_ARROW_CAPWIDTH, n_cw);
+ parent->SetSize(SIZE_ARROW_CAPLENGTH, n_cl);
+ parent->SetColor(COL_ARROW, n_col);
+ parent->Command(CMD_ARROW_TYPE, &tmptype, 0L);
+ bRet = true;
+ }
+ break;
+ case 3: //Cancel
+ if(*Undo.pcb > undo_level) { //restore plot order
+ while(*Undo.pcb > undo_level) Undo.Restore(false, 0L);
+ bRet = true;
+ }
+ break;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Box properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Box::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 50, 10, "Size & Color"};
+ TabSHEET tab2 = {50, 90, 10, "Edit"};
+ char sTxt1[20], sTxt2[20];
+ DlgInfo BoxDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to BOX", 130, 10, 55, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 130, 25, 55, 12},
+ {3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 40, 55, 12},
+ {4, 0, 5, CHECKED | ISPARENT, GROUP, 0L, 138, 40, 55, 12},
+ {5, 6, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 120, 115},
+ {6, 0, 300, ISPARENT, SHEET, &tab2, 5, 10, 120, 115},
+ {100, 105, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 8, 30, 90, 50},
+ {105, 0, 109, CHECKED | ISPARENT, GROUP, 0L, 0, 0, 0, 0},
+ {109, 110, 0, 0x0L, LTEXT, (void*)"bar width:", 10, 80, 45, 8},
+ {110, 111, 0, 0x0L, RADIO1, (void*)" fixed", 20, 92, 25, 8},
+ {111, 112, 0, 0x0L, EDTEXT, &sTxt1[1], 60, 92, 25, 10},
+ {112, 113, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 87, 92, 20, 8},
+ {113, 114, 0, 0x0L, RADIO1, (void*)" relative", 20, 104, 25, 8},
+ {114, 115, 0, 0x0L, EDTEXT, &sTxt2[1], 60, 104, 25, 10},
+ {115, 0, 0, 0x0L, LTEXT, (void*)"%", 87, 104, 10, 8},
+ {300, 301, 0, 0x0L, RTEXT, (void*)"point 1 x", 15, 40, 28, 8},
+ {301, 302, 0, 0x0L, EDVAL1, &pos1.fx, 46, 40, 35, 10},
+ {302, 303, 0, 0x0L, RTEXT, (void*)"y", 15, 52, 28, 8},
+ {303, 304, 0, 0x0L, EDVAL1, &pos1.fy, 46, 52, 35, 10},
+ {304, 305, 0, 0x0L, RTEXT, (void*)"point 2 x", 15, 70, 28, 8},
+ {305, 306, 0, 0x0L, EDVAL1, &pos2.fx, 46, 70, 35, 10},
+ {306, 307, 0, 0x0L, RTEXT, (void*)"y", 15, 82, 28, 8},
+ {307, 308, 0, 0x0L, EDVAL1, &pos2.fy, 46, 82, 35, 10},
+ {308, 309, 0, HIDDEN, RTEXT, (void*)"box width", 15, 100, 28, 8},
+ {309, 0, 0, HIDDEN | LASTOBJ, EDVAL1, &size, 46, 100, 35, 10},
+ };
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, tmpType = type;
+ FillDEF newFill;
+ LineDEF newLine, newHatchLine;
+ DWORD undo_flags = 0L;
+ lfPOINT n_pos;
+ double tmpVal, o_size, n_size;
+ bool bRet = false;
+ GraphObj *ppar = parent;
+
+ if(!parent) return false;
+ memcpy(&newHatchLine, &Hatchline, sizeof(LineDEF));
+ OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&Outline, 0);
+ OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&Fill, 0);
+ if(type & BAR_RELWIDTH) {
+ WriteNatFloatToBuff(sTxt2, size);
+ WriteNatFloatToBuff(sTxt1, defs.GetSize(SIZE_BAR));
+ }
+ else {
+ WriteNatFloatToBuff(sTxt1, size);
+ strcpy(sTxt2, " 50");
+ }
+ Dlg = new DlgRoot(BoxDlg);
+ if(type & BAR_WIDTHDATA) {
+ Dlg->ShowItem(105, false);
+ Dlg->ShowItem(308, true); Dlg->ShowItem(309, true);
+ }
+ if(type & BAR_RELWIDTH) Dlg->SetCheck(113, 0L, true);
+ else Dlg->SetCheck(110, 0L, true);
+ if(parent && parent->name) sprintf(TmpTxt, "Box of %s", parent->name);
+ else strcpy(TmpTxt, "Box properties");
+ Dlg->GetValue(309, &o_size);
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 390, 290, Dlg, 0x0L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 1: //accept for this object
+ case 2: // or all objects of plot
+ OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
+ OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&newFill, 0);
+ if(newFill.hatch) memcpy(&newHatchLine, newFill.hatch, sizeof(LineDEF));
+ newFill.hatch = &newHatchLine;
+ if(type & BAR_WIDTHDATA) Dlg->GetValue(309, &size);
+ else {
+ if(Dlg->GetCheck(113)) {
+ tmpType |= BAR_RELWIDTH;
+ Dlg->GetValue(114, &n_size);
+ }
+ else {
+ tmpType &= ~BAR_RELWIDTH;
+ Dlg->GetValue(111, &n_size);
+ }
+ }
+ break;
+ }
+ }while (res < 0);
+ switch (res) {
+ case 1: //new setting for current box
+ if(cmpLineDEF(&Outline, &newLine)) {
+ Undo.Line(parent, &Outline, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&Outline, &newLine, sizeof(LineDEF));
+ }
+ if(newFill.type && cmpLineDEF(&Hatchline, &newHatchLine)) {
+ Undo.Line(parent, &Hatchline, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&Hatchline, &newHatchLine, sizeof(LineDEF));
+ }
+ if(cmpFillDEF(&Fill, &newFill)) {
+ Undo.Fill(parent, &Fill, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&Fill, &newFill, sizeof(FillDEF));
+ }
+ Fill.hatch = &Hatchline;
+ if(Dlg->GetValue(301, &tmpVal)) n_pos.fx = tmpVal;
+ else n_pos.fx = pos1.fx;
+ if(Dlg->GetValue(303, &tmpVal)) n_pos.fy = tmpVal;
+ else n_pos.fy = pos1.fy;
+ undo_flags = CheckNewLFPoint(&pos1, &pos1, &n_pos, parent, undo_flags);
+ if(Dlg->GetValue(305, &tmpVal)) n_pos.fx = tmpVal;
+ else n_pos.fx = pos2.fx;
+ if(Dlg->GetValue(307, &tmpVal)) n_pos.fy = tmpVal;
+ else n_pos.fy = pos2.fy;
+ undo_flags = CheckNewLFPoint(&pos2, &pos2, &n_pos, parent, undo_flags);
+ undo_flags = CheckNewFloat(&size, o_size, n_size, parent, undo_flags);
+ if(undo_flags & UNDO_CONTINUE) bRet = true;
+ break;
+ case 2: //new settings to all boxes of plot
+ if(type != tmpType || Outline.width != newLine.width || o_size != n_size) {
+ Undo.ValInt(this, &type, 0L); //dummy: all following have UNDO_CONTINUE
+ undo_flags |= UNDO_CONTINUE;
+ if(parent->parent && parent->parent->Id == GO_STACKBAR) ppar = parent->parent;
+ }
+ else if(newLine.color != Outline.color || cmpFillDEF(&Fill, &newFill)) {
+ Undo.ValInt(this, &type, 0L); //dummy: all following have UNDO_CONTINUE
+ }
+ ppar->Command(CMD_SAVE_BARS_CONT, 0L, 0L);
+ ppar->Command(CMD_BOX_TYPE, (void*)(& tmpType), 0L);
+ ppar->SetSize(SIZE_BOX_LINE, newLine.width);
+ ppar->SetSize(SIZE_BOX, n_size);
+ parent->SetColor(COL_BOX_LINE, newLine.color);
+ parent->Command(CMD_BOX_FILL, &newFill, 0L);
+ bRet = true;
+ break;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Whisker properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Whisker::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 38, 10, "Whisker"};
+ TabSHEET tab2 = {65, 90, 10, "Edit"};
+ TabSHEET tab3 = {38, 65, 10, "Style"};
+ DlgInfo ErrDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to WHISKER", 100, 10, 64, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 100, 25, 64, 12},
+ {3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 100, 40, 64, 12},
+ {4, 0, 5, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
+ {5, 6, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 90, 100},
+ {6, 7, 500, ISPARENT, SHEET, &tab3, 5, 10, 90, 100},
+ {7, 0, 300, ISPARENT, SHEET, &tab2, 5, 10, 90, 100},
+ {100, 101, 0, 0x0L, RTEXT, (void*)"cap width", 15, 40, 28, 8},
+ {101, 102, 0, 0x0L, EDVAL1, &size, 46, 40, 25, 10},
+ {102, 103, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 73, 40, 20, 8},
+ {103, 104, 0, 0x0L, RTEXT, (void*)"line width", 15, 55, 28, 8},
+ {104, 105, 0, 0x0L, EDVAL1, &LineDef.width, 46, 55, 25, 10},
+ {105, 106, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 73, 55, 20, 8},
+ {106, 107, 0, 0x0L, RTEXT, (void*)"line color", 15, 70, 28, 8},
+ {107, 0, 0, OWNDIALOG, COLBUTTON, (void *)LineDef.color, 46, 70, 25, 10},
+ {300, 301, 0, 0x0L, RTEXT, (void*)"point 1 x", 15, 40, 28, 8},
+ {301, 302, 0, 0x0L, EDVAL1, &pos1.fx, 46, 40, 35, 10},
+ {302, 303, 0, 0x0L, RTEXT, (void*)"y", 15, 52, 28, 8},
+ {303, 304, 0, 0x0L, EDVAL1, &pos1.fy, 46, 52, 35, 10},
+ {304, 305, 0, 0x0L, RTEXT, (void*)"point 2 x", 15, 70, 28, 8},
+ {305, 306, 0, 0x0L, EDVAL1, &pos2.fx, 46, 70, 35, 10},
+ {306, 307, 0, 0x0L, RTEXT, (void*)"y", 15, 82, 28, 8},
+ {307, 0, 0, 0x0L, EDVAL1, &pos2.fy, 46, 82, 35, 10},
+ {500, 501, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_WhiskerTempl),32,40,18,18},
+ {501, 502, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_WhiskerTempl), 14, 40, 18, 18},
+ {502, 503, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_WhiskerTempl), 50, 40, 18, 18},
+ {503, 504, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_WhiskerTempl), 68, 40, 18, 18},
+ {504, 0, 0, LASTOBJ, LTEXT, (void*)"select style:", 14, 30, 30, 9}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, tmp_type;
+ DWORD undo_flags = 0L, n_col = LineDef.color;
+ lfPOINT n_pos;
+ double tmpVal, o_size, n_size, o_lw, n_lw;
+ bool bRet = false;
+
+ if(!parent) return false;
+ tmp_type = type;
+ Dlg = new DlgRoot(ErrDlg);
+ Dlg->SetCheck(500 + (tmp_type & 0x03), 0L, true);
+ Dlg->GetValue(101, &o_size); Dlg->GetValue(104, &o_lw);
+ if(parent && parent->name) sprintf(TmpTxt, "Whisker of %s", parent->name);
+ else strcpy(TmpTxt, "Whisker properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 339, 260, Dlg, 0x0L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 500: case 501: case 502: case 503:
+ tmp_type &= ~0x0f; tmp_type |= (res-500); res = -1;
+ break;
+ case 1: //accept for this object
+ case 2: // or all objects of plot
+ Dlg->GetValue(101, &n_size); Dlg->GetValue(104, &n_lw);
+ Dlg->GetColor(107, &n_col);
+ break;
+ }
+ }while (res <0);
+ switch (res) {
+ case 1: //new setting for current whisker
+ if(Dlg->GetValue(301, &tmpVal)) n_pos.fx = tmpVal;
+ else n_pos.fx = pos1.fx;
+ if(Dlg->GetValue(303, &tmpVal)) n_pos.fy = tmpVal;
+ else n_pos.fy = pos1.fy;
+ undo_flags = CheckNewLFPoint(&pos1, &pos1, &n_pos, parent, undo_flags);
+ if(Dlg->GetValue(305, &tmpVal)) n_pos.fx = tmpVal;
+ else n_pos.fx = pos2.fx;
+ if(Dlg->GetValue(307, &tmpVal)) n_pos.fy = tmpVal;
+ else n_pos.fy = pos2.fy;
+ undo_flags = CheckNewLFPoint(&pos2, &pos2, &n_pos, parent, undo_flags);
+ undo_flags = CheckNewFloat(&size, o_size, n_size, parent, undo_flags);
+ undo_flags = CheckNewInt(&type, type, tmp_type, parent, undo_flags);
+ undo_flags = CheckNewFloat(&LineDef.width, o_lw, n_lw, parent, undo_flags);
+ undo_flags = CheckNewDword(&LineDef.color, LineDef.color, n_col, parent, undo_flags);
+ if(undo_flags & UNDO_CONTINUE) bRet = true;
+ break;
+ case 2: //new settings to all whiskers of plot
+ if(o_size == n_size && type == tmp_type && o_lw == n_lw
+ && n_col == LineDef.color) break;
+ parent->Command(CMD_SAVE_ERRS, 0L, 0L);
+ parent->SetSize(SIZE_WHISKER, n_size);
+ parent->SetSize(SIZE_WHISKER_LINE, n_lw);
+ parent->SetColor(COL_WHISKER, n_col);
+ parent->Command(CMD_WHISKER_STYLE, &tmp_type, 0L);
+ bRet = true;
+ break;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Drop line properties
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+DropLine::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 21, 10, "Line"};
+ TabSHEET tab2 = {21, 42, 10, "Edit"};
+ DlgInfo LineDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to LINE", 150, 10, 50, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 150, 25, 50, 12},
+ {3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 150, 40, 50, 12},
+ {4, 300, 10, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
+ {10, 11, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 139, 120},
+ {11, 0, 200, ISPARENT, SHEET, &tab2, 5, 10, 139, 120},
+ {100, 0, 0, NOSELECT, ODBUTTON, (void*)OD_linedef, 10, 38, 130, 100},
+ {200, 201, 0, 0x0L, RTEXT, (void*)"x-value", 35, 40, 28, 8},
+ {201, 202, 0, 0x0L, EDVAL1, &fPos.fx, 76, 40, 35, 10},
+ {202, 203, 0, 0x0L, RTEXT, (void*)"y-value", 35, 52, 28, 8},
+ {203, 204, 0, 0x0L, EDVAL1, &fPos.fy, 76, 52, 35, 10},
+ {204, 0, 250, CHECKED | ISPARENT, GROUPBOX, (void*)" Shape ", 10, 70, 129, 50},
+ {250, 251, 0, 0x0L, RTEXT, (void*)"line to:", 15, 80, 28, 8},
+ {251, 252, 0, 0x0L, CHECKBOX, (void*)"left", 46, 80, 35, 8},
+ {252, 253, 0, 0x0L, CHECKBOX, (void*)"right", 46, 90, 35, 8},
+ {253, 254, 0, 0x0L, CHECKBOX, (void*)"y-axis", 46, 100, 35, 8},
+ {254, 255, 0, 0x0L, CHECKBOX, (void*)"top", 86, 80, 35, 8},
+ {255, 256, 0, 0x0L, CHECKBOX, (void*)"bottom", 86, 90, 35, 8},
+ {256, 0, 0, LASTOBJ, CHECKBOX, (void*)"x-axis", 86, 100, 35, 8}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, tmptype;
+ bool bRet = false;
+ LineDEF newLine;
+ DWORD undo_flags = 0L;
+ lfPOINT o_pos, n_pos;
+
+ if(!parent) return false;
+ OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
+ Dlg = new DlgRoot(LineDlg);
+ Dlg->SetCheck(251, 0L, type & DL_LEFT ? true : false);
+ Dlg->SetCheck(252, 0L, type & DL_RIGHT ? true : false);
+ Dlg->SetCheck(253, 0L, type & DL_YAXIS ? true : false);
+ Dlg->SetCheck(254, 0L, type & DL_TOP ? true : false);
+ Dlg->SetCheck(255, 0L, type & DL_BOTTOM ? true : false);
+ Dlg->SetCheck(256, 0L, type & DL_XAXIS ? true : false);
+ Dlg->GetValue(201, &o_pos.fx); Dlg->GetValue(203, &o_pos.fy);
+ if(parent->name) sprintf(TmpTxt, "Dropline of %s", parent->name);
+ else strcpy(TmpTxt, "Dropline properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 415, 300, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 1: //this line
+ case 2: //all lines of plot
+ tmptype = 0;
+ if(Dlg->GetCheck(251)) tmptype |= DL_LEFT;
+ if(Dlg->GetCheck(252)) tmptype |= DL_RIGHT;
+ if(Dlg->GetCheck(253)) tmptype |= DL_YAXIS;
+ if(Dlg->GetCheck(254)) tmptype |= DL_TOP;
+ if(Dlg->GetCheck(255)) tmptype |= DL_BOTTOM;
+ if(Dlg->GetCheck(256)) tmptype |= DL_XAXIS;
+ OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
+ break;
+ }
+ }while (res < 0);
+ if(res == 1){ //Apply to line
+ if(cmpLineDEF(&LineDef, &newLine)) {
+ Undo.Line(this, &LineDef, undo_flags);
+ memcpy(&LineDef, &newLine, sizeof(LineDEF));
+ undo_flags |= UNDO_CONTINUE;
+ }
+ Dlg->GetValue(201, &n_pos.fx); Dlg->GetValue(203, &n_pos.fy);
+ undo_flags = CheckNewLFPoint(&fPos, &o_pos, &n_pos, this, undo_flags);
+ undo_flags = CheckNewInt(&type, type, tmptype, this, undo_flags);
+ if (undo_flags & UNDO_CONTINUE) bModified = true;
+ bRet = true;
+ }
+ else if(res == 2) { //Apply to plot
+ if(cmpLineDEF(&LineDef, &newLine) || type != tmptype) {
+ parent->Command(CMD_SAVE_DROPLINES, 0L, 0L);
+ if(cmpLineDEF(&LineDef, &newLine)) parent->Command(CMD_DL_LINE, (void*)&newLine, 0L);
+ if(type != tmptype) parent->Command(CMD_DL_TYPE, (void*)(&tmptype), 0L);
+ bRet = true;
+ }
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Drop line properties: DropLine 3D
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+DropLine3D::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 21, 10, "Line"};
+ TabSHEET tab2 = {21, 42, 10, "Edit"};
+ DlgInfo LineDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to LINE", 150, 10, 50, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 150, 25, 50, 12},
+ {3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 150, 40, 50, 12},
+ {4, 300, 10, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
+ {10, 11, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 139, 120},
+ {11, 0, 200, ISPARENT, SHEET, &tab2, 5, 10, 139, 120},
+ {100, 0, 0, NOSELECT, ODBUTTON, (void*)OD_linedef, 10, 38, 130, 100},
+ {200, 201, 0, 0x0L, RTEXT, (void*)"x-value", 35, 30, 28, 8},
+ {201, 202, 0, 0x0L, EDVAL1, &fPos.fx, 76, 30, 35, 10},
+ {202, 203, 0, 0x0L, RTEXT, (void*)"y-value", 35, 42, 28, 8},
+ {203, 204, 0, 0x0L, EDVAL1, &fPos.fy, 76, 42, 35, 10},
+ {204, 205, 0, 0x0L, RTEXT, (void*)"z-value", 35, 54, 28, 8},
+ {205, 240, 0, 0x0L, EDVAL1, &fPos.fz, 76, 54, 35, 10},
+ {240, 0, 250, CHECKED | ISPARENT, GROUPBOX, (void*)" Shape ", 10, 70, 129, 50},
+ {250, 251, 0, 0x0L, RTEXT, (void*)"line to:", 15, 80, 28, 8},
+ {251, 252, 0, 0x0L, CHECKBOX, (void*)"bottom", 46, 80, 35, 8},
+ {252, 253, 0, 0x0L, CHECKBOX, (void*)"top", 86, 80, 35, 8},
+ {253, 254, 0, 0x0L, CHECKBOX, (void*)"back", 46, 90, 35, 8},
+ {254, 255, 0, 0x0L, CHECKBOX, (void*)"front", 86, 90, 35, 8},
+ {255, 256, 0, 0x0L, CHECKBOX, (void*)"left", 46, 100, 35, 8},
+ {256, 0, 0, LASTOBJ, CHECKBOX, (void*)"right", 86, 100, 35, 8}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, tmptype, i;
+ bool bRet = false;
+ LineDEF newLine;
+ DWORD undo_flags = 0L;
+ fPOINT3D o_pos, n_pos;
+
+ if(!parent) return false;
+ OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
+ Dlg = new DlgRoot(LineDlg);
+ for(i = 0; i < 6; i++) {
+ Dlg->SetCheck(251+i, 0L, (type & (1<<i)) ? true : false);
+ }
+ Dlg->GetValue(201, &o_pos.fx); Dlg->GetValue(203, &o_pos.fy);
+ Dlg->GetValue(205, &o_pos.fz);
+ if(parent->name) sprintf(TmpTxt, "Dropline of %s", parent->name);
+ else strcpy(TmpTxt, "Dropline properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 415, 300, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 1: //this line
+ case 2: //all lines of plot
+ OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
+ for(i = tmptype = 0; i < 6; i++) {
+ tmptype |= Dlg->GetCheck(251+i) ? 1<<i : 0;
+ }
+ break;
+ }
+ }while (res < 0);
+ if(res == 1){ //Apply to line
+ if(cmpLineDEF(&Line, &newLine)) {
+ Undo.Line(this, &Line, undo_flags);
+ memcpy(&Line, &newLine, sizeof(LineDEF));
+ undo_flags |= UNDO_CONTINUE;
+ }
+ Dlg->GetValue(201, &n_pos.fx); Dlg->GetValue(203, &n_pos.fy);
+ Dlg->GetValue(205, &n_pos.fz);
+ if(n_pos.fx != o_pos.fx || n_pos.fy != o_pos.fy || n_pos.fz != o_pos.fz) {
+ Undo.ValLFP3D(this, &fPos, undo_flags);
+ memcpy(&fPos, &n_pos, sizeof(fPOINT3D));
+ undo_flags |= UNDO_CONTINUE;
+ }
+ undo_flags = CheckNewInt(&type, type, tmptype, this, undo_flags);
+ if (undo_flags & UNDO_CONTINUE) bModified = true;
+ bRet = true;
+ }
+ else if(res == 2) { //Apply to plot
+ if(cmpLineDEF(&Line, &newLine) || type != tmptype) {
+ parent->Command(CMD_SAVE_DROPLINES, 0L, 0L);
+ if(cmpLineDEF(&Line, &newLine)) parent->Command(CMD_DL_LINE, (void*)&newLine, 0L);
+ if(type != tmptype) parent->Command(CMD_DL_TYPE, (void*)(&tmptype), 0L);
+ bRet = true;
+ }
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// sphere (ball) properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Sphere::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 22, 10, "Ball"};
+ TabSHEET tab2 = {22, 45, 10, "Edit"};
+ FillDEF newFill;
+ char *type_text[] = {Units[defs.cUnits].display, "[x-data]", "[y-data]", "[z-data]"};
+ DlgInfo BallDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to BALL", 110, 10, 50, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 110, 25, 50, 12},
+ {3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 110, 40, 50, 12},
+ {4, 0, 10, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
+ {10, 11, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 100, 80},
+ {11, 0, 200, ISPARENT, SHEET, &tab2, 5, 10, 100, 80},
+ {100, 101, 0, 0x0L, RTEXT, (void*)"ball size", 15, 35, 28, 8},
+ {101, 102, 0, 0x0L, EDVAL1, &size, 46, 35, 25, 10},
+ {102, 103, 0, 0x0L, LTEXT, (void*)type_text[type], 73, 35, 15, 8},
+ {103, 104, 0, 0x0L, RTEXT, (void*)"line width", 15, 47, 28, 8},
+ {104, 105, 0, 0x0L, EDVAL1, &Line.width, 46, 47, 25, 10},
+ {105, 106, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 73, 47, 15, 8},
+ {106, 107, 0, 0x0L, RTEXT, (void*)"line color", 15, 59, 28, 8},
+ {107, 108, 0, OWNDIALOG, COLBUTTON, (void *)Line.color, 46, 59, 25, 10},
+ {108, 109, 0, 0x0L, RTEXT, (void*)"fill color", 15, 71, 28, 8},
+ {109, 0, 0, OWNDIALOG, SHADE3D, &newFill, 46, 71, 25, 10},
+ {200, 201, 0, 0x0L, RTEXT, (void*)"x-value", 15, 35, 28, 8},
+ {201, 202, 0, 0x0L, EDVAL1, &fPos.fx, 46, 35, 35, 10},
+ {202, 203, 0, 0x0L, RTEXT, (void*)"y-value", 15, 47, 28, 8},
+ {203, 204, 0, 0x0L, EDVAL1, &fPos.fy, 46, 47, 35, 10},
+ {204, 205, 0, 0x0L, RTEXT, (void*)"z-value", 15, 59, 28, 8},
+ {205, 0, 0, LASTOBJ, EDVAL1, &fPos.fz, 46, 59, 35, 10}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res;
+ bool bRet = false, bContinue = false;
+ fPOINT3D n_pos, o_pos;
+ DWORD new_lcolor = Line.color, undo_flags = 0L;
+ double o_size, n_size, o_lsize, n_lsize;
+
+ if(!parent) return false;
+ memcpy(&newFill, &Fill, sizeof(FillDEF));
+ Dlg = new DlgRoot(BallDlg);
+ Dlg->GetValue(201, &o_pos.fx); Dlg->GetValue(203, &o_pos.fy);
+ Dlg->GetValue(205, &o_pos.fz); Dlg->GetValue(101, &o_size);
+ Dlg->GetValue(104, &o_lsize);
+ if(parent->name) sprintf(TmpTxt, "Ball of %s", parent->name);
+ else strcpy(TmpTxt, "Ball properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 335, 216, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 0:
+ if(bContinue) res = -1;
+ bContinue = false;
+ break;
+ case 1: case 2:
+ Dlg->GetColor(107, &new_lcolor); Dlg->GetValue(101, &n_size);
+ Dlg->GetValue(104, &n_lsize);
+ break;
+ case 109:
+ Dlg->DoPlot(0L);
+ bContinue = true;
+ break;
+ }
+ }while (res < 0);
+ if(res == 1){
+ Dlg->GetValue(201, &n_pos.fx); Dlg->GetValue(203, &n_pos.fy);
+ Dlg->GetValue(205, &n_pos.fz);
+ if(n_pos.fx != o_pos.fx || n_pos.fy != o_pos.fy || n_pos.fz != o_pos.fz) {
+ Undo.ValLFP3D(this, &fPos, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&fPos, &n_pos, sizeof(fPOINT3D)); parent->Command(CMD_MRK_DIRTY, 0L, 0L);
+ }
+ undo_flags = CheckNewFloat(&size, o_size, n_size, this, undo_flags);
+ undo_flags = CheckNewFloat(&Line.width, o_lsize, n_lsize, this, undo_flags);
+ undo_flags = CheckNewDword(&Line.color, Line.color, new_lcolor, this, undo_flags);
+ undo_flags = CheckNewDword(&Fill.color, Fill.color, newFill.color, this, undo_flags);
+ undo_flags = CheckNewDword(&Fill.color2, Fill.color2, newFill.color2, this, undo_flags);
+ undo_flags = CheckNewInt(&Fill.type, Fill.type, newFill.type, this, undo_flags);
+ if(undo_flags & UNDO_CONTINUE) bRet = bModified = true;
+ }
+ else if(res == 2) {
+ if(cmpFillDEF(&Fill, &newFill) || n_size != o_size || n_lsize != o_lsize ||
+ new_lcolor != Line.color) {
+ parent->Command(CMD_SAVE_SYMBOLS, 0L, 0L);
+ if(cmpFillDEF(&Fill, &newFill)) parent->Command(CMD_SYM_FILL, &newFill, 0L);
+ if(n_size != o_size) parent->SetSize(SIZE_SYMBOL, n_size);
+ if(n_lsize != o_lsize) parent->SetSize(SIZE_SYM_LINE, n_lsize);
+ if(new_lcolor != Line.color) parent->SetColor(COL_SYM_LINE, new_lcolor);
+ bRet = true;
+ }
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// properties of 3D plane
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Plane3D::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 27, 10, "Plane"};
+ double rb_width = 0.0, rb_z = 0.0;
+ FillDEF newFill;
+ DlgInfo PlaneDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to PLANE", 115, 10, 55, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 115, 25, 55, 12},
+ {3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 115, 40, 55, 12},
+ {4, 0, 10, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
+ {10, 0, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 105, 85},
+ {100, 101, 0, 0x0L, RTEXT, (void*)"line width", 15, 30, 36, 8},
+ {101, 102, 0, 0x0L, EDVAL1, &Line.width, 53, 30, 25, 10},
+ {102, 103, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 80, 30, 15, 8},
+ {103, 104, 0, 0x0L, RTEXT, (void*)"line color", 15, 42, 36, 8},
+ {104, 105, 0, OWNDIALOG, COLBUTTON, (void *)Line.color, 53, 42, 25, 10},
+ {105, 106, 0, 0x0L, RTEXT, (void*)"fill color", 15, 54, 36, 8},
+ {106, 200, 0, OWNDIALOG, SHADE3D, &newFill, 53, 54, 25, 10},
+ {200, 0, 201, CHECKED, GROUP, NULL, 0, 0, 0, 0},
+ {201, 202, 0, 0x0L, RTEXT, (void*)"ribbon width", 15, 66, 36, 8},
+ {202, 203, 0, 0x0L, INCDECVAL1, &rb_width, 53, 66, 25, 10},
+ {203, 204, 0, 0x0L, LTEXT, (void*)"%", 80, 66, 5, 8},
+ {204, 205, 0, 0x0L, RTEXT, (void*)"ribbon pos.", 15, 78, 36, 8},
+ {205, 206, 0, 0x0L, EDVAL1, &rb_z, 53, 78, 25, 10},
+ {206, 0, 0, 0x0L, LTEXT, (void*)"[z-data]", 80, 78, 40, 8},
+ {800, 0, 0, LASTOBJ, 0L, 0, 0, 0, 0}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res;
+ bool bRet = false;
+ DWORD new_lcolor = Line.color, undo_flags = 0L;
+ double o_lsize, n_lsize, o_rbw, n_rbw, o_rbz, n_rbz;
+
+ if(!parent) return false;
+ memcpy(&newFill, &Fill, sizeof(FillDEF));
+ if(parent->Id == GO_RIBBON && parent->type == 1) {
+ rb_width = parent->GetSize(SIZE_CELLWIDTH) *100.0;
+ rb_z = parent->GetSize(SIZE_ZPOS);
+ }
+ Dlg = new DlgRoot(PlaneDlg);
+ Dlg->GetValue(101, &o_lsize); Dlg->GetValue(202, &o_rbw);
+ Dlg->GetValue(205, &o_rbz);
+ if(parent && parent->Id==GO_RIBBON && parent->type == 2)
+ Dlg->ShowItem(200, false); //paravent plot
+ if(parent->name) sprintf(TmpTxt, "Plane of %s", parent->name);
+ else strcpy(TmpTxt, "Plane properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 355, 226, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 1: case 2:
+ Dlg->GetColor(104, &new_lcolor); Dlg->GetValue(101, &n_lsize); Dlg->GetValue(202, &n_rbw);
+ Dlg->GetValue(205, &n_rbz);
+ break;
+ }
+ }while (res < 0);
+ if(res == 1){
+ undo_flags = CheckNewFloat(&Line.width, o_lsize, n_lsize, this, undo_flags);
+ undo_flags = CheckNewDword(&Line.color, Line.color, new_lcolor, this, undo_flags);
+ undo_flags = CheckNewDword(&Fill.color, Fill.color, newFill.color, this, undo_flags);
+ undo_flags = CheckNewDword(&Fill.color2, Fill.color2, newFill.color2, this, undo_flags);
+ undo_flags = CheckNewInt(&Fill.type, Fill.type, newFill.type, this, undo_flags);
+ if(undo_flags & UNDO_CONTINUE) bRet = true;
+ }
+ else if(res == 2) {
+ if(cmpFillDEF(&Fill, &newFill) || n_lsize != o_lsize || new_lcolor != Line.color ||
+ o_rbw != n_rbw || o_rbz != n_rbz) {
+ parent->Command(CMD_SAVE_SYMBOLS, 0L, 0L);
+ if(cmpFillDEF(&Fill, &newFill)) parent->Command(CMD_SYM_FILL, &newFill, 0L);
+ if(n_lsize != o_lsize) parent->SetSize(SIZE_SYM_LINE, n_lsize);
+ if(new_lcolor != Line.color) parent->SetColor(COL_POLYLINE, new_lcolor);
+ if(parent->Id == GO_RIBBON && parent->type == 1) {
+ if(o_rbw != n_rbw) parent->SetSize(SIZE_CELLWIDTH, n_rbw/100.0);
+ if(o_rbz != n_rbz) parent->SetSize(SIZE_ZPOS, n_rbz);
+ }
+ bRet = true;
+ }
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// properties of 3D column
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Brick::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 50, 10, "Size & Color"};
+// TabSHEET tab2 = {50, 90, 10, "Baseline"};
+ TabSHEET tab3 = {50, 80, 10, "Edit"};
+ FillDEF newFill;
+ DlgInfo ColumnDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to COLUMN", 130, 10, 65, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 130, 25, 65, 12},
+ {3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 40, 65, 12},
+ {4, 0, 5, CHECKED | ISPARENT, GROUP, NULL, 138, 40, 55, 12},
+ {5, 7, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 120, 120},
+// {6, 7, 0, ISPARENT, SHEET, &tab2, 5, 10, 120, 120},
+ {7, 0, 300, ISPARENT, SHEET, &tab3, 5, 10, 120, 120},
+ {100, 101, 0, 0x0L, RTEXT, (void*)"outline width", 18, 30, 40, 8},
+ {101, 102, 0, 0x0L, EDVAL1, &Line.width, 60, 30, 25, 10},
+ {102, 103, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 87, 30, 20, 8},
+ {103, 104, 0, 0x0L, RTEXT, (void*)"outline color", 18, 42, 40, 8},
+ {104, 105, 0, OWNDIALOG, COLBUTTON, (void *)Line.color, 60, 42, 25, 10},
+ {105, 106, 0, 0x0L, RTEXT,(void*)"fill color" , 18, 54, 40, 8},
+ {106, 107, 0, OWNDIALOG, SHADE3D, &newFill, 60, 54, 25, 10},
+ {107, 108, 0, 0x0L, RTEXT, (void*)"column width", 18, 74, 40, 8},
+ {108, 109, 0, 0x0L, EDVAL1, &width, 60, 74, 25, 10},
+ {109, 110, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 87, 74, 20, 8},
+ {110, 111, 0, 0x0L, RTEXT, (void*)"column depth", 18, 86, 40, 8},
+ {111, 112, 0, 0x0L, EDVAL1, &depth, 60, 86, 25, 10},
+ {112, 0, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 87, 86, 20, 8},
+ {300, 301, 0, 0x0L, RTEXT, (void*)"x-value", 10, 30, 35, 8},
+ {301, 302, 0, 0x0L, EDVAL1, &fPos.fx, 50, 30, 30, 10},
+ {302, 303, 0, 0x0L, RTEXT, (void*)"base (y)", 10, 75, 35, 8},
+ {303, 304, 0, 0x0L, EDVAL1, &fPos.fy, 50, 75, 30, 10},
+ {304, 305, 0, 0x0L, RTEXT, (void*)"z-value", 10, 42, 35, 8},
+ {305, 306, 0, 0x0L, EDVAL1, &fPos.fz, 50, 42, 30, 10},
+ {306, 307, 0, 0x0L, RTEXT, (void*)"height", 10, 87, 35, 8},
+ {307, 0, 0, LASTOBJ, EDVAL1, &height, 50, 87, 30, 10}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res;
+ bool bRet = false;
+ DWORD col1 = Line.color, undo_flags = 0L;
+ double o_lw = Line.width, n_lw, o_height = height, n_height, o_width = width, n_width;
+ double o_depth = depth, n_depth;
+ fPOINT3D o_pos, n_pos;
+
+ if(!parent) return false;
+ memcpy(&newFill, &Fill, sizeof(FillDEF));
+ Dlg = new DlgRoot(ColumnDlg);
+ Dlg->GetValue(101, &o_lw); Dlg->GetValue(301, &o_pos.fx);
+ Dlg->GetValue(303, &o_pos.fy); Dlg->GetValue(305, &o_pos.fz);
+ Dlg->GetValue(307, &o_height); Dlg->GetValue(108, &o_width);
+ Dlg->GetValue(111, &o_depth);
+ memcpy(&n_pos, &o_pos, sizeof(fPOINT3D));
+ if(parent->name) sprintf(TmpTxt, "Column of %s", parent->name);
+ else strcpy(TmpTxt, "Column properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 405, 296, Dlg, 0x0L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 1:
+ case 2:
+ Dlg->GetColor(104, &col1);
+ Dlg->GetValue(101, &n_lw); Dlg->GetValue(301, &n_pos.fx);
+ Dlg->GetValue(303, &n_pos.fy); Dlg->GetValue(305, &n_pos.fz);
+ Dlg->GetValue(307, &n_height); Dlg->GetValue(108, &n_width);
+ Dlg->GetValue(111, &n_depth);
+ break;
+ }
+ }while (res < 0);
+ switch (res) {
+ case 1: //new setting for current column only
+ undo_flags = CheckNewFloat(&Line.width, o_lw, n_lw, this, undo_flags);
+ undo_flags = CheckNewDword(&Line.color, Line.color, col1, this, undo_flags);
+ undo_flags = CheckNewDword(&Fill.color, Fill.color, newFill.color, this, undo_flags);
+ undo_flags = CheckNewDword(&Fill.color2, Fill.color2, newFill.color2, this, undo_flags);
+ undo_flags = CheckNewInt(&Fill.type, Fill.type, newFill.type, this, undo_flags);
+ if(o_pos.fx != n_pos.fx || o_pos.fy != n_pos.fy || o_pos.fz != n_pos.fz) {
+ Undo.ValLFP3D(this, &fPos, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&fPos, &n_pos, sizeof(fPOINT3D)); parent->Command(CMD_MRK_DIRTY, 0L, 0L);
+ }
+ undo_flags = CheckNewFloat(&height, o_height, n_height, this, undo_flags);
+ if(o_height != n_height) parent->Command(CMD_MRK_DIRTY, 0L, 0L);
+ undo_flags = CheckNewFloat(&width, o_width, n_width, this, undo_flags);
+ undo_flags = CheckNewFloat(&depth, o_depth, n_depth, this, undo_flags);
+ if(undo_flags & UNDO_CONTINUE) bModified = bRet = true;
+ break;
+ case 2:
+ if(cmpFillDEF(&Fill, &newFill) || o_lw != n_lw || Line.color != col1 ||
+ o_pos.fy != n_pos.fy || n_width != o_width || o_depth != n_depth) {
+ parent->Command(CMD_SAVE_BARS, 0L, 0L);
+ if(o_pos.fy != n_pos.fy){
+ parent->Command(CMD_MRK_DIRTY, 0L, 0L);
+ parent->SetSize(SIZE_BAR_BASE, n_pos.fy);
+ }
+ if(n_lw != o_lw) parent->SetSize(SIZE_BAR_LINE, n_lw);
+ if(n_width != o_width) parent->SetSize(SIZE_BAR, n_width);
+ if(o_depth != n_depth) parent->SetSize(SIZE_BAR_DEPTH, n_depth);
+ if(Line.color != col1) parent->SetColor(COL_BAR_LINE, col1);
+ if(cmpFillDEF(&Fill, &newFill)) parent->Command(CMD_BAR_FILL, &newFill, 0L);
+ bRet = true;
+ }
+ break;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Properties of arrow in 3D space
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Arrow3D::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 29, 10, "Arrow"};
+ TabSHEET tab2 = {29, 59, 10, "Type"};
+ TabSHEET tab3 = {59, 90, 10, "Edit"};
+ DlgInfo ArrowDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to ARROW", 100, 10, 57, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 100, 25, 57, 12},
+ {3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 100, 40, 57, 12},
+ {4, 0, 5, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
+ {5, 6, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 90, 100},
+ {6, 7, 200, ISPARENT, SHEET, &tab2, 5, 10, 90, 100},
+ {7, 0, 300, ISPARENT, SHEET, &tab3, 5, 10, 90, 100},
+ {100, 101, 0, 0x0L, RTEXT, (void*)"cap width", 15, 40, 28, 8},
+ {101, 102, 0, 0x0L, EDVAL1, &cw, 46, 40, 25, 10},
+ {102, 103, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 73, 40, 20, 8},
+ {103, 104, 0, 0x0L, RTEXT, (void*)"length", 15, 52, 28, 8},
+ {104, 105, 0, 0x0L, EDVAL1, &cl, 46, 52, 25, 10},
+ {105, 106, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 73, 52, 20, 8},
+ {106, 107, 0, 0x0L, RTEXT, (void*)"line width", 15, 70, 28, 8},
+ {107, 108, 0, 0x0L, EDVAL1, &Line.width, 46, 70, 25, 10},
+ {108, 109, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 73, 70, 20, 8},
+ {109, 110, 0, 0x0L, RTEXT, (void*)"color", 15, 82, 28, 8},
+ {110, 0, 0, OWNDIALOG, COLBUTTON, (void *)Line.color, 46, 82, 25, 10},
+ {200, 201, 0, TOUCHEXIT, RADIO1, (void*)"line only", 15, 40, 60, 8},
+ {201, 202, 0, TOUCHEXIT, RADIO1, (void*)"arrow with lines", 15, 55, 60, 8},
+ {202, 0, 0, TOUCHEXIT, RADIO1, (void*)"filled arrow", 15, 70, 60, 8},
+ {300, 301, 0, 0x0L, RTEXT, (void*)"x-value", 10, 25, 28, 8},
+ {301, 302, 0, 0x0L, EDVAL1, &fPos2.fx, 46, 25, 35, 10},
+ {302, 303, 0, 0x0L, RTEXT, (void*)"y-value", 10, 36, 28, 8},
+ {303, 304, 0, 0x0L, EDVAL1, &fPos2.fy, 46, 36, 35, 10},
+ {304, 305, 0, 0x0L, RTEXT, (void*)"z-value", 10, 47, 28, 8},
+ {305, 306, 0, 0x0L, EDVAL1, &fPos2.fz, 46, 47, 35, 10},
+ {306, 307, 0, 0x0L, RTEXT, (void*)"origin x", 10, 60, 28, 8},
+ {307, 308, 0, 0x0L, EDVAL1, &fPos1.fx, 46, 60, 35, 10},
+ {308, 309, 0, 0x0L, RTEXT, (void*)" y", 10, 71, 28, 8},
+ {309, 310, 0, 0x0L, EDVAL1, &fPos1.fy, 46, 71, 35, 10},
+ {310, 311, 0, 0x0L, RTEXT, (void*)" z", 10, 82, 28, 8},
+ {311, 312, 0, 0x0L, EDVAL1, &fPos1.fz, 46, 82, 35, 10},
+ {312, 0, 0, LASTOBJ, CHECKBOX, (void*)"set common origin", 16, 95, 70, 8}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ fPOINT3D o_pos1, o_pos2, n_pos1, n_pos2;
+ double o_cw, o_cl, n_cw, n_cl, o_lw, n_lw;
+ int res, tmptype = type, undo_level = *Undo.pcb;
+ bool bRet = false;
+ DWORD o_col, n_col, undo_flags = 0L;
+
+ if(!parent) return false;
+ if(!(Dlg = new DlgRoot(ArrowDlg))) return false;
+ Dlg->GetValue(301, &o_pos2.fx); Dlg->GetValue(303, &o_pos2.fy);
+ Dlg->GetValue(305, &o_pos2.fz); Dlg->GetValue(307, &o_pos1.fx);
+ Dlg->GetValue(309, &o_pos1.fy); Dlg->GetValue(311, &o_pos1.fz);
+ Dlg->GetValue(101, &o_cw); Dlg->GetValue(104, &o_cl);
+ Dlg->GetValue(107, &o_lw); Dlg->GetColor(110, &o_col);
+ switch(type & 0xff) {
+ case ARROW_LINE: Dlg->SetCheck(201, 0L, true); break;
+ case ARROW_TRIANGLE: Dlg->SetCheck(202, 0L, true); break;
+ default: Dlg->SetCheck(200, 0L, true); break;
+ }
+ if(parent->name) sprintf(TmpTxt, "Arrow of %s", parent->name);
+ else strcpy(TmpTxt, "Arrow properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 328, 260, Dlg, 0x0L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 200: tmptype = ARROW_NOCAP; res = -1; break;
+ case 201: tmptype = ARROW_LINE; res = -1; break;
+ case 202: tmptype = ARROW_TRIANGLE; res = -1; break;
+ case 1: case 2:
+ Dlg->GetValue(301, &n_pos2.fx); Dlg->GetValue(303, &n_pos2.fy);
+ Dlg->GetValue(305, &n_pos2.fz); Dlg->GetValue(307, &n_pos1.fx);
+ Dlg->GetValue(309, &n_pos1.fy); Dlg->GetValue(311, &n_pos1.fz);
+ Dlg->GetValue(101, &n_cw); Dlg->GetValue(104, &n_cl);
+ Dlg->GetValue(107, &n_lw); Dlg->GetColor(110, &n_col);
+ break;
+ }
+ }while (res <0);
+ switch (res) {
+ case 1: //new setting for current arrow
+ if(n_pos1.fx != o_pos1.fx || n_pos1.fy != o_pos1.fy ||
+ n_pos1.fz != o_pos1.fz){
+ Undo.ValLFP3D(this, &fPos1, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&fPos1, &n_pos1, sizeof(fPOINT3D));
+ parent->Command(CMD_MRK_DIRTY, 0L, 0L);
+ }
+ if(n_pos2.fx != o_pos2.fx || n_pos2.fy != o_pos2.fy ||
+ n_pos2.fz != o_pos2.fz){
+ Undo.ValLFP3D(this, &fPos2, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&fPos2, &n_pos2, sizeof(fPOINT3D));
+ parent->Command(CMD_MRK_DIRTY, 0L, 0L);
+ }
+ if((type & 0xff) != (tmptype & 0xff)){
+ Undo.ValInt(this, &type, undo_flags);
+ type &= ~0xff; type |= (tmptype & 0xff); undo_flags |= UNDO_CONTINUE;
+ }
+ undo_flags = CheckNewFloat(&cw, o_cw, n_cw, this, undo_flags);
+ undo_flags = CheckNewFloat(&cl, o_cl, n_cl, this, undo_flags);
+ undo_flags = CheckNewFloat(&Line.width, o_lw, n_lw, this, undo_flags);
+ undo_flags = CheckNewDword(&Line.color, o_col, n_col, this, undo_flags);
+ if(undo_flags & UNDO_CONTINUE) bModified = true;
+ bRet = true;
+ break;
+ case 2: //new settings to all arrows of plot
+ if(parent->Id >= GO_PLOT && parent->Id < GO_GRAPH && (Dlg->GetCheck(312) || n_lw != o_lw
+ || n_cw != o_cw || n_cl != o_cl || o_col != n_col || type != tmptype)) {
+ parent->Command(CMD_SAVE_ARROWS, 0L, 0L);
+ if(Dlg->GetCheck(312)) parent->Command(CMD_ARROW_ORG3D, &n_pos1, 0L);
+ if(n_lw != o_lw) parent->SetSize(SIZE_ARROW_LINE, n_lw);
+ if(n_cw != o_cw) parent->SetSize(SIZE_ARROW_CAPWIDTH, n_cw);
+ if(n_cl != o_cl) parent->SetSize(SIZE_ARROW_CAPLENGTH, n_cl);
+ if(o_col != n_col) parent->SetColor(COL_ARROW, n_col);
+ if(type != tmptype) parent->Command(CMD_ARROW_TYPE, &tmptype, 0L);
+ bRet = true;
+ }
+ break;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// properties of 3D data line
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Line3D::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 40, 10, "Line"};
+ DlgInfo LineDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 150, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 150, 25, 45, 12},
+ {3, 0, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
+ {4, 0, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 139, 130},
+ {100, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)OD_linedef, 10, 30, 130, 90}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res;
+ bool bRet = false;
+ LineDEF newLine;
+
+ if(!parent) return false;
+ OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
+ if(!(Dlg = new DlgRoot(LineDlg)))return false;
+ sprintf(TmpTxt, "Line of %s", parent->name);
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 410, 314, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ }while (res < 0);
+ switch(res) {
+ case 1: //OK pressed
+ OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
+ if(cmpLineDEF(&Line, &newLine)) {
+ if(parent->Id == GO_GRID3D) {
+ parent->Command(CMD_SET_LINE, &newLine, 0L);
+ }
+ else {
+ Undo.Line(this, &Line, 0L);
+ memcpy(&Line, &newLine, sizeof(LineDEF));
+ bModified = true;
+ }
+ }
+ bRet = true;
+ break;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// label (text) properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Label::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 27, 10, "Label"};
+ TabSHEET tab2 = {27, 75, 10, "Font & Style"};
+ TabSHEET tab3 = {75, 110, 10, "Position"};
+ DlgInfo LabelDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 170, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 170, 25, 45, 12},
+ {3, 50, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
+ {4, 5, 100, ISPARENT, SHEET, &tab1, 5, 10, 159, 100},
+ {5, 6, 200, ISPARENT | CHECKED, SHEET, &tab2, 5, 10, 159, 100},
+ {6, 0, 300, ISPARENT, SHEET, &tab3, 5, 10, 159, 100},
+ {50, 0, 600, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
+ {100, 101, 0, 0x0L, RTEXT, (void*)"size", 10, 33, 45, 8},
+ {101, 102, 0, 0x0L, EDVAL1, &TextDef.fSize, 60, 33, 25, 10},
+ {102, 103, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 87, 33, 20, 8},
+ {103, 104, 0, 0x0L, RTEXT, (void*)"color", 10, 45, 45, 8},
+ {104, 107, 0, OWNDIALOG, COLBUTTON, (void *)TextDef.ColTxt, 60, 45, 25, 10},
+ {105, 106, 0, 0x0L, LTEXT, (void*)"text:", 10, 83, 25, 8},
+ {106, 0, 0, TOUCHEXIT, EDTEXT, (void*)TextDef.text, 10, 95, 149, 10},
+ {107, 108, 0, 0x0L, RTEXT, (void*)"rotation", 10, 57, 45, 8},
+ {108, 109, 0, 0x0L, EDVAL1, &TextDef.RotBL, 60, 57, 25, 10},
+ {109, 105, 0, 0x0L, LTEXT, (void *)"deg.", 87, 57, 20, 8},
+ {200, 244, 221, CHECKED | ISPARENT, GROUPBOX, (void*)" font ", 17, 28, 60, 50},
+ {221, 222, 0, TOUCHEXIT, RADIO1, (void*)"Helvetica", 20, 35, 45, 8},
+ {222, 223, 0, TOUCHEXIT, RADIO1, (void*)"Times", 20, 45, 45, 8},
+ {223, 224, 0, TOUCHEXIT, RADIO1, (void*)"Courier", 20, 55, 45, 8},
+ {224, 0, 0, TOUCHEXIT, RADIO1, (void*)"Greek", 20, 65, 45, 8},
+ {244, 105, 245, CHECKED | ISPARENT, GROUPBOX, (void*)" style ", 87, 28, 67, 60},
+ {245, 246, 0, TOUCHEXIT, CHECKBOX, (void*)"bold", 90, 35, 25, 8},
+ {246, 247, 0, TOUCHEXIT, CHECKBOX, (void*)"italic", 90, 45, 25, 8},
+ {247, 248, 0, TOUCHEXIT, CHECKBOX, (void*)"underlined", 90, 55, 25, 8},
+ {248, 249, 0, TOUCHEXIT, CHECKBOX, (void*)"superscript", 90, 65, 25, 8},
+ {249, 0, 0, TOUCHEXIT, CHECKBOX, (void*)"subscript", 90, 75, 25, 8},
+ {300, 301, 0, 0x0L, LTEXT, (void*)"text anchor at", 10, 25, 30, 8},
+ {301, 302, 0, 0x0L, RTEXT, (void*)"x", 5, 37, 15, 8},
+ {302, 303, 0, 0x0L, EDVAL1, &fPos.fx, 22, 37, 45, 10},
+ {303, 304, 0, 0x0L, LTEXT, (void*)0L, 69, 37, 10, 8},
+ {304, 305, 0, 0x0L, RTEXT, (void*)"y", 85, 37, 10, 8},
+ {305, 306, 0, 0x0L, EDVAL1, &fPos.fy, 97, 37, 45, 10},
+ {306, 307, 0, 0x0L, LTEXT, (void*)0L, 144, 37, 10, 8},
+ {307, 308, 0, 0x0L, LTEXT, (void*)"distance from anchor point", 10, 52, 50, 8},
+ {308, 309, 0, 0x0L, RTEXT, (void*)"dx", 5, 64, 15, 8},
+ {309, 310, 0, 0x0L, EDVAL1, &fDist.fx, 22, 64, 45, 10},
+ {310, 311, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 69, 64, 10, 8},
+ {311, 312, 0, 0x0L, RTEXT, (void*)"dy", 85, 64, 10, 8},
+ {312, 313, 0, 0x0L, EDVAL1, &fDist.fy, 97, 64, 45, 10},
+ {313, 314, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 144, 64, 10, 8},
+ {314, 315, 0, 0x0L, LTEXT, (void*)"hot spot (text alignment):", 10, 85, 80, 8},
+ {315, 0, 0, 0x0L, TXTHSP, (void*)&TextDef.Align, 97, 78, 45, 25},
+ {600, 601, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 165, 45, 15, 15},
+ {601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 165, 60, 15, 15},
+ {602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 165, 75, 15, 15},
+ {603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 165, 90, 15, 15}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, i, c_style, c_font;
+ bool RetVal = false, check;
+ DWORD undo_flags = 0x0;
+ lfPOINT o_pos, o_dist, n_pos, n_dist;
+ TextDEF OldTxtDef, NewTxtDef;
+ Axis *pa;
+ fmtText *fmt = 0L;
+
+ if(parent && (Dlg = new DlgRoot(LabelDlg))) {
+ Dlg->TextFont(221, FONT_HELVETICA); Dlg->TextFont(222, FONT_TIMES);
+ Dlg->TextFont(223, FONT_COURIER); Dlg->TextFont(224, FONT_GREEK);
+ Dlg->TextStyle(205, TXS_BOLD); Dlg->TextStyle(206, TXS_ITALIC);
+ Dlg->TextStyle(207, TXS_UNDERLINE); Dlg->TextStyle(207, TXS_SUPER);
+ Dlg->TextStyle(207, TXS_SUB);
+ switch(TextDef.Font) {
+ case FONT_TIMES: Dlg->SetCheck(222, 0L, true); break;
+ case FONT_COURIER: Dlg->SetCheck(223, 0L, true); break;
+ case FONT_GREEK: Dlg->SetCheck(224, 0L, true); break;
+ default: Dlg->SetCheck(221, 0L, true); break;
+ }
+ if(TextDef.Style & TXS_BOLD) Dlg->SetCheck(245, 0L, true);
+ if(TextDef.Style & TXS_ITALIC) Dlg->SetCheck(246, 0L, true);
+ if(TextDef.Style & TXS_UNDERLINE) Dlg->SetCheck(247, 0L, true);
+ if(TextDef.Style & TXS_SUPER) Dlg->SetCheck(248, 0L, true);
+ if(TextDef.Style & TXS_SUB) Dlg->SetCheck(249, 0L, true);
+ }
+ else return false;
+ if(parent->Id == GO_GRAPH || parent->Id == GO_PAGE) Dlg->ShowItem(50, true);
+ switch(flags & 0x03) {
+ case LB_X_DATA:
+ Dlg->SetText(303, "[data]");
+ break;
+ case LB_X_PARENT:
+ Dlg->SetText(303, " ");
+ TmpTxt[0] = 0;
+ if(parent->Id == GO_MLABEL) {
+ if(parent->parent->Id == GO_AXIS) strcpy(TmpTxt, "(axis)");
+ else if(parent->parent->Id == GO_TICK) strcpy(TmpTxt, "(tick)");
+ }
+ else {
+ if(parent->Id == GO_AXIS) strcpy(TmpTxt, "(axis)");
+ else if(parent->Id == GO_TICK) strcpy(TmpTxt, "(tick)");
+ }
+ if(TmpTxt[0]) {
+ Dlg->SetText(302, TmpTxt); Dlg->Activate(302, false);
+ }
+ break;
+ default:
+ Dlg->SetText(303, Units[defs.cUnits].display);
+ break;
+ }
+ switch(flags & 0x30) {
+ case LB_Y_DATA:
+ Dlg->SetText(306, "[data]");
+ break;
+ case LB_Y_PARENT:
+ Dlg->SetText(306, " "); TmpTxt[0] = 0;
+ if(parent->Id == GO_MLABEL) {
+ if(parent->parent->Id == GO_AXIS) strcpy(TmpTxt, "(axis)");
+ if(parent->parent->Id == GO_TICK) strcpy(TmpTxt, "(tick)");
+ }
+ else {
+ if(parent->Id == GO_AXIS) strcpy(TmpTxt, "(axis)");
+ if(parent->Id == GO_TICK) strcpy(TmpTxt, "(tick)");
+ }
+ if(TmpTxt[0]) {
+ Dlg->SetText(305, TmpTxt); Dlg->Activate(305, false);
+ }
+ break;
+ default:
+ Dlg->SetText(306, Units[defs.cUnits].display);
+ break;
+ }
+ memcpy(&OldTxtDef, &TextDef, sizeof(TextDEF)); OldTxtDef.text = 0L;
+ Dlg->GetValue(101, &OldTxtDef.fSize); Dlg->GetValue(108, &OldTxtDef.RotBL);
+ memcpy(&NewTxtDef, &OldTxtDef, sizeof(TextDEF));
+ o_pos.fx = fPos.fx; o_pos.fy = fPos.fy; o_dist.fx = fDist.fx; o_dist.fy = fDist.fy;
+ Dlg->GetValue(302, &o_pos.fx); Dlg->GetValue(305, &o_pos.fy);
+ Dlg->GetValue(309, &o_dist.fx); Dlg->GetValue(312, &o_dist.fy);
+ n_pos.fx = o_pos.fx; n_pos.fy = o_pos.fy; n_dist.fx = o_dist.fx; n_dist.fy = o_dist.fy;
+ hDlg = CreateDlgWnd("Label properties", 50, 50, 450, 254, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = ExecDrawOrderButt(parent, this, Dlg->GetResult());
+ switch (res) {
+ case 1:
+ Dlg->GetValue(101, &NewTxtDef.fSize); Dlg->GetColor(104, &NewTxtDef.ColTxt);
+ Dlg->GetValue(108, &NewTxtDef.RotBL);
+ Dlg->GetInt(315, &NewTxtDef.Align);
+ Dlg->GetValue(302, &n_pos.fx); Dlg->GetValue(305, &n_pos.fy);
+ Dlg->GetValue(309, &n_dist.fx); Dlg->GetValue(312, &n_dist.fy);
+ break;
+ case 106: //text modified
+ if(!(Dlg->GetText(res, TmpTxt))) TmpTxt[0] = 0;
+ else {
+ if(!fmt) fmt = new fmtText(0L, 0, 0, TmpTxt);
+ else fmt->SetText(0L, TmpTxt, 0L, 0L);
+ }
+ if(fmt && TmpTxt[0] && Dlg->GetInt(106, &i)) {
+ c_style = NewTxtDef.Style; c_font = NewTxtDef.Font;
+ fmt->StyleAt(i, &NewTxtDef, &c_style, &c_font);
+ Dlg->SetCheck(245, 0L, TXS_BOLD == (c_style & TXS_BOLD));
+ Dlg->SetCheck(246, 0L, TXS_ITALIC == (c_style & TXS_ITALIC));
+ Dlg->SetCheck(247, 0L, TXS_UNDERLINE == (c_style & TXS_UNDERLINE));
+ Dlg->SetCheck(248, 0L, TXS_SUPER == (c_style & TXS_SUPER));
+ Dlg->SetCheck(249, 0L, TXS_SUB == (c_style & TXS_SUB));
+ switch(c_font) {
+ case FONT_HELVETICA: Dlg->SetCheck(221, 0L, true); break;
+ case FONT_TIMES: Dlg->SetCheck(222, 0L, true); break;
+ case FONT_COURIER: Dlg->SetCheck(223, 0L, true); break;
+ case FONT_GREEK: Dlg->SetCheck(224, 0L, true); break;
+ }
+ }
+ res = -1;
+ break;
+ case 221: case 222: case 223: case 224: //fonts
+ switch (res){
+ case 221: res = FONT_HELVETICA; break;
+ case 222: res = FONT_TIMES; break;
+ case 223: res = FONT_COURIER; break;
+ case 224: res = FONT_GREEK; break;
+ }
+ if(!Dlg->ItemCmd(106, CMD_SETFONT, &res)) NewTxtDef.Font = res;
+ res = -1;
+ break;
+ case 245: case 246: case 247: case 248: case 249: //styles
+ check = Dlg->GetCheck(res);
+ switch (res){
+ case 245: res = TXS_BOLD; break;
+ case 246: res = TXS_ITALIC; break;
+ case 247: res = TXS_UNDERLINE; break;
+ case 248: res = TXS_SUPER; break;
+ case 249: res = TXS_SUB; break;
+ }
+ if(!check) {
+ res = ~res;
+ if(!Dlg->ItemCmd(106, CMD_SETSTYLE, &res)) NewTxtDef.Style &= res;
+ }
+ else if(!Dlg->ItemCmd(106, CMD_SETSTYLE, &res)) NewTxtDef.Style |= res;
+ res = -1;
+ break;
+ }
+ }while (res < 0);
+ if(res == 1) {
+ if(parent->Id == GO_TICK && parent->parent && parent->parent->Id == GO_AXIS)
+ pa = (Axis*)parent->parent;
+ else if(parent->Id == GO_MLABEL && parent->parent->Id == GO_TICK
+ && parent->parent->parent && parent->parent->parent->Id == GO_AXIS)
+ pa = (Axis*)parent->parent->parent;
+ else pa = 0L;
+ if(pa && (cmpTextDEF(&OldTxtDef, &NewTxtDef) || o_dist.fx != n_dist.fx ||
+ o_dist.fy != n_dist.fy)){
+ pa->Command(CMD_SAVE_TICKS, 0L, 0L); undo_flags |= UNDO_CONTINUE;
+ }
+ TmpTxt[0] = 0; Dlg->GetText(106, TmpTxt);
+ if(TextDef.text && TextDef.text[0] && strcmp(TextDef.text, TmpTxt)) {
+ Undo.String(this, &TextDef.text, undo_flags); undo_flags |= UNDO_CONTINUE;
+ if(TextDef.text) free(TextDef.text); TextDef.text = strdup(TmpTxt);
+ }
+ if(cmpTextDEF(&OldTxtDef, &NewTxtDef)){
+ if(NewTxtDef.ColTxt != TextDef.ColTxt) bBGvalid = false;
+ if (pa) pa->Command(CMD_TLB_TXTDEF, &NewTxtDef, 0L);
+ else if(parent->Id == GO_MLABEL) {
+ if(parent->Command(CMD_SETTEXTDEF, &NewTxtDef, 0L))RetVal = true;
+ }
+ else {
+ Undo.TextDef(this, &TextDef, undo_flags);
+ NewTxtDef.text = TextDef.text; memcpy(&TextDef, &NewTxtDef, sizeof(TextDEF));
+ undo_flags |= UNDO_CONTINUE;
+ }
+ }
+ if(n_pos.fx != o_pos.fx || n_pos.fy != o_pos.fy) {
+ if(parent->Id == GO_MLABEL) {
+ if(parent->SetSize(SIZE_XPOS, n_pos.fx) ||
+ parent->SetSize(SIZE_YPOS, n_pos.fy)) RetVal = true;
+ }
+ else {
+ Undo.SaveLFP(this, &fPos, undo_flags); undo_flags |= UNDO_CONTINUE;
+ fPos.fx = n_pos.fx; fPos.fy = n_pos.fy;
+ }
+ }
+ if(n_dist.fx != o_dist.fx || n_dist.fy != o_dist.fy) {
+ if(pa) {
+ pa->SetSize(SIZE_TLB_XDIST, n_dist.fx); pa->SetSize(SIZE_TLB_YDIST, n_dist.fy);
+ }
+ else if(parent->Id == GO_MLABEL) {
+ if(parent->SetSize(SIZE_LB_XDIST, n_dist.fx) ||
+ parent->SetSize(SIZE_LB_YDIST, n_dist.fy)) RetVal = true;
+ }
+ else {
+ Undo.SaveLFP(this, &fDist, undo_flags); undo_flags |= UNDO_CONTINUE;
+ fDist.fx = n_dist.fx; fDist.fy = n_dist.fy;
+ }
+ }
+ if(undo_flags & UNDO_CONTINUE) RetVal = true;
+ }
+ CloseDlgWnd(hDlg);
+ if(fmt) delete(fmt);
+ delete Dlg;
+ return RetVal;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// segment properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+segment::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 50, 10, "Size & Color"};
+ TabSHEET tab2 = {50, 90, 10, "Edit"};
+ DlgInfo SegDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to SEGMENT", 130, 10, 65, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 130, 25, 65, 12},
+ {3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 40, 65, 12},
+ {4, 0, 5, CHECKED | ISPARENT, GROUP, NULL, 138, 40, 55, 12},
+ {5, 6, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 120, 115},
+ {6, 0, 200, ISPARENT, SHEET, &tab2, 5, 10, 120, 115},
+ {100, 109, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 25, 35, 90, 50},
+ {109, 110, 0, 0x0L, RTEXT, (void*)"shift out (explode)", 10, 90, 55, 8},
+ {110, 111, 0, 0x0L, EDVAL1, &shift, 67, 90, 25, 10},
+ {111, 112, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 94, 90, 20, 8},
+ {112, 0, 0, 0x0L, CHECKBOX, (void*)"enable mouse drag (moveable)", 12, 107, 100, 8},
+ {200, 201, 0, 0x0L, RTEXT, (void*)"center x", 10, 30, 40, 8},
+ {201, 202, 0, 0x0L, EDVAL1, &fCent.fx, 55, 30, 40, 10},
+ {202, 203, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 98, 30, 20, 8},
+ {203, 204, 0, 0x0L, RTEXT, (void*)"y", 10, 42, 40, 8},
+ {204, 205, 0, 0x0L, EDVAL1, &fCent.fy, 55, 42, 40, 10},
+ {205, 206, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 98, 42, 20, 8},
+ {206, 207, 0, 0x0L, RTEXT, (void*)"start angle", 10, 57, 40, 8},
+ {207, 208, 0, 0x0L, EDVAL1, &angle1, 55, 57, 40, 10},
+ {208, 209, 0, 0x0L, LTEXT, (void*)"deg.", 98, 57, 20, 8},
+ {209, 210, 0, 0x0L, RTEXT, (void*)"stop", 10, 69, 40, 8},
+ {210, 211, 0, 0x0L, EDVAL1, &angle2, 55, 69, 40, 10},
+ {211, 212, 0, 0x0L, LTEXT, (void*)"deg.", 98, 69, 20, 8},
+ {212, 213, 0, 0x0L, RTEXT, (void*)"outer radius", 10, 84, 40, 8},
+ {213, 214, 0, 0x0L, EDVAL1, &radius2, 55, 84, 40, 10},
+ {214, 215, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 98, 84, 20, 8},
+ {215, 216, 0, 0x0L, RTEXT, (void*)"inner", 10, 96, 40, 8},
+ {216, 217, 0, 0x0L, EDVAL1, &radius1, 55, 96, 40, 10},
+ {217, 0, 0, LASTOBJ, LTEXT, (void *) Units[defs.cUnits].display, 98, 96, 20, 8}};
+
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, new_mov;
+ double old_r1, old_r2, old_a1, old_a2, old_shift;
+ double new_r1, new_r2, new_a1, new_a2, new_shift;
+ lfPOINT old_cent, new_cent;
+ bool bRet = false;
+ LineDEF newLine, newFillLine;
+ FillDEF newFill;
+ DWORD undo_flags = 0L;
+
+ if(!parent) return false;
+ OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&segLine, 0);
+ OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&segFill, 0);
+ Dlg = new DlgRoot(SegDlg);
+ Dlg->GetValue(216, &old_r1); new_r1 = old_r1;
+ Dlg->GetValue(213, &old_r2); new_r2 = old_r2;
+ Dlg->GetValue(201, &old_cent.fx); new_cent.fx = old_cent.fx;
+ Dlg->GetValue(204, &old_cent.fy); new_cent.fy = old_cent.fy;
+ Dlg->GetValue(207, &old_a1); new_a1 = old_a1;
+ Dlg->GetValue(210, &old_a2); new_a2 = old_a2;
+ Dlg->GetValue(110, &old_shift); new_shift = old_shift;
+ if(moveable) Dlg->SetCheck(112, 0L, true);
+ hDlg = CreateDlgWnd("segment properties", 50, 50, 410, 290, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 1:
+ case 2:
+ OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
+ OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&newFill, 0);
+ memcpy(&newFillLine, &segFillLine, sizeof(LineDEF));
+ if(newFill.hatch) memcpy(&newFillLine, newFill.hatch, sizeof(LineDEF));
+ Dlg->GetValue(201, &new_cent.fx); Dlg->GetValue(204, &new_cent.fy);
+ Dlg->GetValue(207, &new_a1); Dlg->GetValue(210, &new_a2);
+ Dlg->GetValue(216, &new_r1); Dlg->GetValue(213, &new_r2);
+ Dlg->GetValue(110, &new_shift);
+ new_mov = Dlg->GetCheck(112) ? 1 : 0;
+ break;
+ }
+ }while (res < 0);
+ switch (res) {
+ case 1: //new setting for current segment only
+ undo_flags = CheckNewLFPoint(&fCent, &old_cent, &new_cent, parent, undo_flags);
+ undo_flags = CheckNewFloat(&angle1, old_a1, new_a1, parent, undo_flags);
+ undo_flags = CheckNewFloat(&angle2, old_a2, new_a2, parent, undo_flags);
+ undo_flags = CheckNewFloat(&radius1, old_r1, new_r1, parent, undo_flags);
+ undo_flags = CheckNewFloat(&radius2, old_r2, new_r2, parent, undo_flags);
+ undo_flags = CheckNewFloat(&shift, old_shift, new_shift, parent, undo_flags);
+ if(cmpLineDEF(&segLine, &newLine)) {
+ Undo.Line(parent, &segLine, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&segLine, &newLine, sizeof(LineDEF));
+ }
+ if(newFill.type && cmpLineDEF(&segFillLine, &newFillLine)) {
+ Undo.Line(parent, &segFillLine, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&segFillLine, &newFillLine, sizeof(LineDEF));
+ }
+ if(cmpFillDEF(&segFill, &newFill)) {
+ Undo.Fill(parent, &segFill, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&segFill, &newFill, sizeof(FillDEF));
+ }
+ segFill.hatch = &segFillLine;
+ undo_flags = CheckNewInt(&moveable, moveable, new_mov, parent, undo_flags);
+ bRet = bModified = ((undo_flags & UNDO_CONTINUE) == UNDO_CONTINUE);
+ break;
+ case 2: //new settings to all segments of chart
+ if(new_cent.fx != old_cent.fx || new_cent.fy != old_cent.fy || new_r1 != old_r1 ||
+ new_r2 != old_r2 || new_shift != old_shift || cmpLineDEF(&segLine, &newLine) ||
+ (newFill.type && cmpLineDEF(&segFillLine, &newFillLine)) ||
+ cmpFillDEF(&segFill, &newFill) || new_mov != moveable) {
+ parent->Command(CMD_SAVE_SYMBOLS, 0L, 0L);
+ if(new_cent.fx != old_cent.fx || new_cent.fy != old_cent.fy) {
+ parent->SetSize(SIZE_XPOS, new_cent.fx); parent->SetSize(SIZE_YPOS, new_cent.fy);
+ }
+ if(new_r1 != old_r1 || new_r2 != old_r2) {
+ parent->SetSize(SIZE_RADIUS1, new_r1); parent->SetSize(SIZE_RADIUS2, new_r2);
+ }
+ if(new_shift != old_shift) parent->Command(CMD_SHIFT_OUT, (void*)&new_shift, 0L);
+ if(cmpLineDEF(&segLine, &newLine))parent->Command(CMD_SEG_LINE, (void*)&newLine, 0L);
+ if((newFill.type && cmpLineDEF(&segFillLine, &newFillLine)) ||
+ cmpFillDEF(&segFill, &newFill)) parent->Command(CMD_SEG_FILL, (void*)&newFill, 0L);
+ if(new_mov != moveable) parent->Command(CMD_SEG_MOVEABLE, (void *)&new_mov, 0L);
+ bRet = true;
+ }
+ break;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// polyline properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+polyline::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 40, 10, "Line"};
+ DlgInfo LineDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 150, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 150, 25, 45, 12},
+ {3, 0, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
+ {4, 50, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 139, 130},
+ {50, 0, 600, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
+ {100, 101, 0, NOSELECT, ODBUTTON, (void*)OD_linedef, 10, 30, 130, 90},
+ {101, 0, 0, 0x0L, CHECKBOX, (void*)"use this style as default", 10, 125, 60, 9},
+ {600, 601, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 165, 60, 15, 15},
+ {601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 165, 75, 15, 15},
+ {602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 165, 90, 15, 15},
+ {603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 165, 105, 15, 15}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, undo_level = *Undo.pcb;
+ bool bRet = false;
+ LineDEF newLine;
+
+ if(!parent) return false;
+ OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&pgLine, 0);
+ if(!(Dlg = new DlgRoot(LineDlg)))return false;
+ if(parent->Id == GO_GRAPH || parent->Id == GO_PAGE) Dlg->ShowItem(50, true);
+ hDlg = CreateDlgWnd("line properties", 50, 50, 410, 314, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = ExecDrawOrderButt(parent, this, Dlg->GetResult());
+ }while (res < 0);
+ switch(res) {
+ case 1: //OK pressed
+ OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
+ if(cmpLineDEF(&pgLine, &newLine)) {
+ Undo.Line(this, &pgLine, 0L);
+ memcpy(&pgLine, &newLine, sizeof(LineDEF));
+ bModified = true;
+ }
+ if(Dlg->GetCheck(101)) defs.plLineDEF(&pgLine);
+ bRet = true;
+ break;
+ case 2: //Cancel
+ if(*Undo.pcb > undo_level) { //restore plot order
+ while(*Undo.pcb > undo_level) Undo.Restore(false, 0L);
+ bRet = true;
+ }
+ break;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// polygon properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+polygon::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 40, 10, "Polygon"};
+ DlgInfo PolygDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 102, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 102, 25, 45, 12},
+ {3, 50, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 90, 85},
+ {50, 0, 600, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
+ {100, 101, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 8, 30, 90, 50},
+ {101, 0, 0, 0x0L, CHECKBOX, (void*)"use this style as default", 10, 82, 60, 9},
+ {600, 601, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 107, 52, 15, 15},
+ {601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 127, 52, 15, 15},
+ {602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 127, 67, 15, 15},
+ {603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 107, 67, 15, 15}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ LineDEF newLine, newFillLine;
+ FillDEF newFill;
+ DWORD undo_flags = 0L;
+ int res, undo_level = *Undo.pcb;
+ bool bRet = false;
+
+ OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&pgLine, 0);
+ OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&pgFill, 0);
+ Dlg = new DlgRoot(PolygDlg);
+ if(parent->Id == GO_GRAPH || parent->Id == GO_PAGE) Dlg->ShowItem(50, true);
+ hDlg = CreateDlgWnd("polygon properties", 50, 50, 310, 224, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = ExecDrawOrderButt(parent, this, Dlg->GetResult());
+ }while (res < 0);
+ switch (res) {
+ case 1: //OK pressed
+ OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
+ OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&newFill, 0);
+ memcpy(&newFillLine, &pgFillLine, sizeof(LineDEF));
+ if(newFill.hatch) memcpy(&newFillLine, newFill.hatch, sizeof(LineDEF));
+ if(cmpLineDEF(&pgLine, &newLine)) {
+ Undo.Line(this, &pgLine, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&pgLine, &newLine, sizeof(LineDEF));
+ }
+ if(newFill.type && cmpLineDEF(&pgFillLine, &newFillLine)) {
+ Undo.Line(this, &pgFillLine, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&pgFillLine, &newFillLine, sizeof(LineDEF));
+ }
+ if(cmpFillDEF(&pgFill, &newFill)) {
+ Undo.Fill(this, &pgFill, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&pgFill, &newFill, sizeof(FillDEF));
+ }
+ pgFill.hatch = &pgFillLine;
+ if(undo_flags & UNDO_CONTINUE) bModified = true;
+ if(Dlg->GetCheck(101)){
+ defs.pgLineDEF(&pgLine); defs.pgFillDEF(&pgFill);
+ }
+ bRet = true;
+ break;
+ case 2: //Cancel
+ if(*Undo.pcb > undo_level) { //restore plot order
+ while(*Undo.pcb > undo_level) Undo.Restore(false, 0L);
+ bRet = true;
+ }
+ break;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// rectangle, round rectangle and ellipse properties dialogs
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+rectangle::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 40, 10, type == 1 ? (char*)"Ellipse" :(char*)"Rectangle"};
+ TabSHEET tab2 = {40, 63, 10, "Edit"};
+ DlgInfo RecDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 112, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 112, 25, 45, 12},
+ {3, 0, 10, CHECKED | ISPARENT, GROUP, 0L, 0, 0, 0, 0},
+ {10, 11, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 100, 97},
+ {11, 50, 200, ISPARENT, SHEET, &tab2, 5, 10, 100, 97},
+ {50, 0, 600, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
+ {100, 101, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 8, 30, 90, 50},
+ {101, 120, 110, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {110, 111, 0, 0x0L, RTEXT, (void*)"edge radius", 0, 79, 48, 8},
+ {111, 112, 0, 0x0L, EDVAL1, &rad, 50, 79, 25, 10},
+ {112, 0, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 77, 79, 10, 8},
+ {120, 0, 0, 0x0L, CHECKBOX, (void*)"use this style as default", 10, 92, 60, 9},
+ {200, 201, 0, 0x0L, RTEXT, (void*)"top left x", 5, 30, 40, 8},
+ {201, 202, 0, 0x0L, EDVAL1, &fp1.fx, 47, 30, 38, 10},
+ {202, 203, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 87, 30, 10, 8},
+ {203, 204, 0, 0x0L, RTEXT, (void*)"y", 5, 42, 40, 8},
+ {204, 205, 0, 0x0L, EDVAL1, &fp1.fy, 47, 42, 38, 10},
+ {205, 206, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 87, 42, 10, 8},
+ {206, 207, 0, 0x0L, RTEXT, (void*)"lower right x", 5, 55, 40, 8},
+ {207, 208, 0, 0x0L, EDVAL1, &fp2.fx, 47, 55, 38, 10},
+ {208, 209, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 87, 55, 10, 8},
+ {209, 210, 0, 0x0L, RTEXT, (void*)"y", 5, 67, 40, 8},
+ {210, 211, 0, 0x0L, EDVAL1, &fp2.fy, 47, 67, 38, 10},
+ {211, 0, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 87, 67, 10, 8},
+ {600, 601, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 115, 64, 15, 15},
+ {601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 139, 64, 15, 15},
+ {602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 139, 79, 15, 15},
+ {603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 115, 79, 15, 15}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, undo_level = *Undo.pcb;
+ lfPOINT old_fp1, new_fp1, old_fp2, new_fp2;
+ LineDEF old_Line, new_Line, old_FillLine, new_FillLine;
+ FillDEF old_Fill, new_Fill;
+ DWORD undo_flags = 0L;
+ bool bRet = false;
+
+ OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
+ OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&Fill, 0);
+ if(!(Dlg = new DlgRoot(RecDlg)))return false;
+ Dlg->GetValue(201, &old_fp1.fx); Dlg->GetValue(204, &old_fp1.fy);
+ Dlg->GetValue(207, &old_fp2.fx); Dlg->GetValue(210, &old_fp2.fy);
+ if(type != 2) Dlg->ShowItem(101, false);
+ if(parent->Id == GO_GRAPH || parent->Id == GO_PAGE) Dlg->ShowItem(50, true);
+ OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&old_Line, 0);
+ OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&old_Fill, 0);
+ if(old_Fill.hatch) memcpy(&old_FillLine, old_Fill.hatch, sizeof(LineDEF));
+ old_Fill.hatch = &old_FillLine;
+ hDlg = CreateDlgWnd(type == 1 ? (char*)"ellipse properties":
+ type == 2 ? (char*)"rounded rectangle" : (char*)"rectangle properties",
+ 50, 50, 330, 248, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = ExecDrawOrderButt(parent, this, Dlg->GetResult());
+ }while (res < 0);
+ switch (res) {
+ case 1: //OK pressed
+ Dlg->GetValue(201, &new_fp1.fx); Dlg->GetValue(204, &new_fp1.fy);
+ Dlg->GetValue(207, &new_fp2.fx); Dlg->GetValue(210, &new_fp2.fy);
+ undo_flags = CheckNewLFPoint(&fp1, &old_fp1, &new_fp1, this, undo_flags);
+ undo_flags = CheckNewLFPoint(&fp2, &old_fp2, &new_fp2, this, undo_flags);
+ OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&new_Line, 0);
+ OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&new_Fill, 0);
+ if(new_Fill.hatch) memcpy(&new_FillLine, new_Fill.hatch, sizeof(LineDEF));
+ new_Fill.hatch = &new_FillLine;
+ if(cmpLineDEF(&old_Line, &new_Line)) {
+ Undo.Line(this, &Line, undo_flags);
+ undo_flags |= UNDO_CONTINUE;
+ memcpy(&Line, &new_Line, sizeof(LineDEF));
+ }
+ if(new_Fill.type && cmpLineDEF(&old_FillLine, &new_FillLine)) {
+ Undo.Line(this, &FillLine, undo_flags);
+ undo_flags |= UNDO_CONTINUE;
+ memcpy(&FillLine, &new_FillLine, sizeof(LineDEF));
+ }
+ if(cmpFillDEF(&Fill, &new_Fill)) {
+ Undo.Fill(this, &Fill, undo_flags);
+ undo_flags |= UNDO_CONTINUE;
+ memcpy(&Fill, &new_Fill, sizeof(FillDEF));
+ }
+ Fill.hatch = &FillLine;
+ if(type == 2) Dlg->GetValue(111, &rad);
+ else rad = 0.0;
+ if(Dlg->GetCheck(120)){
+ defs.pgLineDEF(&Line); defs.pgFillDEF(&Fill);
+ if(type == 2)defs.rrectRad(rad);
+ }
+ if(undo_flags) bModified = true;
+ bRet = true;
+ break;
+ case 2: //Cancel
+ if(*Undo.pcb > undo_level) { //restore plot order
+ while(*Undo.pcb > undo_level) Undo.Restore(false, 0L);
+ bRet = true;
+ }
+ break;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Create a bar chart: note this is a PlotScatt function
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+PlotScatt::CreateBarChart()
+{
+ TabSHEET tab1 = {0, 25, 10, "Data"};
+ TabSHEET tab2 = {25, 55, 10, "Details"};
+ double start = 1.0, step = 1.0, bw = 60.0;
+ DlgInfo BarDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 130, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 25, 45, 12},
+ {3, 0, 4, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
+ {4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 120, 110},
+ {5, 10, 200, ISPARENT, SHEET, &tab2, 5, 10, 120, 110},
+ {10, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"spread sheet range for values", 10, 25, 60, 8},
+ {101, 102, 0, 0x0L, EDTEXT, TmpTxt, 10, 38, 110, 10},
+ {102, 0, 110, ISPARENT | CHECKED, GROUPBOX, (void*)" style ", 10, 55, 110, 61},
+ {110, 0, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 25, 62, 90, 50},
+ {200, 201, 0, 0x0L, RTEXT, (void*)"start value", 10, 35, 38, 8},
+ {201, 202, 0, 0x0L, EDVAL1, (void*)&start, 58, 35, 35, 10},
+ {202, 203, 0, 0x0L, RTEXT, (void*)"step value", 10, 50, 38, 8},
+ {203, 204, 0, 0x0L, EDVAL1, (void*)&step, 58, 50, 35, 10},
+ {204, 205, 0, 0x0L, RTEXT, (void*)"bar width", 10, 65, 38, 8},
+ {205, 206, 0, 0x0L, EDVAL1, (void*)&bw, 58, 65, 35, 10},
+ {206, 0, 0, LASTOBJ, LTEXT, (void*)"%", 95, 65, 8, 8}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ bool bRet = false;
+ int k, l, n, ic, res, width, height;
+ double x, y;
+ AccRange *rY = 0L;
+ LineDEF Line;
+ FillDEF Fill;
+
+ memcpy(&Line, defs.GetOutLine(), sizeof(LineDEF));
+ memcpy(&Fill, defs.GetFill(), sizeof(FillDEF));
+ OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
+ OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&Fill, 0);
+ data->GetSize(&width, &height);
+ sprintf(TmpTxt, "a1:a%d", height);
+ if(!(Dlg = new DlgRoot(BarDlg)))return false;
+ hDlg = CreateDlgWnd("Simple bar chart", 50, 50, 370, 280, Dlg, 0x0L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 0:
+ if(Dlg->GetCheck(10)) res = -1;
+ break;
+ case 1:
+ if(rY) delete rY;
+ if(Dlg->GetText(101, TmpTxt)) rY = new AccRange(TmpTxt);
+ yRange = strdup(TmpTxt);
+ if(!(n = rY ? rY->CountItems() : 0)) {
+ res = -1;
+ ErrorBox("Data range not valid.");
+ }
+ break;
+ }
+ } while(res < 0);
+ if(res == 1 && n && rY) {
+ OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&Line, 0);
+ OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&Fill, 0);
+ Command(CMD_FLUSH, 0L, 0L);
+ nPoints = n;
+ Bars = (Bar**)calloc(nPoints, sizeof(Bar*));
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ rY->GetFirst(&k, &l); rY->GetNext(&k, &l);
+ Dlg->GetValue(201, &start); Dlg->GetValue(203, &step);
+ if(step < 0.001) step = 1.0;
+ Dlg->GetValue(205, &bw);
+ if(bw < 5) bw = 60;
+ ic = 0;
+ x = start;
+ if(Bars) do {
+ if(data->GetValue(l, k, &y)){
+ Bars[ic] = new Bar(this, data, x, y, BAR_VERTB | BAR_RELWIDTH, -1, -1, k, l);
+ CheckBounds(x, y);
+ x += step;
+ ic++;
+ }
+ }while(rY->GetNext(&k, &l));
+ if(ic){
+ bRet = true;
+ Command(CMD_BAR_FILL, &Fill, 0L);
+ SetColor(COL_BAR_LINE, Line.color);
+ SetSize(SIZE_BAR_LINE, Line.width);
+ SetSize(SIZE_BAR, bw);
+ BarDist.fx = step;
+ }
+ }
+ if(rY) delete rY;
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Scatter plot properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+PlotScatt::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 22, 10, "Data"};
+ TabSHEET tab2 = {22, 50, 10, "Layout"};
+ TabSHEET tab3 = {50, 88, 10, "Error Bars"};
+ TabSHEET tab4 = {88, 131, 10, "Data Labels"};
+ char text1[100], text2[100], text3[100], text4[100];
+ int icon = ICO_INFO;
+ DlgInfo XYDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 140, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 140, 25, 45, 12},
+ {3, 0, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
+ {4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 131, 100},
+ {5, 6, 200, TOUCHEXIT | ISPARENT, SHEET, &tab2, 5, 10, 131, 100},
+ {6, 7, 300, ISPARENT, SHEET, &tab3, 5, 10, 131, 100},
+ {7, 10, 400, ISPARENT, SHEET, &tab4, 5, 10, 131, 100},
+ {10, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"range for X Data", 10, 30, 60, 8},
+ {101, 102, 0, 0x0L, EDTEXT, text1, 20, 40, 100, 10},
+ {102, 103, 0, 0x0L, LTEXT, (void*)"range for Y Data", 10, 55, 60, 8},
+ {103, 104, 0, 0x0L, EDTEXT, text2, 20, 65, 100, 10},
+ {104, 105, 0, 0x0L, ICON, (void*)&icon, 10, 85, 10, 10},
+ {105, 106, 0, 0x0L, LTEXT, (void*)"Valid ranges include e.g. \'a1:g13\'", 30, 85, 30, 6},
+ {106, 107, 0, 0x0L, LTEXT, (void*)"or \'b4:j4\' if data are available.", 30, 91, 30, 6},
+ {107, 0, 0, 0x0L, LTEXT, (void*)"Separate multiple ranges by \' ; \'.", 30, 97, 30, 6},
+ {200, 201, 0, 0x0L, CHECKBOX, (void*)" symbols", 25, 30, 60, 8},
+ {201, 202, 250, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {202, 203, 255, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {203, 204, 0, 0x0L, CHECKBOX, (void*)" arrows", 25, 80, 60, 8},
+ {204, 0, 0, 0x0L, CHECKBOX, (void*)" drop lines", 25, 90, 60, 8},
+ {250, 251, 0, ISRADIO, CHECKBOX, (void*)" line", 25, 40, 60, 8},
+ {251, 0, 0, ISRADIO, CHECKBOX, (void*)" polygon", 25, 70, 60, 8},
+ {255, 256, 0, ISRADIO, CHECKBOX, (void*)" vertical bars", 25, 50, 60, 8},
+ {256, 0, 0, ISRADIO, CHECKBOX, (void*)" horizontal bars", 25, 60, 60, 8},
+ {300, 301, 500, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {301, 302, 0, 0x0L, CHECKBOX, (void*)"draw error bars", 15, 28, 50, 8},
+ {302, 303, 0, 0x0L, LTEXT, (void*)"style:", 35, 40, 20, 8},
+ {303, 304, 0, 0x0L, LTEXT, (void*)"range for error data:", 15, 82, 60, 8},
+ {304, 0, 0, 0x0L, EDTEXT, text3, 20, 93, 100, 10},
+ {400, 401, 0, 0x0L, CHECKBOX, (void*)"add labels to data points", 15, 28, 50, 8},
+ {401, 402, 0, 0x0L, LTEXT, (void*)"spread sheet range for labels:", 15, 40, 60, 8},
+ {402, 0, 0, 0x0L, EDTEXT, text4, 20, 51, 100, 10},
+ {500, 501, 0, TOUCHEXIT|CHECKED|ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl),60,40,20,20},
+ {501, 502, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 80, 40, 20, 20},
+ {502, 503, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 100, 40, 20, 20},
+ {503, 504, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 60, 60, 20, 20},
+ {504, 505, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 80, 60, 20, 20},
+ {505, 0, 0, LASTOBJ | TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 100, 60, 20, 20}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int c, i, j, k, l, i1, j1, k1, l1, m, n, o, p, ic;
+ int ErrType = 0, res, width, height, BarType;
+ double x, y, e;
+ lfPOINT fp1, fp2;
+ bool bRet = false, bLayout = false, bContinue = false;
+ TextDEF lbdef = {defs.Color(COL_TEXT), defs.Color(COL_BG), defs.GetSize(SIZE_TEXT), 0.0f, 0.0f, 0,
+ TXA_HLEFT | TXA_VBOTTOM, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, TmpTxt};
+ AccRange *rX, *rY, *rE, *rL;
+
+ if(Id == GO_BARCHART) return CreateBarChart();
+ data->GetSize(&width, &height);
+ sprintf(text1, "a1:a%d", height); sprintf(text2, "b1:b%d", height);
+ sprintf(text3, "c1:c%d", height); sprintf(text4, "b1:b%d", height);
+ rX = rY = rE = rL = 0L;
+ if(!(Dlg = new DlgRoot(XYDlg)))return false;
+#ifdef _WINDOWS
+ for(i = 104; i <= 107; i++) Dlg->TextSize(i, 12);
+#else
+ for(i = 104; i <= 107; i++) Dlg->TextSize(i, 10);
+#endif
+ if(DefSel & 0x01)Dlg->SetCheck(200, 0L, true);
+ if(DefSel & 0x02)Dlg->SetCheck(250, 0L, true);
+ if(DefSel & 0x04)Dlg->SetCheck(255, 0L, true);
+ if(DefSel & 0x08)Dlg->SetCheck(256, 0L, true);
+ hDlg = CreateDlgWnd("XY Plot properties", 50, 50, 388, 260, Dlg, 0x0L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 0: // focus lost
+ if(bContinue) res = -1;
+ else if(Dlg->GetCheck(10)) res = -1;
+ break;
+ case -1:
+ bContinue = false;
+ break;
+ case 500: case 501: case 502:
+ case 503: case 504: case 505:
+ ErrType = res-500;
+ Dlg->SetCheck(301, 0L, true);
+ res = -1;
+ break;
+ case 5: // the layout tab sheet
+ bLayout = true;
+ res = -1;
+ break;
+ case 1: // OK
+ if(rX) delete rX; if(rY) delete rY; if(rE) delete rE;
+ rX = rY = rE = 0L; // check x-range
+ if(Dlg->GetText(101, TmpTxt)) rX = new AccRange(TmpTxt);
+ if(!(n = rX ? rX->CountItems() : 0)) {
+ Dlg->SetCheck(4, 0L, true);
+ res = -1;
+ bContinue = true;
+ ErrorBox("X-range not specified\nor not valid.");
+ }
+ else { // check y-range
+ if(Dlg->GetText(103, TmpTxt)) rY = new AccRange(TmpTxt);
+ if(n != (rY ? rY->CountItems() : 0)) {
+ Dlg->SetCheck(4, 0L, true);
+ res = -1;
+ bContinue = true;
+ ErrorBox("Y-range missing\nor not valid.\n"
+ "Size must match X-range.");
+ }
+ }
+ //check for error bar
+ if(res >0 && Dlg->GetCheck(301)) {
+ if(Dlg->GetText(304, TmpTxt)) rE = new AccRange(TmpTxt);
+ if(n != (rE ? rE->CountItems() : 0)) {
+ Dlg->SetCheck(6, 0L, true);
+ res = -1;
+ bContinue = true;
+ ErrorBox("Range for errors missing\nor not valid.\n"
+ "Size must match X- and Y-range.");
+ if(rE) delete (rE);
+ rE = 0L;
+ }
+ }
+ //check for data labels
+ if(res >0 && Dlg->GetCheck(400)) {
+ if(Dlg->GetText(402, TmpTxt)) rL = new AccRange(TmpTxt);
+ if(n != (rL ? rL->CountItems() : 0)) {
+ Dlg->SetCheck(7, 0L, true);
+ res = -1;
+ bContinue = true;
+ ErrorBox("Range for labels missing\nor not valid.\n"
+ "Size must match X- and Y-range.");
+ if(rL) delete (rL);
+ rL = 0L;
+ }
+ }
+ //check if something left to do
+ if(res > 0 && !rE && !rL && !Dlg->GetCheck(200) && !Dlg->GetCheck(250) &&
+ !Dlg->GetCheck(251) && !Dlg->GetCheck(255) && !Dlg->GetCheck(256) &&
+ !Dlg->GetCheck(203)) {
+ Dlg->SetCheck(5, 0L, true);
+ res = -1;
+ bContinue = true;
+ ErrorBox("Nothing to do!\nSelect at least one item.");
+ }
+ //the layout menu must have been visited
+ if(res > 0 && !bLayout){
+ Dlg->SetCheck(5, 0L, bLayout = true);
+ res = -1;
+ }
+ break;
+ }
+ }while (res <0);
+ if(res == 1 && n && rX && rY){ //OK pressed
+ Command(CMD_FLUSH, 0L, 0L);
+ nPoints = n;
+ if(Dlg->GetText(101, TmpTxt)) xRange = strdup(TmpTxt);
+ if(Dlg->GetText(103, TmpTxt)) yRange = strdup(TmpTxt);
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ //Create graphic objects
+ rX->GetFirst(&i, &j); rY->GetFirst(&k, &l);
+ rX->GetNext(&i, &j); rY->GetNext(&k, &l);
+ i1 = i; j1 = j; k1 = k; l1 = l;
+ ic = c = 0;
+ if(Dlg->GetCheck(200)) Symbols = (Symbol**)calloc(nPoints, sizeof(Symbol*));
+ if((BarType = Dlg->GetCheck(255) ? BAR_VERTB : Dlg->GetCheck(256) ? BAR_HORL : 0))
+ Bars = (Bar**)calloc(nPoints, sizeof(Bar*));
+ BarType |= BAR_RELWIDTH;
+ if(Dlg->GetCheck(204)) DropLines = (DropLine**)calloc(nPoints, sizeof(DropLine*));
+ if(Dlg->GetCheck(203)) Arrows = (Arrow**)calloc(nPoints, sizeof(Arrow*));
+ if(Dlg->GetCheck(301) && rE) { //error bars ?
+ Errors = (ErrorBar**)calloc(nPoints, sizeof(ErrorBar*));
+ if(Dlg->GetText(304, TmpTxt)) ErrRange = strdup(TmpTxt);
+ rE->GetFirst(&m, &n); rE->GetNext(&m, &n);
+ }
+ if(Dlg->GetCheck(400) && rL) { //labels ?
+ Labels = (Label**)calloc(nPoints, sizeof(Label*));
+ if(Dlg->GetText(402, TmpTxt)) LbRange = strdup(TmpTxt);
+ rL->GetFirst(&o, &p); rL->GetNext(&o, &p);
+ }
+ if(Dlg->GetCheck(250) && nPoints >1) TheLine = new DataLine(this, data, xRange, yRange);
+ else if(Dlg->GetCheck(251) && nPoints >2) TheLine = new DataPolygon(this, data, xRange, yRange);
+ do {
+ if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y)){
+ if(Symbols && (Symbols[ic] = new Symbol(this, data, x, y, DefSym, i, j, k, l))){
+ Symbols[ic]->idx = c;
+ }
+ if(Bars)Bars[ic] = new Bar(this, data, x, y, BarType, i, j, k, l);
+ if(DropLines) DropLines[ic] = new DropLine(this, data, x, y,
+ DL_YAXIS | DL_XAXIS, i, j, k, l);
+ if(Arrows) {
+ if(ic){
+ fp1.fx = fp2.fx; fp1.fy = fp2.fy;
+ }
+ else {
+ fp1.fx = x; fp1.fy = y;
+ }
+ fp2.fx = x; fp2.fy = y;
+ Arrows[ic] = new Arrow(this, data, ic ? fp1 : fp2, fp2, ARROW_LINE,
+ i1, j1, k1, l1, i, j, k, l);
+ //the first arrow has zero length
+ //all other arrows conncect to the following point
+ i1 = i; j1 = j; k1 = k; l1 = l;
+ }
+ if(Labels && rL) {
+ if(data->GetText(p, o, TmpTxt, TMP_TXT_SIZE))
+ Labels[ic] = new Label(this, data, x, y, &lbdef,
+ LB_X_DATA | LB_Y_DATA, i, j, k, l, o, p);
+ rL->GetNext(&o, &p);
+ }
+ if(Errors && rE){
+ if(data->GetValue(n, m, &e))
+ Errors[ic]= new ErrorBar(this, data, x, y, e, ErrType,
+ i, j, k, l, m, n);
+ rE->GetNext(&m, &n);
+ }
+ else CheckBounds(x, y);
+ ic++;
+ }
+ else {
+ if(Labels && rL) rL->GetNext(&o, &p);
+ if(Errors && rE) rE->GetNext(&m, &n);
+ }
+ c++;
+ }while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l));
+ if(ic) bRet = true;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(rX) delete rX; if(rY) delete rY; if(rE) delete rE; if(rL) delete rL;
+ return (dirty = bRet);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Regression properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+FreqDist::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 25, 10, "Data"};
+ TabSHEET tab2 = {25, 52, 10, "Style"};
+ DlgInfo FreqDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 130, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 25, 45, 12},
+ {3, 0, 4, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
+ {4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 120, 113},
+ {5, 10, 200, ISPARENT, SHEET, &tab2, 5, 10, 120, 113},
+ {10, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"spread sheet range for values", 10, 25, 60, 8},
+ {101, 102, 0, 0x0L, EDTEXT, TmpTxt, 10, 38, 110, 10},
+ {102, 103, 120, ISPARENT | CHECKED, GROUPBOX, (void*)" classes ", 10, 55, 110, 42},
+ {103, 0, 150, ISPARENT | CHECKED, GROUPBOX, (void*)" plot function ", 10, 102, 110, 17},
+ {120, 121, 0, CHECKED, RADIO1, (void*)"create", 15, 60, 30, 9},
+ {121, 122, 0, 0x0L, EDTEXT, (void*)"7", 47, 60, 15, 10},
+ {122, 123, 0, 0x0L, LTEXT, (void*)"classes and bars", 64, 60, 35, 8},
+ {123, 124, 0, 0x0L, RADIO1, (void*)"class size is", 15, 72, 45, 9},
+ {124, 125, 0, 0x0L, EDTEXT, 0L, 65, 72, 50, 10},
+ {125, 126, 0, 0x0L, RTEXT, (void*)"starting at", 15, 84, 47, 8},
+ {126, 0, 0, 0x0L, EDTEXT, 0L, 65, 84, 50, 10},
+ {150, 0, 0, ISRADIO, CHECKBOX, (void*)" normal dist.", 15, 107, 30, 8},
+ {200, 0, 210, ISPARENT | CHECKED, GROUPBOX, (void*)" bar style ", 10, 27, 110, 61},
+ {210, 0, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 25, 34, 90, 50},
+ {800, 0, 0, LASTOBJ, NONE, 0L, 0, 0, 0, 0}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ bool bRet = false;
+ int res, width, height;
+
+ if(!parent || !data) return false;
+ OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&BarLine, 0);
+ OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&BarFill, 0);
+ data->GetSize(&width, &height);
+ sprintf(TmpTxt, "a1:a%d", height);
+ if(!(Dlg = new DlgRoot(FreqDlg)))return false;
+ hDlg = CreateDlgWnd("Frequency Distribution", 50, 50, 370, 280, Dlg, 0x0L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 0:
+ if(Dlg->GetCheck(10)) res=-1;
+ break;
+ case 1:
+ if(Dlg->GetText(101, TmpTxt) && TmpTxt[0]) {
+ if(ssRef) free(ssRef);
+ ssRef = strdup(TmpTxt);
+ }
+ type = 0;
+ if(Dlg->GetCheck(150)) type = 1;
+ break;
+ }
+ }while (res <0);
+ if(res==1 && (plots = (GraphObj**)calloc(nPlots=2, sizeof(GraphObj*)))) {
+ OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&BarLine, 0);
+ OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&BarFill, 0);
+ if(BarFill.hatch) memcpy(&HatchLine, BarFill.hatch, sizeof(LineDEF));
+ BarFill.hatch = &HatchLine;
+ if(Dlg->GetCheck(123) && Dlg->GetValue(124, &step) && Dlg->GetValue(126, &start)) ProcData(-2);
+ else {
+ Dlg->GetValue(121, &step); ProcData(-1);
+ }
+ if(plots[0]) bRet = true;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Regression properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Regression::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 40, 10, "Data"};
+ TabSHEET tab2 = {40, 90, 10, "Transform"};
+ char text1[100], text2[100];
+ DlgInfo RegDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 140, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 140, 25, 45, 12},
+ {3, 0, 4, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 130, 85},
+ {5, 10, 200, ISPARENT, SHEET, &tab2, 5, 10, 130, 85},
+ {10, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"range for X Data", 10, 20, 60, 8},
+ {101, 102, 0, 0x0L, EDTEXT, text1, 20, 30, 100, 10},
+ {102, 103, 0, 0x0L, LTEXT, (void*)"range for Y Data", 10, 45, 60, 8},
+ {103, 104, 0, 0x0L, EDTEXT, text2, 20, 55, 100, 10},
+ {104, 105, 0, CHECKED, CHECKBOX, (void*)" include symbols in plot", 10, 70, 100, 8},
+ {105, 0, 0, 0x0L, CHECKBOX, (void*) " draw SD ellipse", 10, 80, 100, 8},
+ {200, 210, 201, CHECKED | ISPARENT, GROUPBOX, (void*)" x-values ", 10, 30, 58, 50},
+ {201, 202, 0, CHECKED, RADIO1, (void*)"x = x", 20, 40, 30, 8},
+ {202, 203, 0, 0x0L, RADIO1, (void*)"x = log(x)", 20, 48, 30, 8},
+ {203, 204, 0, 0x0L, RADIO1, (void*)"x = 1/x", 20, 56, 30, 8},
+ {204, 0, 0, 0x0L, RADIO1, (void*)"x = sqrt(x)", 20, 64, 30, 8},
+ {210, 0, 211, CHECKED | ISPARENT, GROUPBOX, (void*)" y-values ", 72, 30, 58, 50},
+ {211, 212, 0, CHECKED, RADIO1, (void*)"y = y", 82, 40, 30, 8},
+ {212, 213, 0, 0x0L, RADIO1, (void*)"y = log(y)", 82, 48, 30, 8},
+ {213, 214, 0, 0x0L, RADIO1, (void*)"y = 1/y", 82, 56, 30, 8},
+ {214, 0, 0, LASTOBJ, RADIO1, (void*)"y = sqrt(y)", 82, 64, 30, 8}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int c, i, j, k, l, ic, res, width, height, n;
+ double x, y;
+ AccRange *rX, *rY;
+ bool bRet = false, bContinue = false, dValid;
+ lfPOINT *values = 0L;
+
+ rX = rY = 0L;
+ data->GetSize(&width, &height);
+ sprintf(text1, "a1:a%d", height);
+ sprintf(text2, "b1:b%d", height);
+ Dlg = new DlgRoot(RegDlg);
+ hDlg = CreateDlgWnd("Linear regression analysis step 1/2", 50, 50, 380, 225, Dlg, 0x0L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 0: // focus lost
+ if(bContinue) res = -1;
+ else if(Dlg->GetCheck(10)) res = -1;
+ break;
+ case -1:
+ bContinue = false;
+ break;
+ case 1: // OK
+ if(rX) delete rX; if(rY) delete rY;
+ rX = rY = 0L; // check x-range
+ if(Dlg->GetText(101, TmpTxt)) rX = new AccRange(TmpTxt);
+ if(!(n = rX ? rX->CountItems() : 0)) {
+ Dlg->SetCheck(4, 0L, true);
+ res = -1;
+ bContinue = true;
+ ErrorBox("X-range not specified\nor not valid.");
+ }
+ else { // check y-range
+ if(Dlg->GetText(103, TmpTxt)) rY = new AccRange(TmpTxt);
+ if(n != (rY ? rY->CountItems() : 0)) {
+ res = -1;
+ bContinue = true;
+ ErrorBox("Y-range missing\nor not valid.\n"
+ "Size must match X-range.");
+ }
+ }
+ }
+ }while (res <0);
+ if(res==1 && n && rX && rY && (values =(lfPOINT*)calloc(nPoints=n, sizeof(lfPOINT)))){ //OK pressed
+ Command(CMD_FLUSH, 0L, 0L);
+ if(Dlg->GetText(101, TmpTxt)) xRange = strdup(TmpTxt);
+ if(Dlg->GetText(103, TmpTxt)) yRange = strdup(TmpTxt);
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ rX->GetFirst(&i, &j); rY->GetFirst(&k, &l);
+ rX->GetNext(&i, &j); rY->GetNext(&k, &l);
+ if(Dlg->GetCheck(202)) type = 0x100;
+ else if(Dlg->GetCheck(203)) type = 0x200;
+ else if(Dlg->GetCheck(204)) type = 0x300;
+ if(Dlg->GetCheck(212)) type |= 0x1000;
+ else if(Dlg->GetCheck(213)) type |= 0x2000;
+ else if(Dlg->GetCheck(214)) type |= 0x3000;
+ ic = c = 0;
+ if(Dlg->GetCheck(104)) Symbols = (Symbol**)calloc(nPoints, sizeof(Symbol*));
+ do {
+ if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y)){
+ dValid = true;
+ switch(type & 0x700) {
+ case 0x100: //logarithmic x
+ if(dValid = x > defs.min4log) values[ic].fx = log10(x);
+ break;
+ case 0x200: //reciprocal x
+ if(dValid = fabs(x) >defs.min4log) values[ic].fx = 1.0/x;
+ break;
+ case 0x300: //square root x
+ if(dValid = fabs(x) >defs.min4log) values[ic].fx = sqrt(x);
+ break;
+ default: values[ic].fx = x; break; //linear x
+ }
+ if(dValid) switch(type & 0x7000) {
+ case 0x1000: //logarithmic y
+ if(dValid = y > defs.min4log) values[ic].fy = log10(y);
+ break;
+ case 0x2000: //reciprocal y
+ if(dValid = fabs(y) > defs.min4log) values[ic].fy = 1.0/y;
+ break;
+ case 0x3000: //square root y
+ if(dValid = fabs(y) > defs.min4log) values[ic].fy = sqrt(y);
+ break;
+ default: values[ic].fy = y; break; //linear y
+ }
+ if(dValid && Symbols && (Symbols[ic] = new Symbol(this, data, x, y,
+ SYM_CIRCLE, i, j, k, l))){
+ Symbols[ic]->idx = c;
+ }
+ if(dValid) {
+ CheckBounds(x, y);
+ ic++;
+ }
+ }
+ c++;
+ }while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l));
+ if(ic) {
+ if(Dlg->GetCheck(105) && (sde = new SDellipse(this, data, values, ic, type | 0x2))&&
+ (bRet= sde->Command(CMD_INIT, 0L, 0L)))sde->Command(CMD_BOUNDS, &Bounds, 0L);
+ else if((rLine = new RegLine(this, data, values, ic, type)) &&
+ (bRet= rLine->PropertyDlg()))rLine->Command(CMD_BOUNDS, &Bounds, 0L);
+ }
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(rX) delete rX; if(rY) delete rY;
+ if(values) free(values);
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Bubble plot properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+BubblePlot::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 40, 10, "Data"};
+ TabSHEET tab2 = {40, 85, 10, "Layout"};
+ TabSHEET tab3 = {85, 130, 10, "Scaling"};
+ char text1[100], text2[100], text3[100];
+ int syms[] = {SYM_CIRCLE, SYM_RECT, SYM_TRIAU, SYM_TRIAD};
+ FillDEF ShowFill;
+ DlgInfo PlotDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 148, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 148, 25, 45, 12},
+ {3, 500, 4, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
+ {4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 130, 120},
+ {5, 6, 200, ISPARENT, SHEET, &tab2, 5, 10, 130, 120},
+ {6, 10, 300, ISPARENT, SHEET, &tab3, 5, 10, 130, 120},
+ {10, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"range for X Data", 10, 40, 60, 8},
+ {101, 102, 0, 0x0L, EDTEXT, text1, 20, 50, 100, 10},
+ {102, 103, 0, 0x0L, LTEXT, (void*)"range for Y Data", 10, 65, 60, 8},
+ {103, 104, 0, 0x0L, EDTEXT, text2, 20, 75, 100, 10},
+ {104, 105, 0, 0x0L, LTEXT, (void*)"range for sizes", 10, 90, 60, 8},
+ {105, 0, 0, 0x0L, EDTEXT, text3, 20, 100, 100, 10},
+ {200, 201, 0, 0x0L, LTEXT, (void*)"Select one of the following shapes", 10, 30, 110, 8},
+ {201, 202, 0, CHECKED, SYMRADIO, (void *)&syms[0], 30, 40, 20, 20},
+ {202, 203, 0, 0x0L, SYMRADIO, (void *)&syms[1], 50, 40, 20, 20},
+ {203, 204, 0, 0x0L, SYMRADIO, (void *)&syms[2], 70, 40, 20, 20},
+ {204, 205, 0, 0x0L, SYMRADIO, (void *)&syms[3], 90, 40, 20, 20},
+ {205, 206, 0, 0x0L, LTEXT, (void*)"outline:", 7, 67, 45, 8},
+ {206, 207, 0, 0x0L, RTEXT, (void*)"color", 7, 75, 20, 8},
+ {207, 208, 0, OWNDIALOG, COLBUTTON, (void *)BubbleLine.color, 29, 75, 25, 10},
+ {208, 209, 0, 0x0L, RTEXT, (void*)"line width", 67, 75, 20, 8},
+ {209, 210, 0, 0x0L, EDVAL1, &BubbleLine.width, 88, 75, 25, 10},
+ {210, 211, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 114, 75, 15, 8},
+ {211, 212, 0, 0x0L, LTEXT, (void*)"fill:", 7, 97, 45, 8},
+ {212, 213, 0, 0x0L, RTEXT, (void*)"color", 7, 105, 20, 8},
+ {213, 214, 0, TOUCHEXIT | OWNDIALOG, COLBUTTON, (void *)BubbleFill.color, 29, 105, 25, 10},
+ {214, 215, 0, 0x0L, RTEXT, (void*)"pattern", 67, 105, 20, 8},
+ {215, 0, 0, TOUCHEXIT | OWNDIALOG, FILLBUTTON, (void *)&ShowFill, 88, 105, 25, 10},
+ {300, 301, 0, 0x0L, LTEXT, (void*)"Sizes are given as", 10, 30, 110, 8},
+ {301, 302, 400, ISPARENT | CHECKED, GROUP, NULL, 0, 0, 0, 0},
+ {302, 303, 0, 0x0L, LTEXT, (void*)"Proportionality (relative to circle)", 10, 75, 110, 8},
+ {303, 0, 410, ISPARENT | CHECKED, GROUP, NULL, 0, 0, 0, 0},
+ {400, 401, 0, CHECKED, RADIO1, (void *) Units[defs.cUnits].display, 40, 40, 45, 8},
+ {401, 402, 0, 0x0L, RADIO1, (void*)"scaling with X axis", 40, 50, 45, 8},
+ {402, 0, 0, 0x0L, RADIO1, (void*)"scaling with Y axis", 40, 60, 45, 8},
+ {410, 411, 0, CHECKED, RADIO1, (void*)"diameter", 40, 85, 45, 8},
+ {411, 412, 0, 0x0L, RADIO1, (void*)"circumference", 40, 95, 45, 8},
+ {412, 0, 0, LASTOBJ, RADIO1, (void*)"area", 40, 105, 45, 8}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, j, k, l, m, n, ic, res, width, height, BubbleType;
+ double x, y, s;
+ double tmp;
+ bool bRetVal = false, bFillChanged, bContinue = false;
+ AccRange *rX, *rY, *rS;
+ LineDEF ShowFillLine ={0.2f, 1.0f, 0x0L, 0x0L};
+
+ data->GetSize(&width, &height);
+ sprintf(text1, "a1:a%d", height);
+ sprintf(text2, "b1:b%d", height);
+ sprintf(text3, "c1:c%d", height);
+ memcpy(&ShowFill, &BubbleFill, sizeof(FillDEF));
+ if(BubbleFill.hatch) memcpy(&ShowFillLine, BubbleFill.hatch, sizeof(LineDEF));
+ ShowFill.hatch = &ShowFillLine;
+ Dlg = new DlgRoot(PlotDlg);
+ hDlg = CreateDlgWnd("Create Bubble Plot", 50, 50, 400, 300, Dlg, 0x0L);
+ rX = rY = rS = 0L;
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 0: // focus lost
+ if(bContinue) res = -1;
+ else if(Dlg->GetCheck(10)) res = -1;
+ break;
+ case -1:
+ bContinue = false;
+ break;
+ case 213: //fillcolor changed
+ Dlg->GetColor(213, &ShowFill.color);
+ Dlg->DoPlot(NULL);
+ res = -1;
+ break;
+ case 215: //copy color from pattern dialog
+ Dlg->SetColor(213, ShowFill.color);
+ bFillChanged = true;
+ res = -1;
+ break;
+ case 1: //OK button
+ if(Dlg->GetText(101, text1) && Dlg->GetText(103, text2) &&
+ Dlg->GetText(105, text3) && (rX = new AccRange(text1)) &&
+ (rY = new AccRange(text2)) && (rS = new AccRange(text3))) {
+ if((i = rX->CountItems()) == rY->CountItems() && i == rS->CountItems()){
+ // OK pressed and ranges checked: exit loop and process data
+ }
+ else {
+ if(rX) delete (rX); if(rY) delete (rY); if(rS) delete (rS);
+ rX = rY = rS = 0L;
+ ErrorBox("Ranges must be of equal size");
+ Dlg->SetCheck(4, 0L, bContinue = true);
+ res = -1;
+ }
+ }
+ else res = -1; //continue with dialog if error
+ }
+ }while (res <0);
+ if(res ==1 && rX && rY && rS && (nPoints = rX->CountItems()) &&
+ (Bubbles = (Bubble**)calloc(nPoints, sizeof(Bubble*)))) {
+ //accept settings and create bubbles for plot
+ if(Dlg->GetCheck(202)) BubbleType = BUBBLE_SQUARE;
+ else if(Dlg->GetCheck(203)) BubbleType = BUBBLE_UPTRIA;
+ else if(Dlg->GetCheck(204)) BubbleType = BUBBLE_DOWNTRIA;
+ else BubbleType = BUBBLE_CIRCLE;
+ if(Dlg->GetCheck(401)) BubbleType |= BUBBLE_XAXIS;
+ else if(Dlg->GetCheck(402)) BubbleType |= BUBBLE_YAXIS;
+ if(Dlg->GetCheck(411)) BubbleType |= BUBBLE_CIRCUM;
+ else if(Dlg->GetCheck(412)) BubbleType |= BUBBLE_AREA;
+ if(Dlg->GetValue(209, &tmp)) BubbleLine.width = (float)tmp;
+ Dlg->GetColor(207, &BubbleLine.color); Dlg->GetColor(213, &BubbleFill.color);
+ rX->GetFirst(&i, &j); rY->GetFirst(&k, &l); rS->GetFirst(&m, &n);
+ rX->GetNext(&i, &j); rY->GetNext(&k, &l); rS->GetNext(&m, &n);
+ ic = 0;
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ if(Bubbles) do {
+ if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y) && data->GetValue(n, m, &s)){
+ CheckBounds(x, y);
+ Bubbles[ic++] = new Bubble(this, data, x, y, s, BubbleType, &ShowFill,
+ &BubbleLine, i, j, k, l, m, n);
+ }
+ }while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l) && rS->GetNext(&m, &n));
+ bRetVal = ic >0;
+ }
+ CloseDlgWnd(hDlg);
+ if(rX) delete (rX); if(rY) delete (rY); if(rS) delete (rS);
+ delete Dlg;
+ return bRetVal;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Polar plot properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+PolarPlot::AddPlot()
+{
+ char text1[100], text2[100];
+ DlgInfo PolDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 140, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 140, 25, 45, 12},
+ {3, 0, 200, ISPARENT | CHECKED, GROUPBOX, (void*)" select template and data range ", 5, 10, 131, 100},
+ {200, 201, 0, CHECKED | TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PolarTempl, 10, 20, 20, 20},
+ {201, 202, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PolarTempl, 30, 20, 20, 20},
+ {202, 203, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PolarTempl, 50, 20, 20, 20},
+ {203, 204, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PolarTempl, 70, 20, 20, 20},
+ {204, 210, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PolarTempl, 90, 20, 20, 20},
+ {210, 211, 0, 0x0L, LTEXT, (void*)"range for x-data (circular or angular data)", 10, 50, 50, 8},
+ {211, 212, 0, 0x0L, EDTEXT, (void*)text1, 20, 62, 100, 10},
+ {212, 213, 0, 0x0L, LTEXT, (void*)"range for y-data (radial data)", 10, 75, 50, 8},
+ {213, 0, 0, LASTOBJ, EDTEXT, (void*)text2, 20, 87, 100, 10}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, j, k, l, ic, n, res, width, height, cType = 200;
+ bool bRet = false;
+ double x, y;
+ AccRange *rX = 0L, *rY = 0L;
+ Symbol **Symbols = 0L;
+ DataLine *TheLine = 0L;
+ Plot **tmpPlots;
+ Function *func;
+
+ data->GetSize(&width, &height);
+ sprintf(text1, "a1:a%d", height);
+ sprintf(text2, "b1:b%d", height);
+ if(!(Dlg = new DlgRoot(PolDlg)))return false;
+ hDlg = CreateDlgWnd("Add Polar Plot", 50, 50, 388, 260, Dlg, 0x0L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 200: case 201: case 202: case 203: case 204:
+ if(res == 204) {
+ Dlg->Activate(211, false); Dlg->Activate(213, false);
+ }
+ else if(cType == 204) {
+ Dlg->Activate(211, true); Dlg->Activate(213, true);
+ }
+ if(res == cType) res = 1;
+ else {
+ cType = res;
+ res = -1;
+ }
+ break;
+ }
+ }while (res <0);
+ if(res == 1 && Dlg->GetText(211, text1) && Dlg->GetText(213, text2) &&
+ (rX = new AccRange(text1)) && (rY = new AccRange(text2)) &&
+ (n = rX ? rX->CountItems() : 0) &&
+ (tmpPlots = (Plot**)realloc(Plots, (nPlots+2)*sizeof(Plot*)))) {
+ Plots = tmpPlots;
+ if(Dlg->GetCheck(200) || Dlg->GetCheck(201))
+ Symbols = (Symbol**) calloc(n+1, sizeof(Symbol*));
+ if(Dlg->GetCheck(201) || Dlg->GetCheck(202))
+ TheLine = new DataLine(this, data, text1, text2);
+ else if(Dlg->GetCheck(203))
+ TheLine = new DataPolygon(this, data, text1, text2);
+ else if(Dlg->GetCheck(204)) {
+ if(func = new Function(this, data)){
+ if(bRet = func->PropertyDlg()){
+ Undo.SetGO(this, (GraphObj**) &Plots[nPlots++], func, 0L);
+ memcpy(&Bounds, &Plots[nPlots-1]->Bounds, sizeof(fRECT));
+ }
+ else DeleteGO(func);
+ }
+ }
+ rX->GetFirst(&i, &j); rY->GetFirst(&k, &l);
+ rX->GetNext(&i, &j); rY->GetNext(&k, &l);
+ ic = 0;
+ if(Symbols || TheLine) {
+ do {
+ if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y)){
+ CheckBounds(y, y);
+ if(Symbols)Symbols[ic++] = new Symbol(this,data,x,y,SYM_CIRCLE,i,j,k,l);
+ }
+ }while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l));
+ Undo.SetGO(this, (GraphObj**) &Plots[nPlots++],
+ new PlotScatt(this, data, ic, Symbols, TheLine), 0L);
+ bRet = true;
+ }
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(rX) delete rX; if(rY) delete rY;
+ return bRet;
+}
+
+bool
+PolarPlot::Config()
+{
+ TabSHEET tab1 = {0, 40, 10, "Plot"};
+ DlgInfo PPDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 102, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 102, 25, 45, 12},
+ {3, 0, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 90, 90},
+ {100, 101, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 8, 30, 90, 50},
+ {101, 0, 0, LASTOBJ, CHECKBOX, (void*)"show radial axis", 15, 85, 60, 9}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res;
+ bool bRet = false;
+ LineDEF OutLine;
+
+ memcpy(&OutLine, defs.GetOutLine(), sizeof(LineDEF));
+ if(Axes && Axes[0]) {
+ OutLine.color = Axes[0]->GetColor(COL_AXIS);
+ OutLine.width = Axes[0]->GetSize(SIZE_AXIS_LINE);
+ }
+ OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&OutLine, 0);
+ OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&Fill, 0);
+ Dlg = new DlgRoot(PPDlg);
+ if(!(type & 0x01))Dlg->SetCheck(101, 0L, true);
+ hDlg = CreateDlgWnd("Polar Plot properties", 50, 50, 310, 234, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ }while (res < 0);
+ if(res == 1){ //OK pressed
+ if(Dlg->GetCheck(101)) type &= ~0x01;
+ else type |= 0x01;
+ OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&OutLine, 0);
+ if(Axes && Axes[0]) {
+ Axes[0]->SetColor(COL_AXIS, OutLine.color);
+ Axes[0]->SetSize(SIZE_AXIS_LINE, OutLine.width);
+ }
+ OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&Fill, 0);
+ if(Fill.hatch) memcpy(&FillLine, Fill.hatch, sizeof(LineDEF));
+ Fill.hatch = &FillLine;
+ bRet = true;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+bool
+PolarPlot::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 45, 10, "Coordinates"};
+ TabSHEET tab2 = {45, 70, 10, "Type"};
+ char text1[100], text2[100];
+ double lox = 0.0, hix = 360.0, fcx =10.0, fcy = 20.0, frad=40.0;
+ DlgInfo PolDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 140, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 140, 25, 45, 12},
+ {3, 50, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
+ {4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 131, 100},
+ {5, 10, 200, ISPARENT | TOUCHEXIT, SHEET, &tab2, 5, 10, 131, 100},
+ {10, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"angular range (full circle)", 10, 25, 60, 8},
+ {101, 102, 0, 0x0L, RTEXT, (void*)"min =", 5, 37, 25, 8},
+ {102, 103, 0, 0x0L, EDVAL1, &lox, 30, 37, 30, 10},
+ {103, 104, 0, 0x0L, RTEXT, (void*)"max =", 60, 37, 25, 8},
+ {104, 105, 0, 0x0L, EDVAL1, &hix, 85, 37, 30, 10},
+ {105, 106, 0, 0x0L, RTEXT, (void*)"angular offset:", 10, 49, 50, 8},
+ {106, 107, 0, 0x0L, EDVAL1, &offs, 62, 49, 30, 10},
+ {107, 108, 0, 0x0L, LTEXT, (void*)"position of center:", 10, 65, 40, 8},
+ {108, 109, 0, 0x0L, RTEXT, (void*)"x =", 5, 77, 25, 8},
+ {109, 110, 0, 0x0L, EDVAL1, &fcx, 30, 77, 30, 10},
+ {110, 111, 0, 0x0L, RTEXT, (void*)"y =", 60, 77, 25, 8},
+ {111, 112, 0, 0x0L, EDVAL1, &fcy, 85, 77, 30, 10},
+ {112, 113, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 117, 77, 15, 8},
+ {113, 114, 0, 0x0L, EDVAL1, &frad, 62, 89, 30, 10},
+ {114, 115, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 94, 89, 15, 8},
+ {115, 0, 0, 0x0L, RTEXT, (void*)"radius:", 10, 89, 50, 8},
+ {200, 201, 0, CHECKED | TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PolarTempl, 10, 25, 20, 20},
+ {201, 202, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PolarTempl, 30, 25, 20, 20},
+ {202, 203, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PolarTempl, 50, 25, 20, 20},
+ {203, 204, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PolarTempl, 70, 25, 20, 20},
+ {204, 210, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PolarTempl, 90, 25, 20, 20},
+ {210, 211, 0, 0x0L, LTEXT, (void*)"range for x-data (circular or angular data)", 10, 55, 50, 8},
+ {211, 212, 0, 0x0L, EDTEXT, (void*)text1, 20, 67, 100, 10},
+ {212, 213, 0, 0x0L, LTEXT, (void*)"range for y-data (radial data)", 10, 80, 50, 8},
+ {213, 0, 0, LASTOBJ, EDTEXT, (void*)text2, 20, 92, 100, 10}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, width, height, i, j, k, l, n, ic, cType = 200;
+ double x, y;
+ bool bRet = false, bType = false;
+ AccRange *rX = 0L, *rY = 0L;
+ Symbol **Symbols = 0L;
+ DataLine *TheLine = 0L;
+ TextDEF tlbdef;
+ AxisDEF ang_axis, rad_axis;
+
+ if(Plots) return Config();
+ if(parent) {
+ frad = (parent->GetSize(SIZE_DRECT_BOTTOM) - parent->GetSize(SIZE_DRECT_TOP))/2.0f;
+ fcx = parent->GetSize(SIZE_GRECT_LEFT) + parent->GetSize(SIZE_DRECT_LEFT)*1.5 + frad;
+ fcy = parent->GetSize(SIZE_GRECT_TOP) + parent->GetSize(SIZE_DRECT_TOP) + frad;
+ }
+ else return false;
+ data->GetSize(&width, &height);
+ sprintf(text1, "a1:a%d", height);
+ sprintf(text2, "b1:b%d", height);
+ tlbdef.ColTxt = defs.Color(COL_AXIS);
+ tlbdef.ColBg = 0x00ffffffL;
+ tlbdef.RotBL = tlbdef.RotCHAR = 0.0f;
+ tlbdef.fSize = defs.GetSize(SIZE_TICK_LABELS);
+ tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
+ tlbdef.Style = TXS_NORMAL;
+ tlbdef.Mode = TXM_TRANSPARENT;
+ tlbdef.Font = FONT_HELVETICA;
+ tlbdef.text = 0L;
+ if(!(Dlg = new DlgRoot(PolDlg)))return false;
+ hDlg = CreateDlgWnd("Create Polar Plot", 50, 50, 388, 260, Dlg, 0x0L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 0:
+ if(Dlg->GetCheck(10)) res = -1;
+ break;
+ case 5:
+ bType = true;
+ res = -1;
+ break;
+ case 1:
+ if(!bType) { //the 'Type' sheet must have been visited
+ bType = true;
+ Dlg->SetCheck(5, 0L, true);
+ res = -1;
+ }
+ break;
+ case 200: case 201: case 202: case 203: case 204:
+ if(res == 204) {
+ Dlg->Activate(211, false); Dlg->Activate(213, false);
+ }
+ else if(cType == 204) {
+ Dlg->Activate(211, true); Dlg->Activate(213, true);
+ }
+ if(res == cType) res = 1;
+ else {
+ cType = res;
+ res = -1;
+ }
+ break;
+ }
+ }while (res <0);
+ if(res == 1) {
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ //set axis information in ang_axis and rad_axis
+ ang_axis.owner = rad_axis.owner = 0L;
+ ang_axis.breaks = rad_axis.breaks = 0L;
+ ang_axis.nBreaks = rad_axis.nBreaks = 0;
+ ang_axis.flags = AXIS_ANGULAR;
+ rad_axis.flags = AXIS_RADIAL | AXIS_DEFRECT;
+ Dlg->GetValue(109, &ang_axis.Center.fx);
+ rad_axis.Center.fx = ang_axis.Center.fx;
+ Dlg->GetValue(111, &ang_axis.Center.fy);
+ rad_axis.Center.fy = ang_axis.Center.fy;
+ Dlg->GetValue(113, &ang_axis.Radius);
+ rad_axis.Radius = ang_axis.Radius;
+ Dlg->GetValue(102, &ang_axis.min);
+ Dlg->GetValue(104, &ang_axis.max);
+ Dlg->GetValue(106, &offs);
+ ang_axis.loc[0].fy = ang_axis.loc[1].fy = ang_axis.Center.fy + ang_axis.Radius;
+ ang_axis.loc[0].fx = ang_axis.Center.fx - ang_axis.Radius;
+ ang_axis.loc[1].fx = ang_axis.Center.fx + ang_axis.Radius;
+ rad_axis.loc[0].fx = rad_axis.loc[1].fx =
+ parent->GetSize(SIZE_GRECT_LEFT) + parent->GetSize(SIZE_DRECT_LEFT);
+ rad_axis.loc[0].fy = rad_axis.Center.fy - rad_axis.Radius;
+ rad_axis.loc[1].fy = rad_axis.Center.fy;
+ if(Dlg->GetText(211, text1) && Dlg->GetText(213, text2) &&
+ (rX = new AccRange(text1)) && (rY = new AccRange(text2)) &&
+ (n = rX ? rX->CountItems() : 0) && (Plots = (Plot**)calloc(2, sizeof(Plot*)))) {
+ if(Dlg->GetCheck(200) || Dlg->GetCheck(201))
+ Symbols = (Symbol**) calloc(n+1, sizeof(Symbol*));
+ if(Dlg->GetCheck(201) || Dlg->GetCheck(202))
+ TheLine = new DataLine(this, data, text1, text2);
+ else if(Dlg->GetCheck(203))
+ TheLine = new DataPolygon(this, data, text1, text2);
+ else if(Dlg->GetCheck(204)) {
+ if(Plots[nPlots++] = new Function(this, data)){
+ if(bRet = Plots[nPlots-1]->PropertyDlg())
+ memcpy(&Bounds, &Plots[nPlots-1]->Bounds, sizeof(fRECT));
+ else {
+ DeleteGO(Plots[nPlots-1]);
+ Plots[nPlots-1] = 0L;
+ }
+ }
+ }
+ rX->GetFirst(&i, &j); rY->GetFirst(&k, &l);
+ rX->GetNext(&i, &j); rY->GetNext(&k, &l);
+ ic = 0;
+ if(Symbols || TheLine) do {
+ if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y)){
+ CheckBounds(y, y);
+ if(Symbols) Symbols[ic++] = new Symbol(this, data, x, y,
+ SYM_CIRCLE, i, j, k, l);
+ }
+ }while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l));
+ rad_axis.min = Bounds.Ymin; rad_axis.max = Bounds.Ymax;
+ NiceAxis(&rad_axis, 4);
+ ang_axis.Start = ang_axis.Step = 0.0;
+ if(Symbols || TheLine)
+ Plots[nPlots++] = new PlotScatt(this, data, ic, Symbols, TheLine);
+ if(Plots[0] && (Axes = (GraphObj**)calloc(3, sizeof(Axis*)))){
+ Axes[0] = new Axis(this, data, &ang_axis, ang_axis.flags);
+ Axes[1] = new Axis(this, data, &rad_axis,
+ rad_axis.flags | AXIS_AUTOTICK | AXIS_NEGTICKS);
+ Axes[1]->SetSize(SIZE_LB_XDIST,
+ NiceValue(-defs.GetSize(SIZE_AXIS_TICKS)*6.0));
+ Axes[1]->SetSize(SIZE_TLB_XDIST,
+ NiceValue(-defs.GetSize(SIZE_AXIS_TICKS)*2.0));
+ Axes[1]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+ nAxes = 2;
+ bRet = true;
+ }
+ }
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(rX) delete rX; if(rY) delete rY;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Box plot properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+BoxPlot::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 36, 10, "Summary"};
+ TabSHEET tab2 = {36, 56, 10, "Box"};
+ TabSHEET tab3 = {56, 89, 10, "Whisker"};
+ TabSHEET tab4 = {89, 119, 10, "Symbol"};
+ TabSHEET tab5 = {119, 140, 10, "Line"};
+ char text1[100];
+ DlgInfo PlotDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 158, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 158, 25, 45, 12},
+ {3, 800, 4, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
+ {4, 5, 0, 0x0L, LTEXT, (void*)"spreadsheet range for common X values", 15, 88, 120, 8},
+ {5, 6, 0, 0x0L, EDTEXT, text1, 25, 100, 100, 10},
+ {6, 7, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 140, 75},
+ {7, 8, 200, ISPARENT, SHEET, &tab2, 5, 10, 140, 75},
+ {8, 9, 300, ISPARENT, SHEET, &tab3, 5, 10, 140, 75},
+ {9, 10, 400, ISPARENT, SHEET, &tab4, 5, 10, 140, 75},
+ {10, 20, 500, ISPARENT, SHEET, &tab5, 5, 10, 140, 75},
+ {20, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"items:", 15, 30, 15, 8},
+ {101, 102, 0, 0x0L, CHECKBOX, (void*)" boxes (rectangles)", 40, 30, 60, 8},
+ {102, 103, 0, 0x0L, CHECKBOX, (void*)" whiskers (error bars)", 40, 40, 60, 8},
+ {103, 104, 0, 0x0L, CHECKBOX, (void*)" symbol in the middle", 40, 50, 60, 8},
+ {104, 105, 0, 0x0L, CHECKBOX, (void*)" line connecting close - open", 40, 60, 60, 8},
+ {105, 0, 0, 0x0L, CHECKBOX, (void*)" horizontal plot", 15, 72, 60, 8},
+ {200, 201, 0, 0x0L, LTEXT, (void*)"range for high values", 15, 30, 60, 8},
+ {201, 202, 0, 0x0L, EDTEXT, 0L, 25, 40, 100, 10},
+ {202, 203, 0, 0x0L, LTEXT, (void*)"range for low values", 15, 55, 60, 8},
+ {203, 0, 0, 0x0L, EDTEXT, 0L, 25, 65, 100, 10},
+ {300, 301, 0, 0x0L, LTEXT, (void*)"range for maxima", 15, 30, 60, 8},
+ {301, 302, 0, 0x0L, EDTEXT, 0L, 25, 40, 100, 10},
+ {302, 303, 0, 0x0L, LTEXT, (void*)"range for minima", 15, 55, 60, 8},
+ {303, 0, 0, 0x0L, EDTEXT, 0L, 25, 65, 100, 10},
+ {400, 401, 0, 0x0L, LTEXT, (void*)"mark centers with symbols,", 15, 30, 60, 8},
+ {401, 402, 0, 0x0L, LTEXT, (void*)"range for centers (means):", 15, 40, 60, 8},
+ {402, 0, 0, 0x0L, EDTEXT, 0L, 25, 55, 100, 10},
+ {500, 501, 0, 0x0L, LTEXT, (void*)"range for first value (open)", 15, 30, 60, 8},
+ {501, 502, 0, 0x0L, EDTEXT, 0L, 25, 40, 100, 10},
+ {502, 503, 0, 0x0L, LTEXT, (void*)"range for second value (close)", 15, 55, 60, 8},
+ {503, 0, 0, LASTOBJ, EDTEXT, 0L, 25, 65, 100, 10}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, j, k, l, m, n, ic, res, width, height;
+ bool bHor, bRet, bContinue = false;
+ lfPOINT fp1, fp2;
+ double x, y1, y2;
+ AccRange *rX, *rB1, *rB2, *rW1, *rW2, *rS, *rL1, *rL2;
+
+ rX = rB1 = rB2 = rW1 = rW2 = rS = rL1 = rL2 = 0L;
+ data->GetSize(&width, &height);
+ sprintf(text1, "a1:a%d", height);
+ Dlg = new DlgRoot(PlotDlg);
+ hDlg = CreateDlgWnd("Box and Whisker Plot", 50, 50, 420, 260, Dlg, 0x0L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 0:
+ if(bContinue) res = -1;
+ else if(Dlg->GetCheck(20)) res = -1;
+ break;
+ case -1:
+ bContinue = false;
+ break;
+ case 1:
+ if(rX) delete rX;
+ if(rB1) delete rB1; if(rB2) delete rB2;
+ if(rW1) delete rW1; if(rW2) delete rW2;
+ if(rS) delete rS;
+ if(rL1) delete rL1; if(rL2) delete rL2;
+ rX = rB1 = rB2 = rW1 = rW2 = rS = rL1 = rL2 = 0L;
+ bHor = Dlg->GetCheck(105);
+ if(Dlg->GetText(5, text1)) rX = new AccRange(text1);
+ n = rX ? rX->CountItems() : 0;
+ if(!n) {
+ ErrorBox("Common X-range not specified\nor not valid.");
+ bContinue = true;
+ res = -1;
+ }
+ if(n && Dlg->GetCheck(101)) { //do boxes ?
+ if(Dlg->GetText(201, TmpTxt)) rB1 = new AccRange(TmpTxt);
+ if(Dlg->GetText(203, TmpTxt)) rB2 = new AccRange(TmpTxt);
+ if(!rB1 || !rB2 || n != rB1->CountItems() || n != rB2->CountItems()) {
+ ErrorBox("Range for boxes missing\nor not valid.\n"
+ "Size must match common X-range.");
+ Dlg->SetCheck(7, 0L, true);
+ bContinue = true;
+ res = -1;
+ }
+ }
+ if(n && Dlg->GetCheck(102)) { //do whiskers ?
+ if(Dlg->GetText(301, TmpTxt)) rW1 = new AccRange(TmpTxt);
+ if(Dlg->GetText(303, TmpTxt)) rW2 = new AccRange(TmpTxt);
+ if(!rW1 || !rW2 || n != rW1->CountItems() || n != rW2->CountItems()) {
+ ErrorBox("Range for whiskers missing\nor not valid.\n"
+ "Size must match common X-range.");
+ Dlg->SetCheck(8, 0L, true);
+ bContinue = true;
+ res = -1;
+ }
+ }
+ if(n && Dlg->GetCheck(103)) { //do symbols ?
+ if(Dlg->GetText(402, TmpTxt)) rS = new AccRange(TmpTxt);
+ if(!rS || n != rS->CountItems()) {
+ ErrorBox("Range for symbols missing\nor not valid.\n"
+ "Size must match common X-range.");
+ bContinue = true;
+ Dlg->SetCheck(9, 0L, true);
+ res = -1;
+ }
+ }
+ if(n && Dlg->GetCheck(104)) { //do line ?
+ if(Dlg->GetText(501, TmpTxt)) rL1 = new AccRange(TmpTxt);
+ if(Dlg->GetText(503, TmpTxt)) rL2 = new AccRange(TmpTxt);
+ if(!rL1 || !rL2 || n != rL1->CountItems() || n != rL2->CountItems()) {
+ ErrorBox("Range for line missing\nor not valid.\n"
+ "Size must match common X-range.");
+ Dlg->SetCheck(10, 0L, true);
+ bContinue = true;
+ res = -1;
+ }
+ }
+ if(n && res > 0 && !rB1 && !rB2 && !rW1 && !rW2 && !rS && !rL1 && !rL2) {
+ ErrorBox("Nothing to do !\n\nSelect at least one of either\n"
+ "Box, Whisker, Symbol or Line.");
+ bContinue = true;
+ res = -1;
+ }
+ break;
+ }
+ }while (res < 0);
+ bRet = false;
+ if(res == 1 && n && rX){ //ok: create objects for plot
+ nPoints = n;
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ if(rB1 && rB2) {
+ //DEBUG: delete existing objects first
+ Boxes =(Box**)calloc(nPoints, sizeof(Box*));
+ if(Boxes) {
+ rX->GetFirst(&i, &j); rB1->GetFirst(&k, &l); rB2->GetFirst(&m, &n);
+ rX->GetNext(&i, &j); rB1->GetNext(&k, &l); rB2->GetNext(&m, &n);
+ ic = 0;
+ do {
+ if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y1) &&
+ data->GetValue(n, m, &y2)){
+ if(bHor) {
+ fp1.fx = y2; fp2.fx = y1; fp1.fy = fp2.fy = x;
+ CheckBounds(y1, x); CheckBounds(y2, x);
+ Boxes[ic++] = new Box(this, data, fp1, fp2, 0, m, n, i, j, k, l, i, j);
+ }
+ else {
+ fp1.fy = y2; fp2.fy = y1; fp1.fx = fp2.fx = x;
+ CheckBounds(x, y1); CheckBounds(x, y2);
+ Boxes[ic++] = new Box(this, data, fp1, fp2, 0, i, j, m, n, i, j, k, l);
+ }
+ }
+ }while(rX->GetNext(&i, &j) && rB1->GetNext(&k, &l) && rB2->GetNext(&m, &n));
+ if(ic) bRet = true;
+ BoxDist.fx = BoxDist.fy = GetSize(bHor ? SIZE_BOXMINY : SIZE_BOXMINX);
+ }
+ }
+ if(rW1 && rW2) {
+ Whiskers = (Whisker**)calloc(nPoints, sizeof(Whisker*));
+ if(Whiskers) {
+ rX->GetFirst(&i, &j); rW1->GetFirst(&k, &l); rW2->GetFirst(&m, &n);
+ rX->GetNext(&i, &j); rW1->GetNext(&k, &l); rW2->GetNext(&m, &n);
+ ic = 0;
+ do {
+ if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y1) &&
+ data->GetValue(n, m, &y2)){
+ if(bHor) {
+ fp1.fx = y2; fp2.fx = y1; fp1.fy = fp2.fy = x;
+ CheckBounds(y1, x); CheckBounds(y2, x);
+ Whiskers[ic++] = new Whisker(this, data, fp1, fp2, 0, m, n, i, j, k, l, i, j);
+ }
+ else {
+ fp1.fy = y2; fp2.fy = y1; fp1.fx = fp2.fx = x;
+ CheckBounds(x, y1); CheckBounds(x, y2);
+ Whiskers[ic++] = new Whisker(this, data, fp1, fp2, 0, i, j, m, n, i, j, k, l);
+ }
+ }
+ }while(rX->GetNext(&i, &j) && rW1->GetNext(&k, &l) && rW2->GetNext(&m, &n));
+ if(ic) bRet = true;
+ }
+ }
+ if(rS) {
+ Symbols = (Symbol**)calloc(nPoints, sizeof(Symbol*));
+ if(Symbols) {
+ rX->GetFirst(&i, &j); rS->GetFirst(&k, &l);
+ rX->GetNext(&i, &j); rS->GetNext(&k, &l);
+ ic = 0;
+ do {
+ if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y1)){
+ if(bHor) {
+ CheckBounds(y1, x);
+ Symbols[ic++] = new Symbol(this, data, y1, x,
+ SYM_PLUS, k, l, i, j);
+ }
+ else {
+ CheckBounds(x, y1);
+ Symbols[ic++] = new Symbol(this, data, x, y1,
+ SYM_PLUS, i, j, k, l);
+ }
+ }
+ }while(rX->GetNext(&i, &j) && rS->GetNext(&k, &l));
+ if(ic) bRet = true;
+ }
+ }
+ if(rL1 && rL2) {
+ Dlg->GetText(501, TmpTxt); i = strlen(TmpTxt);
+ TmpTxt[i++] = ';'; TmpTxt[i++] = ' ';
+ Dlg->GetText(503, TmpTxt+i);
+ TheLine = new DataLine(this, data, text1, TmpTxt);
+ bRet = true;
+ }
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(rX) delete rX;
+ if(rB1) delete rB1; if(rB2) delete rB2;
+ if(rW1) delete rW1; if(rW2) delete rW2;
+ if(rS) delete rS;
+ if(rL1) delete rL1; if(rL2) delete rL2;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create density distribution plot
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+DensDisp::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 25, 10, "Data"};
+ TabSHEET tab2 = {25, 52, 10, "Style"};
+ char text1[100], text2[100];
+ DlgInfo PlotDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 148, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 148, 25, 45, 12},
+ {3, 0, 4, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
+ {4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 130, 100},
+ {5, 10, 200, TOUCHEXIT | ISPARENT, SHEET, &tab2, 5, 10, 130, 100},
+ {10, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"range for direction (time, depth) data", 10, 30, 60, 8},
+ {101, 102, 0, 0x0L, EDTEXT, text1, 20, 40, 100, 10},
+ {102, 103, 0, 0x0L, LTEXT, (void*)"range for width (density) data", 10, 55, 60, 8},
+ {103, 104, 0, 0x0L, EDTEXT, text2, 20, 65, 100, 10},
+ {104, 0, 0, 0x0L, CHECKBOX, (void*)"vertical profile", 10, 90, 100, 8},
+ {200, 201, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 25, 30, 90, 45},
+ {201, 202, 0, TOUCHEXIT | CHECKED, RADIO1, (void*)"symmetric bars", 25, 80, 60, 8},
+ {202, 203, 0, TOUCHEXIT, RADIO1, 0L, 25, 88, 60, 8},
+ {203, 0, 0, TOUCHEXIT | LASTOBJ, RADIO1, 0L, 25, 96, 60, 9}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int n, res, width, height, align = 0;
+ bool bRet = false, bContinue = false, bVert;
+ AccRange *rX = 0L, *rY = 0L;
+
+ OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)defs.GetOutLine(), 0);
+ OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)defs.GetFill(), 0);
+ data->GetSize(&width, &height);
+ sprintf(text1, "a1:a%d", height);
+ sprintf(text2, "b1:b%d", height);
+ Dlg = new DlgRoot(PlotDlg);
+ hDlg = CreateDlgWnd("Density profile", 50, 50, 420, 260, Dlg, 0x0L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 0:
+ if(bContinue) res = -1;
+ else if(Dlg->GetCheck(10)) res = -1;
+ break;
+ case -1:
+ bContinue = false;
+ break;
+ case 5:
+ if(Dlg->GetCheck(104)) {
+ Dlg->SetText(202, "bars right"); Dlg->SetText(203, "bars left");
+ }
+ else {
+ Dlg->SetText(202, "bars up"); Dlg->SetText(203, "bars down");
+ }
+ res = -1;
+ break;
+ case 201: case 202: case 203:
+ align = res - 201;
+ res = -1;
+ break;
+ case 1:
+ if(rX) delete rX; if(rY) delete rY;
+ rX = rY = 0L;
+ if(Dlg->GetText(101, TmpTxt)) rX = new AccRange(TmpTxt);
+ n = rX ? rX->CountItems() : 0;
+ if(!n) {
+ ErrorBox("direction range not specified\nor not valid.");
+ bContinue = true;
+ res = -1;
+ }
+ if(n && Dlg->GetText(103, TmpTxt) && (rY = new AccRange(TmpTxt))){
+ if(n != rY->CountItems()) {
+ ErrorBox("both ranges must be given\nand must have same size");
+ bContinue = true;
+ res = -1;
+ }
+ }
+ }
+ }while (res < 0);
+ if(res == 1 && n && rX && rY) {
+ type = (bVert = Dlg->GetCheck(104)) ? align | 0x10 : align;
+ if(Dlg->GetText(101, TmpTxt)) xRange=strdup(TmpTxt);
+ if(Dlg->GetText(103, TmpTxt)) yRange=strdup(TmpTxt);
+ OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&DefLine, 0);
+ OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&DefFill, 0);
+ if(DefFill.hatch) memcpy(&DefFillLine, DefFill.hatch, sizeof(LineDEF));
+ DefFill.hatch = &DefFillLine;
+ DoUpdate();
+ bRet = true;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(rX) delete rX; if(rY) delete rY;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create stacked bar or stacked polygon
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int com_StackDlg(int res, DlgRoot *Dlg, AccRange **rX, int *nx, char ***rd, int *currYR,
+ AccRange **rY, bool *bContinue, int *ny, int *maxYR, bool *updateYR)
+{
+ char **tmprd;
+
+ switch (res) {
+ case 1:
+ if(rX && nx && Dlg->GetText(101, TmpTxt) && TmpTxt[0] &&
+ (*rX = new AccRange(TmpTxt))) *nx = rX[0]->CountItems();
+ else if(nx) *nx = 0;
+ if(Dlg->GetText(154, TmpTxt) && TmpTxt[0]) {
+ if(rd[0][*currYR]) free(rd[0][*currYR]);
+ rd[0][*currYR] = strdup(TmpTxt);
+ }
+ break;
+ case 155:
+ res = -1;
+ *ny = 0;
+ if(rX) {
+ if(!(*currYR) && Dlg->GetText(101, TmpTxt) && TmpTxt[0]) {
+ if(*rX = new AccRange(TmpTxt)){
+ *nx = rX[0]->CountItems();
+ delete *rX;
+ *rX = 0L;
+ }
+ }
+ if(!(*nx)) {
+ ErrorBox("X-range is empty\nor not valid!\n\nEnter a valid range\n"
+ "for common x-values.");
+ *bContinue = true;
+ break;
+ }
+ }
+ if(Dlg->GetText(154, TmpTxt) && TmpTxt[0]) {
+ if(*rY = new AccRange(TmpTxt)){
+ *ny = rY[0]->CountItems();
+ delete *rY;
+ *rY = 0L;
+ }
+ }
+ if(!(*ny)) {
+ ErrorBox("Y-range is empty\nor not valid!\n\nEnter a valid range\n"
+ "for y-values with the same\nsize as the x-range.");
+ *bContinue = true;
+ break;
+ }
+ if((*currYR)+1 > *maxYR) {
+ tmprd = (char**)realloc(*rd, sizeof(char*)*((*currYR)+2));
+ if(tmprd) *rd = tmprd;
+ else break;
+ *maxYR = (*currYR)+1;
+ rd[0][*currYR] = 0L;
+ rd[0][(*currYR)+1] = 0L;
+ }
+ if(rd[0][*currYR]) free(rd[0][*currYR]);
+ rd[0][*currYR] = strdup(TmpTxt); //store y-ranges
+ *updateYR = true;
+ (*currYR)++;
+ Dlg->SetText(154, rd[0][*currYR]);
+ Dlg->Activate(154, true);
+ break;
+ case 156:
+ if(Dlg->GetText(154, TmpTxt)){
+ if(rd[0][*currYR]) free(rd[0][*currYR]);
+ rd[0][*currYR] = strdup(TmpTxt);
+ }
+ else if(*currYR == *maxYR) (*maxYR)--;
+ (*currYR)--;
+ Dlg->SetText(154, rd[0][*currYR]);
+ *updateYR = true;
+ res = -1;
+ break;
+ }
+ return res;
+}
+
+bool
+StackBar::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 25, 10, "Data"};
+ TabSHEET tab2 = {25, 55, 10, "Details"};
+ TabSHEET tab3 = {55, 90, 10, "Scheme"};
+ DlgInfo StackBarDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 158, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 158, 25, 45, 12},
+ {3, 0, 10, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
+ {10, 11, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 140, 100},
+ {11, 12, 200, ISPARENT, SHEET, &tab2, 5, 10, 140, 100},
+ {12, 20, 300, ISPARENT, SHEET, &tab3, 5, 10, 140, 100},
+ {20, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"range for common x values", 15, 30, 60, 8},
+ {101, 152, 0, 0x0L, EDTEXT, TmpTxt, 25, 40, 100, 10},
+ {152, 153, 0, ISPARENT | CHECKED, GROUPBOX, (void*)" ranges for y values ", 12, 60, 128, 45},
+ {153, 154, 0, 0x0L, LTEXT, 0L, 25, 65, 60, 8},
+ {154, 155, 0, 0x0L, EDTEXT, 0L, 25, 75, 100, 10},
+ {155, 156, 0, 0x0L, PUSHBUTTON, (void*)"Next >>", 95, 87, 30, 12},
+ {156, 0, 0, 0x0L, PUSHBUTTON, (void*)"<< Prev.", 60, 87, 35, 12},
+ {200, 201, 0, CHECKED, RADIO1, (void*)" add each y to start value", 25, 35, 60, 8},
+ {201, 202, 0, 0x0L, RADIO1, (void*)" subtract each y from start value", 25, 50, 60, 8},
+ {202, 203, 0, 0x0L, RTEXT, (void*)"start value:", 31, 65, 38, 8},
+ {203, 204, 0, 0x0L, EDVAL1, &StartVal, 70, 65, 30, 10},
+ {204, 0, 0, 0x0L, CHECKBOX, (void*)" horizontal plot", 25, 90, 60, 8},
+ {300, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)(OD_scheme), 20, 35, 80, 60}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, sc, j, res, width, height, currYR = 0, maxYR = 0, nx = 0, ny;
+ bool updateYR = true, bContinue = false, bSub, bRet = false, bHor;
+ char **rd;
+ AccRange *rX = 0L, *rY = 0L;
+
+ data->GetSize(&width, &height);
+ sprintf(TmpTxt, "a1:a%d", height);
+ if(!(rd = (char**)calloc(1, sizeof(char*))))return false;
+ Dlg = new DlgRoot(StackBarDlg);
+ hDlg = CreateDlgWnd(Id == GO_STACKBAR ? (char*)"Stacked bar plot" :
+ (char*)"Stacked polygons", 50, 50, 420, 260, Dlg, 0x0L);
+ do {
+ if(updateYR) {
+ if(currYR >0) {
+ Dlg->ShowItem(156, true); Dlg->Activate(101, false);
+ }
+ else {
+ Dlg->ShowItem(156, false); Dlg->Activate(101, true);
+ }
+ sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
+ //SetText will also cause a redraw of the whole dialog
+ Dlg->SetText(153, TmpTxt);
+ updateYR = false;
+ }
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ ny = 0;
+ if(rX) delete rX;
+ rX = 0L;
+ switch(res) {
+ case 0:
+ if(bContinue || Dlg->GetCheck(20)) res = -1;
+ break;
+ case -1:
+ bContinue = false;
+ break;
+ case 1:
+ Dlg->GetValue(203, &StartVal);
+ bSub = Dlg->GetCheck(201); bHor = Dlg->GetCheck(204);
+ case 155: case 156:
+ res = com_StackDlg(res, Dlg, &rX, &nx, &rd, &currYR,
+ &rY, &bContinue, &ny, &maxYR, &updateYR);
+ break;
+ }
+ }while (res < 0);
+ if(res == 1 && nx && rX && rd && rd[0] && rd[0][0]){ //accept settings and create plot
+ maxYR++;
+ for(i = j = 0; i < maxYR; i++) {
+ if(i) j += sprintf(TmpTxt+j, "&");
+ j += sprintf(TmpTxt+j, "%s", rd[i]);
+ }
+ ssYrange = strdup(TmpTxt);
+ if(Dlg->GetText(101, TmpTxt)) ssXrange = strdup(TmpTxt);
+ cum_data_mode = Dlg->GetCheck(200) ? 1 : 2;
+ if(Id == GO_STACKPG) cum_data_mode += 2;
+ CumData = CreaCumData(ssXrange, ssYrange, cum_data_mode, StartVal);
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ //do stacked bar
+ if(Id == GO_STACKBAR){
+ numPlots = maxYR;
+ if(Boxes = (BoxPlot**)calloc(numPlots, sizeof(BoxPlot*)))
+ for(i = sc = 0; i < (maxYR); i++) {
+ if(Boxes[i]= new BoxPlot(this, CumData, Dlg->GetCheck(204)?2:1, 0, i+1, i+2)){
+ Boxes[i]->Command(CMD_UPDATE, 0L, 0L);
+ Boxes[i]->Command(CMD_AUTOSCALE, 0L, 0L);
+ Boxes[i]->Command(CMD_BOX_FILL, GetSchemeFill(&sc), 0L);
+ }
+ }
+ }
+ //do stacked polygon
+ else if(Id == GO_STACKPG){
+ numPG = maxYR; sprintf(TmpTxt, "a1:a%d", nx*2);
+ if(Polygons=(DataPolygon**)calloc(numPG,sizeof(DataPolygon*)))for(i=sc=0;i<maxYR;i++){
+ sprintf(TmpTxt+20, "%c1:%c%d", 'c'+i, 'c'+i, nx*2);
+ if(Dlg->GetCheck(204)) Polygons[i]=new DataPolygon(this,CumData,TmpTxt+20,TmpTxt);
+ else Polygons[i] = new DataPolygon(this, CumData, TmpTxt, TmpTxt+20);
+ if(Polygons[i]) {
+ Polygons[i]->Command(CMD_AUTOSCALE, 0L, 0L);
+ Polygons[i]->Command(CMD_PG_FILL, GetSchemeFill(&sc), 0L);
+ }
+ }
+ }
+ if(Bounds.Xmax >= Bounds.Xmin && Bounds.Ymax >= Bounds.Ymin) bRet = true;
+ else bRet = false;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(rd) {
+ for (i = 0; i < maxYR; i++) if(rd[i]) free(rd[i]);
+ free(rd);
+ }
+ if(rX) delete rX; if(rY) delete rY;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create grouped bars chart
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+GroupBars::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 25, 10, "Data"};
+ TabSHEET tab2 = {25, 55, 10, "Details"};
+ TabSHEET tab3 = {55, 90, 10, "Scheme"};
+ double start = 1.0, step = 1.0, bw = 100.0, gg = 100.0;
+ DlgInfo GBDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 130, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 25, 45, 12},
+ {3, 0, 4, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
+ {4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 120, 90},
+ {5, 6, 200, ISPARENT, SHEET, &tab2, 5, 10, 120, 90},
+ {6, 10, 300, ISPARENT, SHEET, &tab3, 5, 10, 120, 90},
+ {10, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"Get values from spreadsheet:", 10, 25, 60, 8},
+ {101, 150, 0, 0x0L, LTEXT, (void*)"All ranges should have equal size!", 10, 33, 60, 8},
+ {150, 0, 153, ISPARENT | CHECKED, GROUPBOX, (void*)" ranges for y values ", 10, 50, 110, 45},
+ {153, 154, 0, 0x0L, LTEXT, 0L, 15, 55, 60, 8},
+ {154, 155, 0, 0x0L, EDTEXT, 0L, 15, 65, 100, 10},
+ {155, 156, 0, 0x0L, PUSHBUTTON, (void*)"Next >>", 85, 77, 30, 12},
+ {156, 0, 0, 0x0L, PUSHBUTTON, (void*)"<< Prev.", 50, 77, 35, 12},
+ {200, 201, 0, 0x0L, RTEXT, (void*)"start value", 10, 35, 38, 8},
+ {201, 202, 0, 0x0L, EDVAL1, (void*)&start, 58, 35, 35, 10},
+ {202, 203, 0, 0x0L, RTEXT, (void*)"group step", 10, 50, 38, 8},
+ {203, 204, 0, 0x0L, EDVAL1, (void*)&step, 58, 50, 35, 10},
+ {204, 205, 0, 0x0L, RTEXT, (void*)"bar width", 10, 65, 38, 8},
+ {205, 206, 0, 0x0L, EDVAL1, (void*)&bw, 58, 65, 35, 10},
+ {206, 207, 0, 0x0L, LTEXT, (void*)"%", 95, 65, 8, 8},
+ {207, 208, 0, 0x0L, RTEXT, (void*)"group gap", 10, 80, 38, 8},
+ {208, 209, 0, 0x0L, EDVAL1, (void*)&gg, 58, 80, 35, 10},
+ {209, 0, 0, 0x0L, LTEXT, (void*)"%", 95, 80, 8, 8},
+ {300, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)(OD_scheme), 20, 30, 90, 60}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ bool bRet = false, updateYR = true, bContinue = false;
+ char **rd;
+ Bar **bars = 0L;
+ AccRange *rY = 0L;
+ int i, ic, res, ix, iy, ny, sc = 0, currYR = 0, maxYR = 0;
+ double x, y, xinc;
+
+ Id = GO_STACKBAR;
+ if(!(rd = (char**)calloc(1, sizeof(char*))))return false;
+ if(!(Dlg = new DlgRoot(GBDlg)))return false;
+ hDlg = CreateDlgWnd("Grouped bar chart", 50, 50, 370, 240, Dlg, 0x0L);
+ do {
+ if(updateYR) {
+ if(currYR >0) Dlg->ShowItem(156, true);
+ else Dlg->ShowItem(156, false);
+ sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
+ //SetText will also cause a redraw of the whole dialog
+ Dlg->SetText(153, TmpTxt);
+ updateYR = false;
+ }
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 0:
+ if(bContinue || Dlg->GetCheck(10)) res = -1;
+ break;
+ case -1:
+ bContinue = false;
+ break;
+ case 1:
+ Dlg->GetValue(201, &start); Dlg->GetValue(203, &step);
+ Dlg->GetValue(205, &bw); Dlg->GetValue(208, &gg);
+ case 155: case 156:
+ res = com_StackDlg(res, Dlg, 0L, 0L, &rd, &currYR,
+ &rY, &bContinue, &ny, &maxYR, &updateYR);
+ break;
+ }
+ } while(res < 0);
+ if(res == 1 && rd && rd[0] && rd[0][0]){ //accept settings and create plots
+ if(rd[maxYR]) maxYR++;
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ if(!(xyPlots = (PlotScatt**)calloc(maxYR, sizeof(PlotScatt*)))){
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(rd) {
+ for (i = 0; i < maxYR; i++) if(rd[i]) free(rd[i]);
+ free(rd);
+ }
+ return false;
+ }
+ xinc = fabs(step / ((double)maxYR + gg/100.0));
+ start -= (xinc * ((double)maxYR-1))/2.0;
+ for(i = 0; i < maxYR; i++) {
+ x = start + xinc * (double)i;
+ if(rd[i] && (rY = new AccRange(rd[i]))) ny = rY->CountItems();
+ else {
+ rY = 0L; ny = 0;
+ }
+ rY->GetFirst(&ix, &iy); rY->GetNext(&ix, &iy);
+ if(ny && rY && (bars = (Bar **)calloc(ny, sizeof(Bar*)))){
+ for(ic = 0; ic < ny; ic++) {
+ if(data->GetValue(iy, ix, &y)){
+ bars[ic] = new Bar(0L, data, x, y, BAR_VERTB | BAR_RELWIDTH,
+ -1, -1, ix, iy);
+ CheckBounds(x, y);
+ }
+ x += step;
+ if(!rY->GetNext(&ix, &iy))break;
+ }
+ xyPlots[numXY++] = new PlotScatt(this, data, ic+1, bars);
+ if(xyPlots[i]) {
+ xyPlots[i]->SetSize(SIZE_BARMINX, xinc);
+ xyPlots[i]->SetSize(SIZE_BAR, bw);
+ xyPlots[i]->Command(CMD_BAR_FILL, GetSchemeFill(&sc), 0L);
+ }
+ for(ic = 0; ic < ny; ic++) if(bars[ic]) delete(bars[ic]);
+ free(bars);
+ bRet = true;
+ }
+ if(rY) delete(rY);
+ rY = 0L;
+ }
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(rd) {
+ for (i = 0; i < maxYR; i++) if(rd[i]) free(rd[i]);
+ free(rd);
+ }
+ if(rY) delete rY;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create a waterfall graph
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Waterfall::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 25, 10, "Data"};
+ TabSHEET tab2 = {25, 55, 10, "Details"};
+ TabSHEET tab3 = {55, 90, 10, "Scheme"};
+ static DWORD colarr[] = {0x00000000L, 0x00ff0000L, 0x0000ff00L, 0x000000ffL,
+ 0x00ff00ff, 0x00ffff00L, 0x0000ffff, 0x00c0c0c0};
+ static DWORD defcol = 0x0L;
+ char text1[100];
+ DlgInfo StackBarDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 158, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 158, 25, 45, 12},
+ {3, 0, 10, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
+ {10, 11, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 140, 100},
+ {11, 12, 200, ISPARENT, SHEET, &tab2, 5, 10, 140, 100},
+ {12, 20, 300, ISPARENT, SHEET, &tab3, 5, 10, 140, 100},
+ {20, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"range for common x values", 15, 30, 60, 8},
+ {101, 152, 0, 0x0L, EDTEXT, text1, 25, 40, 100, 10},
+ {152, 153, 0, ISPARENT | CHECKED, GROUPBOX, (void*)" ranges for y values ", 12, 60, 128, 45},
+ {153, 154, 0, 0x0L, LTEXT, 0L, 25, 65, 60, 8},
+ {154, 155, 0, 0x0L, EDTEXT, 0L, 25, 75, 100, 10},
+ {155, 156, 0, 0x0L, PUSHBUTTON, (void*)"Next >>", 95, 87, 30, 12},
+ {156, 0, 0, 0x0L, PUSHBUTTON, (void*)"<< Prev.", 60, 87, 35, 12},
+ {200, 201, 0, 0x0L, LTEXT, (void*)"line to line displacement:", 20, 35, 80, 8},
+ {201, 202, 0, 0x0L, RTEXT, (void*)"dx =", 28, 45, 13, 8},
+ {202, 203, 0, 0x0L, EDVAL1, &dspm.fx, 43, 45, 25, 10},
+ {203, 204, 0, 0x0L, RTEXT, (void*)"dy =", 73, 45, 13, 8},
+ {204, 205, 0, 0x0L, EDVAL1, &dspm.fy, 88, 45, 25, 10},
+ {205, 0, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 115, 45, 15, 8},
+ {300, 301, 0, CHECKED, RADIO1, (void*)" common color for lines:", 20, 35, 80, 9},
+ {301, 302, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)defcol, 105, 35, 20, 10},
+ {302, 303, 0, 0x0L, RADIO1, (void*)" increment color scheme:", 20, 55, 80, 9},
+ {303, 304, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[0], 25, 70, 10, 10},
+ {304, 305, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[1], 37, 70, 10, 10},
+ {305, 306, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[2], 49, 70, 10, 10},
+ {306, 307, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[3], 61, 70, 10, 10},
+ {307, 308, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[4], 73, 70, 10, 10},
+ {308, 309, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[5], 85, 70, 10, 10},
+ {309, 310, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[6], 97, 70, 10, 10},
+ {310, 0, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[7], 109, 70, 10, 10},
+ {500, 0, 0, LASTOBJ, NONE, 0L, 0, 0, 0, 0}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, res, width, height, currYR=0, maxYR=0, nx=0, ny;
+ char **rd;
+ bool updateYR = true, bContinue = false, bRet = false, bUseSch;
+ AccRange *rX = 0L, *rY = 0L;
+
+ data->GetSize(&width, &height);
+ sprintf(text1, "a1:a%d", height);
+ if(!(rd = (char**)calloc(1, sizeof(char*))))return false;
+ Dlg = new DlgRoot(StackBarDlg);
+ hDlg = CreateDlgWnd("Create waterfall plot", 50, 50, 420, 260, Dlg, 0x0L);
+ do {
+ if(updateYR) {
+ if(currYR >0) {
+ Dlg->ShowItem(156, true);
+ Dlg->Activate(101, false);
+ }
+ else {
+ Dlg->ShowItem(156, false);
+ Dlg->Activate(101, true);
+ }
+ sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
+ //SetText will also cause a redraw of the whole dialog
+ Dlg->SetText(153, TmpTxt);
+ updateYR = false;
+ }
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ ny = 0;
+ if(rX) delete rX;
+ rX = 0L;
+ switch(res) {
+ case 0:
+ if(bContinue || Dlg->GetCheck(20)) res = -1;
+ break;
+ case -1:
+ bContinue = false; break;
+ case 1:
+ for(i = 0; i < 8; i++) Dlg->GetColor(303+i, &colarr[i]);
+ Dlg->GetColor(301, &defcol);
+ bUseSch = Dlg->GetCheck(302);
+ Dlg->GetValue(202, &dspm.fx); Dlg->GetValue(204, &dspm.fy);
+ //execute com_StackDlg for <OK>
+ case 155: case 156:
+ res = com_StackDlg(res, Dlg, &rX, &nx, &rd, &currYR,
+ &rY, &bContinue, &ny, &maxYR, &updateYR);
+ break;
+ case 301:
+ Dlg->SetCheck(300, 0L, true);
+ res = -1; break;
+ case 303: case 304: case 305: case 306:
+ case 307: case 308: case 309: case 310:
+ Dlg->SetCheck(302, 0L, true);
+ res = -1; break;
+ }
+ }while (res < 0);
+ if(res == 1 && nx && rX && rd && rd[0] && rd[0][0]) {
+ maxYR++;
+ numPL = maxYR;
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ Dlg->GetText(101, text1);
+ if(Lines=(DataLine**)calloc(numPL,sizeof(DataLine*)))for(i=0;i<maxYR;i++){
+ if(rd[i] && rd[i][0]) Lines[i] = new DataLine(this, data, text1, rd[i]);
+ if(Lines[i]) {
+ if(bUseSch) Lines[i]->SetColor(COL_DATA_LINE, colarr[(i & 0x07)]);
+ else Lines[i]->SetColor(COL_DATA_LINE, defcol);
+ bRet = true;
+ }
+ }
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(rd) {
+ for (i = 0; i < maxYR; i++) if(rd[i]) free(rd[i]);
+ free(rd);
+ }
+ if(rX) delete rX; if(rY) delete rY;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create a multi data line plot
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+MultiLines::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 25, 10, "Data"};
+ TabSHEET tab2 = {25, 60, 10, "Scheme"};
+ static DWORD colarr[] = {0x00000000L, 0x00ff0000L, 0x0000ff00L, 0x000000ffL,
+ 0x00ff00ff, 0x00ffff00L, 0x0000ffff, 0x00c0c0c0};
+ static DWORD defcol = 0x0L;
+ char x_txt[100], y_txt[100];
+ DlgInfo StackBarDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 158, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 158, 25, 45, 12},
+ {3, 0, 10, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
+ {10, 11, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 140, 100},
+ {11, 20, 300, ISPARENT, SHEET, &tab2, 5, 10, 140, 100},
+ {20, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
+ {100, 101, 0, ISPARENT | CHECKED, GROUPBOX, (void*)" ranges for x- and y- values ", 12, 30, 128, 75},
+ {101, 102, 0, 0x0L, LTEXT, 0L, 25, 39, 60, 8},
+ {102, 103, 0, 0x0L, EDTEXT, (void*)x_txt, 25, 49, 100, 10},
+ {103, 104, 0, 0x0L, LTEXT, 0L, 25, 61, 60, 8},
+ {104, 105, 0, 0x0L, EDTEXT, (void*)y_txt, 25, 71, 100, 10},
+ {105, 106, 0, 0x0L, PUSHBUTTON, (void*)"Next >>", 95, 87, 30, 12},
+ {106, 107, 0, 0x0L, PUSHBUTTON, (void*)"<< Prev.", 60, 87, 35, 12},
+ {107, 0, 0, OWNDIALOG, COLBUTTON, (void*)colarr[0], 25, 87, 20, 12},
+ {300, 301, 0, TOUCHEXIT, RADIO1, (void*)" common color for lines:", 20, 35, 80, 9},
+ {301, 302, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)defcol, 105, 35, 20, 10},
+ {302, 303, 0, CHECKED | TOUCHEXIT, RADIO1, (void*)" increment color scheme:", 20, 55, 80, 9},
+ {303, 304, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[0], 25, 70, 10, 10},
+ {304, 305, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[1], 37, 70, 10, 10},
+ {305, 306, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[2], 49, 70, 10, 10},
+ {306, 307, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[3], 61, 70, 10, 10},
+ {307, 308, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[4], 73, 70, 10, 10},
+ {308, 309, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[5], 85, 70, 10, 10},
+ {309, 310, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[6], 97, 70, 10, 10},
+ {310, 0, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[7], 109, 70, 10, 10},
+ {500, 0, 0, LASTOBJ, NONE, 0L, 0, 0, 0, 0}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ char **rdx=0L, **rdy=0L;
+ DWORD *rdc = 0L, curr_col;
+ int i, width, height, res, currYR=0, maxYR=0, s1, s2;
+ bool updateYR = true, bContinue = false, bError, bRet = false;
+ AccRange *rX = 0L, *rY = 0L;
+ DataLine *dl;
+
+ data->GetSize(&width, &height);
+ sprintf(x_txt, "a1:a%d", height);
+ sprintf(y_txt, "b1:b%d", height);
+ Dlg = new DlgRoot(StackBarDlg);
+ hDlg = CreateDlgWnd("Create multi line plot", 50, 50, 420, 260, Dlg, 0x0L);
+ do {
+ if(updateYR) {
+ if(currYR >0) Dlg->ShowItem(106, true);
+ else Dlg->ShowItem(106, false);
+ sprintf(TmpTxt,"x-range # %d/%d", currYR+1, maxYR+1);
+ //SetText will also cause a redraw of the whole dialog
+ Dlg->SetText(101, TmpTxt);
+ sprintf(TmpTxt,"y-range # %d/%d", currYR+1, maxYR+1);
+ Dlg->SetText(103, TmpTxt);
+ updateYR = false;
+ }
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 0:
+ if(bContinue || Dlg->GetCheck(20)) res = -1;
+ break;
+ case -1:
+ bContinue = false;
+ break;
+ case 1:
+ case 105: //next button
+ bError=false; s1 = s2 = 0;
+ if(Dlg->GetText(102, x_txt)) {
+ if(rX = new AccRange(x_txt)) {
+ s1 = rX->CountItems();
+ if(s1 < 2) {
+ ErrorBox("x-range not valid");
+ bContinue=bError=true;
+ Dlg->Activate(102, true);
+ }
+ delete rX;
+ }
+ else bError = true;
+ }
+ else bError = true;
+ if(Dlg->GetText(104, y_txt) && !bError) {
+ if(rY = new AccRange(y_txt)) {
+ s2 = rY->CountItems();
+ if(s2 < 2) {
+ ErrorBox("y-range not valid");
+ bContinue=bError=true;
+ Dlg->Activate(104, true);
+ }
+ delete rY;
+ }
+ else bError = true;
+ }
+ else {
+ Dlg->Activate(104, true);
+ bError = true;
+ }
+ if(!s1 || !s2) bError = true;
+ rX = rY = 0L;
+ if(!bError && s1!=s2) {
+ ErrorBox("X-range and y-range are\ndifferent in size");
+ bContinue=bError=true;
+ }
+ if(!bError) {
+ if((currYR+1) > maxYR) {
+ rdx = (char**)realloc(rdx, sizeof(char*)*(currYR+2));
+ rdy = (char**)realloc(rdy, sizeof(char*)*(currYR+2));
+ rdc = (DWORD*)realloc(rdc, sizeof(DWORD)*(currYR+2));
+ rdx[currYR] = rdx[currYR+1] = rdy[currYR] = rdy[currYR+1] = 0L;
+ maxYR = currYR+1;
+ rdc[currYR] = rdc[currYR+1] = Dlg->GetCheck(302) ? colarr[maxYR & 0x07] : defcol;
+ }
+ if(rdx[currYR]) free(rdx[currYR]);
+ rdx[currYR] = strdup(x_txt); //store x-range
+ if(rdy[currYR]) free(rdy[currYR]);
+ rdy[currYR] = strdup(y_txt); //store y-range
+ Dlg->GetColor(107, &curr_col); rdc[currYR] = curr_col;
+ updateYR = true; currYR++;
+ Dlg->SetColor(107, rdc[currYR]); Dlg->SetText(102, rdx[currYR]);
+ Dlg->SetText(104, rdy[currYR]); Dlg->Activate(102, true);
+ if(res != 1) res = -1;
+ }
+ else if(res != 1){
+ bContinue = true;
+ res = -1;
+ }
+ break;
+ case 106: //prev button
+ if(Dlg->GetText(102, x_txt) && Dlg->GetText(104, y_txt)){
+ if(rdx[currYR]) free(rdx[currYR]); rdx[currYR] = strdup(x_txt);
+ if(rdy[currYR]) free(rdy[currYR]); rdy[currYR] = strdup(y_txt);
+ Dlg->GetColor(107, &curr_col); rdc[currYR] = curr_col;
+ }
+ else if(currYR == maxYR) maxYR--;
+ currYR--;
+ Dlg->SetColor(107, rdc[currYR]); Dlg->SetText(102, rdx[currYR]);
+ Dlg->SetText(104, rdy[currYR]); Dlg->Activate(102, true);
+ updateYR = true;
+ res = -1;
+ break;
+ case 300:
+ Dlg->SetColor(107, defcol);
+ bContinue = true;
+ res = -1; break;
+ case 301:
+ Dlg->SetCheck(300, 0L, true); Dlg->GetColor(res, &defcol);
+ res = -1; break;
+ case 302:
+ Dlg->SetColor(107, colarr[currYR & 0x07]);
+ bContinue = true;
+ res = -1; break;
+ case 303: case 304: case 305: case 306:
+ case 307: case 308: case 309: case 310:
+ Dlg->SetCheck(302, 0L, true);
+ Dlg->GetColor(res, &colarr[res-303]);
+ res = -1; break;
+ }
+ }while (res < 0);
+
+ if(res == 1 && rdx && rdy && maxYR) {
+ maxYR++;
+ if(xyPlots=(PlotScatt**)calloc(maxYR, sizeof(PlotScatt*))) for(i = numXY = 0; i < maxYR; i++){
+ if(rdx[i] && rdy[i] && rdx[i][0] && rdy[i][0]) {
+ if(dl = new DataLine(this, data, rdx[i], rdy[i])) {
+ dl->SetColor(COL_DATA_LINE, rdc[i]);
+ if(xyPlots[numXY] = new PlotScatt(this, data, 0, 0L, dl)) numXY++;
+ else delete dl;
+ }
+ }
+ }
+ if(numXY) bRet = true;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(rdx) {
+ for (i = 0; i < maxYR; i++) if(rdx[i]) free(rdx[i]);
+ free(rdx);
+ }
+ if(rdy) {
+ for (i = 0; i < maxYR; i++) if(rdy[i]) free(rdy[i]);
+ free(rdy);
+ }
+ if(rdc) free(rdc);
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Pie and ring chart properties
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+PieChart::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 25, 10, "Data"};
+ TabSHEET tab2 = {25, 55, 10, "Details"};
+ TabSHEET tab3 = {55, 90, 10, "Scheme"};
+ double fcx =10.0, fcy = 20.0, frad=40.0, firad = 30.0;
+ char txt2[80];
+ DlgInfo PieDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 130, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 25, 45, 12},
+ {3, 0, 4, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
+ {4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 120, 103},
+ {5, 6, 200, ISPARENT, SHEET, &tab2, 5, 10, 120, 103},
+ {6, 10, 300, ISPARENT, SHEET, &tab3, 5, 10, 120, 103},
+ {10, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"spread sheet range for values", 10, 25, 60, 8},
+ {101, 105, 0, 0x0L, EDTEXT, TmpTxt, 15, 35, 100, 10},
+ {105, 106, 500, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {106, 107, 600, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {107, 108, 0, 0x0L, EDVAL1, &frad, 58, 59, 30, 10},
+ {108, 0, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 89, 59, 15, 8},
+ {200, 201, 0, 0x0L, LTEXT, (void*)"position of center:", 15, 30, 60, 8},
+ {201, 202, 0, 0x0L, RTEXT, (void*)"x", 2, 42, 20, 8},
+ {202, 204, 0, 0x0L, EDVAL1, &fcx, 23, 42, 30, 10},
+ {204, 205, 0, 0x0L, RTEXT, (void*)"y", 47, 42, 20, 8},
+ {205, 206, 0, 0x0L, EDVAL1, &fcy, 68, 42, 30, 10},
+ {206, 207, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 99, 42, 15, 8},
+ {207, 208, 0, 0x0L, RTEXT, (void*)"start angle", 27, 58, 20, 8},
+ {208, 209, 0, 0x0L, EDVAL1, &CtDef.fx, 48, 58, 30, 10},
+ {209, 210, 0, 0x0L, LTEXT, (void*)"degree", 79, 58, 15, 8},
+ {210, 211, 400, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {211, 212, 410, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {212, 0, 0, 0x0L, LTEXT, (void*)"style:", 15, 80, 30, 8},
+ {300, 0, 0, NOSELECT, ODBUTTON, (void*)(OD_scheme), 20, 35, 80, 60},
+ {400, 401, 0, TOUCHEXIT | CHECKED | ISRADIO, ODBUTTON, (void*)OD_PieTempl, 40, 75, 30, 30},
+ {401, 0, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PieTempl, 70, 75, 30, 30},
+ {410, 411, 0, TOUCHEXIT | CHECKED | ISRADIO, ODBUTTON, (void*)OD_PieTempl, 40, 75, 30, 30},
+ {411, 0, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PieTempl, 70, 75, 30, 30},
+ {500, 501, 0, CHECKED, RADIO1, (void*)"fixed radius", 10, 59, 20, 8},
+ {501, 502, 0, 0x0L, RADIO1, (void*)"pick radii from spreadsheet range", 10, 71, 40, 8},
+ {502, 503, 0, 0x0L, EDTEXT, TmpTxt+100, 15, 82, 100, 10},
+ {503, 504, 0, 0x0L, LTEXT, (void*)"x factor", 15, 94, 10, 8},
+ {504, 505, 0, 0x0L, EDVAL1, &FacRad, 42, 94, 25, 10},
+ {505, 0, 0, 0x0L, LTEXT, &txt2, 70, 94, 15, 8},
+ {600, 601, 0, 0x0L, RTEXT, (void*)"outer radius", 8, 59, 45, 8},
+ {601, 602, 0, 0x0L, RTEXT, (void*)"inner radius", 8, 74, 45, 8},
+ {602, 603, 0, 0x0L, EDVAL1, &firad, 58, 74, 30, 10},
+ {603, 0, 0, LASTOBJ, LTEXT, (void *) Units[defs.cUnits].display, 89, 74, 15, 8}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, ix, iy, rix, riy, ny, res, width, height, cf;
+ bool bRet = false, bContinue = false;
+ double sum = 0.0, dang1, dang2;
+ double fv;
+ lfPOINT fpCent;
+ AccRange *rY = 0L, *rR = 0L;
+
+ data->GetSize(&width, &height);
+ sprintf(TmpTxt, "a1:a%d", height);
+ sprintf(TmpTxt+100, "b1:b%d", height);
+ sprintf(txt2, "= [%s]", Units[defs.cUnits].display);
+ if(parent) {
+ frad = (parent->GetSize(SIZE_DRECT_BOTTOM) - parent->GetSize(SIZE_DRECT_TOP))/2.0;
+ fcx = parent->GetSize(SIZE_GRECT_LEFT) + (parent->GetSize(SIZE_DRECT_LEFT))/2.0 + frad;
+ fcy = parent->GetSize(SIZE_GRECT_TOP) + parent->GetSize(SIZE_DRECT_TOP) + frad;
+ }
+ firad = frad-frad/10.0f;
+ Dlg = new DlgRoot(PieDlg);
+ if(Id == GO_PIECHART) {
+ Dlg->ShowItem(105, true); Dlg->ShowItem(106, false);
+ Dlg->ShowItem(210, true); Dlg->ShowItem(211, false);
+ }
+ else {
+ Dlg->ShowItem(105, false); Dlg->ShowItem(106, true);
+ Dlg->ShowItem(210, false); Dlg->ShowItem(211, true);
+ }
+ hDlg = CreateDlgWnd(Id == GO_PIECHART ? (char*)"Create pie chart" :
+ (char*)"Create ring chart", 50, 50, 370, 260, Dlg, 0x0L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ //rY is defined by OK. If other buttons use rY reset to 0L!
+ switch(res) {
+ case 0: //lost focus ?
+ if(bContinue) res = -1;
+ else if(Dlg->GetCheck(10)) res = -1;
+ break;
+ case -1:
+ bContinue = false;
+ break;
+ case 400: case 410:
+ Dlg->SetText(208, "90"); Dlg->DoPlot(0L);
+ CtDef.fy = 360.0; res = -1;
+ break;
+ case 401: case 411:
+ Dlg->SetText(208, "180"); Dlg->DoPlot(0L);
+ CtDef.fy = 180.0; res = -1;
+ break;
+ case 1:
+ if(Dlg->GetText(101, TmpTxt) && TmpTxt[0] && (rY = new AccRange(TmpTxt)))
+ ny = rY->CountItems();
+ else ny = 0;
+ Dlg->GetValue(208, &CtDef.fx); Dlg->GetValue(202, &fcx);
+ Dlg->GetValue(205, &fcy); Dlg->GetValue(107, &frad);
+ Dlg->GetValue(602, &firad); Dlg->GetValue(504, &FacRad);
+ if(Dlg->GetCheck(501) && ny && Dlg->GetText(502, TmpTxt) &&
+ (rR = new AccRange(TmpTxt))){
+ if(rR->CountItems() != ny) {
+ delete rR;
+ delete rY;
+ rR = rY = 0L;
+ ErrorBox("Range for values and\nrange for radii must\nhave the same size!");
+ bContinue = true;
+ res = -1;
+ }
+ }
+ break;
+ }
+ }while (res < 0);
+
+ if(res == 1 && rY && ny >1 && (Segments = (segment **)calloc(ny, sizeof(segment*)))) {
+ nPts = ny;
+ if(Dlg->GetText(101, TmpTxt)) ssRefA = strdup(TmpTxt);
+ if(rR && Dlg->GetText(502, TmpTxt)) ssRefR = strdup(TmpTxt);
+ Bounds.Xmax = Bounds.Ymax = 100.0; Bounds.Xmin = Bounds.Ymin = -100.0;
+ fpCent.fx = fcx; fpCent.fy = fcy;
+ rY->GetFirst(&ix, &iy); rY->GetNext(&ix, &iy);
+ for(i = 0; i < ny; i++){
+ if(data->GetValue(iy, ix, &fv)) sum += fv;
+ rY->GetNext(&ix, &iy);
+ }
+ sum /= CtDef.fy;
+ dang1 = dang2 = CtDef.fx;
+ rY->GetFirst(&ix, &iy); rY->GetNext(&ix, &iy);
+ if(rR) {
+ rR->GetFirst(&rix, &riy); rR->GetNext(&rix, &riy);
+ }
+ for(i = cf = 0; i < ny; i++){
+ if(data->GetValue(iy, ix, &fv)) {
+ dang2 -= (double)fv / sum;
+ if(dang2 < 0.0) dang2 += 360.0;
+ if(rR && data->GetValue(riy, rix, &frad)) frad *= FacRad;
+ Segments[i] = new segment(this, data, &fpCent,
+ Id == GO_PIECHART ? 0.0 : firad, frad,
+ dang1, dang2);
+ if(Segments[i])Segments[i]->Command(CMD_SEG_FILL, GetSchemeFill(&cf), 0L);
+ dang1 = dang2;
+ }
+ rY->GetNext(&ix, &iy);
+ if(rR) rR->GetNext(&rix, &riy);
+ }
+ bRet = true;
+ }
+ if(rY) delete rY; if(rR) delete rR;
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Create a star chart
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+StarChart::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 25, 10, "Data"};
+ TabSHEET tab2 = {25, 55, 10, "Labels"};
+ double sa = 90.0, factor = 1.0, lbdist = NiceValue(defs.GetSize(SIZE_TEXT)*1.2);
+ char txt1[80], txt2[80];
+ DlgInfo StarDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 130, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 25, 45, 12},
+ {3, 0, 4, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
+ {4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 120, 103},
+ {5, 10, 200, ISPARENT, SHEET, &tab2, 5, 10, 120, 103},
+ {10, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"spread sheet range for values", 10, 30, 60, 8},
+ {101, 102, 0, 0x0L, EDTEXT, txt1, 15, 45, 100, 10},
+ {102, 103, 0, 0x0L, RTEXT, (void*)"x factor", 17, 57, 30, 8},
+ {103, 104, 0, 0x0L, EDVAL1, &factor, 48, 57, 30, 10},
+ {104, 105, 0, 0x0L, LTEXT, &txt2, 79, 57, 15, 8},
+ {105, 106, 0, 0x0L, RTEXT, (void*)"start angle", 17, 72, 30, 8},
+ {106, 107, 0, 0x0L, EDVAL1, &sa, 48, 72, 30, 10},
+ {107, 108, 0, 0x0L, LTEXT, (void*)"degree", 79, 72, 15, 8},
+ {108, 109, 0, CHECKED, CHECKBOX, (void*)"draw polygon", 25, 87, 20, 8},
+ {109, 0, 0, CHECKED, CHECKBOX, (void*)"draw rays", 25, 97, 20, 8},
+ {200, 201, 0, 0x0L, CHECKBOX, (void*)"add labels to data points", 15, 28, 50, 8},
+ {201, 202, 0, 0x0L, EDTEXT, (void*)txt1, 15, 51, 100, 10},
+ {202, 203, 0, 0x0L, LTEXT, (void*)"spread sheet range for labels:", 15, 40, 60, 8},
+ {203, 204, 0, 0x0L, RTEXT, (void*)"distance:", 10, 70, 40, 8},
+ {204, 205, 0, 0x0L, EDVAL1, &lbdist, 52, 70, 30, 10},
+ {205, 0, 0, LASTOBJ, LTEXT, (void*)Units[defs.cUnits].display, 85, 70, 10, 8}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, ix, iy, res, width, height, ny;
+ bool bRet = false, bContinue = false;
+ AccRange *rY = 0L, *rL = 0L;
+ Label *lb;
+ lfPOINT *fp = 0L, *fpt = 0L, fl[2];
+ double fx, fy, tmpval, frad;
+ double sia, csia;
+ polyline *plo;
+ TextDEF td = {0x00000000L, 0x00ffffffL, defs.GetSize(SIZE_TEXT), 0.0, 0.0, 0,
+ TXA_HCENTER | TXA_VCENTER, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, 0L};
+
+
+ data->GetSize(&width, &height);
+ sprintf(txt1, "a1:a%d", height);
+ sprintf(txt2, "= [%s]", Units[defs.cUnits].display);
+ if(parent) {
+ frad = (parent->GetSize(SIZE_DRECT_BOTTOM) - parent->GetSize(SIZE_DRECT_TOP))/2.0f;
+ fPos.fx = parent->GetSize(SIZE_GRECT_LEFT) + parent->GetSize(SIZE_DRECT_LEFT) + frad;
+ fPos.fy = parent->GetSize(SIZE_GRECT_TOP) + parent->GetSize(SIZE_DRECT_TOP) + frad;
+ }
+ if(!(Dlg = new DlgRoot(StarDlg)))return false;
+ hDlg = CreateDlgWnd("Create star chart", 50, 50, 370, 260, Dlg, 0x0L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 0: //lost focus ?
+ if(bContinue) res = -1;
+ else if(Dlg->GetCheck(10)) res = -1;
+ break;
+ case -1:
+ bContinue = false;
+ break;
+ case 1:
+ if(Dlg->GetText(101, TmpTxt) && TmpTxt[0] && (rY = new AccRange(TmpTxt)))
+ ny = rY->CountItems();
+ else ny = 0;
+ Dlg->GetValue(106, &sa); Dlg->GetValue(103, &factor);
+ Dlg->GetValue(204, &lbdist);
+ break;
+ }
+ }while (res < 0);
+ if(res == 1 && rY && ny >1 && (fp = (lfPOINT*)calloc(ny+1, sizeof(lfPOINT))) &&
+ (fpt = (lfPOINT*)calloc(ny+1, sizeof(lfPOINT)))){
+ Bounds.Xmax = Bounds.Ymax = 100.0; Bounds.Xmin = Bounds.Ymin = -100.0;
+ rY->GetFirst(&ix, &iy);
+ for(i = 0; i < ny; i++){
+ rY->GetNext(&ix, &iy);
+ if(data->GetValue(iy, ix, &tmpval)){
+ tmpval *= factor;
+ sia = sin(sa * 0.01745329252); csia = cos(sa * 0.01745329252);
+ fx = (tmpval * csia); fy = (-tmpval * sia);
+ }
+ else fx = fy = 0.0f;
+ fp[i].fx = fpt[i].fx = fx; fp[i].fy = fpt[i].fy = fy;
+ fpt[i].fx += lbdist *csia; fpt[i].fy += (-lbdist * sia);
+ sa -= 360.0/ny;
+ }
+ fp[i].fx = fp[0].fx; fp[i].fy = fp[0].fy;
+ if(Dlg->GetCheck(108)){
+ if((plo = new polygon(this, data, fp, ny+1))) { //ny+1 to close the shape!
+ if(!(bRet = Command(CMD_DROP_OBJECT, (void*)plo, 0L))) delete plo;
+ }
+ }
+ if(Dlg->GetCheck(109)){
+ fl[0].fx = fl[0].fy = 0.0f;
+ for(i = 0; i < ny; i++) {
+ fl[1].fx = fp[i].fx; fl[1].fy = fp[i].fy;
+ if((plo = new polyline(this, data, fl, 2))) {
+ if(Command(CMD_DROP_OBJECT, (void*)plo, 0L)) bRet = true;
+ else delete plo;
+ }
+ }
+ }
+ if(Dlg->GetCheck(200) && Dlg->GetText(201, TmpTxt) && TmpTxt[0] && (rL = new AccRange(TmpTxt))){
+ rL->GetFirst(&ix, &iy);
+ td.text = TmpTxt;
+ for(i = 0; i < ny; i++) {
+ rL->GetNext(&ix, &iy);
+ if(data->GetText(iy, ix, TmpTxt, TMP_TXT_SIZE)){
+ if((lb = new Label(this, data, fpt[i].fx, fpt[i].fy, &td, 0L))) {
+ if(Command(CMD_DROP_OBJECT, (void*)lb, 0L)) bRet = true;
+ else delete lb;
+ }
+ }
+ }
+ }
+ }
+ if(rY) delete rY; if(rL) delete rL;
+ if(fp) free(fp); if(fpt) free(fpt);
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Scatt3D is a layer representing most simple 3D plots
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Scatt3D::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 22, 10, "Data"};
+ TabSHEET tab2 = {22, 50, 10, "Layout"};
+ TabSHEET tab3 = {50, 75, 10, "Axes"};
+ char text1[100], text2[100], text3[100];
+ int icon = ICO_INFO;
+ DlgInfo Dlg3D[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 142, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 142, 25, 45, 12},
+ {3, 50, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
+ {4, 5, 100, TOUCHEXIT | ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 131, 100},
+ {5, 6, 200, TOUCHEXIT | ISPARENT, SHEET, &tab2, 5, 10, 131, 100},
+ {6, 10, 400, TOUCHEXIT | ISPARENT, SHEET, &tab3, 5, 10, 131, 100},
+ {10, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
+ {50, 60, 0, NOSELECT, ODBUTTON, (void*)(OD_AxisDesc3D), 142, 65, 45, 45},
+ {60, 61, 0, 0x0L, ICON, (void*)&icon, 10, 114, 20, 20},
+ {61, 62, 0, 0x0L, LTEXT, (void*)"Use [arrow keys], [shift]+[arrow key],", 30, 116, 100, 6},
+ {62, 0, 0, 0x0L, LTEXT, (void*)"and [r], [R], [l] or [L] to rotate graph.", 30, 122, 100, 6},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"range for X Data", 10, 30, 60, 8},
+ {101, 102, 0, 0x0L, EDTEXT, text1, 20, 40, 100, 10},
+ {102, 103, 0, 0x0L, LTEXT, (void*)"range for Y Data", 10, 55, 60, 8},
+ {103, 104, 0, 0x0L, EDTEXT, text2, 20, 65, 100, 10},
+ {104, 105, 0, 0x0L, LTEXT, (void*)"range for Z Data", 10, 80, 60, 8},
+ {105, 0, 0, 0x0L, EDTEXT, text3, 20, 90, 100, 10},
+ {200, 201, 0, 0x0L, LTEXT, (void*)"select style:", 25, 30, 60, 8},
+ {201, 202, 0, 0x0L, CHECKBOX, (void*)" balls", 30, 55, 60, 8},
+ {202, 203, 0, TOUCHEXIT, CHECKBOX, (void*)" columns", 30, 65, 60, 8},
+ {203, 204, 0, TOUCHEXIT, CHECKBOX, (void*)" line", 30, 45, 60, 8},
+ {204, 205, 0, TOUCHEXIT, CHECKBOX, (void*)" drop lines", 30, 75, 60, 8},
+ {205, 0, 0, TOUCHEXIT, CHECKBOX, (void*)" arrows", 30, 85, 60, 8},
+ {400, 410, 0, 0x0L, LTEXT, (void*)"select template:", 20, 30, 60, 8},
+ {410, 411, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl3D), 20, 42, 25, 25},
+ {411, 412, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl3D), 45, 42, 25, 25},
+ {412, 0, 0, LASTOBJ | TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl3D), 70, 42, 25, 25}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, width, height, n1, n2, n3, ic = 0;
+ int i, j, k, l, m, n, i2, j2, k2, l2, m2;
+ double x, y, z, bar_w, bar_d, rad;
+ bool bRet = false, bContinue = false;
+ AccRange *rX, *rY, *rZ;
+ fPOINT3D pos1, pos2;
+
+ if(!data || !parent || parent->Id != GO_PLOT3D)return false;
+ data->GetSize(&width, &height);
+ sprintf(text1, "a1:a%d", height); sprintf(text2, "b1:b%d", height);
+ sprintf(text3, "c1:c%d", height);
+ if(!(Dlg = new DlgRoot(Dlg3D)))return false;
+ Dlg->SetCheck(410 + AxisTempl3D, 0L, true);
+ for(i = 0; i < 5; i++) Dlg->SetCheck(201+i, 0L, (c_flags & (1<<i))!=0);
+ if(c_flags == 0x2000) {
+ Dlg->ShowItem(5, false); Dlg->ShowItem(6, false);
+ }
+ else Dlg->ShowItem(6, (c_flags & 0x1000) == 0x1000);
+ rX = rY = rZ = 0L;
+ rad = defs.GetSize(SIZE_SYMBOL);
+#ifdef _WINDOWS
+ for(i = 61; i <= 62; i++) Dlg->TextSize(i, 12);
+#else
+ for(i = 61; i <= 62; i++) Dlg->TextSize(i, 10);
+#endif
+ hDlg = CreateDlgWnd(c_flags != 0x2000 ? (char*)"Create 3D Plot":(char*)"Create Paravent Plot", 50, 50, 388, 300, Dlg, 0x0L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 0: // focus lost
+ if(bContinue) res = -1;
+ else if(Dlg->GetCheck(10)) res = -1;
+ break;
+ case -1:
+ bContinue = false;
+ break;
+ case 4: case 5: case 6: //the tab sheets
+ res = -1;
+ break;
+ case 202:
+ Dlg->SetCheck(204, 0L, false);
+ res = -1;
+ break;
+ case 204:
+ Dlg->SetCheck(202, 0L, false);
+ res = -1;
+ break;
+ case 203:
+ Dlg->SetCheck(205, 0L, false);
+ res = -1;
+ break;
+ case 205:
+ Dlg->SetCheck(203, 0L, false);
+ res = -1;
+ break;
+ case 410: case 411: case 412: //axis templates
+ AxisTempl3D = res-410;
+ res = -1;
+ break;
+ case 1:
+ if(rX) delete rX; if(rY) delete rY; if(rZ) delete rZ;
+ rX = rY = rZ = 0L; n1 = n2 = n3 = 0;
+ if(Dlg->GetText(101, text1) && (rX = new AccRange(text1))) n1 = rX->CountItems();
+ if(Dlg->GetText(103, text2) && (rY = new AccRange(text2))) n2 = rY->CountItems();
+ if(Dlg->GetText(105, text3) && (rZ = new AccRange(text3))) n3 = rZ->CountItems();
+ if(n1 && n2 && n3){
+ if(c_flags == 0x2000) {
+ //no more but a ribbon
+ }
+ else if(n1 == n2 && n2 == n3) {
+ //o.k., three ranges of equal size have been defined
+ c_flags = 0;
+ for(i = 0; i < 5; i++) if(Dlg->GetCheck(201+i)) c_flags |= (1<<i);
+ }
+ else {
+ InfoBox("All ranges must have\nthe same size.");
+ res = -1; bContinue = true;
+ }
+ }
+ else {
+ sprintf(TmpTxt, "Ranges for\n%s%s%s\n\nnot given or not valid.",
+ n1 == 0 ? "\n X Data" : "", n2 == 0 ? "\n Y Data" : "",
+ n3 == 0 ? "\n Z Data" : "");
+ InfoBox(TmpTxt);
+ res = -1; bContinue = true;
+ }
+ break;
+ }
+ }while (res <0);
+ if(res == 1 && rX && rY && rZ) {
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
+ xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
+ bar_w = bar_d = (defs.GetSize(SIZE_BAR)/2.0);
+ if(c_flags & 0x01) (Balls = (Sphere**)calloc((nBalls = n1)+1, sizeof(Sphere*)));
+ if(c_flags & 0x02) (Columns = (Brick**)calloc((nColumns = n1)+1, sizeof(Brick*)));
+ if(c_flags & 0x04) Line = new Line3D(this, data, text1, text2, text3);
+ if(c_flags & 0x08) (DropLines = (DropLine3D**)calloc((nDropLines = n1)+1, sizeof(DropLine3D*)));
+ if(c_flags & 0x010) (Arrows = (Arrow3D**)calloc((nArrows = n1)+1, sizeof(Arrow3D*)));
+ rX->GetFirst(&i, &j); rX->GetNext(&i, &j);
+ rY->GetFirst(&k, &l); rY->GetNext(&k, &l);
+ rZ->GetFirst(&m, &n); rZ->GetNext(&m, &n);
+ i2 = i; j2 = j; k2 = k; l2 = l; m2 = m; n2 = n;
+ if(c_flags == 0x2000){
+ Bounds.Ymin = 0.0;
+ rib = new Ribbon(this, data, text1, text2, text3);
+ }
+ do {
+ if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y) &&
+ data->GetValue(n, m, &z)){
+ if(ic) {
+ pos1.fx = pos2.fx; pos1.fy = pos2.fy; pos1.fz = pos2.fz;
+ }
+ else {
+ pos1.fx = x; pos1.fy = y; pos1.fz = z;
+ }
+ pos2.fx = x; pos2.fy = y; pos2.fz = z;
+ if(!bRet) memcpy(&pos1, &pos2, sizeof(fPOINT3D));
+ if(Balls) Balls[ic] = new Sphere(this, data, 0, x, y, z, rad, i, j, k, l, m, n);
+ if(Columns)Columns[ic] = new Brick(this, data, x, 0.0, z,
+ bar_d, bar_w, y, 0x800L, i, j, -1, -1, m, n, -1, -1, -1, -1, k, l);
+ if(DropLines) DropLines[ic] = new DropLine3D(this, data, &pos2, i, j, k, l, m, n);
+ if(Arrows) Arrows[ic] = new Arrow3D(this, data, &pos1, &pos2,
+ i, j, k, l, m, n, i2, j2, k2, l2, m2, n2);
+ ((Plot3D *)parent)->CheckBounds3D(x, y, z); CheckBounds3D(x, y, z);
+ bRet = true;
+ }
+ i2 = i; j2 = j; k2 = k; l2 = l; m2 = m; n2 = n;
+ ic++;
+ }while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l) && rZ->GetNext(&m, &n));
+ if(!bRet) InfoBox("The selected data range\nis empty or does not contain\nvalid"
+ " data triplets!");
+ bRet = true;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(rX) delete rX; if(rY) delete rY; if(rZ) delete rZ;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// user defined function properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Function::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 37, 10, "Function"};
+ TabSHEET tab2 = {37, 60, 10, "Line"};
+ DlgInfo FuncDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 160, 10, 32, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 160, 25, 32, 12},
+ {3, 10, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
+ {4, 5, 100, ISPARENT, SHEET, &tab1, 5, 10, 149, 110},
+ {5, 0, 500, ISPARENT | CHECKED, SHEET, &tab2, 5, 10, 149, 110},
+ {10, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"plot user defined function", 10, 24, 100, 8},
+ {101, 102, 0, 0x0L, RTEXT, (void*)"where x=", 10, 40, 28, 8},
+ {102, 103, 0, 0x0L, EDVAL1, &x1, 38, 40, 25, 10},
+ {103, 104, 0, 0x0L, RTEXT, (void*)"until", 61, 40, 17, 8},
+ {104, 105, 0, 0x0L, EDVAL1, &x2, 78, 40, 25, 10},
+ {105, 106, 0, 0x0L, RTEXT, (void*)"step", 102, 40, 17, 8},
+ {106, 107, 0, 0x0L, EDVAL1, &xstep, 119, 40, 25, 10},
+ {107, 200, 0, 0x0L, RTEXT, (void*)"y=", 10, 56, 10, 8},
+ {200, 0, 0, 0x0L, TEXTBOX, (void*)cmdxy, 22, 54, 122, 40},
+ {500, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)OD_linedef, 15, 25, 130, 100}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, undo_level = *Undo.pcb;
+ bool bRet = false, bNew = (dl == 0L);
+ DWORD undo_flags = 0L;
+ LineDEF newLine;
+ double o_x1, n_x1, o_x2, n_x2, o_xstep, n_xstep;
+
+ if(!parent) return false;
+ if(parent->Id == GO_FITFUNC) return parent->PropertyDlg();
+ OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
+ if(!(Dlg = new DlgRoot(FuncDlg))) return false;
+ if(!bNew) Dlg->ShowItem(10, false);
+ Dlg->GetValue(102, &o_x1); n_x1 = o_x1;
+ Dlg->GetValue(104, &o_x2); n_x2 = o_x2;
+ Dlg->GetValue(106, &o_xstep); n_xstep = o_xstep;
+ hDlg = CreateDlgWnd("Function Plot", 50, 50, 400, 276, Dlg, 0x0L);
+ if(bNew) Dlg->SetCheck(4, 0L, true);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 0:
+ if(Dlg->GetCheck(10)) res = -1;
+ break;
+ }
+ }while (res < 0);
+ while(*Undo.pcb > undo_level) Undo.Pop();
+ if(res == 1){ //OK pressed
+ if(bNew) { //create function
+ OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&Line, 0);
+ Dlg->GetValue(102, &x1); Dlg->GetValue(104, &x2);
+ Dlg->GetValue(106, &xstep); Dlg->GetText(200, TmpTxt);
+ cmdxy = strdup(TmpTxt);
+ bRet = Update(0L, 0L);
+ }
+ else { //edit existing function
+ Dlg->GetValue(102, &n_x1); Dlg->GetValue(104, &n_x2);
+ Dlg->GetValue(106, &n_xstep);
+ undo_flags = CheckNewFloat(&x1, o_x1, n_x1, this, undo_flags);
+ undo_flags = CheckNewFloat(&x2, o_x2, n_x2, this, undo_flags);
+ undo_flags = CheckNewFloat(&xstep, o_xstep, n_xstep, this, undo_flags);
+ Dlg->GetText(200, TmpTxt);
+ if(cmdxy && strcmp(cmdxy, TmpTxt)) {
+ Undo.String(this, &cmdxy, undo_flags);
+ free(cmdxy); cmdxy = strdup(TmpTxt); undo_flags |= UNDO_CONTINUE;
+ }
+ if(undo_flags & UNDO_CONTINUE) Update(0L, UNDO_CONTINUE);
+ OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
+ if(cmpLineDEF(&Line, &newLine)) {
+ Undo.Line(parent, &Line, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&Line, &newLine, sizeof(LineDEF));
+ }
+ bRet = (undo_flags & UNDO_CONTINUE) != 0;
+ }
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// fit function by nonlinear regression
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+FitFunc::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 22, 10, "Data"};
+ TabSHEET tab2 = {22, 59, 10, "Function"};
+ TabSHEET tab3 = {59, 82, 10, "Line"};
+ char text1[100], text2[100];
+ double iter;
+ bool bNew = (dl == 0L);
+ DlgInfo FuncDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 160, 10, 32, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 160, 25, 32, 12},
+ {3, 10, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
+ {4, 5, 400, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 149, 125},
+ {5, 6, 100, ISPARENT, SHEET, &tab2, 5, 10, 149, 125},
+ {6, 7, 500, ISPARENT, SHEET, &tab3, 5, 10, 149, 125},
+ {7, 0, 0, 0x0L, PUSHBUTTON, (void*)"Fit", 160, 123, 32, 12},
+ {10, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"fit function by nonlinear regression", 10, 24, 100, 8},
+ {101, 102, 0, 0x0L, LTEXT, (void*)"parameters and initial values:", 10, 34, 100, 8},
+ {102, 150, 0, 0x0L, TEXTBOX, (void*)parxy, 22, 44, 122, 25},
+ {150, 151, 0, 0x0L, LTEXT, (void*)"function, y=f(x):", 10, 72, 10, 8},
+ {151, 152, 0, 0x0L, RTEXT, (void*)"y=", 10, 86, 10, 8},
+ {152, 153, 0, 0x0L, RTEXT, (void*)"converg.:", 20, 118, 26, 8},
+ {153, 154, 0, 0x0L, EDVAL1, &conv, 46, 118, 25, 10},
+ {154, 155, 0, 0x0L, RTEXT, (void*)"iterations:", 72, 118, 47, 8},
+ {155, 200, 0, 0x0L, EDVAL1, &iter, 119, 118, 25, 10},
+ {200, 0, 0, 0x0L, TEXTBOX, (void*)cmdxy, 22, 84, 122, 30},
+ {400, 401, 0, 0x0L, LTEXT, (void*)"range for X Data", 10, 30, 60, 8},
+ {401, 402, 0, 0x0L, EDTEXT, (void*)ssXref, 20, 40, 100, 10},
+ {402, 403, 0, 0x0L, LTEXT, (void*)"range for Y Data", 10, 55, 60, 8},
+ {403, 404, 0, 0x0L, EDTEXT, (void*)ssYref, 20, 65, 100, 10},
+ {404, 405, 0, CHECKED, CHECKBOX, (void*)"draw symbols", 20, 95, 60, 8},
+ {405, 0, 0, HIDDEN, LTEXT, 0L, 20, 95, 60, 8},
+ {500, 550, 501, CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {501, 502, 0, 0x0L, RTEXT, (void*)"plot x=", 10, 30, 28, 8},
+ {502, 503, 0, 0x0L, EDVAL1, &x1, 38, 30, 25, 10},
+ {503, 504, 0, 0x0L, RTEXT, (void*)"until", 61, 30, 17, 8},
+ {504, 505, 0, 0x0L, EDVAL1, &x2, 78, 30, 25, 10},
+ {505, 506, 0, 0x0L, RTEXT, (void*)"step", 102, 30, 17, 8},
+ {506, 0, 0, 0x0L, EDVAL1, &xstep, 119, 30, 25, 10},
+ {550, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)OD_linedef, 15, bNew ? 35:45, 130, 100}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, undo_level = *Undo.pcb, i, j, k, l, cs;
+ bool bRet = false, bContinue = false;
+ DWORD undo_flags = 0L;
+ LineDEF newLine;
+ double tmp, tmpy, o_x1, n_x1, o_x2, n_x2, o_xstep, n_xstep, n_chi2=chi2;
+ AccRange *rX, *rY;
+ char *o_cmdxy, *o_parxy, *tmp_char;
+
+ if(!parent || !data) return false;
+ if(!(o_cmdxy = strdup(cmdxy))) return false;
+ if(!(o_parxy = strdup(parxy))) return false;
+ iter = (double)maxiter;
+ OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
+ if(!(Dlg = new DlgRoot(FuncDlg))) return false;
+ if(!bNew){
+ Dlg->ShowItem(10, false); Dlg->Activate(401, false);
+ Dlg->Activate(403, false); Dlg->SetCheck(6, 0L, true);
+ Dlg->SetCheck(4, 0L, false); Dlg->ShowItem(404, false);
+ if(chi2 > 0.0) {
+ sprintf(TmpTxt, "Chi 2 = %g", chi2);
+ Dlg->SetText(405,TmpTxt); Dlg->ShowItem(405, true);
+ }
+ }
+ else {
+ Dlg->ShowItem(500, false);
+ }
+ Dlg->GetValue(502, &o_x1); n_x1 = o_x1;
+ Dlg->GetValue(504, &o_x2); n_x2 = o_x2;
+ Dlg->GetValue(506, &o_xstep); n_xstep = o_xstep;
+ hDlg = CreateDlgWnd("Fit Function to Data", 50, 50, 400, 306, Dlg, 0x0L);
+ if(bNew) Dlg->SetCheck(4, 0L, true);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 0:
+ if(Dlg->GetCheck(10)) res = -1;
+ if(bContinue) res = -1;
+ bContinue = false;
+ break;
+ case 1:
+ if(!bNew){
+ if(Dlg->GetText(102, TmpTxt) && parxy) {
+ free(parxy); parxy = strdup(TmpTxt);
+ }
+ if(Dlg->GetText(200, TmpTxt) && cmdxy) {
+ free(cmdxy); cmdxy = strdup(TmpTxt);
+ }
+ ReshapeFormula(&parxy); ReshapeFormula(&cmdxy);
+ dirty = true;
+ break;
+ }
+ case 7: //Start: do nonlinear regression
+ if(Dlg->GetCheck(5)) { // the function tab must be shown
+ if(Dlg->CurrDisp) Dlg->CurrDisp->MouseCursor(MC_WAIT, true);
+ Dlg->GetText(401, text1); Dlg->GetText(403, text2);
+ if(Dlg->GetText(102, TmpTxt) && parxy) {
+ free(parxy); parxy = strdup(TmpTxt);
+ }
+ if(Dlg->GetText(200, TmpTxt) && cmdxy) {
+ free(cmdxy); cmdxy = strdup(TmpTxt);
+ }
+ Dlg->GetValue(153, &conv); Dlg->GetValue(155, &iter);
+ ReshapeFormula(&parxy); ReshapeFormula(&cmdxy);
+ i = do_fitfunc(data, text1, text2, 0L, &parxy, cmdxy, conv, (int)iter, &chi2);
+ Dlg->SetText(102, parxy);
+ if(i >1 || res == 7) {
+ sprintf(TmpTxt, "The Levenberg-Marquart algorithm\nexited after %d iterations.\n\nChi2 = %g", i, chi2);
+ InfoBox(TmpTxt);
+ }
+ bContinue = true;
+ if(res == 7) res = -1;
+ if(Dlg->CurrDisp) Dlg->CurrDisp->MouseCursor(MC_ARROW, true);
+ }
+ else { //diplay function tab first
+ Dlg->SetCheck(5, 0L, true);
+ res = -1;
+ }
+ break;
+ }
+ }while (res < 0);
+ while(*Undo.pcb > undo_level) Undo.Pop();
+ if(res == 1){ //OK pressed
+ //get ranges for x- and y data (again).
+ chi2 = n_chi2;
+ Dlg->GetText(401, text1); Dlg->GetText(403, text2);
+ if(ssXref) free(ssXref); if(ssYref) free(ssYref);
+ ssXref = strdup(text1); ssYref = strdup(text2);
+ if(bNew) { //create function
+ if(!(rX = new AccRange(text1)) || ! (rY = new AccRange(text2))) return false;
+ i = rX->CountItems(); maxiter = int(iter);
+ if(Dlg->GetCheck(404)) Symbols = (Symbol**)calloc(i, sizeof(Symbol*));
+ x1 = HUGE_VAL; x2 = -HUGE_VAL; cs = 0;
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL;
+ Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ rX->GetFirst(&i, &j); rY->GetFirst(&k, &l);
+ rX->GetNext(&i, &j); rY->GetNext(&k, &l);
+ do {
+ if(data->GetValue(j, i, &tmp) && data->GetValue(l, k, &tmpy)){
+ if(tmp < x1) x1 = tmp; if(tmp > x2) x2 = tmp;
+ if(Symbols) Symbols[cs++] = new Symbol(this, data, tmp, tmpy, SYM_CIRCLE, i, j, k, l);
+ nPoints = cs; CheckBounds(tmp, tmpy);
+ }
+ }while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l));
+ delete rX; delete rY;
+ if(x1 >= x2 || !(dl = new Function(this, data))){
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return false;
+ }
+ xstep = (x2 - x1)/100.0;
+ OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&Line, 0);
+ dl->SetSize(SIZE_MIN_X, x1); dl->SetSize(SIZE_MAX_X, x2);
+ dl->SetSize(SIZE_XSTEP, xstep); dl->Command(CMD_SETFUNC, cmdxy, 0L);
+ dl->Command(CMD_SETPARAM, parxy, 0L);
+ dl->Command(CMD_SET_LINE, &Line, 0L);
+ dl->Command(CMD_AUTOSCALE, 0L, 0L);
+ CheckBounds(dl->Bounds.Xmin, dl->Bounds.Ymin);
+ CheckBounds(dl->Bounds.Xmax, dl->Bounds.Ymax);
+ bRet = true;
+ }
+ else { //edit existing function
+ Dlg->GetValue(502, &n_x1); Dlg->GetValue(504, &n_x2);
+ Dlg->GetValue(506, &n_xstep);
+ undo_flags = CheckNewFloat(&x1, o_x1, n_x1, this, undo_flags);
+ undo_flags = CheckNewFloat(&x2, o_x2, n_x2, this, undo_flags);
+ if(o_parxy && parxy && strcmp(o_parxy, parxy)) {
+ tmp_char = parxy; parxy = o_parxy;
+ Undo.String(this, &parxy, undo_flags);
+ free(parxy); parxy = tmp_char; undo_flags |= UNDO_CONTINUE;
+ o_parxy = 0L;
+ }
+ if(o_cmdxy && cmdxy && strcmp(o_cmdxy, cmdxy)) {
+ tmp_char = cmdxy; cmdxy = o_cmdxy;
+ Undo.String(this, &cmdxy, undo_flags);
+ free(cmdxy); cmdxy = tmp_char; undo_flags |= UNDO_CONTINUE;
+ o_cmdxy = 0L;
+ }
+ if(undo_flags & UNDO_CONTINUE) {
+ Undo.ValInt(parent, (int*)&dirty, undo_flags);
+ Command(CMD_MRK_DIRTY, 0L, 0L);
+ }
+ undo_flags = CheckNewFloat(&xstep, o_xstep, n_xstep, this, undo_flags);
+// Dlg->GetText(200, TmpTxt);
+// if(cmdxy && strcmp(cmdxy, TmpTxt)) {
+// Undo.String(this, &cmdxy, undo_flags);
+// free(cmdxy); cmdxy = strdup(TmpTxt); undo_flags |= UNDO_CONTINUE;
+// }
+// if(undo_flags & UNDO_CONTINUE) Update(0L, UNDO_CONTINUE);
+// cmdxy = strdup(TmpTxt);
+// bRet = Update(0L, 0L);
+ OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
+ if(cmpLineDEF(&Line, &newLine)) {
+ Undo.Line(parent, &Line, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&Line, &newLine, sizeof(LineDEF));
+ }
+ bRet = (undo_flags & UNDO_CONTINUE) != 0;
+ }
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(o_parxy) free(o_parxy); if(o_cmdxy) free(o_cmdxy);
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Create a three dimensional graph
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Plot3D::AddPlot(int family)
+{
+ DlgInfo PlotsDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 150, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 150, 25, 45, 12},
+ {3, 0, 560, ISPARENT | CHECKED, GROUPBOX, (void *)" select template ", 5, 10, 140, 70},
+ {560, 561, 0, TOUCHEXIT | CHECKED | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 12, 20, 25, 25},
+ {561, 562, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 37, 20, 25, 25},
+ {562, 563, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 62, 20, 25, 25},
+ {563, 564, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 87, 20, 25, 25},
+ {564, 0, 0, LASTOBJ | TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 112, 20, 25, 25}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, cSel = 560;
+ bool bRet = false;
+ Plot *p;
+
+ if(!(Dlg = new DlgRoot(PlotsDlg)))return false;
+ hDlg = CreateDlgWnd("Add Plot", 50, 50, 410, 204, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 560: case 561: case 562: case 563: case 564:
+ if(res == cSel) res = 1;
+ else {
+ cSel = res;
+ res = -1;
+ }
+ break;
+ }
+ }while (res < 0);
+ if(res == 1){ //OK pressed
+ if(Dlg->GetCheck(560)) p = new Scatt3D(this, data, 0x01);
+ else if(Dlg->GetCheck(561)) p = new Scatt3D(this, data, 0x02);
+ else if(Dlg->GetCheck(562)) p = new Scatt3D(this, data, 0x04);
+ else if(Dlg->GetCheck(563)) p = new BubblePlot3D(this, data);
+ else if(Dlg->GetCheck(564)) p = new Scatt3D(this, data, 0x2000);
+ if(p && p->PropertyDlg()) {
+ if(p->Id == GO_PLOT3D) delete p;
+ else if(!(bRet = Command(CMD_DROP_PLOT, p, (anyOutput *)NULL))) delete p;
+ }
+ else if(p) delete p;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+bool
+Plot3D::PropertyDlg()
+{
+ Plot *p;
+ bool bRet = false;
+
+ if(plots) {
+ //plots already created - jump to configuration dialog
+ return false;
+ }
+ if((p = new Scatt3D(this, data, crea_flags)) && p->PropertyDlg()) {
+ if(!(bRet = Command(CMD_DROP_PLOT, p, (anyOutput *)NULL))) DeleteGO(p);
+ }
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Create a 2.5 dimensional chart
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Chart25D::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 25, 10, "Data"};
+ TabSHEET tab2 = {25, 55, 10, "Details"};
+ TabSHEET tab3 = {55, 90, 10, "Scheme"};
+ static DWORD colarr[] = {0x000080ffL, 0x00ff8000L, 0x0000ff00L, 0x000000ffL,
+ 0x00ff00ff, 0x00ffff00L, 0x0000ffff, 0x00c0c0c0};
+ static DWORD defcol = 0x00ffffffL;
+ char text1[100];
+ double start_z = 1.0;
+ DlgInfo Bar3D_Dlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 158, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 158, 25, 45, 12},
+ {3, 0, 10, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
+ {10, 11, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 140, 100},
+ {11, 12, 200, ISPARENT, SHEET, &tab2, 5, 10, 140, 100},
+ {12, 20, 300, ISPARENT, SHEET, &tab3, 5, 10, 140, 100},
+ {20, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"range for common x values", 15, 30, 60, 8},
+ {101, 152, 0, 0x0L, EDTEXT, text1, 25, 40, 100, 10},
+ {152, 153, 0, ISPARENT | CHECKED, GROUPBOX, (void*)" ranges for y values ", 12, 60, 128, 45},
+ {153, 154, 0, 0x0L, LTEXT, 0L, 25, 65, 60, 8},
+ {154, 155, 0, 0x0L, EDTEXT, 0L, 25, 75, 100, 10},
+ {155, 156, 0, 0x0L, PUSHBUTTON, (void*)"Next >>", 95, 87, 30, 12},
+ {156, 0, 0, 0x0L, PUSHBUTTON, (void*)"<< Prev.", 60, 87, 35, 12},
+ {200, 201, 0, 0x0L, LTEXT, (void*)"distances:", 20, 35, 80, 8},
+ {201, 202, 0, 0x0L, RTEXT, (void*)"start z =", 48, 45, 13, 8},
+ {202, 203, 0, 0x0L, EDVAL1, &start_z, 65, 45, 25, 10},
+ {203, 204, 0, 0x0L, RTEXT, (void*)"step =", 48, 57, 13, 8},
+ {204, 0, 0, 0x0L, EDVAL1, &dspm.fz, 65, 57, 25, 10},
+ {300, 301, 0, CHECKED, RADIO1, (void*)" common color for columns:", 15, 35, 80, 9},
+ {301, 302, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)defcol, 110, 35, 20, 10},
+ {302, 303, 0, 0x0L, RADIO1, (void*)" increment color scheme:", 15, 55, 80, 9},
+ {303, 304, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[0], 25, 70, 10, 10},
+ {304, 305, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[1], 37, 70, 10, 10},
+ {305, 306, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[2], 49, 70, 10, 10},
+ {306, 307, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[3], 61, 70, 10, 10},
+ {307, 308, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[4], 73, 70, 10, 10},
+ {308, 309, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[5], 85, 70, 10, 10},
+ {309, 310, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[6], 97, 70, 10, 10},
+ {310, 0, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[7], 109, 70, 10, 10},
+ {500, 0, 0, LASTOBJ, NONE, 0L, 0, 0, 0, 0}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, ic, res, width, height, currYR=0, maxYR=0, nx=0, ny, rx, cx, ry, cy, oax;
+ char **rd;
+ double fx, fy, fz, fsz;
+ bool updateYR = true, bContinue = false, bRet = false, bUseSch;
+ AccRange *rX = 0L, *rY = 0L;
+ Brick **cols;
+ Scatt3D *plot;
+ AxisDEF *ax;
+
+ if(plots) {
+ //Plots alredy defined: jump to config dialog
+ return false;
+ }
+ data->GetSize(&width, &height);
+ sprintf(text1, "a1:a%d", height);
+ if(!(rd = (char**)calloc(1, sizeof(char*))))return false;
+ Dlg = new DlgRoot(Bar3D_Dlg);
+ hDlg = CreateDlgWnd("Create 3D Bar Chart", 50, 50, 420, 260, Dlg, 0x0L);
+ do {
+ if(updateYR) {
+ if(currYR >0) {
+ Dlg->ShowItem(156, true);
+ Dlg->Activate(101, false);
+ }
+ else {
+ Dlg->ShowItem(156, false);
+ Dlg->Activate(101, true);
+ }
+ sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
+ //SetText will also cause a redraw of the whole dialog
+ Dlg->SetText(153, TmpTxt);
+ updateYR = false;
+ }
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ ny = 0;
+ if(rX) delete rX;
+ rX = 0L;
+ switch(res) {
+ case 0:
+ if(bContinue || Dlg->GetCheck(20)) res = -1;
+ break;
+ case -1:
+ bContinue = false; break;
+ case 1:
+ for(i = 0; i < 8; i++) Dlg->GetColor(303+i, &colarr[i]);
+ Dlg->GetColor(301, &defcol);
+ bUseSch = Dlg->GetCheck(302);
+ Dlg->GetValue(202, &start_z); Dlg->GetValue(204, &dspm.fz);
+ //execute com_StackDlg for <OK>
+ case 155: case 156:
+ res = com_StackDlg(res, Dlg, &rX, &nx, &rd, &currYR,
+ &rY, &bContinue, &ny, &maxYR, &updateYR);
+ break;
+ case 301:
+ Dlg->SetCheck(300, 0L, true);
+ res = -1; break;
+ case 303: case 304: case 305: case 306:
+ case 307: case 308: case 309: case 310:
+ Dlg->SetCheck(302, 0L, true);
+ res = -1; break;
+ }
+ }while (res < 0);
+ if(res == 1 && nx && rX && rd && rd[0] && rd[0][0]) {
+ if(rd[maxYR]) maxYR++;
+ fsz = defs.GetSize(SIZE_BAR)/2.0; fz = start_z;
+ oax = AxisTempl3D; AxisTempl3D = 1; CreateAxes();
+ if(Axes && nAxes > 2 && Axes[2] && (ax = Axes[2]->GetAxis())){
+ ax->flags = AXIS_3D | AXIS_INVERT | AXIS_DEFRECT;
+ ax->min = start_z-dspm.fz;
+ ax->max = start_z+dspm.fz*maxYR;
+ if(Axes[1] && (ax = Axes[1]->GetAxis())){
+ ax->flags |= AXIS_GRIDLINE;
+ i = 0x0c;
+ Axes[1]->Command(CMD_SET_GRIDTYPE, &i, 0L);
+ }
+ AxisTempl3D = oax;
+ }
+ if(plots = (GraphObj**)calloc(maxYR, sizeof(GraphObj*))) {
+ for(i = 0; i < maxYR; i++, fz += dspm.fz) {
+ if(rd[i] && (cols = (Brick**)calloc(nx, sizeof(Brick*))) && (rY = new AccRange(rd[i]))) {
+ ic = 0;
+ if(rX->GetFirst(&cx, &rx) && rX->GetNext(&cx, &rx) &&
+ rY->GetFirst(&cy, &ry) && rY->GetNext(&cy, &ry)) {
+ do {
+ if(data->GetValue(rx, cx, &fx) && data->GetValue(ry, cy, &fy)){
+ cols[ic] = new Brick(this, data, fx, 0.0, fz,
+ fsz, fsz, fy, 0x800L, cx, rx, -1, -1, -1, -1,
+ -1, -1, -1, -1, cy, ry);
+ }
+ ic++;
+ }while(rX->GetNext(&cx, &rx) && rY->GetNext(&cy, &ry));
+ if(ic) bRet = true;
+ }
+ delete(rY); rY = 0L;
+ if(plot = new Scatt3D(this, data, cols, ic)){
+ if(bUseSch) plot->SetColor(COL_BAR_FILL, colarr[(i & 0x07)]);
+ else plot->SetColor(COL_BAR_FILL, defcol);
+ plots[nPlots++] = plot;
+ }
+ }
+ }
+ }
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(rd) {
+ for (i = 0; i < maxYR; i++) if(rd[i]) free(rd[i]);
+ free(rd);
+ }
+ if(rX) delete rX; if(rY) delete rY;
+ if(bRet) {
+ Command(CMD_MRK_DIRTY, 0L, 0L);
+ }
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Create a 2.5 dimensional ribbon chart
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Ribbon25D::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 25, 10, "Data"};
+ TabSHEET tab2 = {25, 55, 10, "Details"};
+ TabSHEET tab3 = {55, 90, 10, "Scheme"};
+ static DWORD colarr[] = {0x000080ffL, 0x00ff8000L, 0x0000ff00L, 0x000000ffL,
+ 0x00ff00ff, 0x00ffff00L, 0x0000ffff, 0x00c0c0c0};
+ static DWORD defcol = 0x00ffffffL;
+ char text1[100];
+ double start_z = 1.0;
+ DlgInfo Bar3D_Dlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 158, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 158, 25, 45, 12},
+ {3, 0, 10, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
+ {10, 11, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 140, 100},
+ {11, 12, 200, ISPARENT, SHEET, &tab2, 5, 10, 140, 100},
+ {12, 20, 300, ISPARENT, SHEET, &tab3, 5, 10, 140, 100},
+ {20, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"range for common x values", 15, 30, 60, 8},
+ {101, 152, 0, 0x0L, EDTEXT, text1, 25, 40, 100, 10},
+ {152, 153, 0, ISPARENT | CHECKED, GROUPBOX, (void*)" ranges for y values ", 12, 60, 128, 45},
+ {153, 154, 0, 0x0L, LTEXT, 0L, 25, 65, 60, 8},
+ {154, 155, 0, 0x0L, EDTEXT, 0L, 25, 75, 100, 10},
+ {155, 156, 0, 0x0L, PUSHBUTTON, (void*)"Next >>", 95, 87, 30, 12},
+ {156, 0, 0, 0x0L, PUSHBUTTON, (void*)"<< Prev.", 60, 87, 35, 12},
+ {200, 201, 0, 0x0L, LTEXT, (void*)"distances:", 20, 35, 80, 8},
+ {201, 202, 0, 0x0L, RTEXT, (void*)"start z =", 48, 45, 13, 8},
+ {202, 203, 0, 0x0L, EDVAL1, &start_z, 65, 45, 25, 10},
+ {203, 204, 0, 0x0L, RTEXT, (void*)"step =", 48, 57, 13, 8},
+ {204, 0, 0, 0x0L, EDVAL1, &dspm.fz, 65, 57, 25, 10},
+ {300, 301, 0, CHECKED, RADIO1, (void*)" common color for ribbons:", 15, 35, 80, 9},
+ {301, 302, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)defcol, 110, 35, 20, 10},
+ {302, 303, 0, 0x0L, RADIO1, (void*)" increment color scheme:", 15, 55, 80, 9},
+ {303, 304, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[0], 25, 70, 10, 10},
+ {304, 305, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[1], 37, 70, 10, 10},
+ {305, 306, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[2], 49, 70, 10, 10},
+ {306, 307, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[3], 61, 70, 10, 10},
+ {307, 308, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[4], 73, 70, 10, 10},
+ {308, 309, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[5], 85, 70, 10, 10},
+ {309, 310, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[6], 97, 70, 10, 10},
+ {310, 0, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[7], 109, 70, 10, 10},
+ {500, 0, 0, LASTOBJ, NONE, 0L, 0, 0, 0, 0}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, res, width, height, currYR=0, maxYR=0, nx=0, ny, oax;
+ char **rd;
+ double fz;
+ bool updateYR = true, bContinue = false, bRet = false, bUseSch;
+ AccRange *rX = 0L, *rY = 0L;
+ AxisDEF *ax;
+ Ribbon *plot;
+
+ if(plots) {
+ //Plots alredy defined: jump to config dialog
+ return false;
+ }
+ data->GetSize(&width, &height);
+ sprintf(text1, "a1:a%d", height);
+ if(!(rd = (char**)calloc(1, sizeof(char*))))return false;
+ Dlg = new DlgRoot(Bar3D_Dlg);
+ hDlg = CreateDlgWnd("Create 3D Ribbon Chart", 50, 50, 420, 260, Dlg, 0x0L);
+ do {
+ if(updateYR) {
+ if(currYR >0) {
+ Dlg->ShowItem(156, true); Dlg->Activate(101, false);
+ }
+ else {
+ Dlg->ShowItem(156, false); Dlg->Activate(101, true);
+ }
+ sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
+ //SetText will also cause a redraw of the whole dialog
+ Dlg->SetText(153, TmpTxt);
+ updateYR = false;
+ }
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ ny = 0; if(rX) delete rX; rX = 0L;
+ switch(res) {
+ case 0:
+ if(bContinue || Dlg->GetCheck(20)) res = -1;
+ break;
+ case -1:
+ bContinue = false; break;
+ case 1:
+ for(i = 0; i < 8; i++) Dlg->GetColor(303+i, &colarr[i]);
+ Dlg->GetColor(301, &defcol); bUseSch = Dlg->GetCheck(302);
+ Dlg->GetValue(202, &start_z); Dlg->GetValue(204, &dspm.fz);
+ //execute com_StackDlg for <OK>
+ case 155: case 156:
+ res = com_StackDlg(res, Dlg, &rX, &nx, &rd, &currYR,
+ &rY, &bContinue, &ny, &maxYR, &updateYR);
+ break;
+ case 301:
+ Dlg->SetCheck(300, 0L, true);
+ res = -1; break;
+ case 303: case 304: case 305: case 306:
+ case 307: case 308: case 309: case 310:
+ Dlg->SetCheck(302, 0L, true);
+ res = -1; break;
+ }
+ }while (res < 0);
+ if(res == 1 && nx && rX && rd && rd[0] && rd[0][0]) {
+ if(rd[maxYR]) maxYR++; fz = start_z;
+ oax = AxisTempl3D; AxisTempl3D = 1; CreateAxes();
+ Dlg->GetText(101, text1);
+ if(Axes && nAxes > 2 && Axes[2] && (ax = Axes[2]->GetAxis())){
+ ax->flags = AXIS_3D | AXIS_INVERT | AXIS_DEFRECT;
+ ax->min = start_z-dspm.fz;
+ ax->max = start_z+dspm.fz*maxYR;
+ if(Axes[1] && (ax = Axes[1]->GetAxis())){
+ ax->flags |= AXIS_GRIDLINE; i = 0x0c;
+ Axes[1]->Command(CMD_SET_GRIDTYPE, &i, 0L);
+ }
+ AxisTempl3D = oax;
+ }
+ if(plots = (GraphObj**)calloc(maxYR, sizeof(GraphObj*))) {
+ for(i = 0; i < maxYR; i++, fz += dspm.fz) {
+ if(plot = new Ribbon(this, data, fz, dspm.fz, text1, rd[i])){
+ if(bUseSch) plot->SetColor(COL_POLYGON, colarr[(i & 0x07)]);
+ else plot->SetColor(COL_POLYGON, defcol);
+ plots[nPlots++] = plot;
+ }
+ }
+ }
+ Command(CMD_MRK_DIRTY, 0L, 0L); Command(CMD_AUTOSCALE, 0L, 0L);
+ bRet = true;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(rd) {
+ for (i = 0; i < maxYR; i++) if(rd[i]) free(rd[i]);
+ free(rd);
+ }
+ if(rX) delete rX; if(rY) delete rY;
+ if(bRet) {
+ Command(CMD_MRK_DIRTY, 0L, 0L);
+ }
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Create a 3 dimensional bubble plot
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+BubblePlot3D::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 22, 10, "Data"};
+ TabSHEET tab3 = {22, 47, 10, "Axes"};
+ char text1[100], text2[100], text3[100], text4[100];
+ DlgInfo BubDlg3D[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 142, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 142, 25, 45, 12},
+ {3, 50, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
+ {4, 5, 100, TOUCHEXIT | ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 131, 142},
+ {5, 10, 400, TOUCHEXIT | ISPARENT, SHEET, &tab3, 5, 10, 131, 142},
+ {10, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
+ {50, 0, 0, NOSELECT, ODBUTTON, (void*)(OD_AxisDesc3D), 142, 65, 45, 45},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"range for X Data", 10, 25, 60, 8},
+ {101, 102, 0, 0x0L, EDTEXT, text1, 20, 35, 100, 10},
+ {102, 103, 0, 0x0L, LTEXT, (void*)"range for Y Data", 10, 48, 60, 8},
+ {103, 104, 0, 0x0L, EDTEXT, text2, 20, 58, 100, 10},
+ {104, 105, 0, 0x0L, LTEXT, (void*)"range for Z Data", 10, 71, 60, 8},
+ {105, 106, 0, 0x0L, EDTEXT, text3, 20, 81, 100, 10},
+ {106, 0, 150, ISPARENT | CHECKED, GROUPBOX, (void*)" diameter ", 8, 98, 125, 50},
+ {150, 151, 0, 0x0L, LTEXT, (void*)"range for diameters", 12, 102, 60, 8},
+ {151, 152, 0, 0x0L, EDTEXT, text4, 20, 112, 100, 10},
+ {152, 153, 0, 0x0L, LTEXT, (void*)"scaling:", 12, 125, 20, 8},
+ {153, 154, 0, TOUCHEXIT | CHECKED, RADIO1, (void*)Units[defs.cUnits].display, 38, 125, 20, 8},
+ {154, 155, 0, TOUCHEXIT, RADIO1, (void*)"with x-values", 70, 125, 20, 8},
+ {155, 156, 0, TOUCHEXIT, RADIO1, (void*)"with y-values", 20, 135, 20, 8},
+ {156, 0, 0, TOUCHEXIT, RADIO1, (void*)"with z-values", 70, 135, 20, 8},
+ {400, 410, 0, 0x0L, LTEXT, (void*)"select template:", 20, 30, 60, 8},
+ {410, 411, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl3D), 20, 42, 25, 25},
+ {411, 412, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl3D), 45, 42, 25, 25},
+ {412, 0, 0, LASTOBJ | TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl3D), 70, 42, 25, 25}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, res, width, height, count;
+ int cx, rx, cy, ry, cz, rz, cr, rr, s_type = 0;
+ bool bRet = false;
+ double fx, fy, fz, fr;
+ Sphere **Balls;
+ AccRange *rX, *rY, *rZ, *rR;
+ Scatt3D *sc_plot;
+
+ if(!data || !parent)return false;
+ data->GetSize(&width, &height);
+ sprintf(text1, "a1:a%d", height); sprintf(text2, "b1:b%d", height);
+ sprintf(text3, "c1:c%d", height); sprintf(text4, "d1:d%d", height);
+ if(!(Dlg = new DlgRoot(BubDlg3D)))return false;
+ rX = rY = rZ = rR = 0L;
+ Dlg->SetCheck(410 + AxisTempl3D, 0L, true);
+ hDlg = CreateDlgWnd("Bubble Plot 3D", 50, 50, 388, 340, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 0:
+ if(Dlg->GetCheck(10)) res = -1;
+ break;
+ case 4: case 5: //the tab sheets
+ res = -1;
+ break;
+ case 153: case 154: case 155: case 156:
+ s_type = res - 153;
+ res = -1;
+ break;
+ case 410: case 411: case 412: //axis templates
+ AxisTempl3D = res-410;
+ res = -1;
+ break;
+ }
+ }while (res <0);
+ if(res == 1) {
+ if(Dlg->GetText(101, TmpTxt)) rX = new AccRange(TmpTxt);
+ if(Dlg->GetText(103, TmpTxt)) rY = new AccRange(TmpTxt);
+ if(Dlg->GetText(105, TmpTxt)) rZ = new AccRange(TmpTxt);
+ if(Dlg->GetText(151, TmpTxt)) rR = new AccRange(TmpTxt);
+ if(rX && rY && rZ && rR && (count = rX->CountItems())
+ && (Balls = (Sphere**)calloc(count, sizeof(Sphere*)))) {
+ rX->GetFirst(&cx, &rx); rY->GetFirst(&cy, &ry);
+ rZ->GetFirst(&cz, &rz); rR->GetFirst(&cr, &rr);
+ for(i = 0; i < count; i++){
+ if(rX->GetNext(&cx, &rx) && rY->GetNext(&cy, &ry)
+ && rZ->GetNext(&cz, &rz) && rR->GetNext(&cr, &rr)
+ && data->GetValue(rx, cx, &fx) && data->GetValue(ry, cy, &fy)
+ && data->GetValue(rz, cz, &fz) && data->GetValue(rr, cr, &fr)) {
+ Balls[i] = new Sphere(this, data, s_type, fx, fy, fz, fr, cx, rx,
+ cy, ry, cz, rz, cr, rr);
+ }
+ }
+ sc_plot = new Scatt3D(this, data, Balls, count);
+ if(parent->Id == GO_PLOT3D) {
+ if(!(parent->Command(CMD_DROP_PLOT, sc_plot, 0L))) delete(sc_plot);
+ bRet = true;
+ }
+ else if(!(bRet = Command(CMD_DROP_PLOT, sc_plot, 0L))) delete(sc_plot);
+ }
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(rX) delete rX; if(rY) delete rY; if(rZ) delete rZ; if(rR) delete rR;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Grid line properties
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+GridLine::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 21, 10, "Line"};
+ int dh = ((flags & AXIS_ANGULAR) || (flags & AXIS_RADIAL))? -20 : 0;
+ DlgInfo LineDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to LINE", 150, 10, 50, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to AXIS", 150, 25, 50, 12},
+ {3, 10, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 150, 40, 50, 12},
+ {10, 0, 100, ISPARENT | CHECKED, GROUPBOX, (void*)" grid line ", 5, 10, 139, 123+dh},
+ {100, 101, 0, NOSELECT, ODBUTTON, (void*)OD_linedef, 10, 18, 130, 100},
+ {101, 102, 112, HIDDEN | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {102, 103, 115, HIDDEN | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {103, 104, 120, HIDDEN | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {104, 105, 125, HIDDEN | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {105, 0, 130, HIDDEN | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {111, 0, 0, 0x0L, RTEXT, (void*)"line to:", 15, 117, 23, 8},
+ {112, 113, 0, 0x0L, CHECKBOX, (void*)"left", 41, 117, 25, 8},
+ {113, 114, 0, 0x0L, CHECKBOX, (void*)"right", 105, 117, 25, 8},
+ {114, 111, 0, 0x0L, CHECKBOX, (void*)"y-axis", 70, 117, 25, 8},
+ {115, 116, 0, 0x0L, CHECKBOX, (void*)"top", 41, 117, 25, 8},
+ {116, 117, 0, 0x0L, CHECKBOX, (void*)"bottom", 105, 117, 25, 8},
+ {117, 111, 0, 0x0L, CHECKBOX, (void*)"x-axis", 70, 117, 25, 8},
+ {120, 121, 0, 0x0L, CHECKBOX, (void*) "x-axis", 55, 117, 25, 8},
+ {121, 135, 0, 0x0L, CHECKBOX, (void*) "y-axis", 90, 117, 25, 8},
+ {125, 126, 0, 0x0L, CHECKBOX, (void*) "x-axis", 55, 117, 25, 8},
+ {126, 135, 0, 0x0L, CHECKBOX, (void*) "z-axis", 90, 117, 25, 8},
+ {130, 131, 0, 0x0L, CHECKBOX, (void*) "y-axis", 55, 117, 25, 8},
+ {131, 135, 0, 0x0L, CHECKBOX, (void*) "z-axis", 90, 117, 25, 8},
+ {135, 0, 0, LASTOBJ, LTEXT, (void*)"parallel to:", 15, 117, 55, 8}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, tmptype;
+ bool bRet = false;
+ DWORD undo_flags = 0L;
+ LineDEF newLine;
+
+ if(!parent || !parent->parent) return false;
+ OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
+ if(!(Dlg = new DlgRoot(LineDlg)))return false;
+ if ((flags & AXIS_ANGULAR) || (flags & AXIS_RADIAL)) {
+ //no checkboxes
+ }
+ else if(flags &AXIS_3D) {
+ Dlg->SetCheck(120, 0L, type & 0x01 ? true : false);
+ Dlg->SetCheck(121, 0L, type & 0x02 ? true : false);
+ Dlg->SetCheck(125, 0L, type & 0x04 ? true : false);
+ Dlg->SetCheck(126, 0L, type & 0x08 ? true : false);
+ Dlg->SetCheck(130, 0L, type & 0x10 ? true : false);
+ Dlg->SetCheck(131, 0L, type & 0x20 ? true : false);
+ switch(parent->parent->type) {
+ case 1: Dlg->ShowItem(105, true); break;
+ case 2: Dlg->ShowItem(104, true); break;
+ case 3: Dlg->ShowItem(103, true); break;
+ }
+ }
+ else {
+ Dlg->SetCheck(112, 0L, type & DL_LEFT ? true : false);
+ Dlg->SetCheck(113, 0L, type & DL_RIGHT ? true : false);
+ Dlg->SetCheck(114, 0L, type & DL_YAXIS ? true : false);
+ Dlg->SetCheck(115, 0L, type & DL_TOP ? true : false);
+ Dlg->SetCheck(116, 0L, type & DL_BOTTOM ? true : false);
+ Dlg->SetCheck(117, 0L, type & DL_XAXIS ? true : false);
+ if(type & 0x07) Dlg->ShowItem(101, true);
+ else Dlg->ShowItem(102, true);
+ }
+ hDlg = CreateDlgWnd("Grid line properties", 50, 50, 415, 300 + dh*2, Dlg, 0x0L);
+ do{ //dh*2 means dh * ybase
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 1: //this line
+ case 2: //all lines of plot
+ if(flags &AXIS_3D) {
+ tmptype = 0;
+ if(Dlg->GetCheck(120)) tmptype |= 0x01;
+ if(Dlg->GetCheck(121)) tmptype |= 0x02;
+ if(Dlg->GetCheck(125)) tmptype |= 0x04;
+ if(Dlg->GetCheck(126)) tmptype |= 0x08;
+ if(Dlg->GetCheck(130)) tmptype |= 0x10;
+ if(Dlg->GetCheck(131)) tmptype |= 0x20;
+ }
+ else {
+ tmptype = (type & ~0xff);
+ if(Dlg->GetCheck(112)) tmptype |= DL_LEFT;
+ if(Dlg->GetCheck(113)) tmptype |= DL_RIGHT;
+ if(Dlg->GetCheck(114)) tmptype |= DL_YAXIS;
+ if(Dlg->GetCheck(115)) tmptype |= DL_TOP;
+ if(Dlg->GetCheck(116)) tmptype |= DL_BOTTOM;
+ if(Dlg->GetCheck(117)) tmptype |= DL_XAXIS;
+ }
+ OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
+ break;
+ }
+ }while (res < 0);
+ if(res == 1){ //Apply to line
+ undo_flags = CheckNewInt(&type, type, tmptype, parent, undo_flags);
+ if(cmpLineDEF(&LineDef, &newLine)) {
+ Undo.Line(parent, &LineDef, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&LineDef, &newLine, sizeof(LineDEF));
+ }
+ if(undo_flags & UNDO_CONTINUE) bRet = bModified = true;
+ }
+ else if(res == 2) { //Apply to axis
+ if(parent->Id == GO_TICK && parent->parent->Id == GO_AXIS &&
+ (tmptype != type || cmpLineDEF(&LineDef, &newLine))) {
+ parent->parent->Command(CMD_SAVE_TICKS, 0L, 0L);
+ if(cmpLineDEF(&LineDef, &newLine)) parent->parent->Command(CMD_SET_GRIDLINE, (void*)&newLine, 0L);
+ if(tmptype != type) parent->parent->Command(CMD_SET_GRIDTYPE, (void*)(& tmptype), 0L);
+ bRet = true;
+ }
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Tick properties
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Tick::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 25, 10, "Tick"};
+ TabSHEET tab2 = {64, 90, 10, "Edit"};
+ TabSHEET tab3 = {25, 64, 10, "Direction"};
+ double tick_rot;
+ DlgInfo TickDlg[] = {
+ {1, 2, 0, 0x0L, PUSHBUTTON, (void*)"Apply to TICK", 100, 10, 50, 12},
+ {2, 3, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to AXIS", 100, 25, 50, 12},
+ {3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 100, 40, 50, 12},
+ {4, 0, 5, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
+ {5, 6, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 90, 100},
+ {6, 7, 300, ISPARENT, SHEET, &tab3, 5, 10, 90, 100},
+ {7, 0, 200, ISPARENT, SHEET, &tab2, 5, 10, 90, 100},
+ {100, 101, 0, 0x0L, RTEXT, (void*)"tick size", 10, 30, 35, 8},
+ {101, 102, 0, 0x0L, EDVAL1, &size, 50, 30, 25, 10},
+ {102, 103, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 77, 30, 20, 8},
+ {103, 104, 0, 0x0L, CHECKBOX, (void*)"major tick", 18, 45, 30, 8},
+ {104, 105, 0, 0x0L, LTEXT, (void*)"type:", 18, 60, 20, 8},
+ {105, 106, 0, 0x0L, RADIO1, 0L, 40, 70, 35, 8},
+ {106, 107, 0, 0x0L, RADIO1, 0L, 40, 60, 35, 8},
+ {107, 108, 0, 0x0L, RADIO1, (void*)"symetric", 40, 80, 35, 8},
+ {108, 0, 0, 0x0L, CHECKBOX, (void*)"draw grid line(s)", 18, 95, 30, 8},
+ {200, 201, 0, 0x0L, RTEXT, (void*)"value:", 10, 35, 23, 8},
+ {201, 202, 0, 0x0L, EDVAL1, &value, 40, 35, 35, 10},
+ {202, 203, 0, 0x0L, LTEXT, (void*)"label:", 15, 50, 20, 8},
+ {203, 0, 0, 0x0L, EDTEXT, (void*)0L, 15, 62, 70, 10},
+ {300, 301, 0, 0x0L, LTEXT, (void*)"direction of ticks", 15, 30, 70, 8},
+ {301, 302, 0, TOUCHEXIT, RADIO1, (void*)"perpendicular to axis", 15, 42, 70, 8},
+ {302, 303, 0, TOUCHEXIT, RADIO1, (void*)"fixed angle", 15, 52, 70, 8},
+ {303, 304, 0, TOUCHEXIT, RADIO1, (void*)"x-axis", 15, 74, 70, 8},
+ {304, 305, 0, TOUCHEXIT, RADIO1, (void*)"y-axis", 15, 84, 70, 8},
+ {305, 306, 0, TOUCHEXIT, RADIO1, (void*)"z-axis", 15, 94, 70, 8},
+ {306, 307, 0, 0x0L, EDVAL1, &tick_rot, 28, 62, 35, 10},
+ {307, 0, 0, LASTOBJ, LTEXT, (void*)"degree", 65, 62, 20, 8}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ DWORD old_flags;
+ double new_size, old_size, new_angle, old_angle, new_value, old_value;
+ int res, tmp_type = type;
+ bool bRet = false;
+ DWORD new_flags = flags, undo_flags = 0;
+ char *old_label = 0L;
+ TextDEF *td;
+
+ if(!parent || parent->Id != GO_AXIS) return false;
+ switch(type & 0x0f) {
+ case 1: tick_rot = angle; break;
+ default: tick_rot = trig2deg(lsi, lcsi); break;
+ }
+ old_flags = flags;
+ Dlg = new DlgRoot(TickDlg);
+ Dlg->SetCheck(301 + (type & 0x07), 0L, true);
+ if(flags & AXIS_ANGULAR) {
+ Dlg->SetText(105, "outside"); Dlg->SetText(106, "inside");
+ Dlg->ShowItem(303, false); Dlg->ShowItem(304, false);
+ Dlg->ShowItem(305, false);
+ }
+ else if(flags & AXIS_3D) {
+ Dlg->SetText(105, "positive"); Dlg->SetText(106, "negative");
+ if(parent->Id == GO_AXIS) {
+ //disable tick direction onto the axis
+ switch(parent->type) {
+ case 1: Dlg->Activate(303, false); break;
+ case 2: Dlg->Activate(304, false); break;
+ case 3: Dlg->Activate(305, false); break;
+ }
+ }
+ }
+ else {
+ Dlg->ShowItem(303, false); Dlg->ShowItem(304, false);
+ Dlg->ShowItem(305, false);
+ if(abs(pts[1].x - pts[0].x) > abs(pts[1].y - pts[0].y)){
+ Dlg->SetText(105, "right"); Dlg->SetText(106, "left");
+ }
+ else {
+ Dlg->SetText(105, "up"); Dlg->SetText(106, "down");
+ }
+ }
+ if(label) {
+ label->Command(CMD_GETTEXT, &TmpTxt, 0L);
+ if(TmpTxt[0]) {
+ old_label = strdup(TmpTxt);
+ Dlg->SetText(203, old_label);
+ }
+ if(label->Id != GO_LABEL) Dlg->Activate(203, false);
+ }
+ switch(flags &0x03) {
+ case AXIS_NEGTICKS: Dlg->SetCheck(106, 0L, true); break;
+ case AXIS_SYMTICKS: Dlg->SetCheck(107, 0L, true); break;
+ default: Dlg->SetCheck(105, 0L, true); break;
+ }
+ if(flags & AXIS_GRIDLINE) Dlg->SetCheck(108, 0L, true);
+ if(!(flags & AXIS_MINORTICK)) Dlg->SetCheck(103, 0L, true);
+ if(Dlg->GetValue(101, &old_size)) new_size = old_size;
+ else new_size = old_size = size;
+ if(Dlg->GetValue(306, &old_angle)) new_angle = old_angle;
+ else new_angle = old_angle = tick_rot;
+ if(Dlg->GetValue(201, &old_value)) new_value = old_value;
+ else new_value = old_value = value;
+ hDlg = CreateDlgWnd("Tick properties", 50, 50, 315, 260, Dlg, 0x0L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 1: case 2:
+ new_flags &= ~0x7;
+ if(Dlg->GetCheck(105)) new_flags |= AXIS_POSTICKS;
+ else if(Dlg->GetCheck(106)) new_flags |= AXIS_NEGTICKS;
+ else new_flags |= AXIS_SYMTICKS;
+ if(Dlg->GetCheck(108)) new_flags |= AXIS_GRIDLINE;
+ Dlg->GetValue(101, &new_size); Dlg->GetValue(306, &new_angle);
+ Dlg->GetValue(201, &new_value);
+ break;
+ case 301: case 302: case 303: case 304: case 305:
+ tmp_type = (tmp_type & ~0x0f) | (res -301);
+ res = -1;
+ break;
+ }
+ }while (res <0);
+ if(res == 1) {
+ if(Dlg->GetCheck(103)) new_flags &= ~AXIS_MINORTICK;
+ else new_flags |= AXIS_MINORTICK;
+ undo_flags = CheckNewDword(&flags, flags, new_flags, parent, undo_flags);
+ undo_flags = CheckNewInt(&type, type, tmp_type, parent, undo_flags);
+ undo_flags = CheckNewFloat(&size, old_size, new_size, parent, undo_flags);
+ undo_flags = CheckNewFloat(&angle, old_angle, new_angle, parent, undo_flags);
+ undo_flags = CheckNewFloat(&value, old_value, new_value, parent, undo_flags);
+ if(label && label->Id == GO_LABEL) {
+ td = ((Label*)label)->GetTextDef();
+ if(!Dlg->GetText(203, TmpTxt)) TmpTxt[0] = 0;
+ if(td->text && strcmp(td->text, TmpTxt)) {
+ Undo.String(this, &td->text, undo_flags);
+ undo_flags |= UNDO_CONTINUE;
+ label->Command(CMD_SETTEXT, TmpTxt, 0L);
+ }
+ }
+ if (undo_flags & UNDO_CONTINUE) bRet = true;
+ }
+ else if(res == 2) {
+ parent->Command(CMD_SAVE_TICKS, 0L, 0L);
+ if((new_flags & 0x07) != (old_flags & 0x07))
+ parent->Command(CMD_SET_TICKSTYLE, &new_flags, 0L);
+ parent->SetSize(SIZE_AXIS_TICKS, new_size);
+ parent->Command(CMD_TICK_TYPE, &tmp_type, 0L);
+ parent->SetSize(SIZE_TICK_ANGLE, new_angle);
+ parent->Command(CMD_REDRAW, 0L, 0L);
+ bRet = true;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(old_label) free(old_label);
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Axis properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Axis::ssTicks()
+{
+ DlgInfo TickDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 113, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 113, 25, 45, 12},
+ {3, 4, 0, 0x0L, LTEXT, (void*)"range for major tick VALUES:", 5, 10, 100, 9},
+ {4, 5, 0, 0x0L, EDTEXT, (void*)ssMATval, 10, 20, 90, 10},
+ {5, 6, 0, 0x0L, LTEXT, (void*)"range for major tick LABELS:", 5, 32, 100, 9},
+ {6, 7, 0, 0x0L, EDTEXT, (void*)ssMATlbl, 10, 42, 90, 10},
+ {7, 8, 0, 0x0L, LTEXT, (void*)"minor tick VALUES:", 5, 54, 80, 8},
+ {8, 0, 0, LASTOBJ, EDTEXT, (void*)ssMITval, 10, 64, 90, 10}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, n, n1, n2, n3;
+ bool bRet = false, bContinue = false;
+ AccRange *rT, *rL, *rMT;
+
+ if(!data) return false;
+ n = n1 = n2 = n3 = 0; rT = rL = rMT = 0L;
+ if(!(Dlg = new DlgRoot(TickDlg)))return false;
+ hDlg = CreateDlgWnd("choose ticks from spreadsheet", 50, 50, 330, 190, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 0: // focus lost
+ if(bContinue) res = -1;
+ break;
+ case -1:
+ bContinue = false;
+ break;
+ case 1:
+ if(rT) delete rT; if(rL) delete rL; if(rMT) delete rMT;
+ n = n1 = n2 = n3 = 0; rT = rL = rMT = 0L;
+ if(Dlg->GetText(4,TmpTxt) && (rT=new AccRange(TmpTxt)) && (n1=rT->CountItems())){
+ if(Dlg->GetText(6,TmpTxt) && (rL = new AccRange(TmpTxt)) &&
+ (n2 = rL->CountItems()) && n1 != n2){
+ ErrorBox("Ranges for tick values\nand tick labels must"
+ " have\nthe same size");
+ res = -1; bContinue = true;
+ break;
+ }
+ }
+ if(Dlg->GetText(8,TmpTxt) && (rMT=new AccRange(TmpTxt)) && (n3=rMT->CountItems())){
+ //minor ticks are valid
+ }
+ if(!(n = n1 + n3)) {
+ ErrorBox("Ranges not valid or\nno range specified");
+ res = -1; bContinue = true;
+ }
+ }
+ }while (res < 0);
+ if(res == 1 && n) {
+ if(n1) {
+ if(ssMATval) free(ssMATval); if(ssMATlbl) free(ssMATlbl);
+ if(ssMITval) free(ssMITval); ssMATval = ssMATlbl = ssMITval = 0L;
+ if(Dlg->GetText(4, TmpTxt))ssMATval = strdup(TmpTxt);
+ if(Dlg->GetText(6, TmpTxt))ssMATlbl = strdup(TmpTxt);
+ if(Dlg->GetText(8, TmpTxt))ssMITval = strdup(TmpTxt);
+ UpdateTicks();
+ }
+ bRet = true;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(rT) delete rT; if(rL) delete rL; if(rMT) delete rMT;
+ return bRet;
+}
+
+bool
+Axis::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 25, 10, "Axis"};
+ TabSHEET tab2 = {25, 50, 10, "Ticks"};
+ TabSHEET tab3 = {50, 92, 10, "Transforms"};
+ TabSHEET tab4 = {92, 123, 10, "Breaks"};
+ TabSHEET tab5 = {123, 148, 10, "Plots"};
+ int v1 = (axis->flags & AXIS_3D) ? 77 : (axis->flags & AXIS_RADIAL) ? 83 : 89;
+ DlgInfo AxisDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 166, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 166, 25, 45, 12},
+ {3, 0, 4, ISPARENT | CHECKED, GROUP, NULL, 0, 0, 0, 0},
+ {4, 5, 50, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 148, 165},
+ {5, 6, 200, ISPARENT, SHEET, &tab2, 5, 10, 148, 165},
+ {6, 7, 300, ISPARENT, SHEET, &tab3, 5, 10, 148, 165},
+ {7, 8, 400, ISPARENT, SHEET, &tab4, 5, 10, 148, 165},
+ {8, 0, 500, HIDDEN | ISPARENT, SHEET, &tab5, 5, 10, 148, 165},
+ {50, 51, 100, ISPARENT | CHECKED, GROUPBOX, (void*)" scaling ", 10, 30, 138, 36},
+ {51, 104, 0, TOUCHEXIT, CHECKBOX, (void*)" automatic scaling", 17, 37, 80, 8},
+ {100, 101, 0, 0x0L, RTEXT, (void*)"axis from", 10, 51, 35, 8},
+ {101, 102, 0, 0x0L, EDVAL1, &axis->min, 48, 51, 41, 10},
+ {102, 103, 0, 0x0L, CTEXT, (void*)"to", 90, 51, 11, 8},
+ {103, 0, 0, 0x0L, EDVAL1, &axis->max, 102, 51, 41, 10},
+ {104, 120, 105, ISPARENT | CHECKED, GROUPBOX, (void*)" placement ", 10, 72, 138, 45},
+ {105, 106, 0, TOUCHEXIT | ISRADIO, CHECKBOX, (void*)"left", 54, 77, 20, 8},
+ {106, 107, 0, TOUCHEXIT | ISRADIO, CHECKBOX, (void*)"right", 84, 77, 20, 8},
+ {107, 108, 0, TOUCHEXIT | ISRADIO, CHECKBOX, (void*)"top", 54, 77, 20, 8},
+ {108, 109, 0, TOUCHEXIT | ISRADIO, CHECKBOX, (void*)"bottom", 84, 77, 20, 8},
+ {109, 110, 0, 0x0L, RTEXT, (void*)"x", 10, v1, 15, 8},
+ {110, 111, 0, 0x0L, EDVAL1, &axis->loc[0].fx, 27, v1, 45, 10},
+ {111, 112, 0, 0x0L, LTEXT, (void*)"-", 75, v1, 5, 8},
+ {112, 113, 0, 0x0L, EDVAL1, &axis->loc[1].fx, 81, v1, 45, 10},
+ {113, 114, 0, 0x0L, LTEXT, (void*)0L, 129, v1, 15, 8},
+ {114, 115, 0, 0x0L, RTEXT, (void*)"y", 10, v1+12, 15, 8},
+ {115, 116, 0, 0x0L, EDVAL1, &axis->loc[0].fy, 27, v1+12, 45, 10},
+ {116, 117, 0, 0x0L, LTEXT, (void*)"-", 75, v1+12, 5, 8},
+ {117, 118, 0, 0x0L, EDVAL1, &axis->loc[1].fy, 81, v1+12, 45, 10},
+ {118, 150, 0, 0x0L, LTEXT, (void*)0L, 129, v1+12, 15, 8},
+ {150, 151, 0, 0x0L, RTEXT, (void*)"z", 10, v1+24, 15, 8},
+ {151, 152, 0, 0x0L, EDVAL1, &axis->loc[0].fz, 27, v1+24, 45, 10},
+ {152, 153, 0, 0x0L, LTEXT, (void*)"-", 75, v1+24, 5, 8},
+ {153, 154, 0, 0x0L, EDVAL1, &axis->loc[1].fz, 81, v1+24, 45, 10},
+ {154, 0, 0, 0x0L, LTEXT, (void*)0L, 129, v1+24, 15, 8},
+ {120, 180, 121, ISPARENT | CHECKED, GROUPBOX, (void*)" line ", 10, 123, 138, 20},
+ {121, 122, 0, 0x0L, RTEXT, (void*)"width", 10, 128, 25, 8},
+ {122, 123, 0, 0x0L, EDVAL1, &sizAxLine, 37, 128, 25, 10},
+ {123, 124, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 63, 128, 10, 8},
+ {124, 125, 0, 0x0L, RTEXT, (void*)"color", 82, 128, 25, 8},
+ {125, 130, 0, OWNDIALOG, COLBUTTON, (void *)colAxis, 109, 128, 25, 10},
+ {130, 0, 131, ISPARENT | CHECKED, GROUPBOX, (void*)" axis label ", 10, 149, 138, 20},
+ {131, 0, 0, 0x0L, EDTEXT, (void*)"abc", 15, 154, 128, 10},
+ {180, 0, 181, HIDDEN | ISPARENT | CHECKED, GROUPBOX, (void*)" placement ", 10, 72, 138, 45},
+ {181, 182, 0, 0x0L, RTEXT, (void*)"center x", 10, v1-12, 50, 8},
+ {182, 183, 0, 0x0L, EDVAL1, &axis->Center.fx, 62, v1-12, 45, 10},
+ {183, 184, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 109, v1-12, 15, 8},
+ {184, 185, 0, 0x0L, RTEXT, (void*)"y", 10, v1, 50, 8},
+ {185, 186, 0, 0x0L, EDVAL1, &axis->Center.fy, 62, v1, 45, 10},
+ {186, 187, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 109, v1, 15, 8},
+ {187, 188, 0, 0x0L, RTEXT, (void*)"radius", 10, v1+12, 50, 8},
+ {188, 189, 0, 0x0L, EDVAL1, &axis->Radius, 62, v1+12, 45, 10},
+ {189, 0, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 109, v1+12, 15, 8},
+ {200, 201, 0, TOUCHEXIT, RADIO1, (void*)"no ticks", 20, 35, 40, 8},
+ {201, 202, 0, TOUCHEXIT, RADIO1, (void*)"automatic", 20, 47, 40, 8},
+ {202, 204, 0, TOUCHEXIT, RADIO1, (void*)"leave unchanged", 20, 59, 40, 8},
+ {203, 205, 0, TOUCHEXIT, RADIO1, (void*)"set manually", 20, 71, 40, 8},
+ {204, 203, 250, CHECKED | ISPARENT, GROUPBOX, (void*)" ", 15, 75, 110, 50},
+ {205, 206, 0, 0x0L, PUSHBUTTON, (void*)"use spread sheet values", 30, 130, 80, 12},
+ {206, 0, 0, TOUCHEXIT, RADIO1, 0L, 20, 130, 8, 8},
+ {250, 251, 0, 0x0L, RTEXT, (void*)"start value", 30, 83, 45, 8},
+ {251, 252, 0, 0x0L, EDVAL1, &axis->Start, 77, 83, 35, 10},
+ {252, 253, 0, 0x0L, RTEXT, (void*)"interval", 30, 95, 45, 8},
+ {253, 254, 0, 0x0L, EDVAL1, &axis->Step, 77, 95, 35, 10},
+ {254, 255, 0, 0x0L, RTEXT, (void*)"minor ticks per interval", 20, 107, 75, 8},
+ {255, 0, 0, 0x0L, EDTEXT, (void*)"0", 97, 107, 15, 10},
+ {300, 301, 0, 0x0L, LTEXT, (void*)"Transforms:", 10, 30, 110, 8},
+ {301, 302, 0, TOUCHEXIT, RADIO1, (void*)"none (linear)", 20, 45, 70, 8},
+ {302, 303, 0, TOUCHEXIT, RADIO1, (void*)"logarithmic (log base 10)", 20, 57, 70, 8},
+ {303, 304, 0, TOUCHEXIT, RADIO1, (void*)"reciprocal (1/x)", 20, 69, 70, 8},
+ {304, 305, 0, TOUCHEXIT, RADIO1, (void*)"square root", 20, 81, 70, 8},
+ {305, 0, 0, 0x0L, CHECKBOX, axis->loc[0].fx == axis->loc[1].fx ?
+ (void*)"low vaues top of graph" : (void*)"low values right of graph", 20, 115, 80, 12},
+ {400, 450, 0, 0x0L, LTEXT, (void*)"style:", 10, 30, 110, 8},
+ {401, 402, 0, ISRADIO, ODBUTTON, (void*)(OD_BreakTempl), 29, 40, 25, 25},
+ {402, 403, 0, ISRADIO, ODBUTTON, (void*)(OD_BreakTempl), 54, 40, 25, 25},
+ {403, 404, 0, ISRADIO, ODBUTTON, (void*)(OD_BreakTempl), 79, 40, 25, 25},
+ {404, 405, 0, ISRADIO, ODBUTTON, (void*)(OD_BreakTempl), 104, 40, 25, 25},
+ {405, 406, 0, 0x0L, RTEXT, (void*)"break gap", 15, 75, 48, 8},
+ {406, 407, 0, 0x0L, EDVAL1, &brkgap, 65, 75, 29, 10},
+ {407, 408, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 97, 75, 10, 8},
+ {408, 409, 0, 0x0L, RTEXT, (void*)"symbol size", 15, 87, 48, 8},
+ {409, 410, 0, 0x0L, EDVAL1, &brksymsize, 65, 87, 29, 10},
+ {410, 0, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 97, 87, 10, 8},
+ {450, 451, 0, ISPARENT | CHECKED, GROUPBOX, (void*)" break data ", 10, 110, 138, 50},
+ {451, 452, 0, 0x0L, LTEXT, 0L, 20, 115, 60, 8},
+ {452, 453, 0, 0x0L, PUSHBUTTON, (void*)"Next >>", 98, 142, 41, 12},
+ {453, 454, 0, 0x0L, PUSHBUTTON, (void*)"<< Prev.", 57, 142, 41, 12},
+ {454, 455, 0, 0x0L, RTEXT, (void*)"from", 15, 125, 20, 8},
+ {455, 456, 0, 0x0L, EDTEXT, 0L, 37, 125, 41, 10},
+ {456, 457, 0, 0x0L, RTEXT, (void*)"to", 82, 125, 9, 8},
+ {457, 458, 0, 0x0L, EDTEXT, 0L, 93, 125, 41, 10},
+ {458, 401, 0, 0x0L, PUSHBUTTON, (void*)"Delete", 16, 142, 41, 12},
+ {500, 0, 0, NOSELECT, ODBUTTON, (void*)OD_axisplot, 25, 30, 110, 140},
+ {600, 0, 0, LASTOBJ, NONE, 0L, 0, 0, 0, 0}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, j, res, nbrk, cbrk, ttmpl;
+ double tmp, tmp2, old_x1, old_x2, old_y1, old_y2;
+ bool bRet = false, bChanged = false, upd_brk = true, bContinue = false;
+ DWORD new_color, undo_flags = 0L;
+ lfPOINT *brks = 0L, *tmpbrks = 0L;
+ char *old_Label = 0L, *type_txt;
+ TextDEF label_def, *lb_def;
+ char **names;
+ GraphObj **somePlots = 0L, **scp = 0L;
+ AxisDEF old_a, new_a;
+ void *sv_ptr;
+
+
+ nbrk = cbrk = 0;
+ if(!parent) return false;
+ if(parent->Id == GO_GRAPH && (res=((Graph*)parent)->nscp)){
+ scp = ((Graph*)parent)->Sc_Plots;
+ CurrAxes = ((Graph*)parent)->Axes;
+ if(!scp || !(names = (char**)calloc(res+2, sizeof(char*))) ||
+ !(somePlots = (GraphObj**)calloc(res+2, sizeof(GraphObj*))))
+ return false;
+ names[j=0] = strdup("[unchanged]");
+ for(i = 0, j = 1; i < res; i++) {
+ if(scp[i] && scp[i]->name){
+ names[j] = strdup(scp[i]->name);
+ somePlots[j++] = scp[i];
+ }
+ }
+ }
+ else {
+ names = (char**)calloc(2, sizeof(char*));
+ names[0] = strdup("n.a.");
+ }
+ OD_axisplot(OD_ACCEPT, 0L, 0L, 0L, names, 0);
+ if(!(Dlg = new DlgRoot(AxisDlg)))return false;
+ if(names && somePlots) Dlg->ShowItem(8, true); //show tab
+ if(axis->breaks && axis->nBreaks) {
+ if(!(brks = (lfPOINT*)calloc(axis->nBreaks+2, sizeof(lfPOINT)))) return false;
+ memcpy(brks, axis->breaks, axis->nBreaks*sizeof(lfPOINT));
+ nbrk = axis->nBreaks-1;
+ WriteNatFloatToBuff(TmpTxt, brks[cbrk].fx);
+ Dlg->SetText(455, TmpTxt+1);
+ WriteNatFloatToBuff(TmpTxt, brks[cbrk].fy);
+ Dlg->SetText(457, TmpTxt+1);
+ }
+ switch(brksym) {
+ case 2: Dlg->SetCheck(402, 0L, true); break;
+ case 3: Dlg->SetCheck(403, 0L, true); break;
+ case 4: Dlg->SetCheck(404, 0L, true); break;
+ default: Dlg->SetCheck(401, 0L, true); break;
+ }
+ if(!(axis->flags & 0x03)) Dlg->SetCheck(ttmpl = 200, 0L, true);
+ else if(axis->flags & AXIS_AUTOTICK)Dlg->SetCheck(ttmpl = 201, 0L, true);
+ else if(Ticks) Dlg->SetCheck(ttmpl = 202, 0L, true);
+ else Dlg->SetCheck(ttmpl = 201, 0L, true);
+ Dlg->Activate(251, false); Dlg->Activate(253, false); Dlg->Activate(255, false);
+ Dlg->SetCheck(305, 0L, (AXIS_INVERT == (axis->flags & AXIS_INVERT)));
+ if(axis->flags & AXIS_AUTOSCALE) {
+ Dlg->SetCheck(51, 0L, true);
+ Dlg->Activate(101, false); Dlg->Activate(103, false);
+ }
+ //check transforms
+ switch(axis->flags & 0x7000L) {
+ case AXIS_LINEAR: Dlg->SetCheck(301, 0L, true); break;
+ case AXIS_LOG: Dlg->SetCheck(302, 0L, true); break;
+ case AXIS_RECI: Dlg->SetCheck(303, 0L, true); break;
+ case AXIS_SQR: Dlg->SetCheck(304, 0L, true); break;
+ }
+ //align to frame ?
+ if(axis->flags & AXIS_3D) {
+ Dlg->ShowItem(105, false); Dlg->ShowItem(106, false);
+ Dlg->ShowItem(107, false); Dlg->ShowItem(108, false);
+ }
+ else if(axis->flags & AXIS_ANGULAR) {
+ Dlg->ShowItem(104, false); Dlg->ShowItem(130, false);
+ Dlg->ShowItem(180, true); Dlg->ShowItem(7, false);
+ }
+ else {
+ if(axis->flags & AXIS_RADIAL) {
+ Dlg->ShowItem(105, false); Dlg->ShowItem(106, false);
+ Dlg->ShowItem(107, false); Dlg->ShowItem(108, false);
+ }
+ Dlg->ShowItem(150, false); Dlg->ShowItem(151, false);
+ Dlg->ShowItem(152, false); Dlg->ShowItem(153, false);
+ Dlg->ShowItem(154, false);
+ if(axis->loc[0].fx != axis->loc[1].fx) {
+ Dlg->ShowItem(105, false); Dlg->ShowItem(106, false);
+ }
+ if(axis->loc[0].fy != axis->loc[1].fy) {
+ Dlg->ShowItem(107, false); Dlg->ShowItem(108, false);
+ }
+ }
+ switch(axis->flags & 0x70) {
+ case AXIS_LEFT: Dlg->SetCheck(105, 0L, true); break;
+ case AXIS_RIGHT: Dlg->SetCheck(106, 0L, true); break;
+ case AXIS_TOP: Dlg->SetCheck(107, 0L, true); break;
+ case AXIS_BOTTOM: Dlg->SetCheck(108, 0L, true); break;
+ }
+ if(axis->flags & AXIS_X_DATA) Dlg->SetText(113, "[data]");
+ else Dlg->SetText(113, Units[defs.cUnits].display);
+ if(axis->flags & AXIS_Y_DATA) Dlg->SetText(118, "[data]");
+ else Dlg->SetText(118, Units[defs.cUnits].display);
+ if(axis->flags & AXIS_Z_DATA) Dlg->SetText(118, "[data]");
+ else Dlg->SetText(154, Units[defs.cUnits].display);
+ //any label ?
+ if(axisLabel){
+ TmpTxt[0] = 0;
+ axisLabel->Command(CMD_GETTEXT, TmpTxt, 0L);
+ Dlg->SetText(131,TmpTxt);
+ old_Label = strdup(TmpTxt);
+ if(axisLabel->Id == GO_MLABEL) Dlg->Activate(131, false);
+ }
+ else Dlg->SetText(131, 0L);
+ //remember: any updated values ?
+ Dlg->GetValue(110, &old_x1); Dlg->GetValue(112, &old_x2);
+ Dlg->GetValue(115, &old_y1); Dlg->GetValue(117, &old_y2);
+ switch(type) {
+ case 1: type_txt = (char*)(&"X-a"); break;
+ case 2: type_txt = (char*)(&"Y-a"); break;
+ case 3: type_txt = (char*)(&"Z-a"); break;
+ default: type_txt = (char*)(&"A"); break;
+ }
+ //angular radial axis specials
+ if(axis->flags & AXIS_ANGULAR){
+ Dlg->SetText(305, "set direction cw");
+ type_txt = (char*)(&"angular a");
+ }
+ if(axis->flags & AXIS_RADIAL) type_txt = (char*)(&"radial a");
+ //save old axis definition
+ memcpy(&old_a, axis, sizeof(AxisDEF));
+ Dlg->GetValue(101, &old_a.min); Dlg->GetValue(103, &old_a.max);
+ Dlg->GetValue(110, &old_a.loc[0].fx); Dlg->GetValue(112, &old_a.loc[1].fx);
+ Dlg->GetValue(115, &old_a.loc[0].fy); Dlg->GetValue(117, &old_a.loc[1].fy);
+ Dlg->GetValue(151, &old_a.loc[0].fz); Dlg->GetValue(153, &old_a.loc[1].fz);
+ Dlg->GetValue(182, &old_a.Center.fx); Dlg->GetValue(185, &old_a.Center.fy);
+ Dlg->GetValue(188, &old_a.Radius);
+ memcpy(&new_a, &old_a, sizeof(AxisDEF));
+ sprintf(TmpTxt, "%sxis properties", type_txt);
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 436, 384, Dlg, 0x0L);
+ switch(axis->flags & 0x70) {
+ case AXIS_LEFT:
+ case AXIS_RIGHT:
+ Dlg->Activate(110, false); Dlg->Activate(112, false);
+ break;
+ case AXIS_TOP:
+ case AXIS_BOTTOM:
+ Dlg->Activate(115, false); Dlg->Activate(117, false);
+ break;
+ }
+ do{
+ if(upd_brk) {
+ Dlg->ShowItem(453, cbrk > 0);
+ sprintf(TmpTxt,"break # %d/%d", cbrk+1, nbrk+1);
+ Dlg->SetText(451, TmpTxt);
+ upd_brk = false;
+ }
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 0: //lost focus ?
+ if(bContinue) res = -1;
+ ShowDlgWnd(hDlg);
+ break;
+ case -1:
+ bContinue = false;
+ break;
+ case 51:
+ if(Dlg->GetCheck(51)) {
+ Dlg->Activate(101, false); Dlg->Activate(103, false);
+ }
+ else {
+ Dlg->Activate(101, true); Dlg->Activate(103, true);
+ }
+ res = -1;
+ break;
+ case 105: case 106: case 107: case 108: //axis left | right | top | bottom
+ if(Dlg->GetCheck(105) || Dlg->GetCheck(106)) {
+ Dlg->Activate(110, false); Dlg->Activate(112, false);
+ }
+ else {
+ Dlg->Activate(110, true); Dlg->Activate(112, true);
+ }
+ if(Dlg->GetCheck(107) || Dlg->GetCheck(108)) {
+ Dlg->Activate(115, false); Dlg->Activate(117, false);
+ }
+ else {
+ Dlg->Activate(115, true); Dlg->Activate(117, true);
+ }
+ res = -1;
+ break;
+ case 301: case 302: case 303: case 304: //transform radiobuttons
+ new_a.flags &= ~0x7000L;
+ if(res == 302) new_a.flags |= AXIS_LOG;
+ else if(res == 303) new_a.flags |= AXIS_RECI;
+ else if(res == 304) new_a.flags |= AXIS_SQR;
+ res = -1;
+ break;
+ case 200: case 201: case 202:
+ ttmpl = res;
+ Dlg->Activate(251, false); Dlg->Activate(253, false); Dlg->Activate(255, false);
+ res = -1;
+ break;
+ case 203:
+ ttmpl = res;
+ Dlg->Activate(251, true); Dlg->Activate(253, true); Dlg->Activate(255, true);
+ res = -1;
+ break;
+ case 205: case 206:
+ Dlg->SetCheck(206, 0L, true);
+ if (ssTicks()) {
+ Dlg->SetCheck(ttmpl = 202, 0L, true); Dlg->Activate(251, false);
+ Dlg->Activate(253, false); Dlg->Activate(255, false);
+ undo_flags |= UNDO_CONTINUE; res = 1;
+ }
+ else {
+ Dlg->SetCheck(ttmpl, 0L, true);
+ res = -1;
+ }
+ bContinue = true;
+ break;
+ case 452: //next break
+ if(Dlg->GetValue(455, &tmp) && Dlg->GetValue(457, &tmp2)){
+ if(!brks && (brks = (lfPOINT*)calloc(2, sizeof(lfPOINT)))) {
+ brks[0].fx = tmp; brks[0].fy = tmp2;
+ cbrk = nbrk = 0;
+ }
+ if(!brks) return false; //mem allocation error
+ if(cbrk && cbrk >= nbrk) {
+ if(tmpbrks = (lfPOINT*)realloc(brks, (cbrk+2)*sizeof(lfPOINT))){
+ brks = tmpbrks;
+ brks[cbrk].fx = tmp; brks[cbrk].fy = tmp2;
+ brks[cbrk+1].fx = brks[cbrk+1].fy = 0.0;
+ }
+ else return false; //mem allocation error
+ }
+ else {
+ brks[cbrk].fx = tmp; brks[cbrk].fy = tmp2;
+ }
+ cbrk++;
+ }
+ if(cbrk>nbrk){
+ nbrk = cbrk;
+ Dlg->SetText(455,0L); Dlg->SetText(457,0L);
+ }
+ else if(nbrk){
+ if(brks[cbrk].fx == brks[cbrk].fy && cbrk == nbrk) {
+ Dlg->SetText(455,0L); Dlg->SetText(457,0L);
+ }
+ else {
+ WriteNatFloatToBuff(TmpTxt, brks[cbrk].fx);
+ Dlg->SetText(455, TmpTxt+1);
+ WriteNatFloatToBuff(TmpTxt, brks[cbrk].fy);
+ Dlg->SetText(457, TmpTxt+1);
+ }
+ }
+ bChanged = upd_brk = true;
+ res= -1;
+ break;
+ case 453: //previous break
+ if(cbrk >0){
+ if(Dlg->GetValue(455, &tmp) && Dlg->GetValue(457, &tmp2)){
+ brks[cbrk].fx = tmp; brks[cbrk].fy = tmp2;
+ }
+ else if(cbrk == nbrk)nbrk--;
+ cbrk--;
+ WriteNatFloatToBuff(TmpTxt, brks[cbrk].fx);
+ Dlg->SetText(455, TmpTxt+1);
+ WriteNatFloatToBuff(TmpTxt, brks[cbrk].fy);
+ Dlg->SetText(457, TmpTxt+1);
+ }
+ bChanged = upd_brk = true;
+ res= -1;
+ break;
+ case 458: //delete break;
+ if(brks && nbrk > cbrk) {
+ for(i = cbrk; i < nbrk; i++) {
+ brks[i].fx = brks[i+1].fx;
+ brks[i].fy = brks[i+1].fy;
+ }
+ nbrk--;
+ if(brks[cbrk].fx == brks[cbrk].fy && cbrk == nbrk) {
+ Dlg->SetText(455,0L); Dlg->SetText(457,0L);
+ }
+ else {
+ WriteNatFloatToBuff(TmpTxt, brks[cbrk].fx);
+ Dlg->SetText(455, TmpTxt+1);
+ WriteNatFloatToBuff(TmpTxt, brks[cbrk].fy);
+ Dlg->SetText(457, TmpTxt+1);
+ }
+ }
+ else {
+ Dlg->SetText(455,0L); Dlg->SetText(457,0L);
+ }
+ bChanged = upd_brk = true;
+ res = -1;
+ break;
+ }
+ }while (res < 0);
+ switch (res) {
+ case 1: //OK pressed
+ bModified = true;
+ if(names && CurrAxes && somePlots) { //apply axis to plot ?
+ for(i = 0; CurrAxes[i] != this; i++); //find index
+ OD_axisplot(OD_ACCEPT, 0L, 0L, (anyOutput*) &res, 0L, 0);
+ if(somePlots[res] && somePlots[res]->Command(CMD_USEAXIS, &i, 0L))
+ undo_flags |= UNDO_CONTINUE;
+ }
+ if(Dlg->GetValue(455, &tmp) && Dlg->GetValue(457, &tmp2)){
+ if(!brks && (brks = (lfPOINT*)calloc(2, sizeof(lfPOINT)))) {
+ brks[0].fx = tmp; brks[0].fy = tmp2; cbrk = nbrk = 1;
+ }
+ else if(brks) {
+ brks[cbrk].fx = tmp; brks[cbrk].fy = tmp2; nbrk++;
+ }
+ }
+ Dlg->GetValue(101, &new_a.min); Dlg->GetValue(103, &new_a.max);
+ Dlg->GetValue(110, &new_a.loc[0].fx); Dlg->GetValue(112, &new_a.loc[1].fx);
+ Dlg->GetValue(115, &new_a.loc[0].fy); Dlg->GetValue(117, &new_a.loc[1].fy);
+ Dlg->GetValue(151, &new_a.loc[0].fz); Dlg->GetValue(153, &new_a.loc[1].fz);
+ Dlg->GetValue(182, &new_a.Center.fx); Dlg->GetValue(185, &new_a.Center.fy);
+ Dlg->GetValue(188, &new_a.Radius);
+ new_a.breaks = brks; new_a.nBreaks = nbrk;
+ if(new_a.breaks) SortAxisBreaks(&new_a);
+ brks = 0L; nbrk = 0;
+ if(Dlg->GetCheck(51)) {
+ if(!(new_a.flags & AXIS_AUTOSCALE)) parent->Command(CMD_MRK_DIRTY, 0L, 0L);
+ new_a.flags |= AXIS_AUTOSCALE;
+ }
+ else new_a.flags &= ~AXIS_AUTOSCALE;
+ if(Dlg->GetCheck(201)) new_a.flags |= AXIS_AUTOTICK;
+ else new_a.flags &= ~AXIS_AUTOTICK;
+ if(Dlg->GetCheck(200)) new_a.flags &= ~0x03;
+ if(Dlg->GetCheck(305)) new_a.flags |= AXIS_INVERT;
+ else new_a.flags &= ~AXIS_INVERT;
+ new_a.flags &= ~0x70;
+ if(Dlg->GetCheck(105)) new_a.flags |= AXIS_LEFT;
+ else if(Dlg->GetCheck(106)) new_a.flags |= AXIS_RIGHT;
+ else if(Dlg->GetCheck(107)) new_a.flags |= AXIS_TOP;
+ else if(Dlg->GetCheck(108)) new_a.flags |= AXIS_BOTTOM;
+ if(cmpAxisDEF(&old_a, &new_a)) {
+ bChanged = true;
+ if(axis->flags != new_a.flags) parent->Command(CMD_MRK_DIRTY, 0L, 0L);
+ Undo.AxisDef(this, axis, undo_flags);
+ memcpy(axis, &new_a, sizeof(AxisDEF)); undo_flags |= UNDO_CONTINUE;
+ }
+ else if(new_a.breaks) free(new_a.breaks);
+ if(axis->nBreaks && Dlg->GetValue(406, &tmp))
+ undo_flags = CheckNewFloat(&brkgap, brkgap, tmp, this, undo_flags);
+ if(axis->nBreaks && Dlg->GetValue(409, &tmp))
+ undo_flags = CheckNewFloat(&brksymsize, brksymsize, tmp, this, undo_flags);
+ if(Dlg->GetCheck(402)) i = 2;
+ else if(Dlg->GetCheck(403)) i = 3;
+ else if(Dlg->GetCheck(404)) i = 4;
+ else i = 0;
+ if(axis->nBreaks) undo_flags = CheckNewInt(&brksym, brksym, i, this, undo_flags);
+ if(Dlg->GetColor(125, &new_color) && new_color != colAxis) {
+ undo_flags = CheckNewDword(&colAxis, colAxis, new_color, this, undo_flags);
+ if ((axis->flags & AXIS_ANGULAR) || (axis->flags & AXIS_RADIAL)) {
+ Undo.ValDword(this, &GridLine.color, undo_flags);
+ GridLine.color = new_color;
+ }
+ if(Ticks || axisLabel) {
+ SavVarInit(200 * NumTicks);
+ if(axisLabel){
+ axisLabel->FileIO(SAVE_VARS);
+ axisLabel->SetColor(COL_TEXT, colAxis);
+ }
+ if(Ticks) for(i = 0; i < NumTicks; i++) if(Ticks[i]){
+ Ticks[i]->FileIO(SAVE_VARS);
+ Ticks[i]->SetColor(COL_AXIS, colAxis);
+ }
+ sv_ptr = SavVarFetch();
+ Undo.SavVarBlock(this, &sv_ptr, undo_flags);
+ }
+ }
+ if(Dlg->GetValue(122, &tmp))
+ undo_flags = CheckNewFloat(&sizAxLine, sizAxLine, tmp, this, undo_flags);
+ if(Dlg->GetText(131, TmpTxt) && TmpTxt[0]) {
+ if(old_Label && strcmp(old_Label,TmpTxt) && axisLabel->Id == GO_LABEL){
+ lb_def = ((Label*)axisLabel)->GetTextDef();
+ Undo.String(axisLabel, &lb_def->text, undo_flags);
+ if(lb_def->text) free(lb_def->text);
+ lb_def->text = strdup(TmpTxt); undo_flags |= UNDO_CONTINUE;
+ }
+ else if(!axisLabel) {
+ label_def.ColTxt = colAxis; label_def.ColBg = 0x00ffffffL;
+ label_def.fSize = defs.GetSize(SIZE_TICK_LABELS)*1.2;
+ label_def.RotBL = fabs(si)>0.80 ? 90.0 : 0.0;
+ label_def.RotCHAR = 0.0f; label_def.iSize = 0;
+ label_def.Align = TXA_VCENTER | TXA_HCENTER;
+ label_def.Mode = TXM_TRANSPARENT; label_def.Style = TXS_NORMAL;
+ label_def.Font = FONT_HELVETICA; label_def.text = TmpTxt;
+ Undo.SetGO(this, &axisLabel, new Label(this, data, 0, 0, &label_def,
+ LB_Y_PARENT | LB_X_PARENT), undo_flags);
+ undo_flags |= UNDO_CONTINUE;
+ }
+ }
+ else if(axisLabel) {
+ Undo.DeleteGO(&axisLabel, undo_flags, 0L); undo_flags |= UNDO_CONTINUE;
+ }
+ if((!(axis->flags & 0x03) && Ticks && NumTicks) || (Dlg->GetCheck(203)) ||
+ ((old_a.flags & 0x7000) != (new_a.flags & 0x7000) && (new_a.flags & AXIS_AUTOTICK))
+ || ((new_a.flags & AXIS_AUTOTICK) &&(new_a.min != old_a.min || new_a.max != old_a.max))){
+ Undo.DropListGO(this, (GraphObj ***)&Ticks, &NumTicks, undo_flags);
+ undo_flags |= UNDO_CONTINUE;
+ }
+ if(Dlg->GetCheck(203)) { //set ticks manually
+ if(!Dlg->GetValue(255, &tmp)) tmp = 0.0;
+ i = (int)tmp;
+ if(!Dlg->GetValue(251, &tmp)) tmp = axis->Start;
+ if(!Dlg->GetValue(253, &tmp2)) tmp2 = axis->Step;
+ if(!(axis->flags & 0x03)){
+ if(axis->flags & AXIS_ANGULAR) axis->flags |= AXIS_POSTICKS;
+ else axis->flags |= AXIS_SYMTICKS;
+ }
+ axis->flags &= ~AXIS_AUTOTICK;
+ ManuTicks(tmp, tmp2, i, axis->flags);
+ }
+ if(!(new_a.flags & 0x03) && (new_a.flags & AXIS_AUTOTICK)){
+ if(new_a.flags & AXIS_ANGULAR) axis->flags |= AXIS_POSTICKS;
+ else axis->flags |= AXIS_SYMTICKS;
+ }
+ if(undo_flags & UNDO_CONTINUE) {
+ bRet= true;
+ if((axis->flags & AXIS_RADIAL)||(axis->flags & AXIS_ANGULAR))
+ parent->Command(CMD_AXIS, this, 0L);
+ }
+ break;
+ }
+ if(brks && nbrk) free(brks);
+ if(old_Label) free(old_Label);
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(names) {
+ for(j = 0; names[j]; j++) if(names[j]) free(names[j]);
+ free(names);
+ }
+ if(somePlots) free(somePlots);
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Graph dialogs
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Graph::AddPlot(int family)
+{
+ DlgInfo GraphDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 150, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 150, 25, 45, 12},
+ {3, 0, 520, ISPARENT | CHECKED, GROUPBOX, (void *)" select template ", 5, 10, 135, 95},
+ {520, 521, 0, TOUCHEXIT | CHECKED | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 10, 20, 25, 25},
+ {521, 522, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 35, 20, 25, 25},
+ {522, 523, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 60, 20, 25, 25},
+ {523, 524, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 85, 20, 25, 25},
+ {524, 525, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 110, 20, 25, 25},
+ {525, 526, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 10, 45, 25, 25},
+ {526, 528, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 35, 45, 25, 25},
+ {528, 529, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 60, 45, 25, 25},
+ {529, 530, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 85, 45, 25, 25},
+ {530, 531, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 110, 45, 25, 25},
+ {531, 540, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 10, 70, 25, 25},
+ {540, 541, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 35, 70, 25, 25},
+ {541, 0, 0, LASTOBJ | TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 60, 70, 25, 25}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, res, cSel = 520;
+ bool bRet = false;
+ Plot *p;
+
+ switch(type) {
+ case GT_STANDARD:
+ break;
+ case GT_POLARPLOT:
+ for(i = 0; i < NumPlots; i++) {
+ if(Plots[i] && Plots[i]->Id == GO_POLARPLOT) {
+ if (((PolarPlot*)Plots[i])->AddPlot())
+ return Command(CMD_REDRAW, 0L, 0L);
+ }
+ }
+ return false;
+ default:
+ InfoBox("Don\'t know how to\nadd a plot to the\ncurrent graph.");
+ return false;
+ }
+ Dlg = new DlgRoot(GraphDlg);
+ hDlg = CreateDlgWnd("Add Plot", 50, 50, 410, 240, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 520: case 521: case 522: case 523: case 524:
+ case 525: case 526: case 528: case 529: case 530:
+ case 531: case 540: case 541:
+ if(res == cSel) res = 1;
+ else {
+ cSel = res; res = -1;
+ }
+ break;
+ }
+ }while (res < 0);
+ if(res == 1){ //OK pressed
+ if(Dlg->GetCheck(524)) p = new BubblePlot(this, data);
+ else if(Dlg->GetCheck(525)) p = new BoxPlot(this, data);
+ else if(Dlg->GetCheck(521)) p = new PlotScatt(this, data, 0x03);
+ else if(Dlg->GetCheck(522)) p = new PlotScatt(this, data, 0x08);
+ else if(Dlg->GetCheck(523)) p = new PlotScatt(this, data, 0x04);
+ else if(Dlg->GetCheck(526)) p = new Regression(this, data);
+ else if(Dlg->GetCheck(528)) p = new DensDisp(this, data);
+ else if(Dlg->GetCheck(529)) p = new Function(this, data);
+ else if(Dlg->GetCheck(530)) p = new FitFunc(this, data);
+ else if(Dlg->GetCheck(531)) p = new MultiLines(this, data);
+ else if(Dlg->GetCheck(540)) p = new StackBar(this, data);
+ else if(Dlg->GetCheck(541)) p = new StackPG(this, data);
+ else p = new PlotScatt(this, data, 0x01);
+ if(p && p->PropertyDlg()) {
+ if(!Command(CMD_DROP_PLOT, p, (anyOutput *)NULL)) delete p;
+ else bRet = true;
+ }
+ else if(p) delete p;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+bool
+Graph::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 22, 10, "Data"};
+ TabSHEET tab2 = {22, 62, 10, "Placement"};
+ TabSHEET tab3 = {62, 87, 10, "Axes"};
+ TabSHEET tab_A = {0, 27, 10, "only Y"};
+ TabSHEET tab_B = {27, 65, 10, "XY values"};
+ TabSHEET tab_C = {65, 104, 10, "X, many Y"};
+ TabSHEET tab_D = {104, 147, 10, "XYZ values"};
+ DlgInfo GraphDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 170, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 170, 25, 45, 12},
+ {3, 0, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
+ {4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 157, 122},
+ {5, 6, 200, ISPARENT, SHEET, &tab2, 5, 10, 157, 122},
+ {6, 7, 300, ISPARENT, SHEET, &tab3, 5, 10, 157, 122},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"arrangement of data: select plot", 10, 25, 60, 8},
+ {101, 102, 500, TOUCHEXIT | ISPARENT, SHEET, &tab_A, 10, 37, 147, 88},
+ {102, 103, 520, TOUCHEXIT | ISPARENT | CHECKED, SHEET, &tab_B, 10, 37, 147, 90},
+ {103, 104, 540, TOUCHEXIT | ISPARENT, SHEET, &tab_C, 10, 37, 147, 88},
+ {104, 0, 560, TOUCHEXIT | ISPARENT, SHEET, &tab_D, 10, 37, 147, 88},
+ {200, 201, 0, 0x0L, LTEXT, (void*)"bounding rectangle (relative to page)", 10, 35, 60, 8},
+ {201, 202, 0, 0x0L, RTEXT, (void*)"upper left corner x", 5, 47, 58, 8},
+ {202, 203, 0, 0x0L, EDVAL1, &GRect.Xmin, 64, 47, 30, 10},
+ {203, 204, 0, 0x0L, RTEXT, (void*)"y", 95, 47, 10, 8},
+ {204, 205, 0, 0x0L, EDVAL1, &GRect.Ymin, 107, 47, 30, 10},
+ {205, 206, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 140, 47, 20, 8},
+ {206, 207, 0, 0x0L, RTEXT, (void*)"lower right x", 5, 59, 58, 8},
+ {207, 208, 0, 0x0L, EDVAL1, &GRect.Xmax, 64, 59, 30, 10},
+ {208, 209, 0, 0x0L, RTEXT, (void*)"y", 95, 59, 10, 8},
+ {209, 210, 0, 0x0L, EDVAL1, &GRect.Ymax, 107, 59, 30, 10},
+ {210, 211, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 140, 59, 20, 8},
+ {211, 212, 0, 0x0L, LTEXT, (void*)"plotting rectangle (relative to bounding rectangle)", 10, 84, 60, 8},
+ {212, 213, 0, 0x0L, RTEXT, (void*)"upper left corner x", 5, 96, 58, 8},
+ {213, 214, 0, 0x0L, EDVAL1, &DRect.Xmin, 64, 96, 30, 10},
+ {214, 215, 0, 0x0L, RTEXT, (void*)"y", 95, 96, 10, 8},
+ {215, 216, 0, 0x0L, EDVAL1, &DRect.Ymin, 107, 96, 30, 10},
+ {216, 217, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 140, 96, 20, 8},
+ {217, 218, 0, 0x0L, RTEXT, (void*)"lower right x", 5, 108, 58, 8},
+ {218, 219, 0, 0x0L, EDVAL1, &DRect.Xmax, 64, 108, 30, 10},
+ {219, 220, 0, 0x0L, RTEXT, (void*)"y", 95, 108, 10, 8},
+ {220, 221, 0, 0x0L, EDVAL1, &DRect.Ymax, 107, 108, 30, 10},
+ {221, 0, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 140, 108, 20, 8},
+ {300, 301, 0, 0x0L, LTEXT, (void*)"select template:", 20, 30, 60, 8},
+ {301, 400, 310, CHECKED | ISPARENT, GROUP, 0L, 0, 0, 0, 0,},
+ {310, 311, 0, TOUCHEXIT | CHECKED | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl), 20, 42, 25, 25},
+ {311, 312, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl), 45, 42, 25, 25},
+ {312, 313, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl), 70, 42, 25, 25},
+ {313, 314, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl), 95, 42, 25, 25},
+ {314, 315, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl), 120, 42, 25, 25},
+ {315, 316, 0, CHECKED | TOUCHEXIT, RADIO1, (void*)"ticks outside", 12, 85, 40, 8},
+ {316, 317, 0, TOUCHEXIT, RADIO1, (void*)"ticks inside", 12, 93, 40, 8},
+ {317, 318, 0, TOUCHEXIT, RADIO1, (void*)"ticks symmetrical", 12, 101, 40, 8},
+ {318, 319, 0, TOUCHEXIT, CHECKBOX, (void*)"horizontal grid lines", 80, 85, 40, 8},
+ {319, 0, 0, TOUCHEXIT, CHECKBOX, (void*)"vertical grid lines", 80, 93, 40, 8},
+ {400, 0, 410, HIDDEN | CHECKED | ISPARENT, GROUP, 0L, 0, 0, 0, 0,},
+ {410, 411, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl3D), 20, 42, 25, 25},
+ {411, 412, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl3D), 45, 42, 25, 25},
+ {412, 0, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl3D), 70, 42, 25, 25},
+ {500, 501, 0, TOUCHEXIT | CHECKED | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 25, 60, 25, 25},
+ {501, 502, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 50, 60, 25, 25},
+ {502, 503, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 75, 60, 25, 25},
+ {503, 504, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 25, 85, 25, 25},
+ {504, 505, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 50, 85, 25, 25},
+ {505, 0, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 75, 85, 25, 25},
+ {520, 521, 0, TOUCHEXIT | CHECKED | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 20, 50, 25, 25},
+ {521, 522, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 45, 50, 25, 25},
+ {522, 523, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 70, 50, 25, 25},
+ {523, 524, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 95, 50, 25, 25},
+ {524, 525, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 120, 50, 25, 25},
+ {525, 526, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 20, 75, 25, 25},
+ {526, 527, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 45, 75, 25, 25},
+ {527, 528, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 70, 75, 25, 25},
+ {528, 529, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 95, 75, 25, 25},
+ {529, 530, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 120, 75, 25, 25},
+ {530, 531, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 20, 100, 25, 25},
+ {531, 0, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 45, 100, 25, 25},
+ {540, 541, 0, TOUCHEXIT | CHECKED | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 20, 60, 25, 25},
+ {541, 542, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 45, 60, 25, 25},
+ {542, 543, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 70, 60, 25, 25},
+ {543, 544, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 95, 60, 25, 25},
+ {544, 0, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 120, 60, 25, 25},
+ {560, 561, 0, TOUCHEXIT | CHECKED | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 20, 60, 25, 25},
+ {561, 562, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 45, 60, 25, 25},
+ {562, 563, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 70, 60, 25, 25},
+ {563, 564, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 95, 60, 25, 25},
+ {564, 0, 0, LASTOBJ | TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 120, 60, 25, 25}};
+ DlgRoot *Dlg;
+ GraphObj *p;
+ void *hDlg;
+ int i, res, selPlt = 520, selAxis = 310;
+ bool bRet, bContinue;
+ fRECT rc1, rc2;
+
+ ODtickstyle = tickstyle;
+ AxisTempl = 0;
+ if(!parent) return false;
+ Dlg = new DlgRoot(GraphDlg);
+ Dlg->SetCheck(410 + AxisTempl3D, 0L, true);
+ if(parent->Id != GO_PAGE) {
+ Dlg->Activate(202, false); Dlg->Activate(204, false);
+ }
+ hDlg = CreateDlgWnd("Create graph", 50, 50, 450, 300, Dlg, 0x0L);
+ bContinue = false;
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ bRet = false;
+ switch(res) {
+ case 0:
+ if(bContinue) res = -1;
+ break;
+ case -1:
+ bContinue = false;
+ break;
+ case 101:
+ for(i = 500; i <= 505; i++) if(Dlg->GetCheck(i))selPlt = i;
+ Dlg->ShowItem(301, true); Dlg->ShowItem(400, false);
+ res = -1;
+ break;
+ case 102:
+ for(i = 520; i <= 531; i++) if(Dlg->GetCheck(i))selPlt = i;
+ Dlg->ShowItem(301, true); Dlg->ShowItem(400, false);
+ res = -1;
+ break;
+ case 103:
+ for(i = 540; i <= 544; i++) if(Dlg->GetCheck(i))selPlt = i;
+ Dlg->ShowItem(301, true); Dlg->ShowItem(400, false);
+ res = -1;
+ break;
+ case 104:
+ for(i = 560; i <= 564; i++) if(Dlg->GetCheck(i))selPlt = i;
+ Dlg->ShowItem(301, false); Dlg->ShowItem(400, true);
+ res = -1;
+ break;
+ case 310: case 311: case 312: case 313: case 314:
+ AxisTempl = res-310;
+ if(res == selAxis) Dlg->SetCheck(4, 0L, true);
+ selAxis = res;
+ res = -1;
+ break;
+ case 315: case 316: case 317: //tick style
+ tickstyle = res -315;
+ case 318: case 319: //horizontal or vertical grid
+ tickstyle &= ~0x300;
+ if(Dlg->GetCheck(318)) tickstyle |= 0x200;
+ if(Dlg->GetCheck(319)) tickstyle |= 0x100;
+ ODtickstyle = tickstyle;
+ Dlg->DoPlot(0L);
+ res = -1;
+ break;
+ case 410: case 411: case 412: //axis templates
+ AxisTempl3D = res-410;
+ res = -1;
+ break;
+ case 500: case 501: case 502: case 503:
+ case 504: case 505:
+ case 520: case 521: case 522: case 523:
+ case 524: case 525: case 526: case 527:
+ case 528: case 529: case 530: case 531:
+ case 540: case 541: case 542: case 543:
+ case 544:
+ case 560: case 561: case 562: case 563:
+ case 564:
+ if(res != selPlt) {
+ selPlt = res;
+ res = -1;
+ break;
+ }
+ //double click means select: continue as if OK
+ res = 1;
+ case 1:
+ if(!Dlg->GetCheck(4)) {
+ Dlg->SetCheck(4, 0L, true);
+ res = -1;
+ break;
+ }
+ memcpy(&rc1, &GRect, sizeof(fRECT));
+ memcpy(&rc2, &DRect, sizeof(fRECT));
+ Dlg->GetValue(202, &rc1.Xmin); Dlg->GetValue(204, &rc1.Ymin);
+ Dlg->GetValue(207, &rc1.Xmax); Dlg->GetValue(209, &rc1.Ymax);
+ Dlg->GetValue(213, &rc2.Xmin); Dlg->GetValue(215, &rc2.Ymin);
+ Dlg->GetValue(218, &rc2.Xmax); Dlg->GetValue(220, &rc2.Ymax);
+ if(rc1.Xmin < 0.0 || rc1.Xmax < 0.0 || rc1.Ymin < 0.0 ||
+ rc1.Ymax < 0.0 || rc2.Xmin < 0.0 || rc2.Xmax < 0.0 ||
+ rc2.Ymin < 0.0 || rc2.Ymax < 0.0) {
+ ErrorBox("All values defining\nthe placement of the plot\n"
+ "must be positive.");
+ res = -1;
+ bContinue = true;
+ Dlg->SetCheck(5, 0L, true);
+ break;
+ }
+ if(rc2.Xmin > (rc1.Xmax-rc1.Xmin) || rc2.Ymax > (rc1.Ymax-rc1.Ymin)
+ || (rc2.Xmax-rc2.Xmin) > (rc1.Xmax-rc1.Xmin)
+ || (rc2.Ymax-rc2.Ymin) > (rc1.Ymax-rc1.Ymin)){
+ ErrorBox("The plotting rectangle must\nfit inside the\n"
+ "bounding rectangle.");
+ res = -1;
+ bContinue = true;
+ Dlg->SetCheck(5, 0L, true);
+ break;
+ }
+ memcpy(&GRect, &rc1, sizeof(fRECT));
+ memcpy(&DRect, &rc2, sizeof(fRECT));
+ p = 0L;
+ if(Dlg->GetCheck(101)) {
+ if(Dlg->GetCheck(500))p = new PieChart(this, data);
+ else if(Dlg->GetCheck(501))p = new RingChart(this, data);
+ else if(Dlg->GetCheck(502))p = new StarChart(this, data);
+ else if(Dlg->GetCheck(503))p = new BarChart(this, data);
+ else if(Dlg->GetCheck(504))p = new GroupBars(this, data);
+ else if(Dlg->GetCheck(505))p = new FreqDist(this, data);
+ }
+ else if(Dlg->GetCheck(102)){
+ if(Dlg->GetCheck(524)) p = new BubblePlot(this, data);
+ else if(Dlg->GetCheck(525)) p = new BoxPlot(this, data);
+ else if(Dlg->GetCheck(521)) p = new PlotScatt(this, data, 0x03);
+ else if(Dlg->GetCheck(522)) p = new PlotScatt(this, data, 0x08);
+ else if(Dlg->GetCheck(523)) p = new PlotScatt(this, data, 0x04);
+ else if(Dlg->GetCheck(526)) p = new Regression(this, data);
+ else if(Dlg->GetCheck(527)) p = new PolarPlot(this, data);
+ else if(Dlg->GetCheck(528)) p = new DensDisp(this, data);
+ else if(Dlg->GetCheck(529)) p = new Function(this, data);
+ else if(Dlg->GetCheck(530)) p = new FitFunc(this, data);
+ else if(Dlg->GetCheck(531)) p = new MultiLines(this, data);
+ else p = new PlotScatt(this, data, 0x01);
+ }
+ else if(Dlg->GetCheck(103)) {
+ if(Dlg->GetCheck(540)) p = new StackBar(this, data);
+ else if(Dlg->GetCheck(542)) p = new Waterfall(this, data);
+ else if(Dlg->GetCheck(543)) p = new Chart25D(this, data, 0L);
+ else if(Dlg->GetCheck(544)) p = new Ribbon25D(this, data, 0L);
+ else p = new StackPG(this, data);
+ }
+ else if(Dlg->GetCheck(104)) {
+ if(Dlg->GetCheck(560)) p = new Plot3D(this, data, 0x1001);
+ else if(Dlg->GetCheck(561)) p = new Plot3D(this, data, 0x1002);
+ else if(Dlg->GetCheck(562)) p = new Plot3D(this, data, 0x1004);
+ else if(Dlg->GetCheck(563)) p = new BubblePlot3D(this, data);
+ else if(Dlg->GetCheck(564)) p = new Plot3D(this, data, 0x2000);
+ }
+ if(p && p->PropertyDlg()) {
+ if(!Command(CMD_DROP_PLOT, p, 0L)) DeleteGO(p);
+ else bRet = true;
+ }
+ else if(p) {
+ Dlg->SetCheck(410 + AxisTempl3D, 0L, true);
+ DeleteGO(p); Dlg->DoPlot(0L); ShowDlgWnd(hDlg);
+ }
+ if(!bRet) {
+ res = -1;
+ //we might have lost the focus
+ bContinue = true;
+ }
+ break;
+ }
+ }while(res <0);
+ if(!bRet) parent->Command(CMD_DELOBJ, this, NULL);
+ else Command(CMD_SET_DATAOBJ, (void*)data, 0L);
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+bool
+Graph::Configure()
+{
+ TabSHEET tab1 = {0, 28, 10, "Colors"};
+ TabSHEET tab2 = {28, 68, 10, "Placement"};
+ DlgInfo GraphDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 170, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 170, 25, 45, 12},
+ {3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Add Plot", 170, 73, 45, 12},
+ {4, 5, 0, 0x0L, PUSHBUTTON, (void*)"Add Axis", 170, 88, 45, 12},
+ {5, 6, 0, 0x0L, PUSHBUTTON, (void*)"Add Legend", 170, 103, 45, 12},
+ {6, 13, 0, 0x0L, PUSHBUTTON, (void*)"Layers", 170, 118, 45, 12},
+ {13, 50, 14, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
+ {14, 15, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 155, 120},
+ {15, 0, 200, ISPARENT, SHEET, &tab2, 5, 10, 155, 120},
+ {50, 0, 600, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"bounding rectangle", 20, 30, 60, 8},
+ {101, 102, 0, 0x0L, RTEXT, (void*)"fill color", 15, 42, 58, 8},
+ {102, 103, 0, TOUCHEXIT | OWNDIALOG, COLBUTTON, (void *)ColGR, 74, 42, 25, 10},
+ {103, 104, 0, 0x0L, RTEXT, (void*)"outline color", 15, 54, 58, 8},
+ {104, 105, 0, TOUCHEXIT | OWNDIALOG, COLBUTTON, (void *)ColGRL, 74, 54, 25, 10},
+ {105, 106, 0, 0x0L, LTEXT, (void*)"plotting rectangle", 20, 68, 60, 8},
+ {106, 107, 0, 0x0L, RTEXT, (void*)"fill color", 15, 80, 58, 8},
+ {107, 108, 0, TOUCHEXIT | OWNDIALOG, COLBUTTON, (void *)ColDR, 74, 80, 25, 10},
+ {108, 109, 0, 0x0L, LTEXT, (void*)"axes, ticks, and axis labels", 20, 94, 60, 8},
+ {109, 110, 0, 0x0L, RTEXT, (void*)"axis color", 15, 106, 58, 8},
+ {110, 0, 0, TOUCHEXIT | OWNDIALOG, COLBUTTON, (void *)ColAX, 74, 106, 25, 10},
+ {200, 201, 0, 0x0L, LTEXT, (void*)"bounding rectangle (relative to page)", 10, 35, 60, 8},
+ {201, 202, 0, 0x0L, RTEXT, (void*)"upper left corner x", 5, 47, 58, 8},
+ {202, 203, 0, 0x0L, EDVAL1, &GRect.Xmin, 64, 47, 30, 10},
+ {203, 204, 0, 0x0L, RTEXT, (void*)"y", 95, 47, 10, 8},
+ {204, 205, 0, 0x0L, EDVAL1, &GRect.Ymin, 107, 47, 30, 10},
+ {205, 206, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 140, 47, 20, 8},
+ {206, 207, 0, 0x0L, RTEXT, (void*)"lower right x", 5, 59, 58, 8},
+ {207, 208, 0, 0x0L, EDVAL1, &GRect.Xmax, 64, 59, 30, 10},
+ {208, 209, 0, 0x0L, RTEXT, (void*)"y", 95, 59, 10, 8},
+ {209, 210, 0, 0x0L, EDVAL1, &GRect.Ymax, 107, 59, 30, 10},
+ {210, 211, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 140, 59, 20, 8},
+ {211, 212, 0, 0x0L, LTEXT, (void*)"plotting rectangle (relative to bounding rectangle)", 10, 84, 60, 8},
+ {212, 213, 0, 0x0L, RTEXT, (void*)"upper left corner x", 5, 96, 58, 8},
+ {213, 214, 0, 0x0L, EDVAL1, &DRect.Xmin, 64, 96, 30, 10},
+ {214, 215, 0, 0x0L, RTEXT, (void*)"y", 95, 96, 10, 8},
+ {215, 216, 0, 0x0L, EDVAL1, &DRect.Ymin, 107, 96, 30, 10},
+ {216, 217, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 140, 96, 20, 8},
+ {217, 218, 0, 0x0L, RTEXT, (void*)"lower right x", 5, 108, 58, 8},
+ {218, 219, 0, 0x0L, EDVAL1, &DRect.Xmax, 64, 108, 30, 10},
+ {219, 220, 0, 0x0L, RTEXT, (void*)"y", 95, 108, 10, 8},
+ {220, 221, 0, 0x0L, EDVAL1, &DRect.Ymax, 107, 108, 30, 10},
+ {221, 0, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 140, 108, 20, 8},
+ {600, 601, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 170, 40, 15, 15},
+ {601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 190, 40, 15, 15},
+ {602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 190, 55, 15, 15},
+ {603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 170, 55, 15, 15}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, res, undo_level = *Undo.pcb;
+ DWORD undo_flags = 0, tmpcol;
+ bool bRet = false, bContinue = false;
+ fRECT o_gr, n_gr, o_dr, n_dr;
+
+ if(!(Dlg = new DlgRoot(GraphDlg)))return false;
+ Dlg->GetValue(202, &o_gr.Xmin); Dlg->GetValue(204, &o_gr.Ymin);
+ Dlg->GetValue(207, &o_gr.Xmax); Dlg->GetValue(209, &o_gr.Ymax);
+ Dlg->GetValue(213, &o_dr.Xmin); Dlg->GetValue(215, &o_dr.Ymin);
+ Dlg->GetValue(218, &o_dr.Xmax); Dlg->GetValue(220, &o_dr.Ymax);
+ if(parent && parent->Id == GO_PAGE) Dlg->ShowItem(50, true);
+ sprintf(TmpTxt, "%s properties", name ? name : "Graph");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 450, 300, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = ExecDrawOrderButt(parent, this, Dlg->GetResult());
+ switch(res) {
+ case 0:
+ if(bContinue) res = -1;
+ break;
+ case -1:
+ bContinue = false;
+ break;
+ case 102: case 104: case 107: case 110:
+ res = -1;
+ break;
+ case 1:
+ Dlg->GetValue(202, &n_gr.Xmin); Dlg->GetValue(204, &n_gr.Ymin);
+ Dlg->GetValue(207, &n_gr.Xmax); Dlg->GetValue(209, &n_gr.Ymax);
+ Dlg->GetValue(213, &n_dr.Xmin); Dlg->GetValue(215, &n_dr.Ymin);
+ Dlg->GetValue(218, &n_dr.Xmax); Dlg->GetValue(220, &n_dr.Ymax);
+ if(n_gr.Xmin < 0.0 || n_gr.Xmax < 0.0 || n_gr.Ymin < 0.0 ||
+ n_gr.Ymax < 0.0 || n_dr.Xmin < 0.0 || n_dr.Xmax < 0.0 ||
+ n_dr.Ymin < 0.0 || n_dr.Ymax < 0.0) {
+ ErrorBox("All values defining\nthe placement of the plot\n"
+ "must be positive.");
+ res = -1;
+ bContinue = true;
+ Dlg->SetCheck(5, 0L, true);
+ break;
+ }
+ if(n_dr.Xmin > (n_gr.Xmax-n_gr.Xmin) || n_dr.Ymax > (n_gr.Ymax-n_gr.Ymin)
+ || (n_dr.Xmax-n_dr.Xmin) > (n_gr.Xmax-n_gr.Xmin)
+ || (n_dr.Ymax-n_dr.Ymin) > (n_gr.Ymax-n_gr.Ymin)){
+ ErrorBox("The plotting rectangle must\nfit inside the\n"
+ "bounding rectangle.");
+ res = -1;
+ bContinue = true;
+ Dlg->SetCheck(5, 0L, true);
+ break;
+ }
+ bRet = true;
+ break;
+ case 3:
+ if(bRet = Command(CMD_ADDPLOT, 0L, 0L)) break;
+ case 4:
+ if(res == 4 && (bRet = Command(CMD_ADDAXIS, 0L, 0L))) break;
+ bContinue = true;
+ res = -1;
+ break;
+ case 5:
+ Command(CMD_LEGEND, 0L, 0L);
+ res = -1;
+ break;
+ case 6:
+ Command(CMD_LAYERS, 0L, 0L);
+ bContinue = true;
+ res = -1;
+ break;
+ }
+ }while(res <0);
+ if(res == 1 && bRet) {
+ if(n_gr.Xmin != o_gr.Xmin || n_gr.Xmax != o_gr.Xmax ||
+ n_gr.Ymin != o_gr.Ymin || n_gr.Ymax != o_gr.Ymax ||
+ n_dr.Xmin != o_dr.Xmin || n_dr.Xmax != o_dr.Xmax ||
+ n_dr.Ymin != o_dr.Ymin || n_dr.Ymax != o_dr.Ymax){
+ Command(CMD_SAVEPOS, 0L, 0L);
+ memcpy(&GRect, &n_gr, sizeof(fRECT));
+ memcpy(&DRect, &n_dr, sizeof(fRECT));
+ undo_flags |= UNDO_CONTINUE;
+ }
+ if(Dlg->GetColor(102, &tmpcol))
+ undo_flags = CheckNewDword(&ColGR, ColGR, tmpcol, this, undo_flags);
+ if(Dlg->GetColor(104, &tmpcol))
+ undo_flags = CheckNewDword(&ColGRL, ColGRL, tmpcol, this, undo_flags);
+ if(Dlg->GetColor(107, &tmpcol))
+ undo_flags = CheckNewDword(&ColDR, ColDR, tmpcol, this, undo_flags);
+ if(Dlg->GetColor(110, &tmpcol) && tmpcol != ColAX) {
+ undo_flags = CheckNewDword(&ColAX, ColAX, tmpcol, this, undo_flags);
+ if(Axes) for(i = 0; i < NumAxes; i++)
+ if(Axes[i]) Axes[i]->SetColor(COL_AXIS | UNDO_STORESET, ColAX);
+ if(Plots && NumPlots && Plots[0] && Plots[0]->Id == GO_PLOT3D)
+ Plots[0]->SetColor(COL_AXIS | UNDO_STORESET, ColAX);
+ }
+ }
+ else if(res == 2) {
+ if(*Undo.pcb > undo_level) { //restore plot order
+ while(*Undo.pcb > undo_level) Undo.Restore(false, 0L);
+ bRet = true;
+ }
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+bool
+Graph::AddAxis()
+{
+ TabSHEET tab1 = {0, 25, 10, "Axis"};
+ TabSHEET tab2 = {25, 52, 10, "Style"};
+ TabSHEET tab3 = {52, 78, 10, "Plots"};
+ AxisDEF axis;
+ double sizAxLine = defs.GetSize(SIZE_AXIS_LINE);
+ DWORD colAxis = ColAX;
+ DlgInfo NewAxisDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 148, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 148, 25, 45, 12},
+ {3, 0, 4, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
+ {4, 5, 50, TOUCHEXIT | ISPARENT, SHEET, &tab1, 5, 10, 130, 130},
+ {5, 6, 200, ISPARENT | CHECKED, SHEET, &tab2, 5, 10, 130, 130},
+ {6, 0, 300, ISPARENT, SHEET, &tab3, 5, 10, 130, 130},
+ {50, 51, 100, ISPARENT | CHECKED, GROUPBOX, (void*)" scaling ", 10, 30, 120, 36},
+ {51, 120, 0, 0x0L, CHECKBOX, (void*)" automatic scaling", 17, 37, 80, 8},
+ {100, 101, 0, 0x0L, RTEXT, (void*)"axis from", 10, 51, 35, 8},
+ {101, 102, 0, 0x0L, EDVAL1, &y_axis.min, 48, 51, 32, 10},
+ {102, 103, 0, 0x0L, CTEXT, (void*)"to", 81, 51, 11, 8},
+ {103, 0, 0, 0x0L, EDVAL1, &y_axis.max, 93, 51, 32, 10},
+ {120, 0, 121, ISPARENT | CHECKED, GROUPBOX, (void*)" line ", 10, 72, 120, 20},
+ {121, 122, 0, 0x0L, RTEXT, (void*)"width", 10, 77, 25, 8},
+ {122, 123, 0, 0x0L, EDVAL1, &sizAxLine, 37, 77, 25, 10},
+ {123, 124, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 63, 77, 10, 8},
+ {124, 125, 0, 0x0L, RTEXT, (void*)"color", 73, 77, 25, 8},
+ {125, 130, 0, OWNDIALOG, COLBUTTON, (void *)colAxis, 100, 77, 25, 10},
+ {130, 131, 0, ISPARENT | CHECKED, GROUPBOX, (void*)" axis label ", 10, 98, 120, 20},
+ {131, 0, 0, 0x0L, EDTEXT, (void*)0L, 15, 103, 110, 10},
+ {200, 201, 0, 0x0L, LTEXT, (void*)"select a template:", 10, 30, 70, 9},
+ {201, 202, 0, CHECKED | TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_NewAxisTempl), 20, 42, 25, 25},
+ {202, 203, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_NewAxisTempl), 45, 42, 25, 25},
+ {203, 204, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_NewAxisTempl), 70, 42, 25, 25},
+ {204, 205, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_NewAxisTempl), 95, 42, 25, 25},
+ {205, 206, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_NewAxisTempl), 20, 67, 25, 25},
+ {206, 207, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_NewAxisTempl), 45, 67, 25, 25},
+ {207, 208, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_NewAxisTempl), 70, 67, 25, 25},
+ {208, 210, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_NewAxisTempl), 95, 67, 25, 25},
+ {210, 0, 220, ISPARENT | CHECKED, GROUPBOX, (void*)" placement ", 10, 97, 120, 35},
+ {220, 221, 0, 0x0L, RTEXT, (void*)"x", 10, 105, 15, 8},
+ {221, 222, 0, 0x0L, EDVAL1, &axis.loc[0].fx, 27, 105, 35, 10},
+ {222, 223, 0, 0x0L, LTEXT, (void*)"-", 65, 105, 5, 8},
+ {223, 224, 0, 0x0L, EDVAL1, &axis.loc[1].fx, 71, 105, 35, 10},
+ {224, 225, 0, 0x0L, LTEXT, (void*)Units[units].display, 109, 105, 15, 8},
+ {225, 226, 0, 0x0L, RTEXT, (void*)"y", 10, 117, 15, 8},
+ {226, 227, 0, 0x0L, EDVAL1, &axis.loc[0].fy, 27, 117, 35, 10},
+ {227, 228, 0, 0x0L, LTEXT, (void*)"-", 65, 117, 5, 8},
+ {228, 229, 0, 0x0L, EDVAL1, &axis.loc[1].fy, 71, 117, 35, 10},
+ {229, 0, 0, 0x0L, LTEXT, (void*)Units[units].display, 109, 117, 15, 8},
+ {300, 0, 0, NOSELECT, ODBUTTON, (void*)OD_axisplot, 15, 30, 110, 140},
+ {400, 0, 0, LASTOBJ, NONE, 0L, 0, 0, 0, 0}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, j, res, currTempl = 201;
+ double vx1, vx2, vy1, vy2, hx1, hx2, hy1, hy2;
+ double tlb_dist, tlb_dx, tlb_dy, lb_x, lb_y;
+ TextDEF label_def, tlbdef;
+ DWORD flags;
+ Axis *the_new, **tmpAxes;
+ bool bAxis = false, bRet = false;
+ char **names;
+ GraphObj **somePlots;
+ Label *label;
+
+ if(!(names = (char**)calloc(nscp+2, sizeof(char*))))return false;
+ if(!(somePlots = (GraphObj**)calloc(nscp+2, sizeof(GraphObj*))))return false;
+ if(!Axes) Axes = (Axis**)calloc(2, sizeof(Axis*));
+ names[j=0] = strdup("[none]");
+ for(i = 0, j = 1; i < nscp; i++) {
+ if(Sc_Plots[i] && Sc_Plots[i]->name){
+ names[j] = strdup(Sc_Plots[i]->name);
+ somePlots[j++] = Sc_Plots[i];
+ }
+ }
+ OD_axisplot(OD_ACCEPT, 0L, 0L, 0L, names, 0);
+ axis.loc[0].fx = axis.loc[1].fx = vx1 = vx2 = (DRect.Xmin + DRect.Xmax)/2.0;
+ axis.loc[0].fy = vy1 = DRect.Ymin;
+ axis.loc[1].fy = vy2 = DRect.Ymax;
+ axis.min = y_axis.min; axis.max = y_axis.max;
+ hy1 = hy2 = (DRect.Ymax + DRect.Ymin)/2.0;
+ hx1 = DRect.Xmin; hx2 = DRect.Xmax;
+ if(!(Dlg = new DlgRoot(NewAxisDlg)))return false;
+ if(type != 1 || !nscp){ //must be standard graph to link to plot
+ Dlg->ShowItem(6, false);
+ }
+ hDlg = CreateDlgWnd("New axis properties", 50, 50, 400, 314, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res){
+ case 4: //the axis sheet
+ res = -1;
+ bAxis = true;
+ break;
+ case 201: case 202: case 203: case 204: //axis templates
+ case 205: case 206: case 207: case 208:
+ if(currTempl > 204) {
+ Dlg->GetValue(221, &hx1); Dlg->GetValue(223, &hx2);
+ Dlg->GetValue(226, &hy1); Dlg->GetValue(228, &hy2);
+ }
+ else {
+ Dlg->GetValue(221, &vx1); Dlg->GetValue(223, &vx2);
+ Dlg->GetValue(226, &vy1); Dlg->GetValue(228, &vy2);
+ }
+ if(res > 204) {
+ WriteFloatToBuff(TmpTxt, hx1); Dlg->SetText(221, TmpTxt+1);
+ WriteFloatToBuff(TmpTxt, hx2); Dlg->SetText(223, TmpTxt+1);
+ WriteFloatToBuff(TmpTxt, hy1); Dlg->SetText(226, TmpTxt+1);
+ WriteFloatToBuff(TmpTxt, hy2); Dlg->SetText(228, TmpTxt+1);
+ if(! bAxis) {
+ WriteFloatToBuff(TmpTxt, x_axis.min); Dlg->SetText(101, TmpTxt+1);
+ WriteFloatToBuff(TmpTxt, x_axis.max); Dlg->SetText(103, TmpTxt+1);
+ }
+ }
+ else {
+ WriteFloatToBuff(TmpTxt, vx1); Dlg->SetText(221, TmpTxt+1);
+ WriteFloatToBuff(TmpTxt, vx2); Dlg->SetText(223, TmpTxt+1);
+ WriteFloatToBuff(TmpTxt, vy1); Dlg->SetText(226, TmpTxt+1);
+ WriteFloatToBuff(TmpTxt, vy2); Dlg->SetText(228, TmpTxt+1);
+ if(! bAxis) {
+ WriteFloatToBuff(TmpTxt, y_axis.min); Dlg->SetText(101, TmpTxt+1);
+ WriteFloatToBuff(TmpTxt, y_axis.max); Dlg->SetText(103, TmpTxt+1);
+ }
+ }
+ currTempl = res;
+ Dlg->DoPlot(0L);
+ res = -1;
+ break;
+ }
+ }while (res < 0);
+ if(res == 1) {
+ Dlg->GetValue(122, &sizAxLine); Dlg->GetColor(125, &colAxis);
+ Dlg->GetValue(221, &axis.loc[0].fx); Dlg->GetValue(223, &axis.loc[1].fx);
+ Dlg->GetValue(226, &axis.loc[0].fy); Dlg->GetValue(228, &axis.loc[1].fy);
+ axis.loc[0].fz = axis.loc[1].fz = 0.0; axis.owner = 0L;
+ Dlg->GetValue(101, &axis.min); Dlg->GetValue(103, &axis.max);
+ axis.Start = axis.min; axis.Center.fx = axis.Center.fy = 0.0;
+ axis.nBreaks = 0; axis.breaks = 0L; axis.Radius = 0.0;
+ tlb_dist = NiceValue(defs.GetSize(SIZE_AXIS_TICKS));
+ tlb_dx = tlb_dy = 0.0;
+ tlbdef.ColTxt = colAxis; tlbdef.ColBg = 0x00ffffffL;
+ tlbdef.RotBL = tlbdef.RotCHAR = 0.0f; tlbdef.fSize = defs.GetSize(SIZE_TICK_LABELS);
+ tlbdef.Align = TXA_VCENTER | TXA_HCENTER;
+ tlbdef.Style = TXS_NORMAL; tlbdef.Mode = TXM_TRANSPARENT;
+ tlbdef.Font = FONT_HELVETICA; tlbdef.text = 0L;
+ label_def.ColTxt = colAxis; label_def.ColBg = 0x00ffffffL;
+ label_def.fSize = defs.GetSize(SIZE_TICK_LABELS)*1.2f; label_def.RotBL = 0.0f;
+ label_def.RotCHAR = 0.0f; label_def.iSize = 0;
+ label_def.Align = TXA_VTOP | TXA_HCENTER; label_def.Mode = TXM_TRANSPARENT;
+ label_def.Style = TXS_NORMAL; label_def.Font = FONT_HELVETICA;
+ switch (currTempl) {
+ default: flags = AXIS_NEGTICKS; axis.Step = y_axis.Step;
+ tlb_dx = -tlb_dist * 2.0; tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
+ lb_x = -tlb_dist * 6.0; lb_y = 0; label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
+ label_def.RotBL = 90.0;
+ break;
+ case 202: flags = AXIS_POSTICKS; axis.Step = y_axis.Step;
+ tlb_dx = -tlb_dist; tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
+ lb_x = -tlb_dist * 4.5; lb_y = 0; label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
+ label_def.RotBL = 90.0;
+ break;
+ case 203: flags = AXIS_POSTICKS; axis.Step = y_axis.Step;
+ tlb_dx = tlb_dist * 2.0; tlbdef.Align = TXA_VCENTER | TXA_HLEFT;
+ lb_x = tlb_dist * 6; lb_y = 0; label_def.Align = TXA_VTOP | TXA_HCENTER;
+ label_def.RotBL = 90.0;
+ break;
+ case 204: flags = AXIS_NEGTICKS; axis.Step = y_axis.Step;
+ tlb_dx = tlb_dist; tlbdef.Align = TXA_VCENTER | TXA_HLEFT;
+ lb_x = tlb_dist * 4.5; lb_y = 0; label_def.Align = TXA_VTOP | TXA_HCENTER;
+ label_def.RotBL = 90.0;
+ break;
+ case 205: flags = AXIS_NEGTICKS; axis.Step = x_axis.Step;
+ tlb_dy = tlb_dist * 2.0; tlbdef.Align = TXA_VTOP | TXA_HCENTER;
+ lb_x = 0; lb_y = tlb_dist * 4.0;
+ break;
+ case 206: flags = AXIS_POSTICKS; axis.Step = x_axis.Step;
+ tlb_dy = tlb_dist; tlbdef.Align = TXA_VTOP | TXA_HCENTER;
+ lb_x = 0; lb_y = tlb_dist * 3.0;
+ break;
+ case 207: flags = AXIS_POSTICKS; axis.Step = x_axis.Step;
+ tlb_dy = -tlb_dist * 2.0; tlbdef.Align = TXA_VBOTTOM | TXA_HCENTER;
+ lb_x = 0; lb_y = -tlb_dist * 4.0; label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
+ break;
+ case 208: flags = AXIS_NEGTICKS; axis.Step = x_axis.Step;
+ tlb_dy = -tlb_dist; tlbdef.Align = TXA_VBOTTOM | TXA_HCENTER;
+ lb_x = 0; lb_y = -tlb_dist * 3.0; label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
+ break;
+ }
+ flags |= AXIS_AUTOTICK; flags |= AXIS_DEFRECT;
+ if(Dlg->GetCheck(51)) flags |= AXIS_AUTOSCALE;
+ if(the_new = new Axis(this, data, &axis, flags)){
+ the_new->SetSize(SIZE_TLB_YDIST, tlb_dy); the_new->SetSize(SIZE_TLB_XDIST, tlb_dx);
+ the_new->SetSize(SIZE_AXIS_LINE, sizAxLine);
+ the_new->SetColor(COL_AXIS, colAxis);
+ the_new->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+ the_new->SetSize(SIZE_LB_XDIST, lb_x); the_new->SetSize(SIZE_LB_YDIST, lb_y);
+ if(Dlg->GetText(131, TmpTxt)) label_def.text = TmpTxt;
+ else label_def.text = 0L;
+ if(label = new Label(Axes[0], data, (axis.loc[0].fx + axis.loc[1].fx)/2.0,
+ (axis.loc[0].fy + axis.loc[1].fy)/2.0, &label_def,
+ label_def.RotBL < 45.0 ? LB_Y_PARENT : LB_X_PARENT)){
+ label->SetSize(SIZE_LB_XDIST, lb_x); label->SetSize(SIZE_LB_YDIST, lb_y);
+ if(the_new->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
+ else DeleteGO(label);
+ }
+ for(i = 0; i < NumAxes && Axes[i]; i++);
+ if(i < NumAxes) {
+ Undo.SetGO(this, (GraphObj**)(&Axes[i]), the_new, 0L);
+ bRet = true;
+ }
+ else {
+ if(tmpAxes = (Axis**)calloc(NumAxes+1, sizeof(Axis*))){
+ memcpy(tmpAxes, Axes, NumAxes * sizeof(Axis*));
+ Undo.ListGOmoved((GraphObj**)Axes, (GraphObj**)tmpAxes, NumAxes);
+ Undo.SetGO(this, (GraphObj**)(&tmpAxes[NumAxes]), the_new, 0L);
+ free(Axes); Axes = tmpAxes;
+ i = NumAxes++; bRet = true;
+ }
+ else delete (the_new); //very unlikely memory allocation error
+ }
+ CurrAxes = Axes;
+ if(bRet) {
+ OD_axisplot(OD_ACCEPT, 0L, 0L, (anyOutput*) &res, 0L, 0);
+ if(res && i) somePlots[res]->Command(CMD_USEAXIS, &i, 0L);
+ }
+ }
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(names) {
+ for(j = 0; names[j]; j++) if(names[j]) free(names[j]);
+ free(names);
+ }
+ if(somePlots) free(somePlots);
+ return bRet;
+}
+
+bool
+Page::Configure()
+{
+ TabSHEET tab1 = {0, 50, 10, "Paper Size"};
+ DlgInfo PageDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 135, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 135, 25, 45, 12},
+ {3, 0, 4, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 120, 120},
+ {5, 0, 0, 0x0L, PUSHBUTTON, (void*)"Layers", 135, 118, 45, 12},
+ {100, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)OD_paperdef, 15, 30, 110, 140}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res;
+ bool bRet = false, bContinue = false;
+
+ FindPaper(GRect.Xmax - GRect.Xmin, GRect.Ymax -GRect.Ymin, .0001);
+ if(!(Dlg = new DlgRoot(PageDlg)))return false;
+ sprintf(TmpTxt, "%s properties", name ? name : "Page");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 380, 300, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 0:
+ if(bContinue) res = -1;
+ break;
+ case -1:
+ bContinue = false;
+ break;
+ case 5:
+ Command(CMD_LAYERS, 0L, 0L);
+ bContinue = true;
+ res = -1;
+ }
+ }while(res <0);
+ if(res == 1) {
+ OD_paperdef(OD_ACCEPT, 0L, 0L, 0L, 0L, 0);
+ GRect.Xmin = GRect.Ymin = 0.0;
+ GetPaper(&GRect.Xmax, &GRect.Ymax);
+ DoPlot(CurrDisp);
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Edit global defaults
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Default::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 25, 10, "Line"};
+ TabSHEET tab2 = {25, 60, 10, "Shapes"};
+ TabSHEET tab3 = {60, 93, 10, "Dialogs"};
+ TabSHEET tab4 = {93, 128, 10, "Internat."};
+ double ts = dlgtxtheight;
+ DlgInfo DefsDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 150, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 150, 25, 45, 12},
+ {3, 0, 4, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {4, 5, 100, TOUCHEXIT | ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 139, 120},
+ {5, 6, 200, TOUCHEXIT | ISPARENT, SHEET, &tab2, 5, 10, 139, 120},
+ {6, 7, 300, ISPARENT, SHEET, &tab3, 5, 10, 139, 120},
+ {7, 0, 400, ISPARENT, SHEET, &tab4, 5, 10, 139, 120},
+ {100, 0, 0, NOSELECT, ODBUTTON, (void*)OD_linedef, 10, 38, 130, 100},
+ {200, 0, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 25, 40, 90, 50},
+ {300, 301, 0, 0x0L, RTEXT, (void*)"text size", 20, 30, 38, 8},
+ {301, 302, 0, 0x0L, EDVAL1, (void*)&ts, 60, 30, 20, 10},
+ {302, 0, 0, 0x0L, LTEXT, (void*)"pixel", 82, 30, 20, 8},
+ {400, 401, 0, 0x0L, LTEXT, (void*)"edit country specific information", 20, 30, 100, 8},
+ {401, 402, 0, 0x0L, RTEXT, (void*)"decimal point", 45, 45, 40, 8},
+ {402, 403, 0, 0x0L, EDTEXT, (void*)DecPoint, 90, 45, 10, 10},
+ {403, 404, 0, 0x0L, RTEXT, (void*)"column separator", 45, 57, 40, 8},
+ {404, 405, 0, 0x0L, EDTEXT, (void*)ColSep, 90, 57, 10, 10},
+ {405, 406, 0, 0x0L, RTEXT, (void*)"use units:", 25, 75, 47, 8},
+ {406, 0, 420, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {420, 421, 0, 0x0L, RADIO1, (void*)Units[0].display, 75, 75, 20, 8},
+ {421, 422, 0, 0x0L, RADIO1, (void*)Units[1].display, 75, 83, 20, 8},
+ {422, 0, 0, LASTOBJ, RADIO1, (void*)Units[2].display, 75, 91, 20, 8}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, tmpUnits = cUnits;
+ bool bRet = false;
+ LineDEF LineDef;
+ FillDEF FillDef;
+
+ OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)GetLine(), 0);
+ OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)GetOutLine(), 0);
+ OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)GetFill(), 0);
+ Dlg = new DlgRoot(DefsDlg);
+ switch(dUnits) {
+ case 1: Dlg->SetCheck(421, 0L, true); break;
+ case 2: Dlg->SetCheck(422, 0L, true); break;
+ default: Dlg->SetCheck(420, 0L, true); break;
+ }
+ hDlg = CreateDlgWnd("Edit Global Preferences", 50, 50, 410, 300, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 4: case 5:
+ res = -1;
+ break;
+ case 1:
+ if(Dlg->GetCheck(421)) dUnits = 1;
+ else if(Dlg->GetCheck(422)) dUnits = 2;
+ else dUnits = 0;
+ }
+ }while (res < 0);
+ if(res == 1) {
+ if(Dlg->GetText(402, TmpTxt)) DecPoint[0] = TmpTxt[0];
+ if(Dlg->GetText(404, TmpTxt)) ColSep[0] = TmpTxt[0];
+ bRet = true;
+ OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
+ SetLine(tmpUnits, &LineDef, 0);
+ OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
+ SetLine(tmpUnits, &LineDef, 2);
+ OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&FillDef, 0);
+ SetFill(tmpUnits, &FillDef);
+ Dlg->GetInt(301, &dlgtxtheight);
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
diff --git a/QT_Spec.cpp b/QT_Spec.cpp
new file mode 100755
index 0000000..9d46d8d
--- /dev/null
+++ b/QT_Spec.cpp
@@ -0,0 +1,2667 @@
+//QT_Spec.cpp, Copyright (c) 2001, 2002, 2003, 2004, 2005 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 <qmessagebox.h>
+#include <qpixmap.h>
+#include <qapplication.h>
+#include <qnamespace.h>
+#include <qfiledialog.h>
+#include <qpaintdevicemetrics.h>
+#include <qimage.h>
+#include <qcursor.h>
+#include <qcstring.h>
+#include <qclipboard.h>
+#include <qbuffer.h>
+#include <qbitmap.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "QT_Spec.h"
+
+extern tag_Units Units[];
+extern GraphObj *CurrGO; //Selected Graphic Objects
+extern Graph *CurrGraph;
+extern char *WWWbrowser;
+extern char *LoadFile; //command line argument
+extern char TmpTxt[];
+extern Default defs;
+extern UndoObj Undo;
+
+QApplication *QAppl;
+QWidget *MainWidget =0L;
+POINT CurrWidgetPos = {0,0};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Menu tem identifiers: synchronize this table with rlplot.rc for
+// compatibility with windows
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#define CM_OPEN 500
+#define CM_SAVEDATAAS 501
+#define CM_EXIT 502
+#define CM_NEWGRAPH 503
+#define CM_NEWPAGE 504
+#define CM_DELGRAPH 505
+#define CM_ADDPLOT 506
+#define CM_ABOUT 507
+#define CM_ADDROWCOL 508
+#define CM_COPYGRAPH 509
+#define CM_SAVEGRAPHAS 510
+#define CM_REDRAW 511
+#define CM_ZOOM25 512
+#define CM_ZOOM50 513
+#define CM_ZOOM100 514
+#define CM_ZOOM200 515
+#define CM_ZOOM400 516
+#define CM_PRINT 517
+#define CM_EXPORT 518
+#define CM_DELOBJ 519
+#define CM_REBOOT 520
+#define CM_SHUTDOWN 521
+#define CM_DEFAULTS 522
+#define CM_COPY 523
+#define CM_PASTE 524
+#define CM_UPDATE 525
+#define CM_ADDAXIS 526
+#define CM_UNDO 527
+#define CM_ZOOMIN 528
+#define CM_ZOOMOUT 529
+#define CM_ZOOMFIT 530
+#define CM_FILE1 531
+#define CM_FILE2 532
+#define CM_FILE3 533
+#define CM_FILE4 534
+#define CM_FILE5 535
+#define CM_FILE6 536
+#define CM_FILLRANGE 537
+#define CM_CUT 538
+#define CM_LEGEND 539
+#define CM_LAYERS 540
+
+#define CM_T_STANDARD 550
+#define CM_T_DRAW 551
+#define CM_T_POLYLINE 552
+#define CM_T_POLYGON 553
+#define CM_T_RECTANGLE 554
+#define CM_T_ROUNDREC 555
+#define CM_T_ELLIPSE 556
+#define CM_T_ARROW 557
+#define CM_T_TEXT 558
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Exute a file open dialog for the different situations
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char UserFileName[600];
+// Get a new file name to store data in
+char *SaveDataAsName(char *oldname)
+{
+ QString fileName = QFileDialog::getSaveFileName(oldname?oldname:defs.currPath,
+ "RLPlot workbook (*.rlw)\ndata files (*.csv)\ntab separated (*.tsv)\nXML (*.xml)", QAppl->focusWidget());
+ if(!fileName.isEmpty()){
+ strcpy(UserFileName, fileName);
+ defs.FileHistory(UserFileName);
+ return UserFileName;
+ }
+ return 0L;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get a new file name to store graph
+char *SaveGraphAsName(char *oldname)
+{
+ QString fileName = QFileDialog::getSaveFileName(oldname?oldname:defs.currPath,
+ "RLPlot files (*.rlp)", QAppl->focusWidget());
+ if(!fileName.isEmpty()){
+ strcpy(UserFileName, fileName);
+ defs.FileHistory(UserFileName);
+ return UserFileName;
+ }
+ return 0L;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get file name to read graph
+char *OpenGraphName(char *oldname)
+{
+ QString fileName = QFileDialog::getOpenFileName(oldname?oldname:defs.currPath,
+ "RLPlot files (*.rlp)", QAppl->focusWidget());
+ if(!fileName.isEmpty()){
+ strcpy(UserFileName, fileName);
+ defs.FileHistory(UserFileName);
+ return UserFileName;
+ }
+ return 0L;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get a file name to load data
+char *OpenDataName(char *oldname)
+{
+ QString fileName = QFileDialog::getOpenFileName(oldname?oldname:defs.currPath,
+ "RLPlot workbook (*.rlw)\ndata files (*.csv)\ntab separated file (*.tsv)\n"
+ "RLPlot files (*.rlp)\nall files (*.*)", QAppl->focusWidget());
+ if(!fileName.isEmpty()){
+ strcpy(UserFileName, fileName);
+ defs.FileHistory(UserFileName);
+ return UserFileName;
+ }
+ return 0L;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get a file name to export graph
+void OpenExportName(GraphObj *g, char *oldname)
+{
+ int i;
+ PrintQT *out=0L;
+
+ if (!g) return;
+ QString fileName = QFileDialog::getSaveFileName(oldname?oldname:defs.currPath,
+ "Scalable Vector Graphics (*.svg)\nEncapsulated Post Script (*.eps)\n"
+ "MSWindows MetaFile (*.wmf)\nTag Image File Format(*.tif *.tiff)",
+ QAppl->focusWidget());
+ if(!fileName.isEmpty()){
+ strcpy(UserFileName, fileName);
+ i = strlen(UserFileName);
+ g->Command(CMD_BUSY, 0L, 0L);
+ if(0==strcasecmp(".svg", UserFileName+i-4)) {
+ DoExportSvg(g, UserFileName, 0L);
+ }
+ else if(0==strcasecmp(".wmf", UserFileName+i-4)) {
+ DoExportWmf(g, UserFileName, 600.0f, 0L);
+ }
+ else if(0==strcasecmp(".eps", UserFileName+i-4)) {
+ DoExportEps(g, UserFileName, 0L);
+ }
+ else if(0==strcasecmp(".tif", UserFileName+i-4)) {
+ DoExportTif(g, UserFileName, 0L);
+ }
+ else if(0==strcasecmp(".tiff", UserFileName+i-5)) {
+ DoExportTif(g, UserFileName, 0L);
+ }
+ else ErrorBox("Unknown file extension or format");
+ g->Command(CMD_MOUSECURSOR, 0L, 0L);
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Common alert boxes
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void InfoBox(char *Msg)
+{
+ QMessageBox::information(QAppl->focusWidget(), "Info", Msg);
+}
+
+void ErrorBox(char *Msg)
+{
+ QMessageBox::critical(QAppl->focusWidget(), "ERROR", Msg);
+}
+
+bool YesNoBox(char *Msg)
+{
+ if(QMessageBox::information(QAppl->focusWidget(), "RLPlot", Msg,
+ "&Yes", "&No", 0L, 0, -1)) return false;
+ return true;
+}
+
+void Qt_Box()
+{
+ QMessageBox::aboutQt(QAppl->focusWidget(), "RLPlot uses Qt");
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Display blinking text cursor
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+anyOutput *oTxtCur = 0L;
+RECT rTxtCur, rCopyMark;
+bool bTxtCur = false;
+DWORD coTxtCur = 0x0L;
+TxtCurBlink *cTxtCur = 0L;
+POINT ptTxtCurLine[2];
+
+void HideTextCursor()
+{
+ if(oTxtCur) {
+ bTxtCur = false;
+ oTxtCur->UpdateRect(&rTxtCur, false);
+ }
+ oTxtCur = 0L;
+}
+
+void HideTextCursorObj(anyOutput *out)
+{
+ if(oTxtCur && oTxtCur == out) HideTextCursor();
+}
+
+void ShowTextCursor(anyOutput *out, RECT *disp, DWORD color)
+{
+ coTxtCur = color;
+ HideTextCursor();
+ oTxtCur = out;
+ memcpy(&rTxtCur, disp, sizeof(RECT));
+ ptTxtCurLine[0].x = rTxtCur.left; ptTxtCurLine[0].y = rTxtCur.top;
+ ptTxtCurLine[1].x = rTxtCur.right; ptTxtCurLine[1].y = rTxtCur.bottom;
+ rTxtCur.bottom++; rTxtCur.right++;
+ bTxtCur = true;
+ if(cTxtCur) cTxtCur->Show();
+}
+
+void InitTextCursor(bool init)
+{
+ if(init && !cTxtCur) cTxtCur = new TxtCurBlink();
+ else if(!init && cTxtCur) {
+ delete cTxtCur;
+ cTxtCur = 0L;
+ }
+}
+
+void HideCopyMark()
+{
+ if(cTxtCur && cTxtCur->bmCopyMark && cTxtCur->oCopyMark) {
+ cTxtCur->oCopyMark->UpdateRect(&rCopyMark, false);
+ delete cTxtCur->bmCopyMark;
+ }
+ cTxtCur->bmCopyMark = 0L; cTxtCur->oCopyMark = 0L;
+}
+
+void ShowCopyMark(anyOutput *out, RECT *mrk, int nRec)
+{
+ int i;
+
+ if(!out || !mrk || !nRec || !cTxtCur) return;
+ cTxtCur->oCopyMark = out;
+ rCopyMark.left = mrk[0].left; rCopyMark.right = mrk[0].right;
+ rCopyMark.top = mrk[0].top; rCopyMark.bottom = mrk[0].bottom;
+ for(i = 1; i < nRec; i++) {
+ UpdateMinMaxRect(&rCopyMark, mrk[i].left, mrk[i].top);
+ UpdateMinMaxRect(&rCopyMark, mrk[i].right, mrk[i].bottom);
+ }
+ cTxtCur->bmCopyMark = new BitMapQT(rCopyMark.right - rCopyMark.left,
+ rCopyMark.bottom - rCopyMark.top, out->hres, out->vres);
+}
+
+LineDEF liCopyMark1 = {0.0f, 1.0f, 0x00ffffffL, 0L};
+LineDEF liCopyMark2 = {0.0f, 6.0f, 0x0L, 0xf0f0f0f0L};
+
+TxtCurBlink::TxtCurBlink():QObject(MainWidget, 0)
+{
+ isVis = false;
+ oCopyMark = 0L; bmCopyMark = 0L;
+ count = cp_mark = 0;
+ startTimer(60);
+}
+
+void
+TxtCurBlink::Show()
+{
+ count = -4;
+ isVis = true;
+ if(bTxtCur && oTxtCur)oTxtCur->ShowLine(ptTxtCurLine, 2, coTxtCur);
+
+}
+
+void
+TxtCurBlink::showCopyMark()
+{
+ if(bmCopyMark && oCopyMark) {
+ bmCopyMark->CopyBitmap(0, 0, oCopyMark, rCopyMark.left, rCopyMark.top,
+ rCopyMark.right - rCopyMark.left, rCopyMark.bottom - rCopyMark.top, false);
+ bmCopyMark->SetLine(&liCopyMark1);
+ line[0].x = line[1].x = line[4].x = 0;
+ line[0].y = line[3].y = line[4].y = 0;
+ line[1].y = line[2].y = rCopyMark.bottom-rCopyMark.top-1;
+ line[2].x = line[3].x = rCopyMark.right-rCopyMark.left-1;
+ bmCopyMark->oPolyline(line, 5);
+ bmCopyMark->SetLine(&liCopyMark2);
+ bmCopyMark->RLP.finc = 1.0; bmCopyMark->RLP.fp = (cp_mark & 0x7);
+ bmCopyMark->oPolyline(line, 5);
+ oCopyMark->ShowBitmap(rCopyMark.left, rCopyMark.top, bmCopyMark);
+ cp_mark++;
+ if(isVis && oTxtCur && ptTxtCurLine[0].y != ptTxtCurLine[1].y &&
+ oTxtCur == oCopyMark && OverlapRect(&rCopyMark, &rTxtCur)){
+ oTxtCur->ShowLine(ptTxtCurLine, 2, coTxtCur);
+ }
+ }
+}
+
+void
+TxtCurBlink::timerEvent(QTimerEvent *ev)
+{
+ showCopyMark();
+ if(!oTxtCur || (ptTxtCurLine[0].x == ptTxtCurLine[1].x &&
+ ptTxtCurLine[0].y == ptTxtCurLine[1].y)) return;
+ count++;
+ if(count<0) oTxtCur->ShowLine(ptTxtCurLine, 2, coTxtCur);
+ if(count < 8) return;
+ count = 0;
+ if(bTxtCur && oTxtCur) {
+ if(isVis) {
+ oTxtCur->UpdateRect(&rTxtCur, false);
+ isVis = false;
+ }
+ else {
+ oTxtCur->ShowLine(ptTxtCurLine, 2, coTxtCur);
+ isVis = true;
+ }
+ }
+}
+
+#define MIME_KSPREAD "application/x-kspread-snippet"
+#define MIME_RLPLOT "application/x-rlplot-snippet"
+#define MIME_RLPGRAPH "application/x-rlplot-graph"
+#define MIME_RLPOBJ "application/x-rlplot-object"
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Clipboard support
+// based on KDEs KSpread source: kspread_table.cc
+// copyright (C) 1998, 1999 Torben Weis
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+KSpreadTextDrag::KSpreadTextDrag(QWidget *dragSource, const char *name )
+ :QTextDrag(dragSource, name)
+{
+ go = 0L;
+}
+
+KSpreadTextDrag::~KSpreadTextDrag()
+{
+}
+
+bool
+KSpreadTextDrag::provides(const char *mimeType)
+{
+ if(0 == strcmp(mimeType, "text/plain")) return true;
+ if(0 == strcmp(mimeType, MIME_RLPLOT)) return true;
+ if(0 == strcmp(mimeType, selectionMimeType())) return true;
+ return false;
+}
+
+QByteArray
+KSpreadTextDrag::encodedData(const char *mime) const
+{
+ static QByteArray b;
+ char *ptr = 0L;
+ long cb;
+
+ if(!go || go->Id != GO_SPREADDATA) return 0L;
+ if(0 == strcmp(mime, MIME_RLPLOT)) {
+ go->Command(CMD_COPY_XML, &ptr, 0L);
+ }
+ else if(0 == strcmp(mime, "text/plain")) {
+ go->Command(CMD_COPY_TSV, &ptr, 0L);
+ }
+ else if(0 == strcmp(mime, selectionMimeType())){
+ go->Command(CMD_COPY_XML, &ptr, 0L);
+ }
+ else return 0L;
+ if(!ptr) ptr = (char*)calloc(cb = 4, 1);
+ else cb = strlen(ptr)+1;
+ if(ptr && b.resize(cb)) {
+ memcpy(b.data(), ptr, cb);
+ free (ptr);
+ return (b);
+ }
+ return 0L;
+}
+
+bool
+KSpreadTextDrag::canDecode(QMimeSource *e)
+{
+ if(e->provides(selectionMimeType())) return true;
+ return false;
+}
+
+const char *
+KSpreadTextDrag::format(int i) const
+{
+ static const char *fmt;
+
+ switch(i) {
+ case 0: case 1:
+ fmt = "text/plain";
+ return fmt;
+ case 2:
+ case 3: case 4:
+ return selectionMimeType();
+ default:
+ return 0L;
+ }
+}
+
+const char *
+KSpreadTextDrag::selectionMimeType()
+{
+ return(MIME_KSPREAD);
+}
+
+RLPGraphDrag::RLPGraphDrag(QWidget *dragSource, const char *name)
+ :QTextDrag(dragSource, name)
+{
+ go1 = go2 = 0L;
+}
+
+RLPGraphDrag::~RLPGraphDrag()
+{
+}
+
+bool
+RLPGraphDrag::provides(const char *mimeType)
+{
+ if(go1 && 0 == strcmp(mimeType, MIME_RLPGRAPH)) return true;
+ if(go2 && 0 == strcmp(mimeType, MIME_RLPOBJ)) return true;
+ return false;
+}
+
+void
+RLPGraphDrag::setGraphData(GraphObj *g)
+{
+ go1 = g;
+ if(CurrGraph && CurrGraph != g) go2 = CurrGraph;
+ else go2 = 0L;
+}
+
+QByteArray
+RLPGraphDrag::encodedData(const char* mime) const
+{
+ static QByteArray b;
+ char *ptr = 0L;
+ long cb;
+
+ if(0 == strcmp(mime, "text/plain")) return 0L;
+ else if(go1 && 0 == strcmp(mime, MIME_RLPGRAPH)) ptr = GraphToMem(go1, &cb);
+ else if(go2 && 0 == strcmp(mime, MIME_RLPOBJ)) ptr = GraphToMem(go2, &cb);
+ else return 0L;
+ if(ptr && b.resize(cb+1)) {
+ memcpy(b.data(), ptr, cb+1);
+ free (ptr);
+ return (b);
+ }
+ return 0L;
+}
+
+const char*
+RLPGraphDrag::format(int i) const
+{
+ switch(i) {
+ case 0: return("text/plain");
+ case 1: return MIME_RLPGRAPH;
+ case 2: return MIME_RLPOBJ;
+ default: return 0L;
+ }
+}
+
+bool
+RLPGraphDrag::canDecode(QMimeSource *e)
+{
+ if(e->provides(MIME_RLPGRAPH)) return true;
+ if(e->provides(MIME_RLPOBJ)) return true;
+ return false;
+}
+
+const char*
+RLPGraphDrag::selectionMimeType()
+{
+ return(MIME_RLPGRAPH);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Process paste command: check for clipboard contents
+void TestClipboard(GraphObj *g)
+{
+
+ QClipboard *cb;
+ QMimeSource *mime;
+
+ if(!(cb = QAppl->clipboard()))return;
+ if(!(mime = cb->data()))return;
+ if(g->Id == GO_SPREADDATA) {
+ if(mime->provides(MIME_RLPLOT)){
+ QByteArray b = mime->encodedData(MIME_RLPLOT);
+ if(b) g->Command(CMD_PASTE_XML, (void*)b.data(), 0L);
+ return;
+ }
+ else if(mime->provides(MIME_KSPREAD)){
+ QByteArray b = mime->encodedData(MIME_KSPREAD);
+ if(b) g->Command(CMD_PASTE_XML, (void*)b.data(), 0L);
+ return;
+ }
+ else if(QByteArray b = mime->encodedData(MIME_RLPOBJ)){
+ OpenGraph(g, 0L, (unsigned char*)b.data());
+ return;
+ }
+ else if(QByteArray b = mime->encodedData(MIME_RLPGRAPH)){
+ OpenGraph(g, 0L, (unsigned char*)b.data());
+ return;
+ }
+ else if(mime->provides("text/plain")){
+ QString _text = cb->text();
+ ProcMemData(g, (unsigned char*)_text.latin1(), true);
+ return;
+ }
+ }
+ else if(g->Id == GO_PAGE){
+ if(QByteArray b = mime->encodedData(MIME_RLPOBJ)){
+ OpenGraph(g, 0L, (unsigned char*)b.data());
+ return;
+ }
+ else if(QByteArray b = mime->encodedData(MIME_RLPGRAPH)){
+ OpenGraph(g, 0L, (unsigned char*)b.data());
+ return;
+ }
+ }
+ else if(g->Id == GO_GRAPH)TestClipboard(g->parent);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Copy spreadsheet or graph to clipboard
+void CopyData(GraphObj *g)
+{
+ EmptyClip();
+ KSpreadTextDrag *kd = new KSpreadTextDrag(0L);
+ kd->setText(QString("RLPlot snippet"));
+ kd->setSpreadData(g);
+#ifdef Q_CHECK_PTR //n.a. in Qt version 2
+ if(QAppl->clipboard()->supportsSelection())
+ QAppl->clipboard()->setSelectionMode(TRUE);
+#endif
+ QAppl->clipboard()->setData(kd);
+}
+
+void CopyGraph(GraphObj *g)
+{
+ EmptyClip();
+ RLPGraphDrag *gd = new RLPGraphDrag(0L);
+ gd->setText(QString("RLPlot graph"));
+ gd->setGraphData(g);
+ //no support for X11 clipboard possible
+ QAppl->clipboard()->setData(gd);
+}
+
+void EmptyClip()
+{
+ HideCopyMark();
+ QAppl->clipboard()->clear();
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get display (desktop) size
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void GetDesktopSize(int *width, int *height)
+{
+ QWidget *d = QApplication::desktop();
+ *width = d->width();
+ *height = d->height();
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Swap red and blue in RGB value
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+DWORD SwapRB(DWORD col)
+{
+ DWORD nc = col & 0x0000ff00L;
+
+ nc |= (col>>16)&0x000000ffL;
+ nc |= (col<<16)&0x00ff0000L;
+ return nc;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Common code for all QT output classes
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool com_TextOut(int x, int y, char *ctxt, TextDEF *TxtSet, QPainter *qP, anyOutput *o)
+{
+ int i, w, h, ix, iy;
+ QBrush oldBrush;
+ QPen oldPen, currPen;
+ QWMatrix xf, dxf;
+ QString txt(ctxt);
+
+ if(!ctxt || !ctxt[0] || !TxtSet || !qP || !o) return false;
+ if(TxtSet->Font==FONT_GREEK) {
+ txt.truncate(0);
+ for(i = 0; ctxt[i]; i++) {
+ if((ctxt[i] >= 'A' && ctxt[i] <= 'Z')) txt.append(QChar(ctxt[i] - 'A' + 0x391));
+ else if((ctxt[i] >= 'a' && ctxt[i] <= 'z')) txt.append(QChar(ctxt[i] - 'a' + 0x3B1));
+ else txt.append(QChar(ctxt[i]));
+ }
+ }
+ oldBrush = qP->brush(); dxf = qP->worldMatrix();
+ oldPen = currPen = qP->pen();
+ o->oGetTextExtent(ctxt, -1, &w, &h);
+ if(TxtSet->Align & TXA_VCENTER) iy = y + h/3;
+ else if(TxtSet->Align & TXA_VBOTTOM) iy = y;
+ else iy = y + iround(h*.8);
+ if(TxtSet->Align & TXA_HCENTER) ix = x - w/2;
+ else if(TxtSet->Align & TXA_HRIGHT) ix = x - w;
+ else ix = x;
+ currPen.setColor(SwapRB(TxtSet->ColTxt));
+ qP->setPen(currPen);
+ if(fabs(TxtSet->RotBL) >.01 || fabs(TxtSet->RotCHAR) >.01) {
+ xf.translate(x, y);
+ xf.rotate(-TxtSet->RotBL);
+ qP->setWorldMatrix(xf, TRUE);
+ if(TxtSet->Mode == TXM_OPAQUE){
+ currPen.setColor(SwapRB(TxtSet->ColBg));
+ qP->setPen(currPen);
+ qP->setBrush(QColor(SwapRB(TxtSet->ColBg)));
+ qP->drawRect(0, - iround(h*.8), w, h);
+ currPen.setColor(SwapRB(TxtSet->ColTxt));
+ qP->setPen(currPen);
+ }
+ if(TxtSet->Style & TXS_SUB) {
+ if((TxtSet->Align & TXA_VCENTER) == TXA_VCENTER) iy += o->un2iy(TxtSet->fSize*0.4);
+ else if((TxtSet->Align & TXA_VBOTTOM) == TXA_VBOTTOM) iy += o->un2iy(TxtSet->fSize*0.2);
+ else if((TxtSet->Align & TXA_VTOP) == TXA_VTOP) iy += o->un2iy(TxtSet->fSize*.6);
+ }
+ else if(TxtSet->Style & TXS_SUPER) {
+ if((TxtSet->Align & TXA_VCENTER) == TXA_VCENTER) iy -= o->un2iy(TxtSet->fSize*0.4);
+ else if((TxtSet->Align & TXA_VBOTTOM) == TXA_VBOTTOM) iy -= o->un2iy(TxtSet->fSize*0.6);
+ else if((TxtSet->Align & TXA_VTOP) == TXA_VTOP) iy += o->un2iy(TxtSet->fSize*.0);
+ }
+ qP->drawText(ix-x, iy-y, txt, -1);
+ }
+ else {
+ if(TxtSet->Mode == TXM_OPAQUE){
+ currPen.setColor(SwapRB(TxtSet->ColBg));
+ qP->setPen(currPen);
+ qP->setBrush(QColor(SwapRB(TxtSet->ColBg)));
+ qP->drawRect(ix, iy - iround(h*.8), w, h);
+ currPen.setColor(SwapRB(TxtSet->ColTxt));
+ qP->setPen(currPen);
+ }
+ if(TxtSet->Style & TXS_SUB) {
+ if((TxtSet->Align & TXA_VCENTER) == TXA_VCENTER) iy += o->un2iy(TxtSet->fSize*0.4);
+ else if((TxtSet->Align & TXA_VBOTTOM) == TXA_VBOTTOM) iy += o->un2iy(TxtSet->fSize*0.2);
+ else if((TxtSet->Align & TXA_VTOP) == TXA_VTOP) iy += o->un2iy(TxtSet->fSize*.6);
+ }
+ else if(TxtSet->Style & TXS_SUPER) {
+ if((TxtSet->Align & TXA_VCENTER) == TXA_VCENTER) iy -= o->un2iy(TxtSet->fSize*0.4);
+ else if((TxtSet->Align & TXA_VBOTTOM) == TXA_VBOTTOM) iy -= o->un2iy(TxtSet->fSize*0.6);
+ else if((TxtSet->Align & TXA_VTOP) == TXA_VTOP) iy += o->un2iy(TxtSet->fSize*.0);
+ }
+ qP->drawText(ix, iy, txt, -1);
+ }
+ qP->setPen(oldPen);
+ qP->setBrush(oldBrush);
+ qP->setWorldMatrix(dxf, FALSE);
+ return true;
+}
+
+bool com_SetTextSpec(TextDEF *set, TextDEF *TxtSet, anyOutput *o, QFont qF, QPainter *qP)
+{
+ bool IsModified, RetVal;
+
+ if(!set->iSize && set->fSize > 0.0) set->iSize = o->un2iy(set->fSize);
+ if(!set->iSize) return false;
+ if(TxtSet->iSize != set->iSize || TxtSet->Style != set->Style ||
+ TxtSet->RotBL != set->RotBL || TxtSet->RotCHAR != set->RotCHAR ||
+ TxtSet->Font != set->Font || TxtSet->Mode != set->Mode)
+ IsModified = true;
+ else IsModified = false;
+ RetVal = o->anyOutput::SetTextSpec(set);
+ if(IsModified) {
+ qF.setBold((TxtSet->Style & TXS_BOLD) ? true : false);
+ qF.setItalic((TxtSet->Style & TXS_ITALIC) ? true : false);
+ qF.setUnderline((TxtSet->Style &TXS_UNDERLINE) ? true : false);
+ if((TxtSet->Style & TXS_SUPER) || (TxtSet->Style & TXS_SUB))
+ qF.setPointSize(o->un2iy(set->fSize*0.71));
+ else qF.setPointSize((TxtSet->iSize > 8) ? TxtSet->iSize : 8);
+ switch(TxtSet->Font){
+ case FONT_HELVETICA:
+ default: qF.setFamily("Helvetica"); break;
+ case FONT_GREEK:
+ case FONT_TIMES: qF.setFamily("Times"); break;
+ case FONT_COURIER: qF.setFamily("Courier"); break;
+ }
+ qP->setFont(qF);
+ }
+ return RetVal;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Icon definitions
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//this icon has been taken from trolltech's Qt: qmessagebox.cpp
+static char *information_xpm[]={
+"32 32 5 1",
+". c None",
+"c c #000000",
+"* c #999999",
+"a c #ffffff",
+"b c #0000ff",
+"...........********.............",
+"........***aaaaaaaa***..........",
+"......**aaaaaaaaaaaaaa**........",
+".....*aaaaaaaaaaaaaaaaaa*.......",
+"....*aaaaaaaabbbbaaaaaaaac......",
+"...*aaaaaaaabbbbbbaaaaaaaac.....",
+"..*aaaaaaaaabbbbbbaaaaaaaaac....",
+".*aaaaaaaaaaabbbbaaaaaaaaaaac...",
+".*aaaaaaaaaaaaaaaaaaaaaaaaaac*..",
+"*aaaaaaaaaaaaaaaaaaaaaaaaaaaac*.",
+"*aaaaaaaaaabbbbbbbaaaaaaaaaaac*.",
+"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
+"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
+"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
+"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
+"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
+".*aaaaaaaaaaabbbbbaaaaaaaaaac***",
+".*aaaaaaaaaaabbbbbaaaaaaaaaac***",
+"..*aaaaaaaaaabbbbbaaaaaaaaac***.",
+"...caaaaaaabbbbbbbbbaaaaaac****.",
+"....caaaaaaaaaaaaaaaaaaaac****..",
+".....caaaaaaaaaaaaaaaaaac****...",
+"......ccaaaaaaaaaaaaaacc****....",
+".......*cccaaaaaaaaccc*****.....",
+"........***cccaaaac*******......",
+"..........****caaac*****........",
+".............*caaac**...........",
+"...............caac**...........",
+"................cac**...........",
+".................cc**...........",
+"..................***...........",
+"...................**..........."};
+
+//this icon has been taken from trolltech's Qt: qmessagebox.cpp
+static char *critical_xpm[]={
+"32 32 4 1",
+". c None",
+"a c #999999",
+"* c #ff0000",
+"b c #ffffff",
+"...........********.............",
+".........************...........",
+".......****************.........",
+"......******************........",
+".....********************a......",
+"....**********************a.....",
+"...************************a....",
+"..*******b**********b*******a...",
+"..******bbb********bbb******a...",
+".******bbbbb******bbbbb******a..",
+".*******bbbbb****bbbbb*******a..",
+"*********bbbbb**bbbbb*********a.",
+"**********bbbbbbbbbb**********a.",
+"***********bbbbbbbb***********aa",
+"************bbbbbb************aa",
+"************bbbbbb************aa",
+"***********bbbbbbbb***********aa",
+"**********bbbbbbbbbb**********aa",
+"*********bbbbb**bbbbb*********aa",
+".*******bbbbb****bbbbb*******aa.",
+".******bbbbb******bbbbb******aa.",
+"..******bbb********bbb******aaa.",
+"..*******b**********b*******aa..",
+"...************************aaa..",
+"....**********************aaa...",
+"....a********************aaa....",
+".....a******************aaa.....",
+"......a****************aaa......",
+".......aa************aaaa.......",
+".........aa********aaaaa........",
+"...........aaaaaaaaaaa..........",
+".............aaaaaaa............"};
+
+static char *RLPlot_xpm[]={
+"32 32 12 1",
+"j c #000083",
+"i c #0000ff",
+"d c #008100",
+"e c #00ff00",
+"b c #00ffff",
+"g c #830000",
+"c c #838100",
+"a c #838183",
+". c #c5c2c5",
+"h c #ff0000",
+"f c #ffff00",
+"# c #ffffff",
+".##a###a##bbbbbbbbbbbbbbbbbbbbbb",
+"##a###a###bbbbbbbbbbbbbbbbbbbbbb",
+"#a###a#.#a.b.b.b.b.b.b.b.b.b.b.b",
+"a#.#a#.#a#bbbbbbbbbbbbbbbbbbbbbb",
+"###a##.cccbbbbbbbbbbbbbdddbbbbbb",
+".#a###a#c#bbbbbbbbbbbbbbdbbbbbbb",
+"#a#.#a#.c.b.b.b.b.b.b.b.d.b.b.b.",
+"a###a###c#bbbbbbbbbbbdddddddbbbb",
+"#.#a#.#ac#bbbbbbbbbbbdeedeedbbbb",
+".#a.#cccccccbbbbbbbbbdeedeedbbbb",
+"#a###cffcffc.b.ggg.b.deddded.b.b",
+"a###acffcffcbbbbgbbbbdeeeeedbbbb",
+"..#a.cffcffcbbbbgbbbbdeeeeedbbbb",
+"##a##cffcffcbgggggggbdeeeeedbbbb",
+"#a#.#cfcccfcbghhghhgbdeeeeedb.b.",
+"a###acfffffcbghhghhgbdeeeeedbbbb",
+"#.#a#cfffffcbghggghgbdeeeeedbbbb",
+".#a.#cfffffcbghhhhhgbdeeeeedbbbb",
+"#a###cfffffcbghhhhhg.deeeeed.b.b",
+"a#.#acfffffcbghhhhhgbdeeeeedbbbb",
+"###a#cfffffcbghhhhhgbdeeeeedbbbb",
+".#a#.cfffffcighhhhhgideeeeediiii",
+"#a.##cfffffcighhhhhgideeeeedjiij",
+"a###acccccccigggggggidddddddiiii",
+"#.#a###ijiiijiiijiiijiiijiiiijii",
+".#a#.#ijijjiijiiijiiijiiijiiiiii",
+"#a###ijjiiijiijiijjijiijiijiijii",
+"a##.iijiijijjiijjiiijjijjiijjiij",
+".##jijiijjjiijjjiijjjiijjjiijjji",
+"##jjijijiijjjjijjjjijjjjijjjjijj",
+".jjjjjijjjjjijjjjijjjijjjjjjjjij",
+"jjijjjjjjjjjjjjijjjjjjjjjjijjjjj"};
+
+//this icon has been taken from trolltech's Qt: qmessagebox.cpp
+static char *qtlogo_xpm[] = {
+/* width height ncolors chars_per_pixel */
+"50 50 17 1",
+/* colors */
+" c #000000",
+". c #495808",
+"X c #2A3304",
+"o c #242B04",
+"O c #030401",
+"+ c #9EC011",
+"@ c #93B310",
+"# c #748E0C",
+"$ c #A2C511",
+"% c #8BA90E",
+"& c #99BA10",
+"* c #060701",
+"= c #181D02",
+"- c #212804",
+"; c #61770A",
+": c #0B0D01",
+"/ c None",
+/* pixels */
+"/$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$/",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$+++$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$@;.o=::=o.;@$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$+#X* **X#+$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$#oO* O **o#+$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$&.* OO O*.&$$$$$$$$$$$$$",
+"$$$$$$$$$$$$@XOO * OO X&$$$$$$$$$$$$",
+"$$$$$$$$$$$@XO OO O **:::OOO OOO X@$$$$$$$$$$$",
+"$$$$$$$$$$&XO O-;#@++@%.oOO X&$$$$$$$$$$",
+"$$$$$$$$$$.O : *-#+$$$$$$$$+#- : O O*.$$$$$$$$$$",
+"$$$$$$$$$#*OO O*.&$$$$$$$$$$$$+.OOOO **#$$$$$$$$$",
+"$$$$$$$$+-OO O *;$$$$$$$$$$$&$$$$;* o+$$$$$$$$",
+"$$$$$$$$#O* O .+$$$$$$$$$$@X;$$$+.O *#$$$$$$$$",
+"$$$$$$$$X* -&$$$$$$$$$$@- :;$$$&- OX$$$$$$$$",
+"$$$$$$$@*O *O#$$$$$$$$$$@oOO**;$$$# O*%$$$$$$$",
+"$$$$$$$; -+$$$$$$$$$@o O OO ;+$$-O *;$$$$$$$",
+"$$$$$$$. ;$$$$$$$$$@-OO OO X&$$;O .$$$$$$$",
+"$$$$$$$o *#$$$$$$$$@o O O O-@$$$#O *o$$$$$$$",
+"$$$$$$+= *@$$$$$$$@o* OO -@$$$$&: =$$$$$$$",
+"$$$$$$+: :+$$$$$$@- *-@$$$$$$: :+$$$$$$",
+"$$$$$$+: :+$$$$$@o* O *-@$$$$$$: :+$$$$$$",
+"$$$$$$$= :@$$$$@o*OOO -@$$$$@: =+$$$$$$",
+"$$$$$$$- O%$$$@o* O O O O-@$$$#* OX$$$$$$$",
+"$$$$$$$. O *O;$$&o O*O* *O -@$$; O.$$$$$$$",
+"$$$$$$$;* Oo+$$;O*O:OO-- Oo at += *;$$$$$$$",
+"$$$$$$$@* O O#$$$;*OOOo@@-O Oo;O* **@$$$$$$$",
+"$$$$$$$$X* OOO-+$$$;O o@$$@- O O OX$$$$$$$$",
+"$$$$$$$$#* * O.$$$$;X@$$$$@-O O O#$$$$$$$$",
+"$$$$$$$$+oO O OO.+$$+&$$$$$$@-O o+$$$$$$$$",
+"$$$$$$$$$#* **.&$$$$$$$$$$@o OO:#$$$$$$$$$",
+"$$$$$$$$$+. O* O-#+$$$$$$$$+;O OOO:@$$$$$$$$$",
+"$$$$$$$$$$&X *O -;#@++@#;=O O -@$$$$$$$$",
+"$$$$$$$$$$$&X O O*O::::O OO Oo@$$$$$$$",
+"$$$$$$$$$$$$@XOO OO O*X+$$$$$$",
+"$$$$$$$$$$$$$&.* ** O :: *:#$$$$$$$",
+"$$$$$$$$$$$$$$$#o*OO O Oo#@-OOO=#$$$$$$$$",
+"$$$$$$$$$$$$$$$$+#X:* * O**X#+$$@-*:#$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$%;.o=::=o.#@$$$$$$@X#$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$+++$$$$$$$$$$$+$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+"/$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$/"};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Bitmap class for display export etc.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+BitMapQT::BitMapQT(GraphObj *g, QWidget *wi, int vr, int hr):anyOutput()
+{
+ int w, h;
+
+ hres = (double)hr; vres = (double)vr;
+ image = 0L;
+ hgo = 0L;
+ if(wi) {
+ w = wi->width(); h = wi->height();
+ }
+ else {
+ GetDesktopSize(&w, &h);
+ }
+ Box1.Xmin = Box1.Ymin = 0.0;
+ Box1.Xmax = w; Box1.Ymax = h;
+ DeskRect.left = DeskRect.top = 0;
+ GetDesktopSize(&w, &h);
+ DeskRect.right = w; DeskRect.bottom = h;
+ mempic = new QPixmap(w, h);
+ mempic->fill(0x00ffffffL);
+ qPainter.begin(mempic);
+ qPen.setCapStyle(Qt::RoundCap);
+ qPainter.setPen(qPen);
+ qFont = qPainter.font();
+}
+
+BitMapQT::BitMapQT(int w, int h, double hr, double vr):anyOutput()
+{
+ hres = hr; vres = vr;
+ image = 0L;
+ hgo = 0L;
+ Box1.Xmin = Box1.Ymin = 0.0;
+ Box1.Xmax = w; Box1.Ymax = h;
+ DeskRect.right = w; DeskRect.bottom = h;
+ DeskRect.left = DeskRect.top = 0;
+ mempic = new QPixmap(w, h);
+ mempic->fill(0x00ffffffL);
+ qPainter.begin(mempic);
+ qPen.setCapStyle(Qt::RoundCap);
+ qPainter.setPen(qPen);
+ qFont = qPainter.font();
+}
+
+BitMapQT::~BitMapQT()
+{
+ Undo.KillDisp(this);
+ if(qPainter.isActive()) qPainter.end();
+ HideTextCursorObj(this);
+ if(mempic) delete mempic;
+ if(hgo) delete hgo;
+ if(image) delete image;
+ mempic = 0L; hgo = 0L; image = 0L;
+}
+
+bool
+BitMapQT::SetLine(LineDEF *lDef)
+{
+ int iw;
+
+ if(lDef->width != LineWidth || lDef->width != LineWidth ||
+ lDef->pattern != dPattern || lDef->color != dLineCol) {
+ LineWidth = lDef->width;
+ iw = iround(un2ix(lDef->width));
+ dPattern = lDef->pattern;
+ RLP.finc = 256.0/un2fix(lDef->patlength*8.0);
+ RLP.fp = 0.0;
+ if(iLine == iw && dLineCol == lDef->color) return true;
+ iLine = iw;
+ dLineCol = lDef->color;
+ qPen.setColor(SwapRB(dLineCol));
+ qPen.setWidth(iw);
+ qPen.setStyle(Qt::SolidLine);
+ qPen.setCapStyle(Qt::RoundCap);
+ qPen.setJoinStyle(Qt::RoundJoin);
+ qPainter.setPen(qPen);
+ }
+ return true;
+}
+
+bool
+BitMapQT::SetFill(FillDEF *fill)
+{
+ if(!fill) return false;
+ if((fill->type & 0xff) != FILL_NONE) {
+ if(!hgo) hgo = new HatchOut(this);
+ if(hgo) hgo->SetFill(fill);
+ }
+ else {
+ if(hgo) delete hgo;
+ hgo = 0L;
+ }
+ qPainter.setBrush(QColor(SwapRB(fill->color)));
+ dFillCol = fill->color;
+ dFillCol2 = fill->color2;
+ return true;
+}
+
+bool
+BitMapQT::SetTextSpec(TextDEF *set)
+{
+ return com_SetTextSpec(set, &TxtSet, this, qFont, &qPainter);
+}
+
+bool
+BitMapQT::Erase(DWORD color)
+{
+ if(!mempic) return false;
+ mempic->fill(color);
+ if(image) delete image;
+ image = 0L;
+ return true;
+}
+
+bool
+BitMapQT::CopyBitmap(int x, int y, anyOutput* sr, int sx, int sy,
+ int sw, int sh, bool invert)
+{
+ BitMapQT *src = (BitMapQT*)sr;
+
+ if(!mempic) return false;
+ bitBlt(mempic, x, y, src->mempic, sx, sy, sw, sh,
+ invert ? Qt::NotCopyROP : Qt::CopyROP);
+ return true;
+
+
+}
+
+bool
+BitMapQT::oGetTextExtent(char *text, int cb, int *width, int *height)
+{
+ if(!text) return false;
+ QRect rc = qPainter.boundingRect(0, 0, 10000, 1000, Qt::AlignLeft | Qt::AlignTop,
+ text, cb > 0 ? cb : strlen(text));
+ *width = rc.rRight() - rc.rLeft(); *height = rc.rBottom() - rc.rTop();
+ return true;
+}
+
+bool
+BitMapQT::oGetPix(int x, int y, DWORD *col)
+{
+ DWORD pix;
+
+ if(!image && !(image = new QImage(mempic->convertToImage())))return false;
+ if(x >= DeskRect.left && x < DeskRect.right &&
+ y >= DeskRect.top && y < DeskRect.bottom){
+ pix = SwapRB(image->pixel(x, y));
+ *col = pix;
+ return true;
+ }
+ return false;
+}
+
+bool
+BitMapQT::oDrawIcon(int type, int x, int y)
+{
+ char** xpm_data;
+ QPixmap pm;
+
+ switch (type) {
+ case ICO_INFO:
+ xpm_data = information_xpm;
+ break;
+ case ICO_ERROR:
+ xpm_data = critical_xpm;
+ break;
+ case ICO_RLPLOT:
+ xpm_data = RLPlot_xpm;
+ break;
+ case ICO_QT:
+ xpm_data = qtlogo_xpm;
+ break;
+ default:
+ return false;
+ }
+ if (xpm_data) {
+ QImage image((const char **)xpm_data);
+ pm.convertFromImage(image);
+ bitBlt(mempic, x, y, &pm, 0, 0, -1, -1, Qt::CopyROP);
+ return true;
+ }
+ return false;
+}
+
+bool
+BitMapQT::oCircle(int x1, int y1, int x2, int y2, char* nam)
+{
+ qPainter.drawEllipse(x1, y1, x2-x1, y2-y1);
+ if(hgo) return hgo->oCircle(x1, y1, x2, y2);
+ return true;
+}
+
+bool
+BitMapQT::oPolyline(POINT * pts, int cp, char *nam)
+{
+ int i;
+
+ if(cp < 1) return false;
+ if (dPattern) {
+ for (i = 1; i < cp; i++) PatLine(pts[i-1], pts[i]);
+ }
+ else {
+ qPainter.moveTo(pts[0].x, pts[0].y);
+ for (i = 1; i < cp; i++) qPainter.lineTo(pts[i].x, pts[i].y);
+ }
+ return true;
+}
+
+bool
+BitMapQT::oRectangle(int x1, int y1, int x2, int y2, char *nam)
+{
+ qPainter.drawRect(x1, y1, x2-x1, y2-y1);
+ if(hgo) hgo->oRectangle(x1, y1, x2, y2, 0L);
+ return true;
+}
+
+bool
+BitMapQT::oSolidLine(POINT *p)
+{
+ qPainter.drawLine(p[0].x, p[0].y, p[1].x, p[1].y);
+ return true;
+}
+
+bool
+BitMapQT::oTextOut(int x, int y, char *txt, int cb)
+{
+ return com_TextOut(x, y, txt, &TxtSet, &qPainter, this);
+}
+
+bool
+BitMapQT::oPolygon(POINT *pts, int cp, char *nam)
+{
+ int i;
+
+ QPointArray *a;
+
+ if(!pts || cp <2) return false;
+ a = new QPointArray(cp);
+ if (a) {
+ for(i = 0; i < cp; i++) a->setPoint(i, pts[i].x, pts[i].y);
+ qPainter.drawPolygon(*a);
+ delete a;
+ }
+ if(hgo) hgo->oPolygon(pts, cp);
+}
+
+bool
+BitMapQT::oArc(int x1, int y1, int x2, int y2, int quads)
+{
+ int i, j;
+
+ if(x1 > x2) Swap(x1, x2); if(y1 > y2) Swap(y1, y2);
+ switch(quads) {
+ case 1: i = 270*16; j = 90*16; break;
+ case 2: i = 180*16; j = 180*16; break;
+ case 3: i = 90*16; j = 270*16; break;
+ case 4: i = 0; j = 360*16; break;
+ default: return false;
+ }
+ qPainter.drawArc(x1, y1, x2-x1, y2-y1, i, j);
+ return true;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// The display output class
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+OutputQT::OutputQT(GraphObj *g):BitMapQT(g, 0L)
+{
+ int w, h;
+ RLPwidget *rw;
+
+ HScroll = VScroll = 0L;
+ CreateNewWindow(BaseObj = g);
+ if(rw = (RLPwidget*)widget) {
+ rw->move(CurrWidgetPos.x+50, CurrWidgetPos.y+50);
+ rw->show();
+ rw->mempic = mempic;
+ rw->setBackgroundMode(QWidget::NoBackground);
+ }
+}
+
+OutputQT::OutputQT(DlgWidget *wi):BitMapQT(0L, wi)
+{
+ //assume fixed size (dialog) widget
+ widget = wi;
+ HScroll = VScroll = 0L;
+ BaseObj = 0L;
+ wi->OutputClass = this;
+ wi->mempic = mempic;
+ wi->setBackgroundMode(QWidget::NoBackground);
+ xAxis.flags = 0L;
+ yAxis.flags = AXIS_INVERT; //drawing origin upper left corner
+}
+
+OutputQT::~OutputQT()
+{
+ if(BaseObj) {
+ BaseObj->Command(CMD_CAN_DELETE, 0L, 0L);
+ }
+ if(qPainter.isActive()) qPainter.end();
+ if(widget) delete widget; widget = 0L;
+ HideTextCursorObj(this);
+ if(mempic) delete mempic; mempic = 0L;
+ if(hgo) delete hgo; hgo = 0L;
+ if(image) delete image; image = 0L;
+}
+
+bool
+OutputQT::ActualSize(RECT *rc)
+{
+ if(rc) {
+ rc->left = rc->top = 0;
+ rc->bottom = widget->height() - MenuHeight-6;
+ rc->right = widget->width();
+ return true;
+ }
+ return false;
+}
+
+void
+OutputQT::Caption(char *txt)
+{
+ QString cap(txt);
+ widget->setCaption(cap);
+}
+
+unsigned char hand_bits[] = { //hand cursor bitmap
+ 0x80, 0x01, 0x58, 0x0e, 0x64, 0x12, 0x64, 0x52,
+ 0x48, 0xb2, 0x48, 0x92, 0x16, 0x90, 0x19, 0x80,
+ 0x11, 0x40, 0x02, 0x40, 0x02, 0x40, 0x04, 0x20,
+ 0x08, 0x20, 0x10, 0x10, 0x20, 0x10, 0x20, 0x10};
+
+unsigned char hand_mask[] = { //hand cursor mask
+ 0x80, 0x01, 0xd8, 0x0f, 0xfc, 0x1f, 0xfc, 0x5f,
+ 0xf8, 0xbf, 0xf8, 0xff, 0xfe, 0xff, 0xff, 0xff,
+ 0xff, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfc, 0x3f,
+ 0xf8, 0x3f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0, 0x1f};
+
+unsigned char zoom_bits[] = { //zoom cursor bitmap
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x60, 0x0a,
+ 0x10, 0x10, 0x08, 0x21, 0x08, 0x21, 0x04, 0x40,
+ 0x64, 0x4c, 0x04, 0x40, 0x08, 0x21, 0x08, 0x21,
+ 0x10, 0x10, 0x60, 0x0a, 0x80, 0x03, 0x00, 0x00};
+
+unsigned char zoom_mask[] = { //zoom cursor mask
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0xe0, 0x0f,
+ 0xf0, 0x1f, 0xf8, 0x3f, 0xf8, 0x3f, 0xf4, 0x7e,
+ 0x7c, 0x7c, 0xfc, 0x7e, 0xf8, 0x3f, 0xf8, 0x3f,
+ 0xf0, 0x1f, 0xe0, 0x0f, 0x80, 0x03, 0x00, 0x00};
+
+void
+OutputQT::MouseCursor(int cid, bool force)
+{
+ if(cid == cCursor && !force) return;
+ if(cid == MC_LAST) cid = cCursor;
+ QBitmap cb(16, 16, hand_bits, TRUE); QBitmap cm(16, 16, hand_mask, TRUE);
+ QBitmap zb(16, 16, zoom_bits, TRUE); QBitmap zm(16, 16, zoom_mask, TRUE);
+ switch(cid) {
+#ifdef Q_CHECK_PTR //Qt version 3
+ case MC_ARROW: widget->setCursor(QCursor(Qt::ArrowCursor)); break;
+ case MC_CROSS: widget->setCursor(QCursor(Qt::CrossCursor)); break;
+ case MC_WAIT: widget->setCursor(QCursor(Qt::WaitCursor)); break;
+ case MC_TEXT: widget->setCursor(QCursor(Qt::IbeamCursor)); break;
+ case MC_NORTH: widget->setCursor(QCursor(Qt::SizeVerCursor)); break;
+ case MC_NE: widget->setCursor(QCursor(Qt::SizeBDiagCursor));break;
+ case MC_EAST: widget->setCursor(QCursor(Qt::SizeHorCursor)); break;
+ case MC_SE: widget->setCursor(QCursor(Qt::SizeFDiagCursor));break;
+ case MC_SALL: widget->setCursor(QCursor(Qt::SizeAllCursor)); break;
+#else //Qt version 2
+ case MC_ARROW: widget->setCursor(QCursor(ArrowCursor)); break;
+ case MC_CROSS: widget->setCursor(QCursor(CrossCursor)); break;
+ case MC_WAIT: widget->setCursor(QCursor(WaitCursor)); break;
+ case MC_TEXT: widget->setCursor(QCursor(IbeamCursor)); break;
+ case MC_NORTH: widget->setCursor(QCursor(SizeVerCursor)); break;
+ case MC_NE: widget->setCursor(QCursor(SizeBDiagCursor));break;
+ case MC_EAST: widget->setCursor(QCursor(SizeHorCursor)); break;
+ case MC_SE: widget->setCursor(QCursor(SizeFDiagCursor));break;
+ case MC_SALL: widget->setCursor(QCursor(SizeAllCursor)); break;
+#endif
+ case MC_MOVE:
+ widget->setCursor(QCursor(cb, cm));
+ break;
+ case MC_ZOOM:
+ widget->setCursor(QCursor(zb, zm));
+ break;
+ default: return;
+ }
+ cCursor = cid;
+}
+
+bool
+OutputQT::SetScroll(bool isVert, int iMin, int iMax, int iPSize, int iPos)
+{
+ QScrollBar *sb;
+
+ if(isVert) {
+ if(!(sb = VScroll))return false;
+ }
+ else if(!(sb = HScroll)) return false;
+ if(iPos < sb->minValue()) return false;
+ sb->setRange(iMin, iMax);
+ sb->setPageStep(iPSize);
+ if(BaseObj && BaseObj->Id == GO_GRAPH) sb->setLineStep(8);
+ else sb->setLineStep(1);
+ sb->setValue(iPos);
+ return true;
+}
+
+bool
+OutputQT::EndPage()
+{
+ if(widget)widget->repaint();
+ return true;
+}
+
+bool
+OutputQT::UpdateRect(RECT *rc, bool invert)
+{
+ int x1, x2, y1, y2;
+
+ if(!widget || !mempic)return false;
+ if(rc->right > rc->left) {
+ x1 = rc->left; x2 = rc->right;
+ }
+ else {
+ x1 = rc->right; x2 = rc->left;
+ }
+ if(rc->bottom > rc->top) {
+ y1 = rc->top; y2 = rc->bottom;
+ }
+ else {
+ y1 = rc->bottom; y2 = rc->top;
+ }
+ bitBlt(widget, x1, y1, mempic, x1, y1,
+ x2 - x1, y2 - y1, invert ? Qt::NotCopyROP : Qt::CopyROP);
+ return true;
+}
+
+void
+OutputQT::ShowBitmap(int x, int y, anyOutput* src)
+{
+ BitMapQT *sr;
+ RECT *rc;
+
+ if(!widget || !mempic || !src)return;
+ sr = (BitMapQT*) src; rc = &sr->DeskRect;
+ bitBlt(widget, x, y, sr->mempic, 0, 0, abs(rc->right-rc->left),
+ abs(rc->bottom-rc->top), Qt::CopyROP);
+}
+
+void
+OutputQT::ShowLine(POINT * pts, int cp, DWORD color)
+{
+ int i;
+ QPen qp;
+ QPainter paint(widget);
+
+ qp.setColor(SwapRB(color));
+ qp.setWidth(1);
+ qp.setStyle(Qt::SolidLine);
+ paint.setPen(qp);
+ paint.moveTo(pts[0].x, pts[0].y);
+ for (i = 1; i < cp; i++) paint.lineTo(pts[i].x, pts[i].y);
+ paint.flush();
+}
+
+void
+OutputQT::ShowEllipse(POINT p1, POINT p2, DWORD color)
+{
+ int i;
+ QPen qp;
+ QPainter paint(widget);
+
+ qp.setColor(SwapRB(color));
+ qp.setWidth(1);
+ qp.setStyle(Qt::SolidLine);
+ paint.setPen(qp);
+ paint.drawArc(p1.x, p1.y, p2.x-p1.x, p2.y-p1.y, 0, 5760);
+ paint.flush();
+}
+
+bool
+OutputQT::SetMenu(int type)
+{
+ if(type == MENU_SPREAD){
+ QPopupMenu *file = new QPopupMenu(widget);
+ file->insertItem("&Open", widget, SLOT(cmOpen()));
+ file->insertItem("Save &as", widget, SLOT(cmSaveDataAs()));
+ file->insertSeparator();
+ file->insertItem("&Print", widget, SLOT(cmPrint()));
+ file->insertSeparator();
+ file->insertItem("E&xit", widget, SLOT(cmExit()));
+ file->insertSeparator();
+ file->insertItem("n.a.", widget, SLOT(cmFile1()), 0, CM_FILE1);
+ file->insertItem("n.a.", widget, SLOT(cmFile2()), 0, CM_FILE2);
+ file->insertItem("n.a.", widget, SLOT(cmFile3()), 0, CM_FILE3);
+ file->insertItem("n.a.", widget, SLOT(cmFile4()), 0, CM_FILE4);
+ file->insertItem("n.a.", widget, SLOT(cmFile5()), 0, CM_FILE5);
+ file->insertItem("n.a.", widget, SLOT(cmFile6()), 0, CM_FILE6);
+
+ QPopupMenu *edit = new QPopupMenu(widget);
+ edit->insertItem("&Undo", widget, SLOT(cmUndo()), Qt::CTRL + Qt::Key_Z);
+ edit->insertSeparator();
+ edit->insertItem("&Rows/Cols", widget, SLOT(cmAddRowCol()));
+ edit->insertSeparator();
+ edit->insertItem("&Copy", widget, SLOT(cmCopy()), Qt::CTRL + Qt::Key_C);
+ edit->insertItem("C&ut", widget, SLOT(cmCut()), Qt::CTRL + Qt::Key_X);
+ edit->insertItem("&Paste", widget, SLOT(cmPaste()), Qt::CTRL + Qt::Key_V);
+ edit->insertSeparator();
+ edit->insertItem("&Fill Range", widget, SLOT(cmFillRange()));
+
+ QPopupMenu *graph = new QPopupMenu(widget);
+ graph->insertItem("Create &Graph", widget, SLOT(cmNewGraph()));
+ graph->insertItem("Create &Page", widget, SLOT(cmNewPage()));
+ graph->insertItem("&Flush Graph(s)", widget, SLOT(cmDelGraph()));
+ graph->insertSeparator();
+ graph->insertItem("&Settings", widget, SLOT(cmDefaults()));
+
+ QPopupMenu *about = new QPopupMenu(widget);
+ about->insertItem("&About ...", widget, SLOT(cmAbout()));
+
+ menu = new QMenuBar(widget);
+ menu->insertItem("&File", file); menu->insertItem("&Edit", edit);
+ menu->insertItem("&Graph", graph); menu->insertItem("&?", about);
+#ifdef Q_CHECK_PTR //Qt version 3, n.a. in version 2
+ menu->setItemVisible(CM_FILE1, false); menu->setItemVisible(CM_FILE2, false);
+ menu->setItemVisible(CM_FILE3, false); menu->setItemVisible(CM_FILE4, false);
+ menu->setItemVisible(CM_FILE5, false); menu->setItemVisible(CM_FILE6, false);
+#endif
+ }
+ else if(type == MENU_GRAPH) {
+ QPopupMenu *file = new QPopupMenu(widget);
+ file->insertItem("&Open", widget, SLOT(cmOpen()));
+ file->insertItem("Save &as", widget, SLOT(cmSaveGraphAs()));
+ file->insertItem("&Copy", widget, SLOT(cmCopyGraph()));
+ file->insertSeparator();
+ file->insertItem("&Print", widget, SLOT(cmPrint()));
+ file->insertItem("&Export", widget, SLOT(cmExport()));
+ file->insertSeparator();
+ file->insertItem(widget == MainWidget ? "E&xit" : "&Close", widget, SLOT(cmExit()));
+
+ QPopupMenu *edit = new QPopupMenu(widget);
+ edit->insertItem("&Undo", widget, SLOT(cmUndo()), Qt::CTRL + Qt::Key_Z);
+ edit->insertSeparator();
+ edit->insertItem("&Copy", widget, SLOT(cmCopyGraph()), Qt::CTRL + Qt::Key_C);
+ edit->insertItem("&Paste", widget, SLOT(cmPaste()), Qt::CTRL + Qt::Key_V);
+ edit->insertSeparator();
+ edit->insertItem("&UpdateValues", widget, SLOT(cmUpdate()));
+ edit->insertSeparator();
+ edit->insertItem("&Delete Object", widget, SLOT(cmDelObj()));
+
+ QPopupMenu *zoom = new QPopupMenu(widget);
+ zoom->insertTearOffHandle();
+ zoom->insertItem("zoom &in", widget, SLOT(cmZoomIn()), Qt::CTRL + Qt::Key_Plus);
+ zoom->insertItem("zoom &out", widget, SLOT(cmZoomOut()), Qt::CTRL + Qt::Key_Minus);
+ zoom->insertItem("&fit to widget", widget, SLOT(cmZoomFit()), Qt::CTRL + Qt::Key_F);
+ zoom->insertSeparator();
+ zoom->insertItem("25%", widget, SLOT(cmZoom25()));
+ zoom->insertItem("50%", widget, SLOT(cmZoom50()));
+ zoom->insertItem("100%", widget, SLOT(cmZoom100()));
+ zoom->insertItem("200%", widget, SLOT(cmZoom200()));
+ zoom->insertItem("400%", widget, SLOT(cmZoom400()));
+
+ QPopupMenu *displ = new QPopupMenu(widget);
+ displ->insertItem("&Redraw", widget, SLOT(cmRedraw()));
+ displ->insertItem("&Zoom", zoom);
+ displ->insertItem("&Layers", widget, SLOT(cmLayers()));
+
+ QPopupMenu *tools = new QPopupMenu(widget);
+ tools->insertTearOffHandle();
+ tools->insertItem("&Standard", widget, SLOT(cmtStandard()), Qt::Key_Escape, CM_T_STANDARD);
+ tools->insertSeparator();
+ tools->insertItem("&Draw", widget, SLOT(cmtDraw()), 0, CM_T_DRAW);
+ tools->insertItem("Poly&line", widget, SLOT(cmtPolyline()), 0, CM_T_POLYLINE);
+ tools->insertItem("Poly&gon", widget, SLOT(cmtPolygon()), 0, CM_T_POLYGON);
+ tools->insertItem("&Rectangle", widget, SLOT(cmtRectangle()), 0, CM_T_RECTANGLE);
+ tools->insertItem("&r&ound Rect.", widget, SLOT(cmtRoundrect()), 0, CM_T_ROUNDREC);
+ tools->insertItem("&Ellipse", widget, SLOT(cmtEllipse()), 0, CM_T_ELLIPSE);
+ tools->insertItem("&Arrow", widget, SLOT(cmtArrow()), 0, CM_T_ARROW);
+ tools->insertItem("&Text", widget, SLOT(cmtText()), 0, CM_T_TEXT);
+ tools->setCheckable(true);
+
+ QPopupMenu *plots = new QPopupMenu(widget);
+ plots->insertItem("Add &Plot", widget, SLOT(cmAddPlot()));
+ plots->insertItem("Add &Axis", widget, SLOT(cmAddAxis()));
+ plots->insertItem("Add &Legend", widget, SLOT(cmAddLegend()));
+ plots->insertSeparator();
+ plots->insertItem("&Configure", widget, SLOT(cmDefaults()));
+
+ QPopupMenu *about = new QPopupMenu(widget);
+ about->insertItem("&About ...", widget, SLOT(cmAbout()));
+
+ menu = new QMenuBar(widget);
+ menu->insertItem("&File", file);
+ menu->insertItem("&Edit", edit);
+ menu->insertItem("&Display", displ);
+ menu->insertItem("&Tools", tools);
+ menu->insertItem("&Plots", plots);
+ menu->insertItem("&?", about);
+ }
+ else if(type == MENU_PAGE) {
+ QPopupMenu *file = new QPopupMenu(widget);
+ file->insertItem("&Open", widget, SLOT(cmOpen()));
+ file->insertItem("Save &as", widget, SLOT(cmSaveGraphAs()));
+ file->insertSeparator();
+ file->insertItem("&Print", widget, SLOT(cmPrint()));
+ file->insertItem("&Export", widget, SLOT(cmExport()));
+ file->insertSeparator();
+ file->insertItem(widget == MainWidget ? "E&xit" : "&Close", widget, SLOT(cmExit()));
+
+ QPopupMenu *edit = new QPopupMenu(widget);
+ edit->insertItem("&Undo", widget, SLOT(cmUndo()), Qt::CTRL + Qt::Key_Z);
+ edit->insertSeparator();
+ edit->insertItem("&Copy", widget, SLOT(cmCopyGraph()), Qt::CTRL + Qt::Key_C);
+ edit->insertItem("&Paste", widget, SLOT(cmPaste()), Qt::CTRL + Qt::Key_V);
+ edit->insertSeparator();
+ edit->insertItem("&UpdateValues", widget, SLOT(cmUpdate()));
+ edit->insertSeparator();
+ edit->insertItem("&Delete Object", widget, SLOT(cmDelObj()));
+
+ QPopupMenu *zoom = new QPopupMenu(widget);
+ zoom->insertTearOffHandle();
+ zoom->insertItem("zoom &in", widget, SLOT(cmZoomIn()), Qt::CTRL + Qt::Key_Plus);
+ zoom->insertItem("zoom &out", widget, SLOT(cmZoomOut()), Qt::CTRL + Qt::Key_Minus);
+ zoom->insertItem("&fit to widget", widget, SLOT(cmZoomFit()), Qt::CTRL + Qt::Key_F);
+ zoom->insertSeparator();
+ zoom->insertItem("25%", widget, SLOT(cmZoom25()));
+ zoom->insertItem("50%", widget, SLOT(cmZoom50()));
+ zoom->insertItem("100%", widget, SLOT(cmZoom100()));
+ zoom->insertItem("200%", widget, SLOT(cmZoom200()));
+ zoom->insertItem("400%", widget, SLOT(cmZoom400()));
+
+ QPopupMenu *displ = new QPopupMenu(widget);
+ displ->insertItem("&Redraw", widget, SLOT(cmRedraw()));
+ displ->insertItem("&Zoom", zoom);
+ displ->insertItem("&Layers", widget, SLOT(cmLayers()));
+
+ QPopupMenu *tools = new QPopupMenu(widget);
+ tools->insertTearOffHandle();
+ tools->insertItem("&Standard", widget, SLOT(cmtStandard()), Qt::Key_Escape, CM_T_STANDARD);
+ tools->insertSeparator();
+ tools->insertItem("&Draw", widget, SLOT(cmtDraw()), 0, CM_T_DRAW);
+ tools->insertItem("Poly&line", widget, SLOT(cmtPolyline()), 0, CM_T_POLYLINE);
+ tools->insertItem("Poly&gon", widget, SLOT(cmtPolygon()), 0, CM_T_POLYGON);
+ tools->insertItem("&Rectangle", widget, SLOT(cmtRectangle()), 0, CM_T_RECTANGLE);
+ tools->insertItem("&r&ound Rect.", widget, SLOT(cmtRoundrect()), 0, CM_T_ROUNDREC);
+ tools->insertItem("&Ellipse", widget, SLOT(cmtEllipse()), 0, CM_T_ELLIPSE);
+ tools->insertItem("&Arrow", widget, SLOT(cmtArrow()), 0, CM_T_ARROW);
+ tools->insertItem("&Text", widget, SLOT(cmtText()), 0, CM_T_TEXT);
+ tools->setCheckable(true);
+
+ QPopupMenu *plots = new QPopupMenu(widget);
+ plots->insertItem("Add &Graph", widget, SLOT(cmNewGraph()));
+ plots->insertItem("Add &Plot", widget, SLOT(cmAddPlot()));
+ plots->insertItem("Add &Axis", widget, SLOT(cmAddAxis()));
+ plots->insertItem("Add &Legend", widget, SLOT(cmAddLegend()));
+ plots->insertSeparator();
+ plots->insertItem("Page &Settings", widget, SLOT(cmDefaults()));
+
+ QPopupMenu *about = new QPopupMenu(widget);
+ about->insertItem("&About ...", widget, SLOT(cmAbout()));
+
+ menu = new QMenuBar(widget);
+ menu->insertItem("&File", file);
+ menu->insertItem("&Edit", edit);
+ menu->insertItem("&Display", displ);
+ menu->insertItem("&Tools", tools);
+ menu->insertItem("&Plots", plots);
+ menu->insertItem("&?", about);
+ }
+ else return false;
+ menu->show();
+ MenuHeight = menu->height();
+ widget->resize(widget->width()+8, widget->height()+8);
+ return true;
+}
+
+void
+OutputQT::CheckMenu(int mid, bool check)
+{
+ if(mid < CM_T_STANDARD) switch(mid){ //tool mode identifier
+ case TM_STANDARD: mid = CM_T_STANDARD; break;
+ case TM_DRAW: mid = CM_T_DRAW; break;
+ case TM_POLYLINE: mid = CM_T_POLYLINE; break;
+ case TM_POLYGON: mid = CM_T_POLYGON; break;
+ case TM_RECTANGLE: mid = CM_T_RECTANGLE; break;
+ case TM_ROUNDREC: mid = CM_T_ROUNDREC; break;
+ case TM_ELLIPSE: mid = CM_T_ELLIPSE; break;
+ case TM_ARROW: mid = CM_T_ARROW; break;
+ case TM_TEXT: mid = CM_T_TEXT; break;
+ default: return;
+ }
+ if(menu) menu->setItemChecked(mid, check);
+}
+
+void
+OutputQT::FileHistory()
+{
+ char **history[] = {&defs.File1, &defs.File2, &defs.File3, &defs.File4, &defs.File5, &defs.File6};
+ int i, j, k;
+
+ if(!hasHistMenu || !defs.File1 || !menu) return;
+ for(i = 0; i < 6 && *history[i]; i++) {
+ k = strlen(*history[i]);
+ for (j = 0; j < k && defs.currPath[j] == (*history[i])[j]; j++);
+ if((*history[i])[j] == '\\' || (*history[i])[j] == '/') j++;
+ menu->changeItem(CM_FILE1+i, *history[i]+j);
+#ifdef Q_CHECK_PTR //Qt version 3, n.a. in version 2
+ menu->setItemVisible(CM_FILE1+i, true);
+#endif
+ }
+ HistMenuSize = i;
+}
+
+void
+OutputQT::CreateNewWindow(GraphObj *g)
+{
+ int w, h;
+
+ GetDesktopSize(&w, &h);
+ if(widget = new RLPwidget(0, 0, this, g)) {
+ widget->setCaption("OutputQT::CreateNewWindow");
+ widget->setGeometry(0, 0, (int)(w*.7f), (int)(h*.7f));
+ HScroll = ((RLPwidget*)widget)->HScroll;
+ VScroll = ((RLPwidget*)widget)->VScroll;
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Common widget support
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+RLPwidget::RLPwidget(QWidget *par, const char *name, anyOutput *o, GraphObj *g)
+ : QWidget(par, name)
+{
+ int w, h;
+
+ GetDesktopSize(&w, &h);
+ mempic = new QPixmap(w, h);
+ parent = par;
+ OutputClass = o;
+ BaseObj = g;
+ setMinimumSize(100, 80);
+ setBackgroundMode(NoBackground);
+ HScroll = new QScrollBar(QScrollBar::Horizontal, this, 0);
+ HScroll->setRange(0, 1000);
+ HScroll->setSteps(1, 16);
+ connect(HScroll, SIGNAL(valueChanged(int)), SLOT(hScrollEvent(int)));
+ VScroll = new QScrollBar(QScrollBar::Vertical, this, 0);
+ VScroll->setRange(0, 1000);
+ VScroll->setSteps(1, 16);
+ connect(VScroll, SIGNAL(valueChanged(int)), SLOT(vScrollEvent(int)));
+ if(!MainWidget) QAppl->setMainWidget(MainWidget = this);
+ setMouseTracking(true);
+ setFocusPolicy(StrongFocus);
+}
+
+RLPwidget::~RLPwidget()
+{
+ if(BaseObj){
+ BaseObj->Command(CMD_CAN_DELETE, 0L, 0L);
+ BaseObj = 0L;
+ }
+ if(OutputClass)((OutputQT*)OutputClass)->widget = 0L;
+}
+
+//public slots: menu items, events
+void
+RLPwidget::hScrollEvent(int pos)
+{
+ if(BaseObj){
+ BaseObj->Command(CMD_SETHPOS, (void*)(&pos), OutputClass);
+ repaint();
+ }
+}
+
+void
+RLPwidget::vScrollEvent(int pos)
+{
+ if(BaseObj){
+ BaseObj->Command(CMD_SETVPOS, (void*)(&pos), OutputClass);
+ repaint();
+ }
+}
+
+
+void
+RLPwidget::cmOpen()
+{
+ if(BaseObj)BaseObj->Command(CMD_OPEN, (void *)NULL, OutputClass);
+}
+
+void
+RLPwidget::cmSaveDataAs()
+{
+ if(BaseObj)BaseObj->Command(CMD_SAVEDATAAS, (void *)NULL, OutputClass);
+}
+
+void
+RLPwidget::cmExit()
+{
+ delete(this);
+}
+
+void
+RLPwidget::cmNewGraph()
+{
+ if(BaseObj)BaseObj->Command(CMD_NEWGRAPH, (void *)NULL, OutputClass);
+}
+
+void
+RLPwidget::cmNewPage()
+{
+ if(BaseObj)BaseObj->Command(CMD_NEWPAGE, (void *)NULL, OutputClass);
+}
+
+void
+RLPwidget::cmDelGraph()
+{
+ if(BaseObj)BaseObj->Command(CMD_DELGRAPH, (void *)NULL, OutputClass);
+}
+
+void
+RLPwidget::cmAddPlot()
+{
+ if(BaseObj)BaseObj->Command(CMD_ADDPLOT, (void *)NULL, OutputClass);
+}
+
+void
+RLPwidget::cmAddLegend()
+{
+ if(BaseObj)BaseObj->Command(CMD_LEGEND, (void *)NULL, OutputClass);
+}
+
+void
+RLPwidget::cmLayers()
+{
+ if(BaseObj)BaseObj->Command(CMD_LAYERS, (void *)NULL, OutputClass);
+}
+
+void
+RLPwidget::cmAbout()
+{
+ RLPlotInfo();
+}
+
+void
+RLPwidget::cmAddRowCol()
+{
+ if(BaseObj)BaseObj->Command(CMD_ADDROWCOL, (void *)NULL, OutputClass);
+}
+
+void
+RLPwidget::cmCopy()
+{
+ if(BaseObj && BaseObj->Id == GO_SPREADDATA) {
+ BaseObj->Command(CMD_QUERY_COPY, 0L, OutputClass);
+ CopyData(BaseObj);
+ }
+}
+
+void
+RLPwidget::cmCut()
+{
+ if(BaseObj && BaseObj->Id == GO_SPREADDATA) {
+ BaseObj->Command(CMD_CUT, 0L, OutputClass);
+ CopyData(BaseObj);
+ }
+}
+
+void
+RLPwidget::cmPaste()
+{
+ if(BaseObj) {
+ OutputClass->MouseCursor(MC_WAIT, true);
+ TestClipboard(BaseObj);
+ OutputClass->MouseCursor(MC_ARROW, true);
+ }
+}
+
+void
+RLPwidget::cmCopyGraph()
+{
+ if(BaseObj) CopyGraph(BaseObj);
+}
+
+void
+RLPwidget::cmSaveGraphAs()
+{
+ SaveGraphAs(BaseObj);
+}
+
+void
+RLPwidget::cmRedraw()
+{
+ if(OutputClass && BaseObj && OutputClass->Erase(defs.Color(COL_BG))) {
+ BaseObj->Command(CMD_SETSCROLL, 0L, OutputClass);
+ repaint();
+ }
+}
+
+void
+RLPwidget::cmZoom25()
+{
+ BaseObj->Command(CMD_ZOOM, (void*)(&"25"), OutputClass);
+}
+
+void
+RLPwidget::cmZoom50()
+{
+ BaseObj->Command(CMD_ZOOM, (void*)(&"50"), OutputClass);
+}
+
+void
+RLPwidget::cmZoom100()
+{
+ BaseObj->Command(CMD_ZOOM, (void*)(&"100"), OutputClass);
+}
+
+void
+RLPwidget::cmZoom200()
+{
+ BaseObj->Command(CMD_ZOOM, (void*)(&"200"), OutputClass);
+}
+
+void
+RLPwidget::cmZoom400()
+{
+ BaseObj->Command(CMD_ZOOM, (void*)(&"400"), OutputClass);
+}
+
+void
+RLPwidget::cmZoomIn()
+{
+ BaseObj->Command(CMD_ZOOM, (void*)(&"+"), OutputClass);
+}
+
+void
+RLPwidget::cmZoomOut()
+{
+ BaseObj->Command(CMD_ZOOM, (void*)(&"-"), OutputClass);
+}
+
+void
+RLPwidget::cmZoomFit()
+{
+ BaseObj->Command(CMD_ZOOM, (void*)(&"fit"), OutputClass);
+}
+
+void
+RLPwidget::cmPrint()
+{
+ int m;
+ PrintQT out(0L, 0L);
+
+ if(!BaseObj) return;
+ if(BaseObj->Id == GO_SPREADDATA) {
+ m = iround(out.hres/60.0);
+#ifdef Q_CHECK_PTR //Qt version 3, n.a. in version 2
+ out.printer->setMargins(m, m, m, m);
+#endif
+ BaseObj->Command(CMD_PRINT, 0L, &out);
+ }
+ else if(out.StartPage()){
+ BaseObj->DoPlot(&out);
+ out.EndPage();
+ }
+ BaseObj->DoPlot(OutputClass);
+}
+
+void
+RLPwidget::cmExport()
+{
+ OpenExportName(BaseObj, "hello.svg");
+ BaseObj->DoPlot(0L);
+}
+
+void
+RLPwidget::cmDelObj()
+{
+ if(CurrGO && CurrGO->parent && CurrGO->parent->
+ Command(CMD_DELOBJ, (void*)CurrGO, OutputClass)) {
+ CurrGO = 0L;
+ OutputClass->Erase(defs.Color(COL_BG));
+ BaseObj->DoPlot(OutputClass);
+ }
+ else if(!CurrGO) InfoBox("No object selected!");
+}
+
+void
+RLPwidget::cmUpdate()
+{
+ if(BaseObj) BaseObj->Command(CMD_UPDATE, 0L, OutputClass);
+}
+
+void
+RLPwidget::cmDefaults()
+{
+ BaseObj->Command(CMD_CONFIG, 0L, OutputClass);
+}
+
+void
+RLPwidget::cmAddAxis()
+{
+ BaseObj->Command(CMD_ADDAXIS, 0L, OutputClass);
+}
+
+void
+RLPwidget::cmUndo()
+{
+ BaseObj->Command(CMD_UNDO, 0L, OutputClass);
+}
+
+void
+RLPwidget::cmFillRange()
+{
+ BaseObj->Command(CMD_FILLRANGE, 0L, OutputClass);
+}
+
+void ToolMenu(GraphObj *b, anyOutput *o, int tm)
+{
+ if(b && o) b->Command(CMD_TOOLMODE, (void*)(& tm), o);
+}
+
+void
+RLPwidget::cmtStandard()
+{
+ ToolMenu(BaseObj, OutputClass, TM_STANDARD);
+}
+
+void
+RLPwidget::cmtDraw()
+{
+ ToolMenu(BaseObj, OutputClass, TM_DRAW);
+}
+
+void
+RLPwidget::cmtPolyline()
+{
+ ToolMenu(BaseObj, OutputClass, TM_POLYLINE);
+}
+
+void
+RLPwidget::cmtPolygon()
+{
+ ToolMenu(BaseObj, OutputClass, TM_POLYGON);
+}
+
+void
+RLPwidget::cmtRectangle()
+{
+ ToolMenu(BaseObj, OutputClass, TM_RECTANGLE);
+}
+
+void
+RLPwidget::cmtRoundrect()
+{
+ ToolMenu(BaseObj, OutputClass, TM_ROUNDREC);
+}
+
+void
+RLPwidget::cmtEllipse()
+{
+ ToolMenu(BaseObj, OutputClass, TM_ELLIPSE);
+}
+
+void
+RLPwidget::cmtArrow()
+{
+ ToolMenu(BaseObj, OutputClass, TM_ARROW);
+}
+
+void
+RLPwidget::cmtText()
+{
+ ToolMenu(BaseObj, OutputClass, TM_TEXT);
+}
+
+//protected: widget events
+void
+RLPwidget::paintEvent(QPaintEvent *range)
+{
+ QRect rc;
+
+ rc = range->rect();
+ bitBlt(this, rc.left(), rc.top(), this->mempic, rc.left(), rc.top(),
+ 1+rc.right()-rc.left(), 1+rc.bottom()-rc.top());
+}
+
+void
+RLPwidget::resizeEvent(QResizeEvent *)
+{
+ HScroll->resize(width() -16, 16);
+ HScroll->move(0, height()-16);
+ VScroll->resize(16, height()-OutputClass->MenuHeight-16);
+ VScroll->move(width()-16, OutputClass->MenuHeight);
+ if(BaseObj) BaseObj->Command(CMD_SETSCROLL, 0L, OutputClass);
+}
+
+void
+RLPwidget::closeEvent(QCloseEvent *e)
+{
+ if(BaseObj){
+ BaseObj->Command(CMD_CAN_DELETE, 0L, 0L);
+ BaseObj = 0L;
+ }
+ e->accept();
+}
+
+void
+RLPwidget::mouseDoubleClickEvent(QMouseEvent *e)
+{
+ MouseEvent mev = {1, e->button() == Qt::LeftButton?MOUSE_LBDOUBLECLICK:-1,e->x(),e->y()};
+
+ if (BaseObj)BaseObj->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
+}
+
+void
+RLPwidget::mousePressEvent(QMouseEvent *e)
+{
+ MouseEvent mev = {1, e->button() == Qt::LeftButton ? MOUSE_LBDOWN : -1, e->x(), e->y()};
+
+ HideTextCursor();
+ if (BaseObj)BaseObj->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
+}
+
+void
+RLPwidget::mouseReleaseEvent(QMouseEvent *e)
+{
+ MouseEvent mev = {0, e->button() == Qt::LeftButton ? MOUSE_LBUP :
+ e->button() == Qt::RightButton ? MOUSE_RBUP : -1, e->x(), e->y()};
+
+ if (BaseObj) BaseObj->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
+}
+
+void
+RLPwidget::mouseMoveEvent(QMouseEvent *e)
+{
+ MouseEvent mev = {0, MOUSE_MOVE, e->x(), e->y()};
+
+ if(e->state() == Qt::LeftButton) mev.StateFlags = 1;
+ if (BaseObj) BaseObj->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
+}
+
+void
+RLPwidget::keyPressEvent(QKeyEvent *e)
+{
+ int c;
+
+ if(BaseObj) switch(c = e->key()) {
+ case Key_Prior:
+ BaseObj->Command(CMD_PAGEUP, 0L, OutputClass);
+ break;
+ case Key_Next:
+ BaseObj->Command(CMD_PAGEDOWN, 0L, OutputClass);
+ break;
+ case Key_Left:
+ if(e->state() & ShiftButton) BaseObj->Command(CMD_SHIFTLEFT, 0L, OutputClass);
+ else BaseObj->Command(CMD_CURRLEFT, 0L, OutputClass);
+ break;
+ case Key_Right:
+ if(e->state() & ShiftButton) BaseObj->Command(CMD_SHIFTRIGHT, 0L, OutputClass);
+ else BaseObj->Command(CMD_CURRIGHT, 0L, OutputClass);
+ break;
+ case Key_Up:
+ if(e->state() & ShiftButton) BaseObj->Command(CMD_SHIFTUP, 0L, OutputClass);
+ else BaseObj->Command(CMD_CURRUP, 0L, OutputClass);
+ break;
+ case Key_Down:
+ if(e->state() & ShiftButton) BaseObj->Command(CMD_SHIFTDOWN, 0L, OutputClass);
+ else BaseObj->Command(CMD_CURRDOWN, 0L, OutputClass);
+ break;
+ case Key_Delete:
+ BaseObj->Command(CMD_DELETE, 0L, OutputClass);
+ break;
+ case Key_Tab:
+ BaseObj->Command(CMD_TAB, 0L, OutputClass);
+ break;
+ case Key_Backtab:
+ BaseObj->Command(CMD_SHTAB, 0L, OutputClass);
+ break;
+ case Key_Home:
+ BaseObj->Command(CMD_POS_FIRST, 0L, OutputClass);
+ break;
+ case Key_End:
+ BaseObj->Command(CMD_POS_LAST, 0L, OutputClass);
+ break;
+ default:
+ c = e->ascii();
+ if(c == 3) cmCopy();
+ else if(c == 22) cmPaste();
+ else if(c == 26) cmUndo();
+ else if(c >1 && c < 256)
+ BaseObj->Command(CMD_ADDCHAR, (void *)(& c), OutputClass);
+ break;
+ }
+ e->accept();
+}
+
+void
+RLPwidget::focusInEvent(QFocusEvent *e)
+{
+ CurrWidgetPos.x = x(); CurrWidgetPos.y = y();
+ if(BaseObj) {
+ if(BaseObj->Id == GO_GRAPH) CurrGraph = (Graph*)BaseObj;
+ }
+}
+
+//private functions
+void
+RLPwidget::openHistoryFile(int idx)
+{
+ char *name = 0L;
+
+ switch (idx) {
+ case 0: name = defs.File1; break;
+ case 1: name = defs.File2; break;
+ case 2: name = defs.File3; break;
+ case 3: name = defs.File4; break;
+ case 4: name = defs.File5; break;
+ case 5: name = defs.File6; break;
+ }
+ if(name && FileExist(name)) {
+ BaseObj->Command(CMD_DROPFILE, name, OutputClass);
+ defs.FileHistory(name);
+ OutputClass->FileHistory();
+ }
+}
+
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Print and output EPS to file
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class FileEPS:public QPrinter {
+public:
+ FileEPS(GraphObj *g, anyOutput *o);
+
+protected:
+ int metric(int) const;
+
+private:
+ GraphObj *go;
+ anyOutput *out;
+};
+
+FileEPS::FileEPS(GraphObj *g, anyOutput *o)
+{
+ go = g;
+ out = o;
+}
+
+int
+FileEPS::metric(int m) const
+{
+ if(go && out)switch (m) {
+ case QPaintDeviceMetrics::PdmWidth:
+ return out->un2ix(go->GetSize(SIZE_GRECT_RIGHT) - go->GetSize(SIZE_GRECT_LEFT))/10;
+ case QPaintDeviceMetrics::PdmHeight:
+ return out->un2ix(go->GetSize(SIZE_GRECT_BOTTOM) - go->GetSize(SIZE_GRECT_TOP))/10;
+ case QPaintDeviceMetrics::PdmWidthMM:
+ return iround((go->GetSize(SIZE_GRECT_RIGHT) - go->GetSize(SIZE_GRECT_LEFT)) *
+ Units[defs.cUnits].convert);
+ case QPaintDeviceMetrics::PdmHeightMM:
+ return iround((go->GetSize(SIZE_GRECT_BOTTOM) - go->GetSize(SIZE_GRECT_TOP)) *
+ Units[defs.cUnits].convert);
+ }
+ return QPrinter::metric(m);
+}
+
+PrintQT::PrintQT(GraphObj *g, char *file)
+{
+ hres = vres = 720.0;
+ units = defs.cUnits;
+ Box1.Xmin = Box1.Ymin = 0.0;
+ Box1.Xmax = Box1.Ymax = 6000;
+ DeskRect.left = DeskRect.top = 0;
+ DeskRect.right = (long)(hres*6.0);
+ DeskRect.bottom = (long)(vres*8.0);
+ dxf.setMatrix(0.1, 0.0, 0.0, 0.1, 0.0, 0.0);
+ hgo = 0L;
+ if(file) fileName = strdup(file);
+ else fileName = 0L;
+ go = g;
+ if(fileName && go) printer = new FileEPS(g, this);
+ else printer = new QPrinter;
+ bPrinting = false;
+}
+
+PrintQT::~PrintQT()
+{
+ if(printer) delete(printer);
+ if(hgo) delete(hgo);
+ if(fileName) free(fileName);
+}
+
+bool
+PrintQT::ActualSize(RECT *rc)
+{
+ if(printer) {
+ QPaintDeviceMetrics dm(printer); rc->top = rc->left = 0;
+ rc->bottom = dm.height() *10; rc->right = dm.width() *10;
+ return true;
+ }
+ return false;
+}
+
+bool
+PrintQT::SetLine(LineDEF *lDef)
+{
+ int iw;
+
+ if(lDef->width != LineWidth || lDef->width != LineWidth ||
+ lDef->pattern != dPattern || lDef->color != dLineCol) {
+ LineWidth = lDef->width;
+ iw = iround(un2fix(lDef->width));
+ dPattern = lDef->pattern;
+ RLP.finc = 256.0/un2fix(lDef->patlength*8.0);
+ RLP.fp = 0.0;
+ if(iLine == iw && dLineCol == lDef->color) return true;
+ iLine = iw;
+ dLineCol = lDef->color;
+ qPen.setColor(SwapRB(dLineCol));
+ qPen.setWidth(iw);
+ qPen.setStyle(Qt::SolidLine);
+ qPen.setCapStyle(Qt::RoundCap);
+ qPen.setJoinStyle(Qt::RoundJoin);
+ qPainter.setPen(qPen);
+ }
+ return true;
+}
+
+bool
+PrintQT::SetFill(FillDEF *fill)
+{
+ if(!fill) return false;
+ if((fill->type & 0xff) != FILL_NONE) {
+ if(!hgo) hgo = new HatchOut(this);
+ if(hgo) hgo->SetFill(fill);
+ }
+ else {
+ if(hgo) delete hgo;
+ hgo = 0L;
+ }
+ qPainter.setBrush(QColor(SwapRB(fill->color)));
+ dFillCol = fill->color;
+ dFillCol2 = fill->color2;
+ return true;
+}
+
+bool
+PrintQT::SetTextSpec(TextDEF *set)
+{
+ return com_SetTextSpec(set, &TxtSet, this, qFont, &qPainter);
+}
+
+bool
+PrintQT::StartPage()
+{
+ if(!printer || bPrinting) return false;
+ if(fileName) {
+ VPorg.fy = -co2fiy(go->GetSize(SIZE_GRECT_TOP));
+ VPorg.fx = -co2fix(go->GetSize(SIZE_GRECT_LEFT));
+ printer->setOutputFileName(fileName);
+ printer->setFullPage(true);
+ qPainter.begin(printer);
+ qPainter.setWorldMatrix(dxf, FALSE);
+ return bPrinting = true;
+ }
+
+ if(printer->setup(0)){
+ qPainter.begin(printer);
+ qPainter.setWorldMatrix(dxf, FALSE);
+ return bPrinting = true;
+ }
+ else return false;
+}
+
+bool
+PrintQT::EndPage()
+{
+ qPainter.flush(); qPainter.end(); bPrinting = false;
+ return true;
+}
+
+bool
+PrintQT::Eject()
+{
+ if(!bPrinting) return false;
+ qPainter.flush(); qPainter.end(); qPainter.begin(printer);
+ qPainter.setWorldMatrix(dxf, FALSE);
+ return true;
+}
+
+bool
+PrintQT::oGetTextExtent(char *text, int cb, int *width, int *height)
+{
+ QRect rc = qPainter.boundingRect(0, 0, 10000, 1000, Qt::AlignLeft | Qt::AlignTop,
+ text, cb > 0 ? cb : strlen(text));
+ *width = rc.rRight() - rc.rLeft(); *height = rc.rBottom() - rc.rTop();
+ return true;
+}
+
+bool
+PrintQT::oCircle(int x1, int y1, int x2, int y2, char* nam)
+{
+ qPainter.drawEllipse(x1, y1, x2-x1, y2-y1);
+ if(hgo) return hgo->oCircle(x1, y1, x2, y2);
+ return true;
+}
+
+bool
+PrintQT::oPolyline(POINT * pts, int cp, char *nam)
+{
+ int i;
+
+ if(cp < 1) return false;
+ if (dPattern) {
+ for (i = 1; i < cp; i++) PatLine(pts[i-1], pts[i]);
+ }
+ else {
+ qPainter.moveTo(pts[0].x, pts[0].y);
+ for (i = 1; i < cp; i++) qPainter.lineTo(pts[i].x, pts[i].y);
+ }
+ return true;
+}
+
+bool
+PrintQT::oRectangle(int x1, int y1, int x2, int y2, char *nam)
+{
+ qPainter.drawRect(x1, y1, x2-x1-1, y2-y1-1);
+ if(hgo) hgo->oRectangle(x1, y1, x2, y2, 0L);
+ return true;
+}
+
+bool
+PrintQT::oSolidLine(POINT *p)
+{
+ qPainter.drawLine(p[0].x, p[0].y, p[1].x, p[1].y);
+ return true;
+}
+
+bool
+PrintQT::oTextOut(int x, int y, char *txt, int cb)
+{
+ return com_TextOut(x, y, txt, &TxtSet, &qPainter, this);
+}
+
+bool
+PrintQT::oPolygon(POINT *pts, int cp, char *nam)
+{
+ int i;
+
+ QPointArray *a;
+
+ if(!pts || cp <2) return false;
+ a = new QPointArray(cp);
+ if (a) {
+ for(i = 0; i < cp; i++) a->setPoint(i, pts[i].x, pts[i].y);
+ qPainter.drawPolygon(*a);
+ delete a;
+ }
+ if(hgo) hgo->oPolygon(pts, cp);
+ return true;
+}
+
+bool
+PrintQT::oArc(int x1, int y1, int x2, int y2, int quads)
+{
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Find a suitable www browser
+void FindBrowser()
+{
+ //find a suitable browser
+ if(FileExist("/usr/bin/mozilla")) WWWbrowser = strdup("mozilla");
+ else if(FileExist("/usr/bin/netscape")) WWWbrowser = strdup("netscape");
+ else if(FileExist("/usr/bin/konqueror")) WWWbrowser = strdup("konqueror");
+ else if(FileExist("/opt/kde3/bin/konqueror")) WWWbrowser = strdup("konqueror");
+ //use home as startup directory
+ sprintf(TmpTxt, "%s", getenv("HOME"));
+ defs.currPath = strdup(TmpTxt); strcat(TmpTxt, "/.RLPlot");
+ defs.IniFile = strdup(TmpTxt);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// The MAIN antry point
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int main (int argc, char **argv)
+{
+ QApplication a(argc, argv);
+ DefsRW *drw;
+
+ if(argc > 1 && argv[1] && argv[1][0] && FileExist(argv[1]))
+ LoadFile = strdup(argv[1]);
+ QAppl = &a;
+ InitTextCursor(true);
+ ShowBanner(true);
+ a.exec();
+ if(defs.IniFile) {
+ if(drw = new DefsRW()){
+ drw->FileIO(FILE_WRITE); delete drw;
+ }
+ }
+ SpreadMain(false);
+ InitTextCursor(false);
+ if(WWWbrowser) free(WWWbrowser);
+ if(LoadFile) free(LoadFile);
+ return 0;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Dialog box support
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+DlgWidget::DlgWidget(QWidget *par, const char *name, tag_DlgObj *d)
+#ifdef Q_CHECK_PTR //n.a. in Qt version 2
+: QWidget(par, name, Qt::WType_Dialog)
+#else
+: QWidget(par, name, 0x0000002)
+#endif
+{
+ parent = par;
+ dlg = d;
+ setFocusPolicy(StrongFocus);
+}
+
+DlgWidget::~DlgWidget()
+{
+ if(OutputClass){
+ ((OutputQT*)OutputClass)->widget=0L;
+ delete ((OutputQT*)OutputClass);
+ }
+}
+
+void
+DlgWidget::paintEvent(QPaintEvent *range)
+{
+ QRect rc;
+
+ rc = range->rect();
+ bitBlt(this, rc.left(), rc.top(), this->mempic, rc.left(), rc.top(),
+ 1+rc.right()-rc.left(), 1+rc.bottom()-rc.top());
+}
+
+void
+DlgWidget::mouseDoubleClickEvent(QMouseEvent *e)
+{
+ MouseEvent mev = {1, e->button() == Qt::LeftButton?MOUSE_LBDOUBLECLICK:-1,e->x(),e->y()};
+
+ if (dlg) dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
+}
+
+void
+DlgWidget::mousePressEvent(QMouseEvent *e)
+{
+ MouseEvent mev = {1, e->button() == Qt::LeftButton ? MOUSE_LBDOWN : -1, e->x(), e->y()};
+
+ HideTextCursor();
+ if (dlg) dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
+}
+
+void
+DlgWidget::mouseReleaseEvent(QMouseEvent *e)
+{
+ MouseEvent mev = {0, e->button() == Qt::LeftButton ? MOUSE_LBUP : -1, e->x(), e->y()};
+
+ if (dlg) dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
+}
+
+void
+DlgWidget::mouseMoveEvent(QMouseEvent *e)
+{
+ MouseEvent mev = {1, e->state() == Qt::LeftButton ? MOUSE_MOVE : -1, e->x(), e->y()};
+
+ if (dlg) dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
+}
+
+void
+DlgWidget::keyPressEvent(QKeyEvent *e)
+{
+ int c;
+
+ if(dlg) switch(c = e->key()) {
+ case Key_Left:
+ if(e->state() & ShiftButton) dlg->Command(CMD_SHIFTLEFT, 0L, OutputClass);
+ else dlg->Command(CMD_CURRLEFT, 0L, OutputClass);
+ break;
+ case Key_Right:
+ if(e->state() & ShiftButton) dlg->Command(CMD_SHIFTRIGHT, 0L, OutputClass);
+ else dlg->Command(CMD_CURRIGHT, 0L, OutputClass);
+ break;
+ case Key_Up:
+ if(e->state() & ShiftButton) dlg->Command(CMD_SHIFTUP, 0L, OutputClass);
+ else dlg->Command(CMD_CURRUP, 0L, OutputClass);
+ break;
+ case Key_Down:
+ if(e->state() & ShiftButton) dlg->Command(CMD_SHIFTDOWN, 0L, OutputClass);
+ else dlg->Command(CMD_CURRDOWN, 0L, OutputClass);
+ break;
+ case Key_Delete:
+ dlg->Command(CMD_DELETE, 0L, OutputClass);
+ break;
+ case Key_Tab:
+ dlg->Command(CMD_TAB, 0L, OutputClass);
+ break;
+ case Key_Backtab:
+ dlg->Command(CMD_SHTAB, 0L, OutputClass);
+ break;
+ case Key_Home:
+ dlg->Command(CMD_POS_FIRST, 0L, OutputClass);
+ break;
+ case Key_End:
+ dlg->Command(CMD_POS_LAST, 0L, OutputClass);
+ break;
+ default:
+ c = e->ascii();
+ if(c >1 && c < 256)
+ if(c == 26) dlg->Command(CMD_UNDO, 0L, OutputClass);
+ else dlg->Command(CMD_ADDCHAR, (void *)(& c), OutputClass);
+ break;
+ }
+ e->accept();
+}
+
+void
+DlgWidget::focusInEvent(QFocusEvent *e)
+{
+ CurrWidgetPos.x = x(); CurrWidgetPos.y = y();
+}
+
+void
+DlgWidget::focusOutEvent(QFocusEvent *e)
+{
+ HideTextCursorObj(OutputClass);
+ if(dlg) dlg->Command(CMD_ENDDIALOG, 0L, OutputClass);
+}
+
+void
+DlgWidget::closeEvent(QCloseEvent *e)
+{
+ HideTextCursorObj(OutputClass);
+ e->ignore();
+ if(dlg){
+ dlg->Command(CMD_UNLOCK, 0L, OutputClass);
+ dlg->Command(CMD_ENDDIALOG, 0L, OutputClass);
+ }
+}
+
+void
+DlgWidget::timerEvent(QTimerEvent *)
+{
+ if(dlg) dlg->Command(CMD_ENDDIALOG, dlg, OutputClass);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void *CreateDlgWnd(char *title, int x, int y, int width, int height, tag_DlgObj *d, DWORD flags)
+{
+ DlgWidget *w;
+ OutputQT *o;
+ int dw, dh;
+
+ w = new DlgWidget(QAppl->focusWidget(), 0, d);
+ w->setCaption(title);
+ if(flags & 0x2) w->setFixedSize(width, height);
+ else w->setFixedSize(width-6, height-16);
+ if(flags & 0x1) {
+ GetDesktopSize(&dw, &dh);
+ w->move((dw>>1) - ((w->width())>>1), (dh>>1) - ((w->height())>>1));
+ }
+ else w->move(CurrWidgetPos.x+x, CurrWidgetPos.y+y);
+ o = new OutputQT(w);
+ o->units = defs.cUnits;
+ o->Erase(0x00c0c0c0L);
+ if(flags & 0x04) {
+ w->startTimer(100);
+ }
+ d->DoPlot(o);
+ w->show();
+ return w;
+}
+
+void LoopDlgWnd() //keep message processing running
+{
+ QAppl->processOneEvent();
+}
+
+void CloseDlgWnd(void *hDlg)
+{
+ if(hDlg) {
+ delete((DlgWidget*) hDlg);
+ }
+}
+
+void ShowDlgWnd(void *hDlg)
+{
+ if(hDlg){
+ ((DlgWidget*)hDlg)->show();
+ ((DlgWidget*)hDlg)->setActiveWindow();
+ ((DlgWidget*)hDlg)->raise();
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// OS independent interface to Qt specific classes
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+anyOutput *NewDispClass(GraphObj *g)
+{
+ return new OutputQT(g);
+}
+
+bool DelDispClass(anyOutput *w)
+{
+ if(w) delete (OutputQT*) w;
+ return true;
+}
+
+anyOutput *NewBitmapClass(int w, int h, double hr, double vr)
+{
+ return new BitMapQT(w, h, hr, vr);
+}
+
+bool DelBitmapClass(anyOutput *w)
+{
+ if (w) delete (BitMapQT*) w;
+ return true;
+}
+
diff --git a/QT_Spec.h b/QT_Spec.h
new file mode 100755
index 0000000..582f9b3
--- /dev/null
+++ b/QT_Spec.h
@@ -0,0 +1,284 @@
+//QT_Spec.h, Copyright (c) 2001, 2002, 2003, 2004 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 <qwidget.h>
+#include <qpen.h>
+#include <qpainter.h>
+#include <qprinter.h>
+#include <qmenubar.h>
+#include <qscrollbar.h>
+#include <qdragobject.h>
+#include "TheDialog.h"
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class TxtCurBlink:public QObject {
+ Q_OBJECT
+public:
+ anyOutput *oCopyMark;
+ anyOutput *bmCopyMark;
+
+ TxtCurBlink();
+ void Show();
+ void showCopyMark();
+
+protected:
+ void timerEvent(QTimerEvent *);
+
+private:
+ POINT line[5];
+ bool isVis;
+ int count, cp_mark;
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// based on KDEs KSpread source: kspread_table.h
+// copyright (C) 1998, 1999 Torben Weis
+class KSpreadTextDrag:public QTextDrag {
+ Q_OBJECT
+public:
+ KSpreadTextDrag(QWidget *dragSource = 0L, const char *name = 0L);
+ virtual ~KSpreadTextDrag();
+ virtual bool provides(const char *mimeType);
+ void setSpreadData(GraphObj *g) {go = g;};
+ virtual QByteArray encodedData(const char* mime) const;
+ virtual const char* format(int i) const;
+ static bool canDecode(QMimeSource *e);
+ static const char* selectionMimeType();
+
+protected:
+ GraphObj *go;
+};
+
+class RLPGraphDrag:public QTextDrag {
+ Q_OBJECT
+public:
+ RLPGraphDrag(QWidget *dragSource = 0L, const char *name = 0L);
+ virtual ~RLPGraphDrag();
+ virtual bool provides(const char *mimeType);
+ void setGraphData(GraphObj *g);
+ virtual QByteArray encodedData(const char* mime) const;
+ virtual const char* format(int i) const;
+ static bool canDecode(QMimeSource *e);
+ static const char* selectionMimeType();
+
+protected:
+ GraphObj *go1, *go2;
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class RLPwidget:public QWidget {
+ Q_OBJECT
+
+public:
+ QScrollBar *HScroll, *VScroll;
+ QPixmap *mempic;
+ RLPwidget(QWidget *par=0, const char *name=0, anyOutput *o = 0,
+ GraphObj *g = 0);
+ ~RLPwidget();
+
+public slots:
+ void hScrollEvent(int pos);
+ void vScrollEvent(int pos);
+ void cmOpen();
+ void cmSaveDataAs();
+ void cmExit();
+ void cmNewGraph();
+ void cmNewPage();
+ void cmDelGraph();
+ void cmAddPlot();
+ void cmAbout();
+ void cmAddRowCol();
+ void cmCopy();
+ void cmCut();
+ void cmPaste();
+ void cmCopyGraph();
+ void cmSaveGraphAs();
+ void cmRedraw();
+ void cmZoom25();
+ void cmZoom50();
+ void cmZoom100();
+ void cmZoom200();
+ void cmZoom400();
+ void cmZoomIn();
+ void cmZoomOut();
+ void cmZoomFit();
+ void cmPrint();
+ void cmExport();
+ void cmDelObj();
+ void cmUpdate();
+ void cmDefaults();
+ void cmAddAxis();
+ void cmAddLegend();
+ void cmLayers();
+ void cmUndo();
+ void cmFillRange();
+ void cmtStandard();
+ void cmtDraw();
+ void cmtPolyline();
+ void cmtPolygon();
+ void cmtRectangle();
+ void cmtRoundrect();
+ void cmtEllipse();
+ void cmtArrow();
+ void cmtText();
+ void cmFile1() {openHistoryFile(0);};
+ void cmFile2() {openHistoryFile(1);};
+ void cmFile3() {openHistoryFile(2);};
+ void cmFile4() {openHistoryFile(3);};
+ void cmFile5() {openHistoryFile(4);};
+ void cmFile6() {openHistoryFile(5);};
+
+protected:
+ void paintEvent(QPaintEvent *);
+ void resizeEvent(QResizeEvent *);
+ void closeEvent(QCloseEvent *);
+ void mouseDoubleClickEvent(QMouseEvent *e);
+ void mousePressEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void keyPressEvent(QKeyEvent *e);
+ void focusInEvent(QFocusEvent *e);
+
+private:
+ QWidget *parent;
+ anyOutput *OutputClass;
+ GraphObj *BaseObj;
+
+ void openHistoryFile(int idx);
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class DlgWidget:public QWidget {
+ Q_OBJECT
+public:
+ QPixmap *mempic;
+ anyOutput *OutputClass;
+
+ DlgWidget(QWidget *par=0, const char *name=0, tag_DlgObj *d = 0);
+ ~DlgWidget();
+
+protected:
+ void paintEvent(QPaintEvent *);
+ void mouseDoubleClickEvent(QMouseEvent *e);
+ void mousePressEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void keyPressEvent(QKeyEvent *e);
+ void focusInEvent(QFocusEvent *e);
+ void focusOutEvent(QFocusEvent *e);
+ void closeEvent(QCloseEvent *e);
+ void timerEvent(QTimerEvent *);
+
+private:
+ QWidget *parent;
+ tag_DlgObj *dlg;
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class BitMapQT:public anyOutput {
+public:
+ QWidget *widget;
+ HatchOut *hgo;
+ QPixmap *mempic;
+ QImage *image;
+ QPen qPen;
+ QPainter qPainter;
+ QFont qFont;
+
+ BitMapQT(GraphObj *g, QWidget *wi, int vr = 98, int hr = 98);
+ BitMapQT(int w, int h, double hr, double vr);
+ ~BitMapQT();
+ bool SetLine(LineDEF *lDef);
+ bool SetFill(FillDEF *fill);
+ bool SetTextSpec(TextDEF *set);
+ virtual bool Erase(DWORD Color);
+ virtual bool StartPage() {return true;};
+ bool CopyBitmap(int x, int y, anyOutput* src, int sx, int sy,
+ int sw, int sh, bool invert);
+ bool oGetTextExtent(char *text, int cb, int *width, int *height);
+ bool oGetPix(int x, int y, DWORD *col);
+ bool oDrawIcon(int type, int x, int y);
+ bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L);
+ bool oPolyline(POINT * pts, int cp, char *nam = 0L);
+ bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
+ bool oSolidLine(POINT *p);
+ bool oTextOut(int x, int y, char *txt, int cb);
+ bool oPolygon(POINT *pts, int cp, char *nam = 0L);
+ bool oArc(int x1, int y1, int x2, int y2, int quads);
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class OutputQT:public BitMapQT {
+public:
+ QScrollBar *HScroll, *VScroll;
+
+ OutputQT(GraphObj *g);
+ OutputQT(DlgWidget *wi);
+ ~OutputQT();
+ bool ActualSize(RECT *rc);
+ void Caption(char *txt);
+ void MouseCursor(int cid, bool force);
+ bool SetScroll(bool isVert, int iMin, int iMax, int iPSize, int iPos);
+ bool EndPage();
+ bool UpdateRect(RECT *rc, bool invert);
+ void ShowBitmap(int x, int y, anyOutput* src);
+ void ShowLine(POINT * pts, int cp, DWORD color);
+ void ShowEllipse(POINT p1, POINT p2, DWORD color);
+ bool SetMenu(int type);
+ void CheckMenu(int mid, bool check);
+ void FileHistory();
+ void CreateNewWindow(GraphObj *g);
+
+private:
+ GraphObj *BaseObj;
+ QMenuBar *menu;
+};
+
+class PrintQT:public anyOutput{
+public:
+ HatchOut *hgo;
+ QPrinter *printer;
+
+ PrintQT(GraphObj *g, char *file);
+ ~PrintQT();
+ bool ActualSize(RECT *rc);
+ bool SetLine(LineDEF *lDef);
+ bool SetFill(FillDEF *fill);
+ bool SetTextSpec(TextDEF *set);
+ bool StartPage();
+ bool EndPage();
+ bool Eject();
+ bool oGetTextExtent(char *text, int cb, int *width, int *height);
+ bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L);
+ bool oPolyline(POINT * pts, int cp, char *nam = 0L);
+ bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
+ bool oSolidLine(POINT *p);
+ bool oTextOut(int x, int y, char *txt, int cb);
+ bool oPolygon(POINT *pts, int cp, char *nam = 0L);
+ bool oArc(int x1, int y1, int x2, int y2, int quads);
+
+private:
+ QPen qPen;
+ QFont qFont;
+ QPainter qPainter;
+ QWMatrix dxf;
+ char *fileName;
+ GraphObj *go;
+ bool bPrinting;
+};
diff --git a/README b/README
new file mode 100755
index 0000000..791b432
--- /dev/null
+++ b/README
@@ -0,0 +1,131 @@
+README for RLPlot, Copyright (c) 2002, 2003 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
+
+
+------------------------------------------------------------------------------
+1. Building RLPlot for Linux
+Before building RLPlot for Linux using the supplied 'Makefile' you probably
+need to make some adaptations. RLPlot uses Trolltech's Qt and the default
+Makefile assumes Qt beeing installed in /usr/local/qt.
+Which version of Qt should be used ? The best version is usually that coming
+with your distribution CDs. If there are several versions installed on your
+machine you may experience crashes especially if you try to copy/paste data
+from one application to another.
+Most problems during compilation of RLPlot are due to missing Qt or installation
+of Qt in a different folder.
+On most systems where Qt has been installed from the distribution
+CDs the environment variable 'QTDIR' is defined. In this case you may succeed
+by issuing the following command within the RLPlot folder:
+
+ make -e
+
+If that does not work you have to ...
+
+1.1: Find your Qt directory.
+ This is the directory where Qt has been installed. It contains the files
+ ./bin/moc, ./include/qapplication.h ./lib/libqt.so (However, RLPlot needs
+ more than those). If you don't find this directory you must install Qt devel.
+ first from your distribution CDs or directly from www.trolltech.com.
+
+1.2: Modify Makefile. Find the line (close to the top) where QTDIR is defined
+ and fill in the path to the Qt folder.
+ Possible examples include:
+ QTDIR = /usr/lib/qt3
+ QTDIR = /usr/lib/qt-2.3.1
+ QTDIR = /usr/local/qt-2.3.1
+ QTDIR = /usr/local/qt-x11-free-3.0.4
+
+ Alternatively you may leave the Makefile unchanged and put a symbolic link
+ into /usr/local (if /usr/local/qt does not yet exist), for example:
+ cd /usr/local
+ ln -s /usr/lib/qt-2.3.1 qt
+ The latter method has the advantage that you can have concurrent versions
+ of Qt installed on your system and need not modify Makefile everytime you
+ download a new version of RLPlot. You may need root privileges to create
+ the link in /usr/local
+
+1.3: Create the RLPlot executable by execting 'make' in the RLplot folder.
+ You can remove some intermediary file exceting 'make clean'.
+ No further installation required. Just execute RLPlot.
+
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+Problems and Platform notes:
+Some recent versions of Qt use Open GL which requires additional libraries
+to be included in the Makefile.
+
+Common errors during build:
+
+undefined reference to ...
+ This error usually occurs if a library necessary for link is not specified
+ in the Makefile. You have to find a suitable library and specify it in the
+ LIBS definition (some examples see below). May be you do not need this library
+ and the build is done properly without e.g. '-lGL'.
+ Example: undefined reference to 'glXQueryServerString'
+ libGL.so not specified in LIBS. Add '-lGL' to LIBS or a fully qualified
+ path to the folder with libGL.so, e.g. -L/usr/X11R6/lib
+
+cannot find ....
+ This error occurs if a file is not found, possibly one of the libraries in
+ of the LIBS definition. Probably you do not need this library and you can
+ remove it from the LIBS. If this does not help you may be lucky to find it
+ elsewhere (not very promising) or some package needs to be installed.
+ Example: cannot find -lGL
+ libGL.so specified in LIBS but not found in a standard directory
+ Example: cannot find -lqt-mt
+ libqt-mt.so not found. Modify the Makefile from 'QTLIBS= -lqt-mt' to
+ 'QTLIBS= -lqt'. If this does not help Qt is not properly installed.
+
+There are some LIBS definitions which might work on your system
+ LIBS = -L$(QTDIR)/lib -L/usr/X11R6/lib
+ LIBS = -lGL -L$(QTDIR)/lib -L/usr/X11R6/lib
+ LIBS = -L/usr/lib -L$(QTDIR)/lib -L/usr/X11R6/lib
+
+------------------------------------------------------------------------------
+2. Building RLPlot for Windows
+To compile RLPlot from the sources you need to install
+MS Visual Studio first. Once you have RLPlot.exe no further installation
+is required. RLPlot does not change the registry. Double click on
+the icon in the explorer window to start the program.
+
+2.1 Building RLPlot.exe using NMAKE
+ Open a DOS or command line window and move to the MSVC folder. Execute
+ VCVARS32.BAT in the bin subdirectory. Change directory to the RLPlot
+ folder. Whenever you close the DOS-box you need to execute VCVARS32.BAT
+ again. Now execute nmake to compile and build RLPlot:
+ nmake -f "Makefile.win"
+ After building RLPlot you may wish to remove temporary files:
+ nmake -f "Makefile.win" clean
+
+2.2 Creating a project in the IDE
+ Create a new project (RLPLot) using the MS Developer Studio creating a
+ Win32 Application. Add the following files to the project: Export.cpp,
+ FileIO.cpp, Output.cpp, PropertyDlg.cpp, rlplot.cpp, rlplot.h, RLPLOT.RC,
+ spreadwi.cpp, TheDialog.cpp, TheDialog.h, UtilObj.cpp, Utils.cpp,
+ Version.h, WinSpec.cpp, WinSpec.h. Now execute [!].
+
+------------------------------------------------------------------------------
+
+Success!
+
+reinhard.lackner at uibk.ac.at
+
+Reinhard Lackner Reinhard Lackner
+Ing. Etzelstr. 19 Inst. f. Zoologie u. Limnologie
+A-6020 Innsbruck Technikerstr. 25
+AUSTRIA A-6020 Innsbruck
+ AUSTRIA
diff --git a/RLPLOT.ICO b/RLPLOT.ICO
new file mode 100755
index 0000000..0ba1c92
Binary files /dev/null and b/RLPLOT.ICO differ
diff --git a/RLPLOT.RC b/RLPLOT.RC
new file mode 100755
index 0000000..f7ea45f
--- /dev/null
+++ b/RLPLOT.RC
@@ -0,0 +1,337 @@
+//RLPlot.RC, (C)2000, 2001, 2002, 2003, 2004, 2005 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
+//
+#define CM_OPEN 500
+#define CM_SAVEDATAAS 501
+#define CM_EXIT 502
+#define CM_NEWGRAPH 503
+#define CM_NEWPAGE 504
+#define CM_DELGRAPH 505
+#define CM_ADDPLOT 506
+#define CM_ABOUT 507
+#define CM_ADDROWCOL 508
+#define CM_COPYGRAPH 509
+#define CM_SAVEGRAPHAS 510
+#define CM_REDRAW 511
+#define CM_ZOOM25 512
+#define CM_ZOOM50 513
+#define CM_ZOOM100 514
+#define CM_ZOOM200 515
+#define CM_ZOOM400 516
+#define CM_PRINT 517
+#define CM_EXPORT 518
+#define CM_DELOBJ 519
+#define CM_REBOOT 520
+#define CM_SHUTDOWN 521
+#define CM_DEFAULTS 522
+#define CM_COPY 523
+#define CM_PASTE 524
+#define CM_UPDATE 525
+#define CM_ADDAXIS 526
+#define CM_UNDO 527
+#define CM_ZOOMIN 528
+#define CM_ZOOMOUT 529
+#define CM_ZOOMFIT 530
+#define CM_FILE1 531
+#define CM_FILE2 532
+#define CM_FILE3 533
+#define CM_FILE4 534
+#define CM_FILE5 535
+#define CM_FILE6 536
+#define CM_FILLRANGE 537
+#define CM_CUT 538
+#define CM_LEGEND 539
+#define CM_LAYERS 540
+
+#define CM_T_STANDARD 550
+#define CM_T_DRAW 551
+#define CM_T_POLYLINE 552
+#define CM_T_POLYGON 553
+#define CM_T_RECTANGLE 554
+#define CM_T_ROUNDREC 555
+#define CM_T_ELLIPSE 556
+#define CM_T_ARROW 557
+#define CM_T_TEXT 558
+
+#define CM_DELKEY 600
+#define CM_LEFTARRKEY 601
+#define CM_RIGHTARRKEY 602
+#define CM_UPARRKEY 603
+#define CM_DOWNARRKEY 604
+#define CM_TAB 605
+#define CM_SHTAB 606
+#define CM_PGUP 607
+#define CM_PGDOWN 608
+#define CM_POS_FIRST 609
+#define CM_POS_LAST 610
+#define CM_SHLEFT 611
+#define CM_SHRIGHT 612
+#define CM_SHUP 613
+#define CM_SHDOWN 614
+
+#define MENU_1 400
+#define MENU_2 401
+#define MENU_3 402
+
+#define IDI_EVAL 50
+
+#define ACCELERATORS_1 1
+
+#ifdef RC_INVOKED
+#ifndef WORKSHOP_INVOKED
+#include <windows.h>
+#include "Version.h"
+#endif
+
+MENU_1 MENU DISCARDABLE
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&Open", CM_OPEN
+ MENUITEM "&Save as", CM_SAVEGRAPHAS
+ MENUITEM SEPARATOR
+ MENUITEM "&Print", CM_PRINT
+ MENUITEM "&Export", CM_EXPORT
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", CM_EXIT
+ END
+ POPUP "&Edit"
+ BEGIN
+ MENUITEM "&Undo" CM_UNDO
+ MENUITEM SEPARATOR
+ MENUITEM "&Copy", CM_COPYGRAPH
+ MENUITEM "&Paste", CM_PASTE
+ MENUITEM SEPARATOR
+ MENUITEM "&Update Values", CM_UPDATE
+ MENUITEM SEPARATOR
+ MENUITEM "&Delete Object", CM_DELOBJ
+ END
+ POPUP "&Display"
+ BEGIN
+ MENUITEM "&Redraw", CM_REDRAW
+ POPUP "&Zoom"
+ BEGIN
+ MENUITEM "zoom &in" CM_ZOOMIN
+ MENUITEM "zoom &out" CM_ZOOMOUT
+ MENUITEM "&fit to window" CM_ZOOMFIT
+ MENUITEM SEPARATOR
+ MENUITEM "25%", CM_ZOOM25
+ MENUITEM "50%", CM_ZOOM50
+ MENUITEM "100%", CM_ZOOM100
+ MENUITEM "200%", CM_ZOOM200
+ MENUITEM "400%", CM_ZOOM400
+ END
+ MENUITEM "&Layers", CM_LAYERS
+ END
+ POPUP "&Tools"
+ BEGIN
+ MENUITEM "&Standard", CM_T_STANDARD
+ MENUITEM SEPARATOR
+ MENUITEM "&Draw", CM_T_DRAW
+ MENUITEM "Poly&line", CM_T_POLYLINE
+ MENUITEM "Poly&gon", CM_T_POLYGON
+ MENUITEM "&Rectangle", CM_T_RECTANGLE
+ MENUITEM "r&ound Rect.", CM_T_ROUNDREC
+ MENUITEM "&Ellipse", CM_T_ELLIPSE
+ MENUITEM "&Arrow", CM_T_ARROW
+ MENUITEM "&Text", CM_T_TEXT
+ END
+ POPUP "&Plots"
+ BEGIN
+ MENUITEM "Add &Plot", CM_ADDPLOT
+ MENUITEM "Add &Axis", CM_ADDAXIS
+ MENUITEM "Add &Legend", CM_LEGEND
+ MENUITEM SEPARATOR
+ MENUITEM "&Configure", CM_DEFAULTS
+ END
+ POPUP "&?"
+ BEGIN
+ MENUITEM "&About ...", CM_ABOUT
+ END
+END
+
+MENU_2 MENU DISCARDABLE
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&Open", CM_OPEN
+ MENUITEM "&Save as", CM_SAVEDATAAS
+ MENUITEM SEPARATOR
+ MENUITEM "&Print", CM_PRINT
+ MENUITEM SEPARATOR
+ MENUITEM "&Reboot", CM_REBOOT
+ MENUITEM "Shut &down", CM_SHUTDOWN
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", CM_EXIT
+ END
+ POPUP "&Edit"
+ BEGIN
+ MENUITEM "&Undo" CM_UNDO
+ MENUITEM SEPARATOR
+ MENUITEM "&Rows/Cols", CM_ADDROWCOL
+ MENUITEM SEPARATOR
+ MENUITEM "&Copy", CM_COPY
+ MENUITEM "C&ut", CM_CUT
+ MENUITEM "&Paste", CM_PASTE
+ MENUITEM SEPARATOR
+ MENUITEM "&Fill Range", CM_FILLRANGE
+ END
+ POPUP "&Graph"
+ BEGIN
+ MENUITEM "Create &Graph", CM_NEWGRAPH
+ MENUITEM "Create &Page", CM_NEWPAGE
+ MENUITEM "&Flush Graph(s)", CM_DELGRAPH
+ MENUITEM SEPARATOR
+ MENUITEM "&Settings", CM_DEFAULTS
+ END
+ POPUP "&?"
+ BEGIN
+ MENUITEM "&About ...", CM_ABOUT
+ END
+END
+
+MENU_3 MENU DISCARDABLE
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&Open", CM_OPEN
+ MENUITEM "&Save as", CM_SAVEGRAPHAS
+ MENUITEM SEPARATOR
+ MENUITEM "&Print", CM_PRINT
+ MENUITEM "&Export", CM_EXPORT
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", CM_EXIT
+ END
+ POPUP "&Edit"
+ BEGIN
+ MENUITEM "&Undo" CM_UNDO
+ MENUITEM SEPARATOR
+ MENUITEM "&Copy", CM_COPYGRAPH
+ MENUITEM "&Paste", CM_PASTE
+ MENUITEM SEPARATOR
+ MENUITEM "&Update Values", CM_UPDATE
+ MENUITEM SEPARATOR
+ MENUITEM "&Delete Object", CM_DELOBJ
+ END
+ POPUP "&Display"
+ BEGIN
+ MENUITEM "&Redraw", CM_REDRAW
+ POPUP "&Zoom"
+ BEGIN
+ MENUITEM "zoom &in" CM_ZOOMIN
+ MENUITEM "zoom &out" CM_ZOOMOUT
+ MENUITEM "&fit to window" CM_ZOOMFIT
+ MENUITEM SEPARATOR
+ MENUITEM "25%", CM_ZOOM25
+ MENUITEM "50%", CM_ZOOM50
+ MENUITEM "100%", CM_ZOOM100
+ MENUITEM "200%", CM_ZOOM200
+ MENUITEM "400%", CM_ZOOM400
+ END
+ MENUITEM "&Layers", CM_LAYERS
+ END
+ POPUP "&Tools"
+ BEGIN
+ MENUITEM "&Standard", CM_T_STANDARD
+ MENUITEM SEPARATOR
+ MENUITEM "&Draw", CM_T_DRAW
+ MENUITEM "Poly&line", CM_T_POLYLINE
+ MENUITEM "Poly&gon", CM_T_POLYGON
+ MENUITEM "&Rectangle", CM_T_RECTANGLE
+ MENUITEM "r&ound Rect.", CM_T_ROUNDREC
+ MENUITEM "&Ellipse", CM_T_ELLIPSE
+ MENUITEM "&Arrow", CM_T_ARROW
+ MENUITEM "&Text", CM_T_TEXT
+ END
+ POPUP "&Plots"
+ BEGIN
+ MENUITEM "Add &Graph", CM_NEWGRAPH
+ MENUITEM "Add &Plot", CM_ADDPLOT
+ MENUITEM "Add &Axis", CM_ADDAXIS
+ MENUITEM "Add &Legend", CM_LEGEND
+ MENUITEM SEPARATOR
+ MENUITEM "Page &Settings", CM_DEFAULTS
+ END
+ POPUP "&?"
+ BEGIN
+ MENUITEM "&About ...", CM_ABOUT
+ END
+END
+
+IDI_EVAL ICON DISCARDABLE "rlplot.ico"
+
+
+VERSIONINFO_1 VERSIONINFO
+ FILEVERSION 1,0,0,0
+ PRODUCTVERSION 1,0,0,0
+ FILEFLAGSMASK 0x0L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x10001L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "CompanyName", "R.Lackner\0"
+ VALUE "FileDescription", "Data Plot Program\0"
+ VALUE "FileVersion", SZ_VERSION"\000\000"
+ VALUE "InternalName", "RLPlot\0"
+ VALUE "LegalCopyright", "Copyright � R. Lackner 2000-2004\0"
+ VALUE "OriginalFilename", "RLPlot.exe\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1252
+ END
+END
+
+ACCELERATORS_1 ACCELERATORS MOVEABLE PURE
+BEGIN
+ VK_DELETE, CM_DELKEY, VIRTKEY
+ VK_LEFT, CM_LEFTARRKEY, VIRTKEY
+ VK_RIGHT, CM_RIGHTARRKEY, VIRTKEY
+ VK_UP, CM_UPARRKEY, VIRTKEY
+ VK_DOWN, CM_SHDOWN, VIRTKEY, SHIFT
+ VK_LEFT, CM_SHLEFT, VIRTKEY, SHIFT
+ VK_RIGHT, CM_SHRIGHT, VIRTKEY, SHIFT
+ VK_UP, CM_SHUP, VIRTKEY, SHIFT
+ VK_DOWN, CM_DOWNARRKEY, VIRTKEY
+ VK_TAB, CM_TAB, VIRTKEY
+ VK_TAB, CM_SHTAB, VIRTKEY, SHIFT
+ VK_PRIOR, CM_PGUP, VIRTKEY
+ VK_NEXT, CM_PGDOWN, VIRTKEY
+ VK_HOME, CM_POS_FIRST, VIRTKEY
+ VK_END, CM_POS_LAST, VIRTKEY
+ VK_ESCAPE, CM_T_STANDARD, VIRTKEY
+ "^C", CM_COPY, ASCII
+ "^X", CM_CUT, ASCII
+ "^V", CM_PASTE, ASCII
+ "^Z", CM_UNDO, ASCII
+ "^F", CM_ZOOMFIT, ASCII
+END
+
+#endif // RC_INVOKED
+
+
diff --git a/RLPlot.bmp b/RLPlot.bmp
new file mode 100755
index 0000000..ac10363
Binary files /dev/null and b/RLPlot.bmp differ
diff --git a/RLPlot.xpm b/RLPlot.xpm
new file mode 100755
index 0000000..77b8e92
--- /dev/null
+++ b/RLPlot.xpm
@@ -0,0 +1,47 @@
+/* XPM */
+static char *RLPlot[]={
+"32 32 12 1",
+"j c #000083",
+"i c #0000ff",
+"d c #008100",
+"e c #00ff00",
+"b c #00ffff",
+"g c #830000",
+"c c #838100",
+"a c #838183",
+". c #c5c2c5",
+"h c #ff0000",
+"f c #ffff00",
+"# c #ffffff",
+".##a###a##bbbbbbbbbbbbbbbbbbbbbb",
+"##a###a###bbbbbbbbbbbbbbbbbbbbbb",
+"#a###a#.#a.b.b.b.b.b.b.b.b.b.b.b",
+"a#.#a#.#a#bbbbbbbbbbbbbbbbbbbbbb",
+"###a##.cccbbbbbbbbbbbbbdddbbbbbb",
+".#a###a#c#bbbbbbbbbbbbbbdbbbbbbb",
+"#a#.#a#.c.b.b.b.b.b.b.b.d.b.b.b.",
+"a###a###c#bbbbbbbbbbbdddddddbbbb",
+"#.#a#.#ac#bbbbbbbbbbbdeedeedbbbb",
+".#a.#cccccccbbbbbbbbbdeedeedbbbb",
+"#a###cffcffc.b.ggg.b.deddded.b.b",
+"a###acffcffcbbbbgbbbbdeeeeedbbbb",
+"..#a.cffcffcbbbbgbbbbdeeeeedbbbb",
+"##a##cffcffcbgggggggbdeeeeedbbbb",
+"#a#.#cfcccfcbghhghhgbdeeeeedb.b.",
+"a###acfffffcbghhghhgbdeeeeedbbbb",
+"#.#a#cfffffcbghggghgbdeeeeedbbbb",
+".#a.#cfffffcbghhhhhgbdeeeeedbbbb",
+"#a###cfffffcbghhhhhg.deeeeed.b.b",
+"a#.#acfffffcbghhhhhgbdeeeeedbbbb",
+"###a#cfffffcbghhhhhgbdeeeeedbbbb",
+".#a#.cfffffcighhhhhgideeeeediiii",
+"#a.##cfffffcighhhhhgideeeeedjiij",
+"a###acccccccigggggggidddddddiiii",
+"#.#a###ijiiijiiijiiijiiijiiiijii",
+".#a#.#ijijjiijiiijiiijiiijiiiiii",
+"#a###ijjiiijiijiijjijiijiijiijii",
+"a##.iijiijijjiijjiiijjijjiijjiij",
+".##jijiijjjiijjjiijjjiijjjiijjji",
+"##jjijijiijjjjijjjjijjjjijjjjijj",
+".jjjjjijjjjjijjjjijjjijjjjjjjjij",
+"jjijjjjjjjjjjjjijjjjjjjjjjijjjjj"};
diff --git a/TheDialog.cpp b/TheDialog.cpp
new file mode 100755
index 0000000..7d94615
--- /dev/null
+++ b/TheDialog.cpp
@@ -0,0 +1,4479 @@
+//TheDialog.cpp, Copyright (c) 2001, 2002, 2003, 2004, 2005 R.Lackner
+//Operating system independent code for dialog boxes
+//
+// 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 "TheDialog.h"
+
+extern tag_Units Units[];
+extern char TmpTxt[];
+extern Default defs;
+extern GraphObj *CurrGO;
+extern EditText *CurrText; //current EditText object
+extern RECT rTxtCur; //text cursor position and direction
+extern UndoObj Undo;
+
+char *WWWbrowser = 0L;
+char *LoadFile = 0L;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// internal declarations
+static int xbase = 2;
+static int ybase = 2;
+int dlgtxtheight = 11;
+static unsigned long DlgBGcolor = 0x00c0c0c0L;
+static unsigned long DlgBGhigh = 0x00d0d0d0L;
+TextDEF DlgText = {0x00000000L, 0x00ffffffL, 4.0, 0.0f, 0.0f, 0,
+ TXA_HLEFT | TXA_VTOP, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, 0L};
+
+//prototypes: WinSpec.cpp
+void *CreateDlgWnd(char *title, int x, int y, int width, int height, tag_DlgObj *d, DWORD flags);
+
+//The dialog object which just has the input focus
+Dialog *DialogFocus = 0L;
+Dialog *DialogDefault = 0L;
+Dialog *DialogTabStop = 0L;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Base classes to dialog items
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+DlgRoot::DlgRoot(DlgInfo *tmpl)
+{
+ int i;
+ RECT rc;
+
+ dlg = 0L; flags = 0L; tabstops = 0L;
+ DlgText.iSize = dlgtxtheight; DlgText.ColBg = DlgBGcolor;
+ type = NONE; Id = -2; cContinue = 0;
+ bActive = false; Result = -1;
+ CurrDisp = 0L; oldFocus = DialogFocus; DialogFocus = 0L;
+ oldDefault = DialogDefault; oldTabStop = DialogTabStop;
+ if(tmpl) {
+ //count number of items first, then allocate memory
+ for(cDlgs=1;!(tmpl[cDlgs-1].flags & LASTOBJ); cDlgs++);
+ dlg = (DlgTmpl **)calloc(cDlgs+1, sizeof(DlgTmpl*));
+ tabstops =(Dialog**)calloc(cDlgs, sizeof(Dialog*));
+ if(dlg) for (i = 0; i < cDlgs; i++) {
+ dlg[i] = (DlgTmpl *)malloc(sizeof(DlgTmpl));
+ if(dlg[i]) {
+ dlg[i]->id = tmpl[i].id;
+ dlg[i]->next = tmpl[i].next;
+ dlg[i]->first = tmpl[i].first;
+ dlg[i]->flags = tmpl[i].flags;
+ rc.left = tmpl[i].x * xbase;
+ rc.right = rc.left + tmpl[i].w * xbase;
+ rc.top = tmpl[i].y * ybase;
+ rc.bottom = rc.top + tmpl[i].h * ybase;
+ //an item appearing in the following list should have a corresponding
+ // entry in the list of ~DlgRoot()
+ switch(tmpl[i].type) {
+ case PUSHBUTTON:
+ dlg[i]->dialog = new PushButton(this, &tmpl[i],rc,(char*)tmpl[i].ptype);
+ break;
+ case TEXTBOX:
+ dlg[i]->dialog = new TextBox(this, &tmpl[i],rc,(char*)tmpl[i].ptype);
+ break;
+ case ARROWBUTT:
+ dlg[i]->dialog = new ArrowButton(this, &tmpl[i],rc,(int*)tmpl[i].ptype);
+ break;
+ case COLBUTTON:
+ dlg[i]->dialog = new ColorButton(this, &tmpl[i],rc, (unsigned long)tmpl[i].ptype);
+ break;
+ case FILLBUTTON:
+ dlg[i]->dialog = new FillButton(this, &tmpl[i],rc, (FillDEF *)tmpl[i].ptype);
+ break;
+ case SHADE3D:
+ dlg[i]->dialog = new Shade3D(this, &tmpl[i],rc, (FillDEF *)tmpl[i].ptype);
+ break;
+ case LINEBUTT:
+ dlg[i]->dialog = new LineButton(this, &tmpl[i],rc, (LineDEF *)tmpl[i].ptype);
+ break;
+ case SYMBUTT:
+ dlg[i]->dialog = new SymButton(this, &tmpl[i],rc, (Symbol **)tmpl[i].ptype);
+ break;
+ case FILLRADIO:
+ dlg[i]->dialog = new FillRadioButt(this, &tmpl[i],rc, *((unsigned int*)tmpl[i].ptype));
+ break;
+ case SYMRADIO:
+ dlg[i]->dialog = new SymRadioButt(this, &tmpl[i],rc, (int*)tmpl[i].ptype);
+ break;
+ case CHECKBOX:
+ dlg[i]->dialog = new CheckBox(this, &tmpl[i],rc,(char*)tmpl[i].ptype);
+ break;
+ case CHECKPIN:
+ dlg[i]->dialog = new CheckPin(this, &tmpl[i],rc);
+ break;
+ case TRASH:
+ dlg[i]->dialog = new Trash(this, &tmpl[i],rc);
+ break;
+ case CONFIG:
+ dlg[i]->dialog = new Config(this, &tmpl[i],rc);
+ break;
+ case RADIO0: case RADIO1: case RADIO2:
+ dlg[i]->dialog = new RadioButton(this, &tmpl[i],rc,(char*)tmpl[i].ptype);
+ break;
+ case LTEXT: case RTEXT: case CTEXT:
+ dlg[i]->dialog = new Text(this, &tmpl[i],rc,(char*)tmpl[i].ptype);
+ break;
+ case EDTEXT:
+ dlg[i]->dialog = new InputText(this, &tmpl[i],rc,(char*)tmpl[i].ptype);
+ break;
+ case EDVAL1:
+ dlg[i]->dialog = new InputValue(this, &tmpl[i],rc,(double*)tmpl[i].ptype);
+ break;
+ case INCDECVAL1:
+ dlg[i]->dialog = new IncDecValue(this, &tmpl[i],rc,(double*)tmpl[i].ptype);
+ break;
+ case TXTHSP:
+ dlg[i]->dialog = new TxtHSP(this, &tmpl[i],rc, (int*)tmpl[i].ptype);
+ break;
+ case VSCROLL:
+ dlg[i]->dialog = new ScrollBar(this, &tmpl[i],rc, true);
+ break;
+ case HSCROLL:
+ dlg[i]->dialog = new ScrollBar(this, &tmpl[i],rc, false);
+ break;
+ case ICON:
+ dlg[i]->dialog = new Icon(this, &tmpl[i],rc, (int*)tmpl[i].ptype);
+ break;
+ case GROUP:
+ dlg[i]->dialog = new Group(this, &tmpl[i], rc);
+ break;
+ case GROUPBOX:
+ dlg[i]->dialog = new GroupBox(this, &tmpl[i],rc, (char*)tmpl[i].ptype);
+ break;
+ case SHEET:
+ dlg[i]->dialog = new TabSheet(this, &tmpl[i],rc, (TabSHEET *)tmpl[i].ptype);
+ break;
+ case ODBUTTON:
+ dlg[i]->dialog = new ODbutton(this, &tmpl[i],rc, tmpl[i].ptype);
+ break;
+ case LISTBOX1:
+ dlg[i]->dialog = new Listbox(this, &tmpl[i],rc, (char**)tmpl[i].ptype);
+ break;
+ case TREEVIEW:
+ dlg[i]->dialog = new Treeview(this, &tmpl[i],rc, (GraphObj*)tmpl[i].ptype);
+ break;
+ case LINEPAT:
+ dlg[i]->dialog = new LinePat(this, &tmpl[i],rc, (LineDEF *)tmpl[i].ptype);
+ break;
+ default:
+ dlg[i]->dialog = NULL;
+ }
+ }
+ else break;
+ }
+ }
+}
+
+DlgRoot::~DlgRoot()
+{
+ int i;
+
+ if(dlg){
+ for (i = 0; dlg[i] && i < cDlgs; i++) {
+ //we need to delete each object using a cast on its proper type
+ //to call the proper destructor
+ if(dlg[i]->dialog){
+ switch(dlg[i]->dialog->type) {
+ case PUSHBUTTON: delete((PushButton*)dlg[i]->dialog); break;
+ case TEXTBOX: delete((TextBox*)dlg[i]->dialog); break;
+ case ARROWBUTT: delete((ArrowButton*)dlg[i]->dialog); break;
+ case COLBUTTON: delete((ColorButton*)dlg[i]->dialog); break;
+ case FILLBUTTON: delete((FillButton*)dlg[i]->dialog); break;
+ case SHADE3D: delete((Shade3D*)dlg[i]->dialog); break;
+ case LINEBUTT: delete((LineButton*)dlg[i]->dialog); break;
+ case SYMBUTT: delete((SymButton*)dlg[i]->dialog); break;
+ case FILLRADIO: delete((FillRadioButt*)dlg[i]->dialog); break;
+ case SYMRADIO: delete((SymRadioButt*)dlg[i]->dialog); break;
+ case CHECKBOX: delete((CheckBox*)dlg[i]->dialog); break;
+ case CHECKPIN: delete((CheckPin*)dlg[i]->dialog); break;
+ case TRASH: delete((Trash*)dlg[i]->dialog); break;
+ case CONFIG: delete((Config*)dlg[i]->dialog); break;
+ case RADIO0: case RADIO1:
+ case RADIO2: delete((RadioButton*)dlg[i]->dialog); break;
+ case LTEXT: case RTEXT:
+ case CTEXT: delete((Text*)dlg[i]->dialog); break;
+ case EDTEXT: delete((InputText*)dlg[i]->dialog); break;
+ case EDVAL1: delete((InputValue*)dlg[i]->dialog); break;
+ case INCDECVAL1: delete((IncDecValue*)dlg[i]->dialog); break;
+ case TXTHSP: delete((TxtHSP*)dlg[i]->dialog); break;
+ case HSCROLL:
+ case VSCROLL: delete((ScrollBar*)dlg[i]->dialog); break;
+ case ICON: delete((Icon*)dlg[i]->dialog); break;
+ case GROUP: delete((Group*)dlg[i]->dialog); break;
+ case GROUPBOX: delete((GroupBox*)dlg[i]->dialog); break;
+ case SHEET: delete((TabSheet*)dlg[i]->dialog); break;
+ case ODBUTTON: delete((ODbutton*)dlg[i]->dialog); break;
+ case LISTBOX1: delete((Listbox*)dlg[i]->dialog); break;
+ case TREEVIEW: delete((Treeview*)dlg[i]->dialog); break;
+ case LINEPAT: delete((LinePat*)dlg[i]->dialog); break;
+ default:
+ //DEBUG: we should issue a message that an unknown item is
+ // deleted: this might result in a memory leak;
+ InfoBox("unknown dialog object found\nin \"DlgRoot::~DlgRoot()\"");
+ delete(dlg[i]->dialog);
+ break;
+ }
+ }
+ free(dlg[i]);
+ }
+ free(dlg);
+ }
+ if(tabstops) free(tabstops);
+ DialogFocus = oldFocus; DialogDefault = oldDefault;
+ DialogTabStop = oldTabStop;
+}
+
+bool
+DlgRoot::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ Dialog *d;
+ int i, j;
+ RECT rc;
+
+ switch (cmd) {
+ case CMD_UNDO:
+ if(CurrDisp) {
+ Undo.Restore(false, CurrDisp);
+ }
+ return true;
+ case CMD_REDRAW:
+ if(CurrDisp) {
+ CurrDisp->Erase(DlgBGcolor); DoPlot(CurrDisp);
+ CurrDisp->GetSize(&rc); CurrDisp->UpdateRect(&rc, false);
+ }
+ return true;
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch(mev->Action) {
+ case MOUSE_LBDOWN:
+ DialogFocus = NULL; CurrGO = 0L;
+ bActive = true;
+ case MOUSE_MOVE:
+ if(!(mev->StateFlags & 1))return false;
+ //track mouse and display controls accordingly
+ if(bActive)ForEach(CMD_MOUSE_EVENT, 0, o);
+ return true;
+ case MOUSE_LBDOUBLECLICK:
+ ForEach(CMD_MOUSE_EVENT, 0, o);
+ bActive = false; //skip next event (LB up);
+ return true;
+ case MOUSE_LBUP:
+ CurrGO = 0L;
+ if(bActive)ForEach(CMD_LBUP, 0, o);
+ return true;
+ }
+ return true;
+ case CMD_ENDDIALOG:
+ d = (Dialog *)tmpl;
+ if(d) {
+ Result = d->Id; // end dialog by object
+ cContinue = 0;
+ }
+ else if(cContinue >0) {
+ cContinue--;
+ return true; // no end upon killing the focus
+ }
+ else {
+ Result = 0; // end dialog with closebox or loose focus
+ }
+ return true;
+ case CMD_CONTINUE:
+ cContinue++;
+ return true;
+ case CMD_TABDLG:
+ if(tabstops) for (i = 0; i < cDlgs; i++)
+ if(!tabstops[i] || tabstops[i] == (Dialog*)tmpl) {
+ tabstops[i] = (Dialog*)tmpl;
+ return true;
+ }
+ return false;
+ case CMD_NOTABDLG:
+ if(tabstops) for (i = j = 0; i < cDlgs; i++) {
+ if(tabstops[i] == (Dialog*)tmpl) tabstops[i] = 0L;
+ if(tabstops[i]) tabstops[j++] = tabstops[i];
+ }
+ return true;
+ case CMD_TAB:
+ HideTextCursor();
+ if(tabstops && DialogTabStop) {
+ for(i = 0; tabstops[i] && tabstops[i] != DialogTabStop && i < cDlgs; i++);
+ if(tabstops[i]) i++;
+ if(!tabstops[i]) i = 0;
+ switch(tabstops[i]->type) {
+ case PUSHBUTTON:
+ d = DialogDefault;
+ DialogTabStop = DialogDefault = tabstops[i];
+ d->DoPlot(o);
+ DialogDefault->DoPlot(o);
+ break;
+ case EDTEXT: case EDVAL1:
+ case INCDECVAL1:
+ DialogTabStop = DialogFocus = tabstops[i];
+ if((InputText*)DialogFocus->bActive)
+ ((InputText*)DialogFocus)->Activate(DialogFocus->Id, true);
+ else Command(cmd, tmpl, o);
+ break;
+ }
+ }
+ return true;
+ case CMD_SHTAB:
+ HideTextCursor();
+ if(tabstops && DialogTabStop) {
+ for(j = 0; tabstops[j]; j++);
+ for(i = j-1; tabstops[i] != DialogTabStop && i; i--);
+ i = i >0 ? i-1 : j-1;
+ switch(tabstops[i]->type) {
+ case PUSHBUTTON:
+ d = DialogDefault;
+ DialogTabStop = DialogDefault = tabstops[i];
+ d->DoPlot(o);
+ DialogDefault->DoPlot(o);
+ break;
+ case EDTEXT: case EDVAL1: case INCDECVAL1:
+ DialogTabStop = DialogFocus = tabstops[i];
+ ((InputText*)DialogFocus)->Activate(DialogFocus->Id, true);
+ break;
+ }
+ }
+ return true;
+ case CMD_CURRUP: case CMD_CURRDOWN:
+ if(DialogFocus && DialogFocus->type == TEXTBOX)
+ return DialogFocus->Command(cmd, tmpl, o);
+ else return CurUpDown(cmd);
+ case CMD_CURRLEFT: case CMD_CURRIGHT: case CMD_DELETE:
+ case CMD_POS_FIRST: case CMD_POS_LAST: case CMD_SHIFTLEFT:
+ case CMD_SHIFTRIGHT:
+ bActive = true;
+ if(DialogFocus)return DialogFocus->Command(cmd, tmpl, o);
+ else return false;
+ case CMD_ADDCHAR:
+ if(!tmpl) return false;
+ bActive = true;
+ if(DialogDefault && *((int*)tmpl) == 0x0d){ //return pressed
+ HideTextCursor();
+ return DialogDefault->Command(cmd, tmpl, o);
+ }
+ if(DialogFocus)return DialogFocus->Command(cmd, tmpl, o);
+ else return false;
+ case CMD_UNLOCK:
+ for(i = 0; i < cDlgs; i++)
+ if(dlg[i] && dlg[i]->dialog) dlg[i]->dialog->Command(CMD_UNLOCK, 0L, 0L);
+ break;
+ }
+ return false;
+}
+
+void
+DlgRoot::DoPlot(anyOutput *o)
+{
+ int i;
+
+ if(tabstops) for(i = 0; i < cDlgs; tabstops[i++] = 0);
+ if(o)CurrDisp = o;
+ if(CurrDisp) {
+ CurrDisp->SetTextSpec(&DlgText);
+ ForEach(CMD_DOPLOT, 0, CurrDisp);
+ }
+}
+
+bool
+DlgRoot::CurUpDown(int cmd)
+{
+ int i, ya, yb, dy;
+ Dialog *above=0L, *below=0L;
+
+ ya = -1000; yb = 10000;
+ if(DialogFocus && tabstops && DialogTabStop == DialogFocus) {
+ for(i = 0; tabstops[i] && i < cDlgs; i++) {
+ if(tabstops[i] != DialogTabStop) {
+ switch(tabstops[i]->type) {
+ case EDVAL1: case INCDECVAL1: case EDTEXT:
+ if(rTxtCur.left > tabstops[i]->cr.left &&
+ rTxtCur.right < tabstops[i]->cr.right) {
+ if((dy = (tabstops[i]->cr.top - rTxtCur.top))< 0) {
+ if(dy > ya) {
+ ya = dy; above = tabstops[i];
+ }
+ }
+ else {
+ if(dy < yb) {
+ yb = dy; below = tabstops[i];
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ switch(cmd) {
+ case CMD_CURRUP:
+ if(above) {
+ above->Select(rTxtCur.left, (above->cr.top + above->cr.bottom)>>1, CurrDisp);
+ }
+ break;
+ case CMD_CURRDOWN:
+ if(below) {
+ below->Select(rTxtCur.left, (below->cr.top + below->cr.bottom)>>1, CurrDisp);
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+bool
+DlgRoot::GetColor(int id, DWORD *color)
+{
+ int i;
+
+ i = FindIndex(id);
+ if(i && dlg[i]) return dlg[i]->dialog->GetColor(id, color);
+ return false;
+}
+
+void
+DlgRoot::SetColor(int id, DWORD color)
+{
+ int i;
+
+ i = FindIndex(id);
+ if(i && dlg[i]) {
+ dlg[i]->dialog->SetColor(id, color);
+ if(CurrDisp && !(dlg[i]->dialog->flags & HIDDEN)) dlg[i]->dialog->DoPlot(CurrDisp);
+ }
+}
+
+bool
+DlgRoot::GetValue(int id, double *val)
+{
+ int i;
+
+ i = FindIndex(id);
+ if(i && dlg[i]) return dlg[i]->dialog->GetValue(id, val);
+ return false;
+}
+
+bool
+DlgRoot::GetInt(int id, int *val)
+{
+ int i;
+
+ i = FindIndex(id);
+ if(i && dlg[i]) return dlg[i]->dialog->GetInt(id, val);
+ return false;
+}
+
+bool
+DlgRoot::SetCheck(int id, anyOutput *o, bool state)
+{
+ int i;
+
+ i = FindIndex(id);
+ if(i && dlg[i]) return dlg[i]->dialog->SetCheck(id, o ? o : CurrDisp, state);
+ return false;
+}
+
+bool
+DlgRoot::GetCheck(int Id)
+{
+ int i;
+
+ i = FindIndex(Id);
+ if(i && dlg[i]) return dlg[i]->dialog->GetCheck(Id);
+ return false;
+}
+
+bool
+DlgRoot::GetText(int id, char *txt)
+{
+ int i;
+
+ i = FindIndex(id);
+ if(i && dlg[i]) return dlg[i]->dialog->GetText(id, txt);
+ return false;
+}
+
+bool
+DlgRoot::SetText(int id, char *txt)
+{
+ int i;
+
+ i = FindIndex(id);
+ if(i && dlg[i] && dlg[i]->dialog->Command(CMD_SETTEXT, txt, CurrDisp)) DoPlot(CurrDisp);
+ else return false;
+ return true;
+}
+
+bool
+DlgRoot::TextStyle(int id, int style)
+{
+ int i;
+
+ i = FindIndex(id);
+ if(i && dlg[i]) dlg[i]->dialog->TextDef.Style = style;
+ else return false;
+ return true;
+}
+
+bool
+DlgRoot::TextFont(int id, int font)
+{
+ int i;
+
+ i = FindIndex(id);
+ if(i && dlg[i]) dlg[i]->dialog->TextDef.Font = font;
+ else return false;
+ return true;
+}
+
+bool
+DlgRoot::TextSize(int id, int size)
+{
+ int i;
+
+ i = FindIndex(id);
+ if(size <= 0.001f) return false;
+ if(i && dlg[i]) {
+ dlg[i]->dialog->TextDef.iSize = size;
+ }
+ else return false;
+ return true;
+}
+
+bool
+DlgRoot::ShowItem(int id, bool show)
+{
+ int i;
+
+ i = FindIndex(id);
+ if(i && dlg[i]) dlg[i]->dialog->flags = show ?
+ dlg[i]->dialog->flags & ~HIDDEN : dlg[i]->dialog->flags | HIDDEN;
+ else return false;
+ return true;
+}
+
+int
+DlgRoot::GetResult()
+{
+ int ret;
+
+ //return each result only once !
+ ret = Result;
+ Result = -1;
+ return ret;
+}
+
+int
+DlgRoot::FindIndex(unsigned short id)
+{
+ int i;
+
+ for (i = 0; dlg[i] && i < cDlgs; i++) if(dlg[i]->id == id) return i;
+ return 0;
+}
+
+void
+DlgRoot::ForEach(int cmd, int start, anyOutput *o)
+{
+ int i, j, next;
+
+ if(o)CurrDisp = o;
+ if(dlg && CurrDisp) {
+ next = start;
+ do {
+ if(dlg[next]->first) {
+ if(dlg[next]->flags && ISPARENT) {
+ if(dlg[next]->dialog) {
+ dlg[next]->dialog->Command(CMD_FLUSH, 0L, 0L);
+ //if j equals cDlgs we are caught in a circular reference
+ for(j = 0, i = dlg[next]->first; i && j < cDlgs; j++) {
+ dlg[next]->dialog->Command(CMD_ADDCHILD, (void*)dlg[i = FindIndex(i)]->dialog, 0L);
+ if(i) i = dlg[i]->next;
+ }
+ }
+ else return; //error bad structured template
+ }
+ else { //a debugging aid ....
+ InfoBox("Warning:\ndialog contains\ngroup which is not parent");
+ }
+ //resolve sub-groups recursively
+ // this will not result in any action for children
+ // because the parent is not this!
+ ForEach(cmd, FindIndex(dlg[next]->first), 0L);
+ }
+ //parent objects (groups) will channel command to children
+ if(dlg[next]->dialog && dlg[next]->dialog->parent == this &&
+ !(dlg[next]->dialog->flags & HIDDEN)) switch(cmd) {
+ case CMD_DOPLOT:
+ dlg[next]->dialog->DoPlot(CurrDisp);
+ break;
+ case CMD_LBUP:
+ dlg[next]->dialog->Select(mev->x, mev->y, CurrDisp);
+ break;
+ case CMD_MOUSE_EVENT:
+ dlg[next]->dialog->MBtrack(mev, CurrDisp);
+ break;
+ case CMD_SELECT:
+ dlg[next]->dialog->Select(mev->x, mev->y, CurrDisp);
+ break;
+ }
+ next = FindIndex(dlg[next]->next);
+ }while(next && next < cDlgs);
+ }
+}
+
+void
+DlgRoot::Activate(int id, bool active)
+{
+ int i;
+
+ i = FindIndex(id);
+ if(i && dlg[i]) dlg[i]->dialog->Activate(id, active);
+}
+
+bool
+DlgRoot::ItemCmd(int id, int cmd, void *tmpl)
+{
+ int i;
+
+ if((i = FindIndex(id)) && dlg[i])
+ return dlg[i]->dialog->Command(cmd, tmpl, CurrDisp);
+ return false;
+}
+
+Dialog::Dialog(tag_DlgObj *par, DlgInfo *desc, RECT rec)
+{
+ parent = par;
+ Id = desc->id;
+ flags = desc->flags;
+ memcpy(&cr, &rec, sizeof(RECT));
+ memcpy(&hcr, &rec, sizeof(RECT));
+ Line.width = 0.0;
+ Line.patlength = 1.0;
+ Line.color = DlgBGcolor;
+ Line.pattern = 0x00000000L;
+ Fill.type = FILL_NONE;
+ Fill.color = DlgBGcolor;
+ Fill.scale = 1.0;
+ Fill.hatch = 0L;
+ memcpy(&TextDef, &DlgText, sizeof(TextDEF));
+ type = desc->type;
+ bChecked = flags & CHECKED ? true : false;
+ bLBdown = false;
+ if(DEFAULT == (flags & DEFAULT)) DialogDefault = DialogTabStop = this;
+ bActive = true;
+}
+
+bool
+Dialog::Select(int x, int y, anyOutput *o)
+{
+ if(x > cr.left && x < cr.right && y > cr.top && y < cr.bottom) {
+ if((flags & TOUCHEXIT) && parent)
+ parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ return true;
+ }
+ return false;
+}
+
+bool
+Dialog::SetCheck(int id, anyOutput *o, bool state)
+{
+ if(state != bChecked) {
+ if(parent && state && (flags & ISRADIO)) parent->Command(CMD_RADIOBUTT, (void *)this, o);
+ bChecked = state;
+ if(o) DoPlot(o);
+ return true;
+ }
+ return false;
+}
+
+void
+Dialog::MBtrack(MouseEvent *mev, anyOutput *o)
+{
+ bool bLBstate = false;
+
+ if(mev->Action == MOUSE_LBDOUBLECLICK) {
+ Select(mev->x, mev->y, o);
+ return;
+ }
+ switch(type){
+ case PUSHBUTTON: case ARROWBUTT: case CHECKBOX: case RADIO1:
+ case RADIO2: case TRASH: case CONFIG: case CHECKPIN:
+ if(mev->StateFlags &1) bLBstate = true;
+ if(IsInRect(&hcr, mev->x, mev->y)){
+ if(bLBstate && !bLBdown){
+ bLBdown = bLBstate; DoPlot(o);
+ return;
+ }
+ }
+ else if(bLBdown){
+ bLBdown = false;
+ DoPlot(o);
+ }
+ break;
+ }
+}
+
+void
+Dialog::Activate(int id, bool active)
+{
+ if(id == Id) bActive = active;
+}
+
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Collection of dialog items
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// a simple text button
+PushButton::PushButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text)
+ :Dialog(par, desc, rec)
+{
+ if(text) Text = strdup(text);
+ else Text = 0L;
+ TextDef.Align = TXA_HCENTER | TXA_VCENTER;
+}
+
+PushButton::~PushButton()
+{
+ if(Text) free (Text);
+}
+
+bool
+PushButton::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ switch(cmd) {
+ case CMD_ADDCHAR:
+ if(parent && *((int*)tmpl) == 0x0d) //return pressed
+ parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ return true;
+ }
+ return false;
+}
+
+void
+PushButton::DoPlot(anyOutput *o)
+{
+ POINT pts[3];
+
+ Line.color = 0x00000000L;
+ Fill.color = DlgBGhigh;
+ o->SetLine(&Line);
+ o->SetFill(&Fill);
+ if(bLBdown) o->oRectangle(cr.left, cr.top, cr.right, cr.bottom);
+ else {
+ o->oRectangle(cr.left, cr.top, cr.right-1, cr.bottom-1);
+ Line.color = DlgBGcolor;
+ o->SetLine(&Line);
+ pts[0].x = cr.left; pts[0].y = pts[1].y = cr.bottom-1;
+ pts[1].x = pts[2].x = cr.right-1; pts[2].y = cr.top-1;
+ o->oPolyline(pts, 3);
+ Line.color = 0x00000000L;
+ o->SetLine(&Line);
+ pts[0].x = cr.left+5; pts[0].y = pts[1].y = cr.bottom-1;
+ pts[1].x = pts[2].x = cr.right-1; pts[2].y = cr.top +1;
+ o->oPolyline(pts, 3);
+ Line.color = 0x00ffffffL;
+ o->SetLine(&Line);
+ pts[0].x = pts[1].x = cr.left;
+ pts[0].y = cr.bottom -3;
+ pts[1].y = pts[2].y = cr.top;
+ pts[2].x = cr.right -2;
+ o->oPolyline(pts, 3);
+ }
+ if(Text) {
+ TextDef.Style = DialogDefault == this ? TXS_BOLD : TXS_NORMAL;
+ o->SetTextSpec(&TextDef);
+ o->oTextOut((cr.left + cr.right)/2-2, (cr.top + cr.bottom)/2-1, Text, 0);
+ }
+ o->UpdateRect(&cr, false);
+ if(parent)parent->Command(CMD_TABDLG, this, o);
+}
+
+bool
+PushButton::Select(int x, int y, anyOutput *o)
+{
+ if(IsInRect(&cr, x, y)) {
+ bLBdown = false; DoPlot(o);
+ if(parent) parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ return true;
+ }
+ else if(bLBdown) {
+ bLBdown = false; DoPlot(o);
+ }
+ return false;
+}
+
+TextBox::TextBox(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text)
+ :Dialog(par, desc, rec)
+{
+ TextDef.Font = FONT_COURIER;
+#ifdef _WINDOWS
+// TextDef.fSize unchanged
+#else
+ TextDef.fSize *= .8;
+#endif
+ Fill.color = 0x00ffffffL; Line.color = 0x00000000L; cont = 0L;
+ if(text) cont = new mLabel(0L, 0L, rec.left+3, rec.top+1, &TextDef, text);
+}
+
+TextBox::~TextBox()
+{
+ if(cont)DeleteGO(cont);
+}
+
+bool
+TextBox::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ switch(cmd) {
+ case CMD_CURRLEFT: case CMD_CURRIGHT: case CMD_DELETE:
+ case CMD_POS_FIRST: case CMD_POS_LAST: case CMD_SHIFTLEFT:
+ case CMD_SHIFTRIGHT: case CMD_ADDCHAR:
+ if(bChecked && CurrGO && CurrGO->parent == cont){
+ CurrGO->Command(cmd, tmpl, o);
+ DoPlot(o); o->MrkMode = MRK_NONE;
+ return CurrGO->Command(CMD_REDRAW, 0L, o); //text cursor !
+ }
+ case CMD_CURRUP: case CMD_CURRDOWN:
+ if(bChecked && CurrGO && CurrGO->parent == cont){
+ cont->Command(cmd, tmpl, o);
+ DoPlot(o); o->MrkMode = MRK_NONE;
+ return true;
+ }
+ break;
+ case CMD_SETTEXT:
+ if(cont)DeleteGO(cont);
+ if(tmpl) cont = new mLabel(0L, 0L, cr.left+3, cr.top+1, &TextDef, (char*)tmpl);
+ return true;
+ }
+ return false;
+}
+
+void
+TextBox::DoPlot(anyOutput *o)
+{
+ o->SetLine(&Line); o->SetFill(&Fill);
+ o->oRectangle(cr.left, cr.top, cr.right, cr.bottom);
+ if(cont)cont->DoPlot(o);
+ o->UpdateRect(&cr, false);
+}
+
+bool
+TextBox::Select(int x, int y, anyOutput *o)
+{
+ POINT p1;
+
+ p1.x = x; p1.y = y;
+ if(bActive && IsInRect(&cr, x, y) && !(flags & NOEDIT)) {
+ DialogDefault = DialogFocus = DialogTabStop = this;
+ if(cont) bChecked = cont->Command(CMD_SELECT, &p1, o);
+ }
+ return false;
+}
+
+bool
+TextBox::GetText(int id, char *txt)
+{
+ if(cont) return cont->Command(CMD_ALLTEXT, txt, 0L);
+ return false;
+}
+
+ArrowButton::ArrowButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, int *which)
+ :Dialog(par, desc, rec)
+{
+ direct = which ? *which : 0;
+}
+
+void
+ArrowButton::DoPlot(anyOutput *o)
+{
+ POINT pts[4];
+ int ix, iy, dx, dy;
+
+ Line.color = 0x00000000L;
+ Fill.color = DlgBGhigh;
+ ix = (dx =(cr.right-cr.left))>5 ? dx>>2 : 2;
+ iy = (dy =(cr.bottom-cr.top))>5 ? dy>>2 : 2;
+ o->SetLine(&Line);
+ o->SetFill(&Fill);
+ if(bLBdown) o->oRectangle(cr.left, cr.top, cr.right, cr.bottom);
+ else {
+ o->oRectangle(cr.left, cr.top, cr.right-1, cr.bottom-1);
+ Line.color = DlgBGcolor;
+ o->SetLine(&Line);
+ pts[0].x = cr.left; pts[0].y = pts[1].y = cr.bottom-1;
+ pts[1].x = pts[2].x = cr.right-1; pts[2].y = cr.top-1;
+ o->oPolyline(pts, 3);
+ Line.color = 0x00ffffffL;
+ o->SetLine(&Line);
+ pts[0].x = pts[1].x = cr.left;
+ pts[0].y = cr.bottom -3;
+ pts[1].y = pts[2].y = cr.top;
+ pts[2].x = cr.right -2;
+ o->oPolyline(pts, 3);
+ }
+ Fill.color = Line.color = 0x00000000L;
+ o->SetLine(&Line);
+ o->SetFill(&Fill);
+ switch(direct) {
+ case 1:
+ pts[0].x = pts[3].x = cr.left+ix;
+ pts[0].y = pts[3].y = pts[1].y = cr.bottom-(iy<<1);
+ pts[1].x = cr.right-(ix<<1);
+ pts[2].x = (cr.right + cr.left)/2 -1;
+ pts[2].y = cr.top+iy;
+ o->oPolygon(pts, 4);
+ break;
+ case 2:
+ pts[0].x = pts[3].x = cr.left+ix;
+ pts[0].y = pts[3].y = pts[1].y = cr.top+iy;
+ pts[1].x = cr.right-(ix<<1);
+ pts[2].x = (cr.right + cr.left)/2 -1;
+ pts[2].y = cr.bottom-(iy<<1);
+ o->oPolygon(pts, 4);
+ break;
+ case 3:
+ pts[0].x = pts[3].x = cr.left+ix;
+ pts[0].y = pts[3].y = (cr.bottom + cr.top)/2-1;
+ pts[1].x = pts[2].x = cr.right-(ix<<1);
+ pts[1].y = cr.bottom-(iy<<1);
+ pts[2].y = cr.top+iy;
+ o->oPolygon(pts, 4);
+ break;
+ case 4:
+ pts[0].x = pts[3].x = cr.right-(ix<<1);
+ pts[0].y = pts[3].y = (cr.bottom + cr.top)/2-1;
+ pts[1].x = pts[2].x = cr.left+2;
+ pts[1].y = cr.bottom-(iy<<1);
+ pts[2].y = cr.top+iy;
+ o->oPolygon(pts, 4);
+ break;
+ }
+ o->UpdateRect(&cr, false);
+}
+
+bool
+ArrowButton::Select(int x, int y, anyOutput *o)
+{
+ if(IsInRect(&cr, x, y)) {
+ bLBdown = false;
+ DoPlot(o);
+ if(parent) parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ return true;
+ }
+ else if(bLBdown) {
+ bLBdown = false;
+ DoPlot(o);
+ }
+ return false;
+}
+
+ColorButton::ColorButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, unsigned long color)
+ :Dialog(par, desc, rec)
+{
+ col = color;
+}
+
+void
+ColorButton::DoPlot(anyOutput *o)
+{
+ POINT pts[5];
+
+ Fill.color = col;
+ o->SetFill(&Fill);
+ if(flags & ISRADIO) {
+ Line.color = bChecked ? 0x00000000L : DlgBGcolor;
+ o->SetLine(&Line);
+ pts[0].x = pts[3].x = pts[4].x = cr.left;
+ pts[0].y = pts[1].y = pts[4].y = cr.top;
+ pts[1].x = pts[2].x = cr.right-1;
+ pts[2].y = pts[3].y = cr.bottom-1;
+ o->oPolyline(pts, 5);
+ Line.color = 0x00000000L;
+ o->SetLine(&Line);
+ o->oRectangle(cr.left+3, cr.top+3, cr.right-3, cr.bottom-3);
+ }
+ else {
+ Line.color = 0x00000000L;
+ o->SetLine(&Line);
+ o->oRectangle(cr.left, cr.top, cr.right, cr.bottom);
+ }
+ o->UpdateRect(&cr, false);
+}
+
+bool
+ColorButton::Select(int x, int y, anyOutput *o)
+{
+ if(!parent) return false;
+ if(IsInRect(&cr, x, y)) {
+ bChecked = true;
+ if((flags & OWNDIALOG)) {
+ parent->Command(CMD_CONTINUE, 0L, o);
+ col = GetNewColor(col);
+ }
+ if(flags & ISRADIO) parent->Command(CMD_RADIOBUTT, (void *)this, o);
+ if(flags & TOUCHEXIT) parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ DoPlot(o);
+ return true;
+ }
+ return false;
+}
+
+FillButton::FillButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, FillDEF *fill)
+ :Dialog(par, desc, rec)
+{
+ CurrFill = fill;
+}
+
+void
+FillButton::DoPlot(anyOutput *o)
+{
+ Line.color = 0x00000000L;
+ o->SetLine(&Line);
+ o->SetFill(CurrFill);
+ o->oRectangle(cr.left, cr.top, cr.right, cr.bottom);
+ o->UpdateRect(&cr, false);
+}
+
+bool
+FillButton::Select(int x, int y, anyOutput *o)
+{
+ if(IsInRect(&cr, x, y)) {
+ if((flags & OWNDIALOG)) {
+ if(parent)parent->Command(CMD_CONTINUE, 0L, o);
+ GetNewFill(CurrFill);
+ }
+ if((flags & TOUCHEXIT) && parent)
+ parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ DoPlot(o);
+ return true;
+ }
+ return false;
+}
+
+Shade3D::Shade3D(tag_DlgObj *par, DlgInfo * desc, RECT rec, FillDEF *fill)
+ :Dialog(par, desc, rec)
+{
+ CurrFill = fill;
+}
+
+void
+Shade3D::DoPlot(anyOutput *o)
+{
+ POINT pts[5];
+ FillDEF fd;
+ int dx;
+
+ Line.color = 0x00000000L;
+ o->SetLine(&Line);
+ if(CurrFill->type & FILL_LIGHT3D) {
+ fd.color = fd.color2 = CurrFill->color;
+ fd.hatch = 0L; fd.scale = 1.0;
+ fd.type = 0L;
+ dx = iround(((double)(cr.bottom - cr.top))*.26);
+ pts[0].x = pts[1].x = pts[4].x = ((cr.left + cr.right)>>1);
+ pts[0].y = pts[4].y = cr.bottom;
+ pts[1].y = ((cr.top + cr.bottom)>>1);
+ pts[2].x = pts[3].x = pts[0].x + (dx<<1);
+ pts[2].y = pts[1].y - dx; pts[3].y = pts[0].y - dx;
+ o->SetFill(&fd);
+ o->oPolygon(pts, 5, 0L);
+ fd.color = fd.color2 = IpolCol(CurrFill->color, CurrFill->color2, 0.4);
+ pts[2].x = pts[3].x = pts[0].x - (dx<<1);
+ o->SetFill(&fd);
+ o->oPolygon(pts, 5, 0L);
+ fd.color = fd.color2 = CurrFill->color2;
+ pts[0].y = pts[4].y = pts[1].y;
+ pts[1].x = pts[2].x; pts[1].y = pts[3].y = pts[2].y;
+ pts[2].x = pts[0].x; pts[2].y -= dx;
+ pts[3].x = pts[0].x + (dx<<1);
+ o->SetFill(&fd);
+ o->oPolygon(pts, 5, 0L);
+ }
+ else {
+ o->SetFill(CurrFill);
+ o->oRectangle(cr.left, cr.top, cr.right, cr.bottom);
+ }
+ o->UpdateRect(&cr, false);
+}
+
+void ConfShade(FillDEF *oldfill);
+bool
+Shade3D::Select(int x, int y, anyOutput *o)
+{
+ if(IsInRect(&cr, x, y)) {
+ if((flags & OWNDIALOG)) {
+ if(parent)parent->Command(CMD_CONTINUE, 0L, o);
+ ConfShade(CurrFill);
+ }
+ if((flags & TOUCHEXIT) && parent)
+ parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ DoPlot(o);
+ return true;
+ }
+ return false;
+}
+
+LineButton::LineButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, LineDEF *line)
+ :Dialog(par, desc, rec)
+{
+ Line.color = 0x00000000L;
+ CurrLine = line;
+ Fill.color = defs.Color(COL_BG);
+ pts[0].x = cr.left+4;
+ pts[1].x = cr.right-5;
+ pts[0].y = pts[1].y = (cr.top + cr.bottom)/2;
+}
+
+void
+LineButton::DoPlot(anyOutput *o)
+{
+ o->SetLine(&Line);
+ o->SetFill(&Fill);
+ o->oRectangle(cr.left, cr.top, cr.right, cr.bottom);
+ o->SetLine(CurrLine);
+ o->oPolyline(pts, 2);
+ o->UpdateRect(&cr, false);
+}
+
+bool
+LineButton::Select(int x, int y, anyOutput *o)
+{
+ if(IsInRect(&cr, x, y)) {
+ if((flags & TOUCHEXIT) && parent)
+ parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ DoPlot(o);
+ return true;
+ }
+ return false;
+}
+
+SymButton::SymButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, Symbol **sym)
+ :Dialog(par, desc, rec)
+{
+ symbol = sym;
+ Line.color = 0x00000000L;
+ Fill.color = 0x00ffffffL;
+}
+
+void
+SymButton::DoPlot(anyOutput *o)
+{
+ Line.color = 0x00000000L;
+ o->SetLine(&Line);
+ o->SetFill(&Fill);
+ o->oRectangle(cr.left, cr.top, cr.right, cr.bottom);
+ if(*(symbol)) { //center symbol in the rectangle
+ (*symbol)->SetSize(SIZE_XPOS, (cr.right+cr.left)/2.0);
+ (*symbol)->SetSize(SIZE_YPOS, (cr.bottom+cr.top)/2.0);
+ (*symbol)->DoPlot(o);
+ }
+ o->UpdateRect(&cr, false);
+}
+
+bool
+SymButton::Select(int x, int y, anyOutput *o)
+{
+ if(IsInRect(&cr, x, y)) {
+ if((flags & TOUCHEXIT) && parent)
+ parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ DoPlot(o);
+ return true;
+ }
+ return false;
+}
+
+FillRadioButt::FillRadioButt(tag_DlgObj *par, DlgInfo * desc, RECT rec, unsigned int pattern)
+ :Dialog(par, desc, rec)
+{
+ Line.pattern = 0x00000000L; Fill.type = pattern;
+ Fill.color = 0x00ffffffL; Fill.hatch = &Line;
+ flags |= ISRADIO;
+}
+
+void
+FillRadioButt::DoPlot(anyOutput *o)
+{
+ POINT pts[5];
+
+ Line.color = bChecked ? 0x00000000L : DlgBGcolor;
+ o->SetLine(&Line);
+ pts[0].x = pts[3].x = pts[4].x = cr.left;
+ pts[0].y = pts[1].y = pts[4].y = cr.top;
+ pts[1].x = pts[2].x = cr.right-1;
+ pts[2].y = pts[3].y = cr.bottom-1;
+ o->oPolyline(pts, 5);
+ Line.color = 0x00000000L;
+ o->SetLine(&Line);
+ o->SetFill(&Fill);
+ o->oRectangle(cr.left+3, cr.top+3, cr.right-3, cr.bottom-3);
+ o->UpdateRect(&cr, false);
+}
+
+bool
+FillRadioButt::Select(int x, int y, anyOutput *o)
+{
+ if(IsInRect(&cr, x, y)) {
+ bChecked = true;
+ DoPlot(o);
+ if(parent) parent->Command(CMD_RADIOBUTT, (void *)this, o);
+ if((flags & TOUCHEXIT) && parent)
+ parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ return true;
+ }
+ return false;
+}
+
+SymRadioButt::SymRadioButt(tag_DlgObj *par, DlgInfo * desc, RECT rec, int* type)
+ :Dialog(par, desc, rec)
+{
+ double size;
+
+ if(type && (Sym = new Symbol(0L, 0L, ((double)(cr.right+cr.left))/2.0,
+ ((double)(cr.bottom+cr.top))/2.0, *type))){
+ size = (0.14*(double)(cr.bottom-cr.top))/Units[defs.cUnits].convert;
+ Sym->SetSize(SIZE_SYMBOL, size); Sym->SetSize(SIZE_SYM_LINE, size/10.0);
+ Sym->SetColor(COL_SYM_LINE, 0x00000000L); Sym->SetColor(COL_SYM_FILL, 0x00ffffffL);
+ }
+ Fill.color = DlgBGhigh; flags |= ISRADIO;
+}
+
+SymRadioButt::~SymRadioButt()
+{
+ if (Sym) delete Sym;
+}
+
+void
+SymRadioButt::DoPlot(anyOutput *o)
+{
+ if(!Sym) return;
+ Line.color = bChecked ? 0x00000000L : Fill.color;
+ o->SetFill(&Fill);
+ o->SetLine(&Line);
+ o->oRectangle(cr.left, cr.top, cr.right, cr.bottom);
+ Sym->DoPlot(o);
+ o->UpdateRect(&cr, false);
+}
+
+bool
+SymRadioButt::Select(int x, int y, anyOutput *o)
+{
+ if(IsInRect(&cr, x, y)) {
+ bChecked = true;
+ DoPlot(o);
+ if(parent) parent->Command(CMD_RADIOBUTT, (void *)this, o);
+ if((flags & TOUCHEXIT) && parent)
+ parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ return true;
+ }
+ return false;
+}
+
+CheckBox::CheckBox(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text)
+ :Dialog(par, desc, rec)
+{
+ if(text)Text = strdup(text);
+ else Text = 0L;
+ hcr.left = cr.left+2; hcr.right = cr.left+14;
+ hcr.top = cr.top+3; hcr.bottom = cr.top+15;
+}
+
+CheckBox::~CheckBox()
+{
+ if(Text) free (Text);
+}
+
+bool
+CheckBox::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ switch(cmd) {
+ case CMD_SETTEXT:
+ if(Text) free(Text);
+ if(tmpl) Text = strdup((char *)tmpl);
+ else Text = 0L;
+ return true;
+ }
+ return false;
+}
+
+void
+CheckBox::DoPlot(anyOutput *o)
+{
+ POINT pts[3];
+
+ if(flags & HIDDEN) return;
+ Line.color = 0x00000000L;
+ Line.width = 0.0;
+ Fill.color = bLBdown ? DlgBGcolor : 0x00ffffffL;
+ o->SetLine(&Line);
+ o->SetFill(&Fill);
+ o->oRectangle(cr.left+2, cr.top+3, cr.left+14, cr.top+15);
+ if(bChecked) {
+ Line.width = defs.GetSize(SIZE_SYM_LINE)*2.0;
+ o->SetLine(&Line);
+ pts[0].x = cr.left+4; pts[0].y = cr.top+5;
+ pts[1].x = cr.left+11; pts[1].y = cr.top+12;
+ o->oSolidLine(pts);
+ pts[0].x = cr.left+11; pts[1].x = cr.left+4;
+ o->oSolidLine(pts);
+ }
+ if(Text) {
+ o->SetTextSpec(&TextDef);
+ o->oTextOut(cr.left + 20, cr.top + 1, Text, strlen(Text));
+ }
+ o->UpdateRect(&cr, false);
+}
+
+bool
+CheckBox::Select(int x, int y, anyOutput *o)
+{
+ if(!(flags & HIDDEN) && IsInRect(&hcr, x, y)) {
+ bChecked ^= 0x01; //toggle selection
+ bLBdown = false;
+ DoPlot(o);
+ if((flags & ISRADIO) && parent)
+ parent->Command(CMD_RADIOBUTT, (void *)this, o);
+ if((flags & TOUCHEXIT) && parent)
+ parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ return true;
+ }
+ return false;
+}
+
+CheckPin::CheckPin(tag_DlgObj *par, DlgInfo * desc, RECT rec)
+ :Dialog(par, desc, rec)
+{
+ hcr.left = cr.left+2; hcr.right = cr.right-2;
+ hcr.top = cr.top+2; hcr.bottom = cr.bottom-2;
+}
+
+CheckPin::~CheckPin()
+{
+}
+
+bool
+CheckPin::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ switch(cmd) {
+ case CMD_UNLOCK:
+ bChecked = false;
+ return true;
+ }
+ return false;
+}
+
+void
+CheckPin::DoPlot(anyOutput *o)
+{
+ POINT pts[20];
+
+ if(!o || flags & HIDDEN) return;
+ Line.width = 0.0;
+ Line.color = DlgBGcolor; Fill.color = DlgBGcolor;
+ o->SetLine(&Line); o->SetFill(&Fill);
+ o->oRectangle(hcr.left+2, hcr.top, hcr.right, hcr.bottom);
+ Line.color = 0x00000000L; Fill.color = bLBdown ? 0x00ffffff : 0x00e8e8e8L;
+ o->SetLine(&Line); o->SetFill(&Fill);
+ if(bChecked) {
+ o->oCircle(hcr.left + 5, hcr.top + 1, hcr.left + 15, hcr.top + 12);
+ o->oCircle(hcr.left + 8, hcr.top + 3, hcr.left + 15, hcr.top + 10);
+ }
+ else {
+ pts[0].x = hcr.left + 8; pts[0].y = hcr.top + 4;
+ pts[1].x = pts[0].x - 5; pts[1].y = pts[0].y + 1;
+ pts[2].x = pts[0].x; pts[2].y = pts[1].y + 1;
+ pts[3].x = pts[0].x; pts[3].y = pts[0].y;
+ o->oPolygon(pts, 4);
+ pts[0].x = hcr.left + 8; pts[0].y = hcr.top + 1;
+ pts[1].x = pts[0].x; pts[1].y = pts[0].y + 9;
+ pts[2].x = pts[1].x + 3; pts[2].y = pts[1].y - 3;
+ pts[3].x = pts[2].x + 4; pts[3].y = pts[2].y;
+ pts[4].x = pts[3].x; pts[4].y = pts[3].y - 3;
+ pts[5].x = pts[4].x - 4; pts[5].y = pts[4].y;
+ pts[6].x = pts[0].x; pts[6].y = pts[0].y;
+ o->oPolygon(pts, 7);
+ o->oCircle(pts[4].x-2, pts[0].y, pts[4].x+3, pts[1].y+1);
+ }
+ o->UpdateRect(&cr, false);
+}
+
+bool
+CheckPin::Select(int x, int y, anyOutput *o)
+{
+ if(!(flags & HIDDEN) && IsInRect(&hcr, x, y)) {
+ bChecked ^= 0x01; //toggle selection
+ bLBdown = false; DoPlot(o);
+ if((flags & TOUCHEXIT) && parent)
+ parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ bLBdown=false; DoPlot(o);
+ return true;
+ }
+ return false;
+}
+
+Trash::Trash(tag_DlgObj *par, DlgInfo * desc, RECT rec)
+ :Dialog(par, desc, rec)
+{
+ hcr.left = cr.left+2; hcr.right = cr.right-2;
+ hcr.top = cr.top+2; hcr.bottom = cr.bottom-2;
+}
+
+Trash::~Trash()
+{
+}
+
+bool
+Trash::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ return false;
+}
+
+void
+Trash::DoPlot(anyOutput *o)
+{
+ POINT pts[2];
+
+ if(!o || flags & HIDDEN) return;
+ Line.width = 0.0;
+ Line.color = DlgBGcolor; Fill.color = DlgBGcolor;
+ o->SetLine(&Line); o->SetFill(&Fill);
+ o->oRectangle(hcr.left+2, hcr.top, hcr.right, hcr.bottom);
+ Line.color = 0x00000000L; Fill.color = bLBdown ? 0x00ffffff : 0x00e8e8e8L;
+ o->SetLine(&Line); o->SetFill(&Fill);
+ o->oRectangle(cr.left+8, cr.top+10, cr.right-8, cr.bottom-3);
+ o->oRectangle(cr.left+6, cr.top+5, cr.right-6, cr.top+10);
+ o->oRectangle(cr.left+11, cr.top+2, cr.right-11, cr.top+5);
+ pts[0].y = cr.top + 12; pts[1].y = cr.bottom - 5;
+ pts[0].x = pts[1].x = cr.left + 12; o->oSolidLine(pts);
+ pts[0].x = pts[1].x = cr.right - 13; o->oSolidLine(pts);
+ o->UpdateRect(&cr, false);
+}
+
+bool
+Trash::Select(int x, int y, anyOutput *o)
+{
+ if(!(flags & HIDDEN) && IsInRect(&hcr, x, y)) {
+ if((flags & TOUCHEXIT) && parent)
+ parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ bLBdown=false; DoPlot(o);
+ return true;
+ }
+ return false;
+}
+
+Config::Config(tag_DlgObj *par, DlgInfo * desc, RECT rec)
+ :Dialog(par, desc, rec)
+{
+ hcr.left = cr.left+2; hcr.right = cr.right-2;
+ hcr.top = cr.top+2; hcr.bottom = cr.bottom-2;
+}
+
+Config::~Config()
+{
+}
+
+bool
+Config::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ return false;
+}
+
+void
+Config::DoPlot(anyOutput *o)
+{
+ POINT pts[2];
+
+ if(!o || flags & HIDDEN) return;
+ Line.width = 0.0;
+ Line.color = DlgBGcolor; Fill.color = DlgBGcolor;
+ o->SetLine(&Line); o->SetFill(&Fill);
+ o->oRectangle(hcr.left+2, hcr.top, hcr.right, hcr.bottom);
+ Line.color = 0x00000000L; Fill.color = bLBdown ? 0x00ffffff : 0x00e8e8e8L;
+ o->SetLine(&Line); o->SetFill(&Fill);
+ o->oRectangle(cr.left+3, cr.top+3, cr.right-3, cr.bottom-3);
+ o->oRectangle(cr.left+8, cr.top+6, cr.left+11, cr.top+9);
+ o->oRectangle(cr.left+8, cr.top+10, cr.left+11, cr.top+13);
+ o->oRectangle(cr.left+8, cr.top+14, cr.left+11, cr.top+17);
+ o->oRectangle(cr.left+7, cr.top+18, cr.right-7, cr.bottom-5);
+ pts[0].x = cr.left + 14; pts[1].x = cr.right - 8;
+ pts[0].y = pts[1].y = cr.top + 7; o->oSolidLine(pts);
+ pts[0].y = pts[1].y = cr.top + 11; o->oSolidLine(pts);
+ pts[0].y = pts[1].y = cr.top + 15; o->oSolidLine(pts);
+ o->UpdateRect(&cr, false);
+}
+
+bool
+Config::Select(int x, int y, anyOutput *o)
+{
+ if(!(flags & HIDDEN) && IsInRect(&hcr, x, y)) {
+ if((flags & TOUCHEXIT) && parent)
+ parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ bLBdown=false; DoPlot(o);
+ return true;
+ }
+ return false;
+}
+
+RadioButton::RadioButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text)
+ :Dialog(par, desc, rec)
+{
+ if(text) Text = strdup(text);
+ else Text = 0L;
+ switch(type) {
+ case RADIO0:
+ hcr.left = cr.left+4; hcr.right = cr.left+13;
+ hcr.top = cr.top+4; hcr.bottom = cr.top+13;
+ break;
+ case RADIO1:
+ hcr.left = cr.left+2; hcr.right = cr.left+15;
+ hcr.top = cr.top+3; hcr.bottom = cr.top+16;
+ break;
+ case RADIO2:
+ hcr.left = cr.left; hcr.right = cr.left+15;
+ hcr.top = cr.top+1; hcr.bottom = cr.top+16;
+ break;
+ }
+ flags |= ISRADIO;
+}
+
+RadioButton::~RadioButton()
+{
+ if(Text) free (Text);
+}
+
+bool
+RadioButton::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ switch(cmd) {
+ case CMD_SETTEXT:
+ if(Text) free(Text);
+ if(tmpl)Text = strdup((char *)tmpl);
+ else Text = 0L;
+ return true;
+ }
+ return false;
+}
+
+void
+RadioButton::DoPlot(anyOutput *o)
+{
+ if(flags & HIDDEN) return;
+ Line.color = 0x00000000L;
+ Line.width = 0.0;
+ Fill.color = bLBdown ? DlgBGcolor : 0x00ffffffL;
+ if(bActive) {
+ o->SetLine(&Line);
+ o->SetFill(&Fill);
+ o->oCircle(hcr.left, hcr.top, hcr.right, hcr.bottom);
+ if(bChecked) {
+ Fill.color = 0x00000000L; o->SetFill(&Fill);
+ switch (type) {
+ case RADIO0:
+ o->oCircle(cr.left+6, cr.top+6, cr.left+11, cr.top+11);
+ break;
+ case RADIO1:
+ o->oCircle(cr.left+5, cr.top+6, cr.left+12, cr.top+13);
+ break;
+ case RADIO2:
+ o->oCircle(cr.left+3, cr.top+4, cr.left+12, cr.top+13);
+ break;
+ }
+ }
+ }
+ if(Text) {
+ o->SetTextSpec(&TextDef);
+ o->oTextOut(cr.left + 20, cr.top + 1, Text, strlen(Text));
+ }
+ o->UpdateRect(&cr, false);
+}
+
+bool
+RadioButton::Select(int x, int y, anyOutput *o)
+{
+ if(bActive && !(flags & HIDDEN) && IsInRect(&hcr, x, y)) {
+ bChecked = true; bLBdown = false;
+ DoPlot(o);
+ if(parent) parent->Command(CMD_RADIOBUTT, (void *)this, o);
+ if((flags & TOUCHEXIT) && parent)
+ parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ return true;
+ }
+ return false;
+}
+
+void
+RadioButton::SetColor(int id, DWORD color)
+{
+ TextDef.ColTxt = color;
+}
+
+Text::Text(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text)
+ :Dialog(par, desc, rec)
+{
+ if(text) txt = strdup(text);
+ else txt = 0L;
+ switch (type) {
+ case RTEXT: TextDef.Align = TXA_HRIGHT | TXA_VTOP; break;
+ case CTEXT: TextDef.Align = TXA_HCENTER | TXA_VTOP; break;
+ default: TextDef.Align = TXA_HLEFT | TXA_VTOP; break;
+ }
+}
+
+Text::~Text()
+{
+ if(txt) free(txt);
+}
+
+bool
+Text::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ switch(cmd) {
+ case CMD_SETTEXT:
+ if(txt) free(txt);
+ if(tmpl)txt = strdup((char *)tmpl);
+ else txt = 0L;
+ return true;
+ }
+ return false;
+}
+
+void
+Text::DoPlot(anyOutput *o)
+{
+ if(WWWbrowser && WWWbrowser[0] && (flags & HREF)) {
+ TextDef.ColTxt = 0x00ff0000L;
+ TextDef.Style |= TXS_UNDERLINE;
+ }
+ if(txt){
+ o->SetTextSpec(&TextDef);
+ switch(type) {
+ case RTEXT: o->oTextOut(cr.right - 2, cr.top + 1, txt, 0); break;
+ case CTEXT: o->oTextOut((cr.left + cr.right)/2, cr.top + 1, txt, 0); break;
+ default: o->oTextOut(cr.left + 2, cr.top + 1, txt, 0); break;
+ }
+ o->UpdateRect(&cr, false);
+ }
+}
+
+bool
+Text::Select(int x, int y, anyOutput *o)
+{
+ if(WWWbrowser && WWWbrowser[0] && txt && (flags & HREF) && IsInRect(&cr, x, y)) {
+ sprintf(TmpTxt, "%s %s", WWWbrowser, txt);
+ if(parent)parent->Command(CMD_CONTINUE, 0L, o);
+#ifdef _WINDOWS
+ WinExec(TmpTxt, SW_SHOWMAXIMIZED);
+#else
+ strcat(TmpTxt, " &");
+ system(TmpTxt);
+#endif
+ if(parent)parent->Command(CMD_ENDDIALOG, 0L, o);
+ return true;
+ }
+ return false;
+}
+
+void
+Text::SetColor(int id, DWORD color)
+{
+ TextDef.ColTxt = color;
+}
+
+InputText::InputText(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text)
+ :Dialog(par, desc, rec)
+{
+ POINT p1, p2;
+
+ p1.x = rec.left+1; p1.y = rec.top+1;
+ p2.x = rec.right-1; p2.y = rec.bottom-1;
+ if(type == INCDECVAL1) cr.right = p2.x = cr.right - 7*xbase;
+ Line.color = 0x00000000L;
+ Text = new EditText(0L, p1, p2, text);
+ Disp = 0L;
+}
+
+InputText::~InputText()
+{
+ if(Text) delete (Text); Text = 0L;
+}
+
+bool
+InputText::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ double tmpVal;
+ bool bRet;
+
+ switch(cmd) {
+ case CMD_CURRLEFT: case CMD_CURRIGHT: case CMD_DELETE:
+ case CMD_POS_FIRST: case CMD_POS_LAST: case CMD_SHIFTLEFT:
+ case CMD_SHIFTRIGHT:
+ if(Text && bActive && !(flags & NOEDIT)){
+ o->SetTextSpec(&TextDef);
+ bRet = Text->Command(cmd, o, NULL);
+ if(bRet && (flags & TOUCHEXIT)) parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ return bRet;
+ }
+ break;
+ case CMD_SETFONT: case CMD_SETSTYLE:
+ if(Text) return Text->Command(cmd, o, tmpl);
+ return false;
+ case CMD_ADDCHAR:
+ if(Text && bActive && !(flags & NOEDIT)){
+ if(flags & TOUCHEXIT) parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ o->SetTextSpec(&TextDef);
+ switch(*((int*)tmpl)) {
+ case 8: return Text->Command(CMD_BACKSP, o, NULL); //Backspace
+ default: return Text->AddChar(*((int*)tmpl), o, 0L);
+ }
+ }
+ return false;
+ case CMD_SETTEXT:
+ if(Text) {
+ if(Text->text) free(Text->text);
+ if(tmpl)Text->text = strdup((char*)tmpl);
+ else Text->text = 0L;
+ return false;
+ }
+ break;
+ case CMD_ENDDIALOG: //we should come here for IncDecValue class only
+ if(type == INCDECVAL1 && GetValue(Id, &tmpVal)) {
+ if(((Dialog*)tmpl)->Id == 1) tmpVal *= 1.2;
+ else tmpVal /= 1.2;
+ tmpVal = NiceValue(tmpVal);
+ if(fabs(tmpVal) < 0.0001) switch(defs.cUnits) {
+ case 1: tmpVal = 0.01; break;
+ case 2: tmpVal = 0.004; break;
+ default: tmpVal = 0.1; break;
+ }
+ WriteNatFloatToBuff(TmpTxt, tmpVal);
+ if(Text) {
+ if(Text->text) free(Text->text);
+ Text->text = strdup(TmpTxt+1);
+ DoPlot(o);
+ }
+ }
+ break;
+ }
+ return false;
+}
+
+void
+InputText::DoPlot(anyOutput *o)
+{
+ POINT pts[5];
+
+ Disp = o;
+ pts[0].x = pts[0].y = 0; //that means no caret with update(5)
+ o->SetTextSpec(&TextDef);
+ if(Text) Text->Update(bActive ? 5 : 2, o, &pts[0]);
+ o->SetLine(&Line);
+ pts[0].x = pts[1].x = pts[4].x = cr.left;
+ pts[0].y = pts[3].y = pts[4].y = cr.top;
+ pts[1].y = pts[2].y = cr.bottom-1;
+ pts[2].x = pts[3].x = cr.right-1;
+ o->oPolyline(pts, 5);
+ o->UpdateRect(&cr, false);
+ if(parent && bActive)parent->Command(CMD_TABDLG, this, o);
+}
+
+bool
+InputText::Select(int x, int y, anyOutput *o)
+{
+ POINT p1;
+
+ p1.x = x; p1.y = y;
+ if(bActive && IsInRect(&cr, x, y) && !(flags & NOEDIT)) {
+ DialogFocus = DialogTabStop = this;
+ if(parent) parent->Command(CMD_FOCTXT, (void*)this, 0L);
+ o->SetTextSpec(&TextDef);
+ if(Text) Text->Update(1, o, &p1);
+ if(flags & TOUCHEXIT) parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ }
+ return false;
+}
+
+bool
+InputText::GetValue(int id, double *val)
+{
+ if(Text) {
+ Text->Update(20, NULL, 0L); //convert string to value
+ return Text->GetValue(val);
+ }
+ return false;
+}
+
+bool
+InputText::GetInt(int id, int *val)
+{
+ if(type == EDTEXT) {
+ if(Text) *val = Text->Cursor();
+ else *val = 0;
+ return true;
+ }
+ if(Text && Text->text) {
+ sscanf(Text->text, "%d", val);
+ return true;
+ }
+ return false;
+}
+
+bool
+InputText::GetText(int id, char *txt)
+{
+ if(Text && Text->text && Text->text[0]) {
+ strcpy(txt, Text->text);
+ return true;
+ }
+ return false;
+}
+
+void
+InputText::MBtrack(MouseEvent *mev, anyOutput *o)
+{
+ bool bLBstate;
+ int x, y;
+
+ x = mev->x; y = mev->y;
+ if(mev->StateFlags &1) bLBstate = true;
+ else bLBstate = false;
+ if(bActive && IsInRect(&cr, x, y) && !(flags & NOEDIT) &&
+ bLBstate && Text) {
+ DialogFocus = this;
+ if(parent) parent->Command(CMD_FOCTXT, (void*)this, 0L);
+ o->SetTextSpec(&TextDef);
+ Text->Command(CMD_MOUSE_EVENT, o, (DataObj *)mev);
+ }
+}
+
+void
+InputText::Activate(int id, bool activate)
+{
+ bActive = activate;
+ if(Text && Disp) {
+ Disp->SetTextSpec(&TextDef);
+ if(bActive){
+ Text->Update(1, Disp, 0L);
+ DialogFocus = DialogTabStop = this;
+ if(parent) parent->Command(CMD_FOCTXT, this, Disp);
+ }
+ else Text->Update(2, Disp, 0L);
+ }
+}
+
+InputValue::InputValue(tag_DlgObj *par, DlgInfo * desc, RECT rec, double *value)
+ :InputText(par, desc, rec, 0L)
+{
+ WriteNatFloatToBuff(TmpTxt, *value);
+ if(Text) Text->text = strdup(TmpTxt+1);
+}
+
+InputValue::~InputValue()
+{
+ if(Text) delete (Text);
+ Text = 0L; //in fact the destructor of InputText is also
+ // called. This prevents a double delete of Text.
+}
+
+IncDecValue::IncDecValue(tag_DlgObj *par, DlgInfo * desc, RECT rec, double *value)
+ :InputText(par, desc, rec, 0L)
+{
+ int ab1 = 1, ab2 = 2;
+ static DlgInfo ab[] = {
+ {1, 2, 0, 0x0L, ARROWBUTT, (void*)&ab1, 0, 0, 0, 0},
+ {2, 0, 0, LASTOBJ, ARROWBUTT, (void*)&ab2, 0, 0, 0, 0}};
+ RECT br;
+
+ WriteNatFloatToBuff(TmpTxt, *value);
+ if(Text) Text->text = strdup(TmpTxt+1);
+ br.left = cr.right+1; br.right = br.left + 7*xbase;
+ br.top = cr.top+1; br.bottom = br.top + 5*ybase;
+ butts[0] = new ArrowButton(this, &ab[0], br, &ab1);
+ br.top += 5*ybase; br.bottom += 5*ybase;
+ butts[1] = new ArrowButton(this, &ab[1], br, &ab2);
+}
+
+IncDecValue::~IncDecValue()
+{
+ if(Text) delete (Text);
+ if(butts[0]) delete (butts[0]);
+ if(butts[1]) delete (butts[1]);
+ Text = 0L;
+}
+
+void
+IncDecValue::DoPlot(anyOutput *o)
+{
+ InputText::DoPlot(o);
+ if(butts[0]) butts[0]->DoPlot(o);
+ if(butts[1]) butts[1]->DoPlot(o);
+}
+
+bool
+IncDecValue::Select(int x, int y, anyOutput *o)
+{
+ bool bRet = false;
+
+ if(x > cr.right) {
+ if(butts[0]) bRet = butts[0]->Select(x, y, o);
+ if(!bRet && butts[1]) bRet = butts[1]->Select(x, y, o);
+ }
+ else return InputText::Select(x, y, o);
+ if(bRet && parent) {
+ DialogFocus = DialogTabStop = 0L;
+ if(parent) parent->Command(CMD_FOCTXT, (void*)0L, 0L);
+ if(flags & TOUCHEXIT) parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ }
+ return bRet;
+}
+
+void
+IncDecValue::MBtrack(MouseEvent *mev, anyOutput *o)
+{
+ if(mev->x >cr.right) {
+ if(butts[0]) butts[0]->MBtrack(mev, o);
+ if(butts[1]) butts[1]->MBtrack(mev, o);
+ }
+ else InputText::MBtrack(mev, o);
+}
+
+TxtHSP::TxtHSP(tag_DlgObj *par, DlgInfo *desc, RECT rec, int *align)
+ :Dialog(par, desc, rec)
+{
+ int x1 = cr.left/xbase, x2 = ((cr.left>>1) + (cr.right>>1))/xbase-4,
+ x3 = cr.right/xbase-8, y1 = cr.top/ybase,
+ y2 = ((cr.top>>1) + (cr.bottom>>1))/ybase-4, y3 = cr.bottom/ybase-8;
+ int i;
+ RECT br;
+
+ DlgInfo d1[] = {
+ {1, 2, 0, ISRADIO, RADIO0, 0L, x1, y1, 8, 8},
+ {2, 3, 0, ISRADIO, RADIO0, 0L, x2, y1, 8, 8},
+ {3, 4, 0, ISRADIO, RADIO0, 0L, x3, y1, 8, 8},
+ {4, 5, 0, ISRADIO, RADIO0, 0L, x1, y2, 8, 8},
+ {5, 6, 0, ISRADIO, RADIO0, 0L, x2, y2, 8, 8},
+ {6, 7, 0, ISRADIO, RADIO0, 0L, x3, y2, 8, 8},
+ {7, 8, 0, ISRADIO, RADIO0, 0L, x1, y3, 8, 8},
+ {8, 9, 0, ISRADIO, RADIO0, 0L, x2, y3, 8, 8},
+ {9, 0, 0, ISRADIO | LASTOBJ, RADIO0, 0L, x3, y3, 8, 8}};
+
+ txt.ColTxt = 0x00808080L; txt.ColBg = 0x00ffffff;
+ txt.fSize = 8.0; txt.RotBL = txt.RotCHAR = 0.0;
+ txt.iSize = 0; txt.Align = TXA_HCENTER | TXA_VCENTER;
+ txt.Style = TXS_NORMAL; txt.Font = FONT_HELVETICA;
+ txt.Mode = TXM_TRANSPARENT;
+ txt.text = strdup("text");
+ if((d2 = (DlgInfo*)malloc(9*sizeof(DlgInfo)))){
+ memcpy(d2, &d1,9*sizeof(DlgInfo));
+ if(align) switch(*align) {
+ case 1: d2[1].flags |= CHECKED; break;
+ case 2: d2[2].flags |= CHECKED; break;
+ case 4: d2[3].flags |= CHECKED; break;
+ case 5: d2[4].flags |= CHECKED; break;
+ case 6: d2[5].flags |= CHECKED; break;
+ case 8: d2[6].flags |= CHECKED; break;
+ case 9: d2[7].flags |= CHECKED; break;
+ case 10: d2[8].flags |= CHECKED; break;
+ default: d2[0].flags |= CHECKED; break;
+ }
+ for(i = 0; i < 9; i++) {
+ br.left = d2[i].x*xbase;
+ br.right = br.left + d2[i].w*xbase;
+ br.top = d2[i].y*ybase;
+ br.bottom = br.top + d2[i].h*ybase;
+ butts[i] = new RadioButton(this, &d2[i], br, 0L);
+ }
+ }
+}
+
+TxtHSP::~TxtHSP()
+{
+ int i;
+
+ if(txt.text) free(txt.text);
+ if(d2){
+ for(i = 0; i < 9; i++) if(butts[i]) delete(butts[i]);
+ free(d2);
+ }
+}
+
+bool
+TxtHSP::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i;
+ Dialog *d;
+
+ switch(cmd) {
+ case CMD_RADIOBUTT:
+ d = (Dialog *)tmpl;
+ for(i = 0; i < 9; i++)
+ if(butts[i] && butts[i] != d && butts[i]->type == d->type)
+ butts[i]->SetCheck(0, o, false);
+ break;
+ }
+ return false;
+}
+
+void
+TxtHSP::DoPlot(anyOutput *o)
+{
+ int i;
+
+ if(txt.text){
+ o->SetTextSpec(&txt);
+ o->oTextOut((cr.left + cr.right)>>1, (cr.top + cr.bottom)>>1, txt.text, 0);
+ }
+ for(i = 0; i < 9; i++) if(butts[i]) butts[i]->DoPlot(o);
+ o->UpdateRect(&cr, false);
+}
+
+bool
+TxtHSP::Select(int x, int y, anyOutput *o)
+{
+ int i;
+ bool bRet = false;
+
+ for(i = 0; i < 9; i++) if(butts[i] && butts[i]->Select(x, y, o)) bRet = true;
+ return bRet;
+}
+
+bool
+TxtHSP::GetInt(int id, int *val)
+{
+ int i;
+ bool bRet = false;
+
+ for(i = 0; i < 9; i++) {
+ if(butts[i] && butts[i]->GetCheck(i+1)) {
+ bRet = true;
+ switch (i) {
+ case 0: *val = 0; break;
+ case 1: *val = 1; break;
+ case 2: *val = 2; break;
+ case 3: *val = 4; break;
+ case 4: *val = 5; break;
+ case 5: *val = 6; break;
+ case 6: *val = 8; break;
+ case 7: *val = 9; break;
+ case 8: *val = 10; break;
+ }
+ }
+ }
+ return bRet;
+}
+
+void
+TxtHSP::MBtrack(MouseEvent *mev, anyOutput *o)
+{
+ int i;
+
+ for(i = 0; i < 9; i++) if(butts[i]) butts[i]->MBtrack(mev, o);
+}
+
+SlideRect::SlideRect(tag_DlgObj *par, DlgInfo *desc, RECT rec, bool isVert)
+ :Dialog(par, desc, rec)
+{
+ bV = isVert;
+ if(isVert) {
+ buttrc.left = cr.left+1; buttrc.top = cr.top;
+ buttrc.right = cr.right; buttrc.bottom = cr.top + (w = h = (cr.right-cr.left));
+ }
+ else {
+ buttrc.left = cr.left; buttrc.top = cr.top+1;
+ buttrc.right = cr.left+ (w = h = (cr.bottom - cr.top)); buttrc.bottom = cr.bottom;
+ }
+ dx = w>>1; dy = h>>1;
+ sLine = 1;
+ puSel = pdSel = false;
+
+}
+
+SlideRect::~SlideRect()
+{
+}
+
+bool
+SlideRect::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i;
+ double tmp;
+
+ switch(cmd) {
+ case CMD_SETSCROLL:
+ //DEBUG: replace width/height calulation by variables w and h
+ tmp = *((double*)tmpl);
+ if(tmp < 0.0) tmp = 0.0; if(tmp > 1.0) tmp = 1.0;
+ if(bV) {
+ i = (int)((double)(cr.bottom -cr.top -7*ybase)*tmp);
+ buttrc.bottom -= buttrc.top;
+ buttrc.top = i + cr.top; buttrc.bottom += (i+cr.top);
+ }
+ else {
+ i = (int)((double)(cr.right -cr.left -7*xbase)*tmp);
+ buttrc.right -= buttrc.left;
+ buttrc.left = i + cr.left; buttrc.right += (i+cr.left);
+ }
+ if(o)DoPlot(o);
+ return true;
+ case CMD_LINEUP:
+ i = -sLine;
+ case CMD_LINEDOWN:
+ if(cmd == CMD_LINEDOWN) i = sLine;
+ if(bV) {
+ buttrc.top += i;
+ if(buttrc.top < cr.top) buttrc.top = cr.top;
+ if((buttrc.top + h) > cr.bottom) buttrc.top = cr.bottom -h;
+ buttrc.bottom = buttrc.top + h;
+ }
+ else {
+ buttrc.left += i;
+ if(buttrc.left < cr.left) buttrc.left = cr.left;
+ if((buttrc.left + w) > cr.right) buttrc.left = cr.right -w;
+ buttrc.right = buttrc.left +w;
+ }
+ return true;
+ }
+ return false;
+}
+
+
+void
+SlideRect::DoPlot(anyOutput *o)
+{
+ POINT pts[3];
+
+ Line.color = DlgBGcolor; Fill.color = 0x00e0e0e0L;
+ o->SetLine(&Line); o->SetFill(&Fill);
+ o->oRectangle(cr.left, cr.top, cr.right, cr.bottom);
+ puRC.top = cr.top; puRC.left = cr.left;
+ pdRC.right = cr.right; pdRC.bottom = cr.bottom;
+ if(bV) {
+ puRC.bottom = buttrc.top; puRC.right = cr.right;
+ pdRC.top = buttrc.bottom; pdRC.left = cr.left;
+ }
+ else {
+ puRC.bottom = cr.bottom; puRC.right = buttrc.left;
+ pdRC.top = cr.top; pdRC.left = buttrc.right;
+ }
+ Fill.color = DlgBGhigh;
+ o->SetFill(&Fill);
+ if(bLBdown){
+ Line.color = 0x00808080L; o->SetLine(&Line);
+ o->oRectangle(buttrc.left, buttrc.top, buttrc.right, buttrc.bottom);
+ }
+ else {
+ o->oRectangle(buttrc.left, buttrc.top, buttrc.right-1, buttrc.bottom-1);
+ Line.color = 0x0L;
+ o->SetLine(&Line);
+ pts[0].x = buttrc.left; pts[0].y = pts[1].y = buttrc.bottom-1;
+ pts[1].x = pts[2].x = buttrc.right-1; pts[2].y = buttrc.top-1;
+ o->oPolyline(pts, 3);
+ Line.color = 0x00ffffffL;
+ o->SetLine(&Line);
+ pts[0].x = pts[1].x = buttrc.left;
+ pts[0].y = buttrc.bottom -3;
+ pts[1].y = pts[2].y = buttrc.top;
+ pts[2].x = buttrc.right -2;
+ o->oPolyline(pts, 3);
+ }
+ o->UpdateRect(&cr, false);
+ puSel = pdSel = false;
+}
+
+bool
+SlideRect::Select(int x, int y, anyOutput *o)
+{
+ if(IsInRect(&buttrc, x, y)) {
+ bLBdown = false;
+ DoPlot(o);
+ return true;
+ }
+ else if(bLBdown || puSel || pdSel) {
+ bLBdown = false;
+ DoPlot(o);
+ }
+ if(IsInRect(&puRC, x, y) && parent) parent->Command(CMD_PAGEUP, 0L, o);
+ else if(IsInRect(&pdRC, x, y) && parent) parent->Command(CMD_PAGEDOWN, 0L, o);
+ return false;
+}
+
+bool
+SlideRect::GetValue(int id, double *val)
+{
+ double res;
+
+ if(bV) {
+ res = ((double)(buttrc.top - cr.top))/
+ ((double)(cr.bottom-cr.top-(cr.right-cr.left)));
+ }
+ else {
+ res = ((double)(buttrc.left - cr.left))/
+ ((double)(cr.right-cr.left-(cr.bottom-cr.top)));
+ }
+ *val = res;
+ return true;
+}
+
+void
+SlideRect::MBtrack(MouseEvent *mev, anyOutput *o)
+{
+ bool bLBstate = false;
+
+ if(mev->Action == MOUSE_LBDOUBLECLICK) {
+ bLBdown = false;
+ DoPlot(o);
+ return;
+ }
+ if(mev->StateFlags &1) bLBstate = true;
+ if(IsInRect(&buttrc, mev->x, mev->y)){
+ if(mev->Action == MOUSE_LBDOWN){
+ dx = mev->x-buttrc.left; dy = mev->y - buttrc.top;
+ }
+ if(bLBstate && !bLBdown){
+ bLBdown = bLBstate;
+ DoPlot(o);
+ return;
+ }
+ }
+ if(IsInRect(&puRC, mev->x, mev->y)){
+ if(pdSel) DoPlot(o);
+ Line.color = Fill.color = bLBstate ? DlgBGcolor : 0x00e0e0e0L;
+ o->SetLine(&Line); o->SetFill(&Fill);
+ o->oRectangle(puRC.left+3, puRC.top+3, puRC.right-3, puRC.bottom-3);
+ o->UpdateRect(&puRC, false);
+ puSel = true;
+ }
+ else if(puSel) DoPlot(o);
+ if(IsInRect(&pdRC, mev->x, mev->y)){
+ if(puSel) DoPlot(o);
+ Line.color = Fill.color = bLBstate ? DlgBGcolor : 0x00e0e0e0L;
+ o->SetLine(&Line); o->SetFill(&Fill);
+ o->oRectangle(pdRC.left+3, pdRC.top+3, pdRC.right-3, pdRC.bottom-3);
+ o->UpdateRect(&pdRC, false);
+ pdSel = true;
+ }
+ else if(pdSel) DoPlot(o);
+ if(bLBdown && IsInRect(&cr, mev->x, mev->y)){
+ if(bV) {
+ buttrc.top = mev->y - dy;
+ if(buttrc.top < cr.top) buttrc.top = cr.top;
+ if((buttrc.top + h) > cr.bottom) buttrc.top = cr.bottom -h;
+ buttrc.bottom = buttrc.top + h;
+ }
+ else {
+ buttrc.left = mev->x - dx;
+ if(buttrc.left < cr.left) buttrc.left = cr.left;
+ if((buttrc.left + w) > cr.right) buttrc.left = cr.right -w;
+ buttrc.right = buttrc.left +w;
+ }
+ if(parent && ((Dialog*)parent)->parent &&
+ ((Dialog*)parent)->parent->Command(CMD_REDRAW, 0L, o));
+ else DoPlot(o);
+ }
+ else if(bLBdown){
+ bLBdown = false;
+ DoPlot(o);
+ }
+}
+
+ScrollBar::ScrollBar(tag_DlgObj *par, DlgInfo *desc, RECT rec, bool isVert)
+ :Dialog(par, desc, rec)
+{
+ int ab1 = 1, ab2 = 2, ab3 = 3, ab4 = 4;
+ static DlgInfo ab[] = {
+ {1, 2, 0, 0x0L, ARROWBUTT, (void*)0L, 0, 0, 0, 0},
+ {2, 0, 0, 0x0L, ARROWBUTT, (void*)0L, 0, 0, 0, 0},
+ {3, 0, 0, LASTOBJ, NONE, 0L, 0, 0, 0, 0}};
+ RECT br, sr;
+
+ if(isVert) {
+ sr.left = cr.left; sr.right = cr.right;
+ br.left = cr.left+1; br.right = cr.right+1;
+ br.top = cr.top+1; br.bottom = sr.top = br.top + 5*ybase + 1;
+ sr.top--; hcr.top = sr.top;
+ butts[0] = new ArrowButton(this, &ab[0], br, &ab1);
+ br.top = cr.bottom-5*ybase; br.bottom = cr.bottom+1;
+ butts[1] = new ArrowButton(this, &ab[1], br, &ab2);
+ br.bottom -= 5*ybase; br.top -= 5*ybase;
+ hcr.bottom = sr.bottom = br.top;
+ butts[2] = new ArrowButton(this, &ab[0], br, &ab1);
+ }
+ else {
+ sr.top = cr.top; sr.bottom = cr.bottom;
+ br.left = cr.left+1; br.right = sr.left = br.left + 5*xbase;
+ sr.left--; hcr.left = sr.left;
+ br.top = cr.top+1; br.bottom = cr.bottom+1;
+ butts[0] = new ArrowButton(this, &ab[0], br, &ab3);
+ br.left = cr.right - 5*xbase; br.right = cr.right+1;
+ butts[1] = new ArrowButton(this, &ab[1], br, &ab4);
+ br.left -= 5*xbase; br.right -= 5*xbase;
+ hcr.right = sr.right = br.left;
+ butts[2] = new ArrowButton(this, &ab[0], br, &ab3);
+ }
+ slrc = new SlideRect(this, &ab[2], sr, isVert);
+ sLine = 1; sPage = 8;
+}
+
+ScrollBar::~ScrollBar()
+{
+ int i;
+
+ for(i = 0; i < 3; i++) if(butts[i]) delete butts[i];
+ if(slrc) delete slrc;
+}
+
+bool
+ScrollBar::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i;
+
+ switch(cmd) {
+ case CMD_ENDDIALOG:
+ if(!tmpl || !slrc) return false;
+ i = ((Dialog*)tmpl)->Id;
+ switch(i) {
+ case 1: return slrc->Command(CMD_LINEUP, 0L, o);
+ case 2: return slrc->Command(CMD_LINEDOWN, 0L, o);
+ default: return false;
+ }
+ case CMD_PAGEUP:
+ case CMD_PAGEDOWN:
+ if(parent)return parent->Command(cmd, tmpl, o);
+ break;
+ case CMD_SETSCROLL:
+ if(slrc) return slrc->Command(cmd, tmpl, o);
+ break;
+ }
+ return false;
+}
+
+void
+ScrollBar::DoPlot(anyOutput *o)
+{
+ int i;
+
+ for(i = 0; i < 3; i++) if(butts[i]) butts[i]->DoPlot(o);
+ if(slrc){
+ slrc->sLine = sLine;
+ slrc->DoPlot(o);
+ }
+}
+
+bool
+ScrollBar::Select(int x, int y, anyOutput *o)
+{
+ int i;
+ bool bRet = false;
+
+ if(!IsInRect(&cr, x, y)) return false;
+ for(i = 0; i < 3; i++) if(butts[i] && butts[i]->Select(x, y, o)) bRet = true;
+ if(!bRet && slrc) bRet = slrc->Select(x, y, o);
+ if(bRet && parent) parent->Command(CMD_REDRAW, 0L, o);
+ return bRet;
+}
+
+bool
+ScrollBar::GetValue(int id, double *val)
+{
+ if(slrc) return slrc->GetValue(id, val);
+ return false;
+}
+
+void
+ScrollBar::MBtrack(MouseEvent *mev, anyOutput *o)
+{
+ int i;
+
+ for(i = 0; i < 3; i++) if(butts[i]) butts[i]->MBtrack(mev, o);
+ if(slrc) slrc->MBtrack(mev, o);
+}
+
+Icon::Icon(tag_DlgObj *par, DlgInfo * desc, RECT rec, int *ico)
+ :Dialog(par, desc, rec)
+{
+ icon = ico ? *ico : 0;
+}
+
+void
+Icon::DoPlot(anyOutput *o)
+{
+ o->oDrawIcon(icon, cr.left, cr.top);
+ o->UpdateRect(&cr, false);
+}
+
+Group::Group(tag_DlgObj *par, DlgInfo *desc, RECT rec)
+ :Dialog(par, desc, rec)
+{
+ numChildren = 5;
+ Children = (Dialog **)calloc(numChildren, sizeof(Dialog *));
+ TextFocus = 0L;
+}
+
+Group::~Group()
+{
+ //pointers to child objects are allocated and freed by parent:
+ // pointers are copies and we do not care further;
+ if(Children) free(Children);
+}
+
+bool
+Group::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ Dialog *d, **tmp;
+
+ int i;
+
+ switch (cmd) {
+ case CMD_FLUSH:
+ if(Children) for(i = 0; i < numChildren; Children[i++] = 0L);
+ break;
+ case CMD_CONTINUE:
+ case CMD_ENDDIALOG:
+ case CMD_TABDLG:
+ case CMD_NOTABDLG:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ else return false;
+ case CMD_ADDCHILD:
+ if(Children && numChildren && (d = (Dialog*)tmpl)) {
+ d->parent = this;
+ if(!TextFocus &&(d->type == EDTEXT ||
+ d->type == INCDECVAL1 || d->type == EDVAL1))
+ TextFocus = ((InputText*)tmpl)->bActive ? (InputText*)tmpl: 0L ;
+ for(i = 0; i < numChildren; i++) {
+ if(!Children[i] || Children[i] == d) {
+ Children[i] = d;
+ return true;
+ }
+ }
+ //if we come here the list for children is too short
+ tmp = (Dialog **)realloc(Children, (numChildren+1) * sizeof(Dialog *));
+ if(!tmp) return false;
+ Children = tmp;
+ Children[numChildren++] = d;
+ return true;
+ }
+ break;
+ case CMD_RADIOBUTT:
+ if(Children && numChildren) {
+ d = (Dialog *)tmpl;
+ for(i = 0; i < numChildren; i++) {
+ if(Children[i] && Children[i] != d && Children[i]->type == d->type &&
+ Children[i]->bChecked) {
+ Children[i]->bChecked = false;
+ Children[i]->DoPlot(o);
+ }
+ }
+ }
+ break;
+ case CMD_FOCTXT:
+ DialogTabStop = TextFocus = (InputText *)tmpl;
+ break;
+ }
+ return false;
+}
+
+void
+Group::DoPlot(anyOutput *o)
+{
+ int i;
+
+ if(flags & HIDDEN) return;
+ if(Children && numChildren && bChecked) {
+ for(i = 0; i < numChildren; i++) {
+ if(Children[i] && !(Children[i]->flags & HIDDEN)) {
+ Children[i]->DoPlot(o);
+ if(Children[i] == (Dialog*)TextFocus && DialogFocus != DialogTabStop)
+ TextFocus->Activate(TextFocus->Id, true);
+ }
+ }
+ }
+ else if(Children && numChildren && parent) {
+ for(i = 0; i < numChildren; i++) {
+ if(Children[i]) parent->Command(CMD_NOTABDLG, Children[i], o);
+ }
+ }
+}
+
+bool
+Group::Select(int x, int y, anyOutput *o)
+{
+ int i;
+
+ if(Children && numChildren) {
+ for(i = 0; i < numChildren; i++) {
+ if(Children[i] && !(Children[i]->flags &HIDDEN) && Children[i]->Select(x, y, o))
+ return (bChecked = true);
+ }
+ }
+ return false;
+}
+
+void
+Group::MBtrack(MouseEvent *mev, anyOutput *o)
+{
+ int i;
+
+ if(bChecked && Children && numChildren) {
+ for(i = 0; i < numChildren; i++) {
+ if(Children[i]&& !(Children[i]->flags &HIDDEN)) Children[i]->MBtrack(mev, o);
+ }
+ }
+}
+
+GroupBox::GroupBox(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *txt)
+ :Group(par,desc, rec)
+{
+ if(txt)Text = strdup(txt);
+ else Text = 0L;
+ Line.color = 0x00000000L;
+ Line.width = 0.0;
+ Fill.color = DlgBGhigh;
+ TextDef.ColBg = Fill.color;
+ TextDef.Align = TXA_HLEFT | TXA_VCENTER;
+ TextDef.Mode = TXM_OPAQUE;
+}
+
+GroupBox::~GroupBox()
+{
+ if(Text) free(Text);
+}
+
+void
+GroupBox::DoPlot(anyOutput *o)
+{
+ o->SetLine(&Line);
+ o->SetFill(&Fill);
+ o->oRectangle(cr.left, cr.top, cr.right-1, cr.bottom-1);
+ if(Text) {
+ o->SetTextSpec(&TextDef);
+ hcr.top = cr.top - TextDef.iSize;
+ o->oTextOut(cr.left+4, cr.top, Text, 0);
+ }
+ Group::DoPlot(o);
+ o->UpdateRect(&hcr, false);
+}
+
+TabSheet::TabSheet(tag_DlgObj *par, DlgInfo * desc, RECT rec, TabSHEET * sh)
+ :Group(par, desc, rec)
+{
+ if(sh->text)Text = strdup(sh->text);
+ else Text = 0L;
+ rctab.left = cr.left + sh->x1 * xbase;
+ rctab.right = cr.left + sh->x2 * xbase;
+ rctab.top = cr.top;
+ rctab.bottom = cr.top + sh->height * ybase;
+ TextDef.Align = TXA_HRIGHT | TXA_VTOP;
+ flags |= ISRADIO;
+}
+
+TabSheet::~TabSheet()
+{
+ if(Text) free (Text);
+}
+
+void
+TabSheet::DoPlot(anyOutput *o)
+{
+ POINT pts[6];
+
+ pts[0].x = pts[1].x = pts[5].x = rctab.left;
+ pts[0].y = pts[4].y = pts[5].y = rctab.bottom;
+ pts[1].y = (rctab.top + rctab.bottom)/2;
+ pts[2].x = rctab.left + (rctab.bottom - rctab.top)/2;
+ pts[2].y = pts[3].y = rctab.top;
+ pts[3].x = pts[4].x = rctab.right-1;
+
+ Line.color = 0x00000000L;
+ Line.width = 0.0;
+ Fill.color = bChecked ? DlgBGhigh : DlgBGcolor;
+ o->SetLine(&Line);
+ o->SetFill(&Fill);
+ o->oPolygon(pts, 6);
+ if(bChecked) {
+ o->oRectangle(cr.left, rctab.bottom, cr.right, cr.bottom);
+ Line.color = DlgBGhigh;
+ o->SetLine(&Line);
+ pts[4].x--;
+ o->oSolidLine(pts+4);
+ }
+ o->SetTextSpec(&TextDef);
+ o->oTextOut(rctab.right - 6, rctab.top + 1, Text, 0);
+ Group::DoPlot(o);
+ o->UpdateRect(&cr, false);
+}
+
+bool
+TabSheet::Select(int x, int y, anyOutput *o)
+{
+ if(IsInRect(&rctab, x, y)) {
+ if(parent) parent->Command(CMD_RADIOBUTT, (void *)this, o);
+ bChecked = true;
+ DoPlot(o);
+ if((flags & TOUCHEXIT) && parent)
+ parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ return true;
+ }
+ if(bChecked) return Group::Select(x, y, o);
+ return false;
+}
+
+ODbutton::ODbutton(tag_DlgObj *par, DlgInfo * desc, RECT rec, void *proc)
+ :Dialog(par, desc, rec)
+{
+ ODexec = (void(*)(int, void *, RECT *, anyOutput *, void *, int))proc;
+ if(ODexec) (*ODexec)(OD_CREATE, parent, &cr, 0L, 0L, Id);
+}
+
+ODbutton::~ODbutton()
+{
+ if(ODexec) (*ODexec)(OD_DELETE, (void*)parent, &cr, 0L, 0L, Id);
+}
+
+void
+ODbutton::DoPlot(anyOutput *o)
+{
+ if(ODexec) (*ODexec)(bChecked ? OD_DRAWSELECTED : OD_DRAWNORMAL, (void*)parent, &cr, o, 0L, Id);
+}
+
+bool
+ODbutton::Select(int x, int y, anyOutput *o)
+{
+ POINT p;
+
+ if(!(flags & HIDDEN) && IsInRect(&cr, x, y)) {
+ if(flags & ISRADIO) bChecked = true;
+ else bChecked = bChecked ? false : true;
+ if(flags & NOSELECT) bChecked = false;
+ bLBdown = false;
+ p.x = x; p.y = y;
+ if(ODexec) {
+ (*ODexec)(OD_SELECT, (void*)parent, &cr, o, (void*)&p, Id);
+ if(!(flags & NOSELECT))DoPlot(o);
+ }
+ if((flags & ISRADIO) && parent)
+ parent->Command(CMD_RADIOBUTT, (void *)this, o);
+ if((flags & TOUCHEXIT) && parent)
+ parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ return true;
+ }
+ return false;
+}
+
+void
+ODbutton::MBtrack(MouseEvent *mev, anyOutput *o)
+{
+ int x = mev->x, y = mev->y;
+
+ if(mev->Action == MOUSE_LBDOUBLECLICK) {
+ Select(mev->x, mev->y, o);
+ return;
+ }
+ if(!(flags & HIDDEN) && IsInRect(&cr, x, y) && ODexec)
+ (*ODexec)(OD_MBTRACK, (void*)parent, &cr, o, mev, Id);
+}
+
+Listbox::Listbox(tag_DlgObj *par, DlgInfo *des, RECT rec, char **list)
+ :Dialog(par, des, rec)
+{
+ static DlgInfo sbd[] = {
+ {1, 2, 0, 0x0L, VSCROLL, 0L, 0, 0, 0, 0}};
+ RECT sr;
+ int i;
+
+ sbd[0].x = (sr.left = (cr.right-7*xbase))/xbase;
+ sbd[0].y = (sr.top = cr.top)/ybase; sr.right = cr.right; sbd[0].w = 7;
+ sbd[0].h = ((sr.bottom = cr.bottom) - cr.top)/ybase;
+ sb = new ScrollBar(this, &sbd[0], sr, true);
+ bmp = 0L; cl = bmh = 0; hcr.right -= 7*xbase;
+ Fill.color = 0x00ffffffL; Line.color = 0x00000000L;
+ for(i = ns = 0; list && list[i]; i++); //count lines
+ if(strings = (char **)calloc(i+1, sizeof(char*))){
+ for(ns = i, i = 0; i < ns; strings[i] = strdup(list[i]), i++);
+ }
+}
+
+Listbox::~Listbox()
+{
+ int i;
+
+ if(sb) delete(sb);
+ if(bmp) DelBitmapClass(bmp);
+ if(strings) {
+ for(i = 0; i < ns; i++) if(strings[i])free(strings[i]);
+ free(strings);
+ }
+}
+
+bool
+Listbox::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i;
+ double ps;
+ char *txt;
+
+ ps = ((double)(cr.bottom - cr.top))/((double)(bmh+TextDef.iSize+1));
+ switch(cmd) {
+ case CMD_REDRAW:
+ DoPlot(o);
+ return true;
+ case CMD_PAGEUP:
+ ps *= -1.0;
+ case CMD_PAGEDOWN:
+ if(sb && sb->GetValue(1, &spos)){
+ spos += ps;
+ sb->Command(CMD_SETSCROLL, (void*)&spos, o);
+ DoPlot(o);
+ }
+ return true;
+ case CMD_SETSCROLL:
+ if(sb) return sb->Command(cmd, tmpl, o);
+ break;
+ case CMD_FINDTEXT:
+ txt = (char*)tmpl;
+ if(strings) for (i = 0; i < ns; i++) {
+ if(strings[i] && 0 == strcmp(txt, strings[i])){
+ cl = i;
+ return true;
+ }
+ }
+ return false;
+ }
+ return false;
+}
+
+void
+Listbox::DoPlot(anyOutput *o)
+{
+ RECT mrk;
+
+ if(!ns) return;
+ if(!bmp && !CreateBitMap(o))return;
+ startY = 0;
+ if(sb && sb->GetValue(1, &spos)) startY = (int)(spos*(double)bmh);
+ o->SetLine(&Line); o->SetFill(&Fill);
+ o->oRectangle(hcr.left, hcr.top, hcr.right+1, hcr.bottom);
+ if(sb){
+ sb->sLine = 1+(sb->hcr.bottom-sb->hcr.top-7*ybase)/ns;
+ sb->DoPlot(o);
+ }
+ o->CopyBitmap(hcr.left+1, hcr.top+1, bmp, 0, startY, (hcr.right-hcr.left)-2,
+ (hcr.bottom-hcr.top)-2, false);
+ mrk.left = hcr.left+2; mrk.top = (cl)*TextDef.iSize - startY + hcr.top;
+ mrk.right = hcr.right-2; mrk.bottom = mrk.top + TextDef.iSize;
+ if(mrk.bottom > (hcr.top+1) && mrk.top < (hcr.bottom-1)){
+ if(mrk.top < (hcr.top+1)) mrk.top = hcr.top+1;
+ if(mrk.bottom > (hcr.bottom-1)) mrk.bottom = hcr.bottom-1;
+ o->CopyBitmap(mrk.left, mrk.top, bmp, 1, cl*TextDef.iSize,
+ (hcr.right-hcr.left)-4, mrk.bottom-mrk.top, true);
+ }
+ o->UpdateRect(&cr, false);
+}
+
+bool
+Listbox::Select(int x, int y, anyOutput *o)
+{
+ int il;
+ RECT mrk;
+
+ if(IsInRect(&hcr, x, y)) {
+ il = (y+startY-hcr.top)/TextDef.iSize;
+ if(il >= ns || il < 0){
+ o->UpdateRect(&hcr, false);
+ return false;
+ }
+ cl = il;
+ mrk.left = hcr.left+2; mrk.top = (il)*TextDef.iSize - startY + hcr.top;
+ mrk.right = hcr.right-2; mrk.bottom = mrk.top + TextDef.iSize;
+ o->CopyBitmap(hcr.left+1, hcr.top+1, bmp, 0, startY, (hcr.right-hcr.left)-2,
+ (hcr.bottom-hcr.top)-2, false);
+ o->CopyBitmap(mrk.left, mrk.top, bmp, 1, (cl)*TextDef.iSize,
+ (hcr.right-hcr.left)-4, mrk.bottom-mrk.top, true);
+ o->UpdateRect(&hcr, false);
+ if((flags & TOUCHEXIT) && parent)
+ parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ return true;
+ }
+ if(sb)return sb->Select(x, y, o);
+ return false;
+}
+
+bool
+Listbox::GetInt(int id, int *val)
+{
+ *val = cl;
+ return true;
+}
+
+bool
+Listbox::GetText(int id, char *txt)
+{
+ if(strings && ns && cl >= 0 && cl < ns){
+ strcpy(txt, strings[cl]);
+ return true;
+ }
+ return false;
+}
+
+void
+Listbox::MBtrack(MouseEvent *mev, anyOutput *o)
+{
+ if(sb) sb->MBtrack(mev, o);
+}
+
+bool
+Listbox::CreateBitMap(anyOutput *tmpl)
+{
+ int i, w, h;
+
+ if(bmp) DelBitmapClass(bmp);
+ bmp = 0L;
+ if(tmpl && strings) {
+ h = TextDef.iSize * ns; w = (hcr.right - hcr.left);
+ if(bmp = NewBitmapClass(w, h, tmpl->hres, tmpl->vres)){
+ bmp->Erase(0x00ffffffL);
+ bmp->SetTextSpec(&TextDef);
+ bmh = h - TextDef.iSize;
+ for(i = 0; i < ns; i++) {
+ bmp->oTextOut(5, i*TextDef.iSize, strings[i], 0);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+Treeview::Treeview(tag_DlgObj *par, DlgInfo *des, RECT rec, GraphObj *g)
+ :Dialog(par, des, rec)
+{
+ static DlgInfo sbd[] = {
+ {1, 2, 0, 0x0L, VSCROLL, 0L, 0, 0, 0, 0}};
+ RECT sr;
+
+ sbd[0].x = (sr.left = (cr.right-7*xbase))/xbase;
+ sbd[0].y = (sr.top = cr.top)/ybase; sr.right = cr.right; sbd[0].w = 7;
+ sbd[0].h = ((sr.bottom = cr.bottom) - cr.top)/ybase;
+ sb = new ScrollBar(this, &sbd[0], sr, true);
+ Fill.color = 0x00ffffffL; Line.color = 0x00000000L;
+ bmp = 0L; startY = cl = 0; hcr.right -= 7*xbase;
+ bmh = hcr.bottom - hcr.top; bmw = hcr.right - hcr.left;
+ ot = new ObjTree(0L, 0L, go = g);
+ if(ot) ot->Command(CMD_TEXTDEF, &TextDef, 0L);
+}
+
+Treeview::~Treeview()
+{
+ if(sb) delete(sb); sb = 0L;
+ if(ot) delete(ot); ot = 0L;
+ if(bmp) DelBitmapClass(bmp); bmp = 0L;
+}
+
+bool
+Treeview::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ double ps;
+
+ ps = ((double)(cr.bottom - cr.top))/((double)(bmh+TextDef.iSize+1));
+ switch(cmd) {
+ case CMD_LAYERS:
+ ot->Command(cmd, tmpl, o);
+ case CMD_UPDATE:
+ if(bmp) DelBitmapClass(bmp);
+ bmh = hcr.bottom - hcr.top; bmw = hcr.right - hcr.left;
+ bmp = ot->CreateBitmap(&bmw, &bmh, o);
+ return true;
+ case CMD_REDRAW:
+ DoPlot(o);
+ return true;
+ case CMD_OBJTREE:
+ if(tmpl) *((ObjTree**)tmpl) = ot;
+ return true;
+ case CMD_PAGEUP:
+ ps *= -1.0;
+ case CMD_PAGEDOWN:
+ if(sb && sb->GetValue(1, &spos)){
+ spos += ps;
+ sb->Command(CMD_SETSCROLL, (void*)&spos, o);
+ DoPlot(o);
+ }
+ return true;
+ case CMD_SETSCROLL:
+ if(sb) return sb->Command(cmd, tmpl, o);
+ break;
+ }
+ return false;
+}
+
+void
+Treeview::DoPlot(anyOutput *o)
+{
+ RECT mrk;
+
+ if(!o || !ot) return;
+ ot->Command(CMD_TEXTDEF, &TextDef, 0L);
+ ns = ot->count_lines();
+ if(bmp) ot->DoPlot(bmp);
+ else if(!(bmp = ot->CreateBitmap(&bmw, &bmh, o)))return;
+ startY = 0;
+ if(sb && sb->GetValue(1, &spos)) startY = (int)(spos*(double)bmh);
+ o->SetLine(&Line); o->SetFill(&Fill);
+ o->oRectangle(hcr.left, hcr.top, hcr.right+1, hcr.bottom);
+ if(sb){
+ sb->sLine = 1+(sb->hcr.bottom-sb->hcr.top-7*ybase)/ns;
+ sb->DoPlot(o);
+ }
+ o->CopyBitmap(hcr.left+1, hcr.top+1, bmp, 0, startY, (hcr.right-hcr.left)-2,
+ (hcr.bottom-hcr.top)-2, false);
+ mrk.left = hcr.left+2; mrk.top = (cl)*TextDef.iSize - startY + hcr.top;
+ mrk.right = hcr.right-2; mrk.bottom = mrk.top + TextDef.iSize;
+ if(mrk.bottom > (hcr.top+1) && mrk.top < (hcr.bottom-1)){
+ if(mrk.top < (hcr.top+1)) mrk.top = hcr.top+1;
+ if(mrk.bottom > (hcr.bottom-1)) mrk.bottom = hcr.bottom-1;
+ o->CopyBitmap(mrk.left, mrk.top, bmp, 1, cl*TextDef.iSize,
+ (hcr.right-hcr.left)-4, mrk.bottom-mrk.top, true);
+ }
+ o->UpdateRect(&cr, false);
+}
+
+bool
+Treeview::Select(int x, int y, anyOutput *o)
+{
+ int il;
+ RECT mrk;
+
+ if(IsInRect(&hcr, x, y)) {
+ il = (y+startY-hcr.top)/TextDef.iSize;
+ if(il >= ns || il < 0){
+ o->UpdateRect(&hcr, false);
+ return false;
+ }
+ cl = il;
+ mrk.left = hcr.left+2; mrk.top = (il)*TextDef.iSize - startY + hcr.top;
+ mrk.right = hcr.right-2; mrk.bottom = mrk.top + TextDef.iSize;
+ o->CopyBitmap(hcr.left+1, hcr.top+1, bmp, 0, startY, (hcr.right-hcr.left)-2,
+ (hcr.bottom-hcr.top)-2, false);
+ o->CopyBitmap(mrk.left, mrk.top, bmp, 1, (cl)*TextDef.iSize,
+ (hcr.right-hcr.left)-4, mrk.bottom-mrk.top, true);
+ o->UpdateRect(&hcr, false);
+ if((flags & TOUCHEXIT) && parent)
+ parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ return true;
+ }
+ if(sb)return sb->Select(x, y, o);
+ return false;
+}
+
+void
+Treeview::MBtrack(MouseEvent *mev, anyOutput *o)
+{
+ if(sb) sb->MBtrack(mev, o);
+}
+
+bool
+Treeview::GetInt(int id, int *val)
+{
+ *val = cl;
+ return true;
+}
+
+LinePat::LinePat(tag_DlgObj *par, DlgInfo * desc, RECT rec, LineDEF *line)
+ :Dialog(par, desc, rec)
+{
+ pPattern = &line->pattern;
+ Line.color = 0x00000000L;
+ bDraw = true;
+ cr.right = cr.left + (cr.bottom-cr.top)*32;
+}
+
+void
+LinePat::DoPlot(anyOutput *o)
+{
+ int i, h;
+ POINT ruler[2];
+ RECT gr;
+
+ h = cr.bottom-cr.top;
+ memcpy(&gr, &cr, sizeof(RECT));
+ o->SetLine(&Line);
+ for(i = 0; i < 32; i++) {
+ if(*pPattern &(1<<i)) Fill.color = 0x00ffffffL;
+ else Fill.color = 0x00808080L;
+ o->SetFill(&Fill);
+ o->oRectangle(cr.left+i*h, cr.top, cr.left+i*h+h, cr.top+h);
+ }
+ ruler[0].y = cr.top+h;
+ ruler[1].y = ruler[0].y + h/2;
+ for(i = 0; i <=4; i++) {
+ ruler[0].x = ruler[1].x = cr.left+i*8*h+(i ? -1:0);
+ o->oSolidLine(ruler);
+ }
+ gr.bottom += h;
+ o->UpdateRect(&gr, false);
+}
+
+void
+LinePat::MBtrack(MouseEvent *mev, anyOutput *o)
+{
+ int i, x, y;
+ DWORD mask, oldpat;
+
+ if(!(mev->StateFlags &1))return; //draw with mouse left button
+ x = mev->x; y = mev->y;
+ if(x > cr.left && x < cr.right && y > cr.top && y < cr.bottom){
+ i = (x-cr.left)/(cr.bottom-cr.top);
+ oldpat = *pPattern;
+ mask = (1<<i);
+ //use first hit (button down) to select color, true or false
+ bDraw = mev->Action == MOUSE_LBDOWN ? 0L != (*pPattern & mask) : bDraw;
+ if(bDraw) *pPattern &= ~mask;
+ else *pPattern |= mask;
+ if(oldpat != *pPattern) {
+ DoPlot(o);
+ if((flags & TOUCHEXIT) && parent) parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ }
+ }
+}
+
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Select color out of predefined palette
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+DWORD GetNewColor(DWORD oldColor)
+{
+ DlgInfo *ColDlg, ColDlgTmpl[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 200, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 200, 25, 45, 12},
+ {3, 7, 4, CHECKED | ISPARENT, GROUPBOX, (void*)" RGB ", 200, 55, 45, 40},
+ {4, 5, 0, 0x0L, LTEXT, (void*)0L, 210, 60, 45, 8},
+ {5, 6, 0, 0x0L, LTEXT, (void*)0L, 210, 70, 45, 8},
+ {6, 0, 0, 0x0L, LTEXT, (void*)0L, 210, 80, 45, 8},
+ {7, 0, 8, CHECKED | ISPARENT, GROUP, 0L, 0, 0, 0, 0}};
+ DWORD currcol, newcol;
+ int ilevels[] = {0x0, 0x40, 0x80, 0xc0, 0xe0, 0xff};
+ int i, ir, ig, ib, col, row, res;
+ DlgRoot *Dlg;
+ void *hDlg;
+
+ if(!(ColDlg = (DlgInfo *)malloc(230 * sizeof(DlgInfo))))return oldColor;
+ memcpy(ColDlg, ColDlgTmpl, 14 * sizeof(DlgInfo));
+ for(ir=row=col=0, i= 7; ir<6; ir++) for(ig=0; ig<6; ig++) for(ib=0; ib<6; ib++) {
+ ColDlg[i].id = i+1; ColDlg[i].next = i+2;
+ ColDlg[i].type = COLBUTTON; ColDlg[i].first = 0;
+ currcol = (ilevels[ib]<<16)|(ilevels[ig]<<8)|(ilevels[ir]);
+ ColDlg[i].flags = TOUCHEXIT | ISRADIO;
+ if(currcol == oldColor) ColDlg[i].flags |= CHECKED;
+ ColDlg[i].ptype = (void *)currcol;
+ ColDlg[i].x = 5 + col*10; ColDlg[i].y = 5 + row*10;
+ ColDlg[i].w = ColDlg[i].h = 10;
+ col++;
+ if(col >= 18) {
+ col = 0; row++;
+ }
+ i++;
+ }
+ ColDlg[i-1].next = 0;
+ ColDlg[i-1].flags |= LASTOBJ;
+ newcol = currcol = oldColor;
+ Dlg = new DlgRoot(ColDlg);
+ sprintf(TmpTxt, "R: 0x%02x", currcol & 0xff);
+ Dlg->SetText(4, TmpTxt);
+ sprintf(TmpTxt, "G: 0x%02x", (currcol>>8) & 0xff);
+ Dlg->SetText(5, TmpTxt);
+ sprintf(TmpTxt, "B: 0x%02x", (currcol>>16) & 0xff);
+ Dlg->SetText(6, TmpTxt);
+ hDlg = CreateDlgWnd("Select color", 50, 50, 510, 310, Dlg,0x0L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 0: //close window
+ case 2: //cancel
+ currcol = oldColor;
+ break;
+ case 1: //ok
+ currcol = newcol;
+ break;
+ default:
+ if(res > 7 && res < 225) {
+ currcol = newcol;
+ if(Dlg->GetColor(res, &newcol) && currcol != newcol) {
+ res = -1;
+ sprintf(TmpTxt, "R: 0x%02x", newcol & 0xff);
+ Dlg->SetText(4, TmpTxt);
+ sprintf(TmpTxt, "G: 0x%02x", (newcol>>8) & 0xff);
+ Dlg->SetText(5, TmpTxt);
+ sprintf(TmpTxt, "B: 0x%02x", (newcol>>16) & 0xff);
+ Dlg->SetText(6, TmpTxt);
+ }
+ }
+ break;
+ }
+ }while (res < 0);
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ free(ColDlg);
+ return currcol;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Configure 3D shading
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void ConfShade(FillDEF *oldfill)
+{
+ FillDEF newFill;
+ DlgInfo ShadeDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 95, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 95, 25, 45, 12},
+ {3, 4, 100, CHECKED | ISPARENT, GROUP, NULL, 0, 0, 0, 0},
+ {4, 5, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)oldfill->color, 60, 10, 15, 10},
+ {5, 6, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)oldfill->color2, 60, 37, 15, 10},
+ {6, 7, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)oldfill->color, 60, 49, 15, 10},
+ {7, 8, 0, 0x0L, RTEXT, (void*)"HI-color:", 25, 37, 30, 9},
+ {8, 9, 0, 0x0L, RTEXT, (void*)"LO-color:", 25, 49, 30, 9},
+ {9, 0, 0, 0x0L, SHADE3D, &newFill, 95, 50, 22, 20},
+ {100, 101, 0, TOUCHEXIT, RADIO1, (void*)"fixed color:", 10, 10, 50, 9},
+ {101, 0, 0, TOUCHEXIT | LASTOBJ, RADIO1, (void*)"use light sorce:", 10, 25, 60, 9}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res;
+ bool bRedraw;
+ anyOutput *o;
+ RECT rc_prev;
+
+ if(!oldfill) return;
+ memcpy(&newFill, oldfill, sizeof(FillDEF));
+ newFill.type = FILL_LIGHT3D;
+ if(!(Dlg = new DlgRoot(ShadeDlg))) return;
+ if(oldfill->type & FILL_LIGHT3D) Dlg->SetCheck(101, 0L, true);
+ else {
+ Dlg->SetCheck(100, 0L, true);
+ newFill.color2 = newFill.color;
+ }
+ hDlg = CreateDlgWnd("Shade and Fill Color", 50, 50, 300, 180, Dlg, 0x0L);
+ bRedraw = true;
+ o = Dlg->GetOutputClass(); o->LightSource(8.0, -16.0);
+ rc_prev.left =240; rc_prev.right = 280;
+ rc_prev.top = 100; rc_prev.bottom = 140;
+ do {
+ if(bRedraw) {
+ Dlg->DoPlot(0L); o->SetFill(&newFill);
+ o->oSphere(260, 120, 17, 0L, 0);
+ o->UpdateRect(&rc_prev, false);
+ bRedraw = false;
+ }
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 4: case 100:
+ Dlg->GetColor(4, &newFill.color);
+ newFill.color2 = newFill.color;
+ Dlg->SetCheck(100, 0L, true);
+ bRedraw = true;
+ res = -1;
+ break;
+ case 5: case 6: case 101:
+ Dlg->GetColor(5, &newFill.color2);
+ Dlg->GetColor(6, &newFill.color);
+ Dlg->SetCheck(101, 0L, true);
+ bRedraw = true;
+ res = -1;
+ break;
+ }
+ }while (res < 0);
+ if(res == 1) {
+ memcpy(oldfill, &newFill, sizeof(FillDEF));
+ if(Dlg->GetCheck(100)) oldfill->type &= ~FILL_LIGHT3D;
+ else oldfill->type |= FILL_LIGHT3D;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Select fill pattern
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void GetNewFill(FillDEF *oldfill)
+{
+ LineDEF PrevLine;
+ FillDEF PrevFill;
+ unsigned int EnumFills[] = {FILL_NONE, FILL_HLINES, FILL_VLINES, FILL_HVCROSS, FILL_DLINEU, FILL_DLINED,
+ FILL_DCROSS, FILL_STIPPLE1, FILL_STIPPLE2, FILL_STIPPLE3, FILL_STIPPLE4,
+ FILL_STIPPLE5, FILL_ZIGZAG, FILL_COMBS, FILL_BRICKH, FILL_BRICKV, FILL_BRICKDU,
+ FILL_BRICKDD, FILL_TEXTURE1, FILL_TEXTURE2, FILL_WAVES1, FILL_SCALES, FILL_SHINGLES,
+ FILL_WAVES2, FILL_HERRING, FILL_CIRCLES, FILL_GRASS, FILL_FOAM, FILL_RECS};
+ double fscale;
+ DlgInfo FillDlgBase[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 170, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 170, 25, 45, 12},
+ {3, 100, 500, CHECKED | ISPARENT, GROUP, NULL, 0, 0, 0, 0},
+ {100, 101, 0, TOUCHEXIT, FILLBUTTON, (void *)&PrevFill, 170, 75, 45, 45},
+ {101, 102, 0, 0x0L, RTEXT, (void*)"line width", 78, 95, 40, 8},
+ {102, 103, 0, TOUCHEXIT, INCDECVAL1, &PrevLine.width, 119, 95, 32, 10},
+ {103, 104, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 152, 95, 15, 8},
+ {104, 105, 0, 0x0L, RTEXT, (void*)"line color", 5, 95, 30, 8},
+ {105, 106, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, 0x0L, 36, 95, 25, 10},
+ {106, 107, 0, 0x0L, RTEXT, (void*)"pattern size", 78, 110, 40, 8},
+ {107, 108, 0, TOUCHEXIT, INCDECVAL1, (void*)&fscale, 119, 110, 32, 10},
+ {108, 109, 0, 0x0L, LTEXT, (void*)"%", 152, 110, 8, 8},
+ {109, 110, 0, 0x0L, RTEXT, (void*)"BG color", 5, 110, 30, 8},
+ {110, 0, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, 0x0L, 36, 110, 25, 10}};
+ DlgInfo *FillDlg;
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, j, res;
+ anyOutput *o;
+ bool bRedraw;
+ double tmp;
+
+ PrevLine.width = (oldfill && oldfill->hatch)? oldfill->hatch->width : 0.2f;
+ PrevLine.patlength = 1.0f;
+ PrevLine.color = (oldfill && oldfill->hatch)? oldfill->hatch->color : 0x00000000L;
+ PrevLine.pattern = 0x00000000L;
+ PrevFill.type = oldfill ? oldfill->type : FILL_NONE;
+ PrevFill.color = oldfill ? oldfill->color : 0x00ffffffL;
+ PrevFill.scale = oldfill ? oldfill->scale : 1.0f;
+ PrevFill.hatch = &PrevLine;
+ PrevFill.color2 = oldfill ? oldfill->color2 : 0x00ffffffL;
+ fscale = PrevFill.scale *100.0f;
+ FillDlg = (DlgInfo*)calloc(NUM_FILLS + 15, sizeof(DlgInfo));
+ if(FillDlg) {
+ memcpy(FillDlg, FillDlgBase, 14 * sizeof(DlgInfo));
+ for(i = 14, j = 0; j < NUM_FILLS; i++, j++) {
+ FillDlg[i].id = j+500; FillDlg[i].next = j+501;
+ FillDlg[i].first = 0; FillDlg[i].flags = TOUCHEXIT;
+ FillDlg[i].type = FILLRADIO; FillDlg[i].ptype = (void*)(EnumFills+j);
+ FillDlg[i].x = (j &0x07)*20+5; FillDlg[i].y = (j>>3)*20+5;
+ FillDlg[i].w = FillDlg[i].h = 20;
+ }
+ FillDlg[i-1].next = 0;
+ FillDlg[i-1].flags |= LASTOBJ;
+ }
+ else return;
+ Dlg = new DlgRoot(FillDlg);
+ for(i = Dlg->FindIndex(500), j = 0; FillDlg[i].type == FILLRADIO; i++, j++)
+ if(*((int*)FillDlg[i].ptype) == PrevFill.type)Dlg->SetCheck(500+j, 0L, true);
+ Dlg->SetColor(105, PrevLine.color);
+ Dlg->SetColor(110, PrevFill.color);
+ hDlg = CreateDlgWnd("Fill patterns", 50, 50, 450, 280, Dlg, 0x0L);
+ bRedraw = true;
+ o = Dlg->GetOutputClass();
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ if (res >= 0) switch (res) { // first the radio buttons: fill type
+ default: // test for pattern
+ i = Dlg->FindIndex(res);
+ if(FillDlg[i].type == FILLRADIO) {
+ bRedraw = true;
+ i = *((int*)FillDlg[i].ptype);
+ if(i != PrevFill.type){ // process double click on pattern
+ PrevFill.type = i;
+ res = -1;
+ }
+ else res = 1; // assume OK pressed
+ break;
+ }
+ else break;
+ case 110: // fill color changed
+ case 102: // line width changed
+ case 105: // line color changed
+ case 107: // scaling changed
+ case 100: // update preview
+ res = -1; // ...these buttons do not exit dialog
+ case 1: // but exit with OK
+ if((bRedraw = Dlg->GetValue(102, &tmp)))PrevLine.width = tmp;
+ if(bRedraw) bRedraw = Dlg->GetColor(105, &PrevLine.color);
+ if(bRedraw) bRedraw = Dlg->GetColor(110, &PrevFill.color);
+ if(bRedraw && (bRedraw = Dlg->GetValue(107, &tmp)))
+ PrevFill.scale = tmp/100.0;
+ break;
+ }
+ if (o && bRedraw) { // send update preview to dialog
+ Dlg->ForEach(CMD_DOPLOT, Dlg->FindIndex(100), o);
+ bRedraw = false;
+ }
+ }while (res < 0);
+ switch(res) {
+ case 1: //OK button pressed
+ if(oldfill) {
+ oldfill->type = PrevFill.type;
+ oldfill->color = PrevFill.color;
+ oldfill->scale = PrevFill.scale;
+ if(oldfill->hatch) {
+ oldfill->hatch->width = PrevLine.width;
+ oldfill->hatch->patlength = PrevLine.patlength;
+ oldfill->hatch->color = PrevLine.color;
+ oldfill->hatch->pattern = PrevLine.pattern;
+ }
+ }
+ break;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ free(FillDlg);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// execute layers dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool ShowLayers(GraphObj *root)
+{
+ char curr_name[50];
+ DlgInfo PageDlg[] = {
+ {1, 3, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 165, 10, 45, 12},
+ {3, 20, 100, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {20, 550, 0, 0x0L, CHECKPIN, 0L, 10, 0, 12, 8},
+ {100, 101, 0, TOUCHEXIT, TREEVIEW, (void*)root, 10, 15, 100, 70},
+ {101, 102, 0, 0x0L, EDTEXT, (void*)curr_name, 120, 25, 90, 10},
+ {102, 200, 150, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
+ {150, 151, 0, TOUCHEXIT, RADIO1, (void*)"hidden", 120, 35, 40, 9},
+ {151, 0, 0, TOUCHEXIT, RADIO1, (void*)"visible", 160, 35, 40, 9},
+ {200, 500, 0, 0x0L, LTEXT, (void*)"Layers:", 10, 5, 110, 9},
+ {500, 501, 600, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
+ {501, 0, 0, HIDDEN | TOUCHEXIT, TRASH, 0L, 125, 72, 15, 15},
+ {550, 0, 0, HIDDEN | TOUCHEXIT, CONFIG, 0L, 140, 72, 15, 15},
+ {600, 601, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 125, 50, 15, 15},
+ {601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 145, 50, 15, 15},
+ {602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 165, 50, 15, 15},
+ {603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 185, 50, 15, 15}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, cl;
+ bool bContinue = false;
+ ObjTree *ot = 0L;
+ GraphObj *cgo = 0L;
+
+ if(!root) return false;
+ sprintf(curr_name, "(root)");
+ if(!(Dlg = new DlgRoot(PageDlg)))return false;
+ Dlg->ItemCmd(100, CMD_OBJTREE, &ot);
+ if(!ot) {
+ delete Dlg; return false;
+ }
+ Dlg->SetText(101, ot->get_name(0)); Dlg->Activate(101, false);
+ Dlg->SetColor(150, 0x00000080L); Dlg->SetColor(151, 0x00008000L);
+ if(root->Id == GO_GRAPH || root->Id == GO_PAGE) Dlg->ShowItem(550, true);
+ hDlg = CreateDlgWnd("Layer Control", 50, 50, 440, 210, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 0:
+ if(bContinue || Dlg->GetCheck(20)) res = -1;
+ break;
+ case -1:
+ bContinue = false;
+ break;
+ case 550:
+ bContinue = true;
+ case 501:
+ if (res == 501) {
+ if(cgo && cgo->parent) cgo->parent->Command(CMD_DELOBJ, cgo, 0L);
+ Dlg->ItemCmd(100, CMD_LAYERS, 0L);
+ }
+ case 100:
+ if(Dlg->GetInt(100, &cl)) Dlg->SetText(101, ot->get_name(cl));
+ switch(ot->get_vis(cl)) {
+ case 0:
+ Dlg->SetCheck(150, 0L, true); Dlg->ShowItem(102, true);
+ break;
+ case 1:
+ Dlg->SetCheck(151, 0L, true); Dlg->ShowItem(102, true);
+ break;
+ case 2:
+ Dlg->ShowItem(102, false);
+ break;
+ }
+ if((cgo = ot->get_obj(cl)) && cgo->parent) {
+ if(cgo->parent->Id == GO_STACKBAR || cgo->parent->Id == GO_STACKPG ||
+ cgo->parent->Id == GO_WATERFALL) {
+ Dlg->ShowItem(501, true);
+ }
+ else if(cgo->parent->Id == GO_GRAPH || cgo->parent->Id == GO_PAGE){
+ Dlg->ShowItem(500, cgo->parent->Command(CMD_HASSTACK, 0L, 0L));
+ Dlg->ShowItem(501, true);
+ }
+ else {
+ Dlg->ShowItem(500, false); Dlg->ShowItem(501, false);
+ }
+ if(cgo->Id == GO_GRAPH || cgo->Id == GO_PAGE || cgo->Id == GO_POLARPLOT){
+ Dlg->ShowItem(550, true);
+ if(res == 550) if(cgo->Command(CMD_CONFIG, 0L, 0L))
+ cgo->Command(CMD_REDRAW, 0L, 0L);
+ }
+ else Dlg->ShowItem(550, false);
+ }
+ Dlg->Command(CMD_REDRAW, 0L, 0L);
+ res = -1;
+ break;
+ case 150: case 151:
+ ot->set_vis(cl, res == 151);
+ Dlg->ItemCmd(100, CMD_UPDATE, 0L); Dlg->Command(CMD_REDRAW, 0L, 0L);
+ res = -1;
+ break;
+ case 600: case 601: case 602: case 603:
+ if(cgo && cgo->parent){
+ ExecDrawOrderButt(cgo->parent, cgo, res);
+ }
+ Dlg->ItemCmd(100, CMD_UPDATE, 0L); Dlg->Command(CMD_REDRAW, 0L, 0L);
+ res = -1;
+ }
+ }while(res <0);
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// display a welcome banner
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void ShowBanner(bool show)
+{
+ int icon = ICO_RLPLOT;
+ static DlgInfo BannerDlg[] = {
+ {1, 2, 0, 0x0L, PUSHBUTTON, 0L, 0, 0, 100, 40},
+ {2, 3, 0, 0x0L, ICON, (void*)&icon, 5, 5, 20, 20},
+ {3, 4, 0, 0x0L, LTEXT, (void*)"RLPlot", 40, 5, 50, 20},
+ {4, 5, 0, 0x0L, LTEXT, (void*)SZ_VERSION, 8, 25, 35, 9},
+ {5, 0, 0, LASTOBJ, LTEXT, (void*)"... is loading", 45, 25, 50, 9}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, cnt = 5;
+
+ if(!show) return;
+ if(!(Dlg = new DlgRoot(BannerDlg)))return;
+#ifdef _WINDOWS
+ Dlg->TextSize(3, 36);
+#else
+ Dlg->TextSize(3, 24);
+#endif
+ Dlg->TextStyle(3, TXS_ITALIC | TXS_BOLD);
+ Dlg->TextFont(3, FONT_TIMES);
+ Dlg->SetColor(3, 0x00ff0000L);
+ hDlg = CreateDlgWnd("RLPlot", 50, 50, 200, 80, Dlg, 0x7L);
+ FindBrowser();
+ SpreadMain(true);
+ ShowDlgWnd(hDlg);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 0: //loose focus: get it again
+ ShowDlgWnd(hDlg);
+ res = -1;
+ break;
+ case -2: //Timer event
+ if((cnt--) <=0) res = 1;
+ break;
+ }
+ }while(res < 0);
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// the RLPlot about dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void RLPlotInfo()
+{
+ int ico_rlp = ICO_RLPLOT;
+#ifdef _WINDOWS
+ DlgInfo AboutDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 40, 110, 40, 12},
+ {2, 3, 0, 0x0L, ICON, (void*)&ico_rlp, 10, 10, 16, 16},
+ {3, 4, 0, 0x0L, LTEXT, (void*)"RLPlot", 40, 10, 60, 18},
+ {4, 5, 0, 0x0L, CTEXT, (void*)"scientific plotting program", 10, 30, 100, 8},
+ {5, 6, 0, 0x0L, CTEXT, (void*)"version "SZ_VERSION, 10, 38, 100, 8},
+ {6, 7, 0, HREF, CTEXT, (void*)"http://rlplot.sourceforge.net/", 5, 46, 110, 8},
+ {7, 8, 0, 0x0L, CTEXT, (void*)"Copyright (C) 2002-2004 R. Lackner", 5, 54, 110, 8},
+ {8, 9, 0, 0x0L, CTEXT, (void*)"reinhard.lackner at uibk.ac.at", 5, 62, 110, 9},
+ {9, 10, 0, 0x0L, CTEXT, (void*)"This is free software published", 5, 80, 110, 8},
+ {10, 11, 0, 0x0L, CTEXT, (void*)"under the GNU general public.", 5, 88, 110, 8},
+ {11, 0, 0, LASTOBJ, CTEXT, (void*)"license (GPL).", 5, 96, 110, 9}};
+#else
+ int ico_qt = ICO_QT;
+ DlgInfo AboutDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 40, 128, 40, 12},
+ {2, 3, 0, 0x0L, ICON, (void*)&ico_rlp, 10, 10, 16, 16},
+ {3, 4, 0, 0x0L, LTEXT, (void*)"RLPlot", 40, 10, 60, 18},
+ {4, 5, 0, 0x0L, CTEXT, (void*)"scientific plotting program", 10, 30, 100, 8},
+ {5, 6, 0, 0x0L, CTEXT, (void*)"version "SZ_VERSION, 10, 38, 100, 8},
+ {6, 7, 0, HREF, CTEXT, (void*)"http://rlplot.sourceforge.net/", 5, 46, 110, 8},
+ {7, 8, 0, 0x0L, CTEXT, (void*)"Copyright (C) 2002-2004 R. Lackner", 5, 54, 110, 8},
+ {8, 9, 0, 0x0L, CTEXT, (void*)"reinhard.lackner at uibk.ac.at", 5, 62, 110, 9},
+ {9, 10, 0, 0x0L, LTEXT, (void*)"powered by Trolltech\'s Qt", 35, 72, 80, 8},
+ {10, 11, 0, HREF, LTEXT, (void*)"http://www.trolltech.com", 35, 80, 80, 9},
+ {11, 12, 0, TOUCHEXIT, ICON, (void*)&ico_qt, 5, 72, 25, 25},
+ {12, 13, 0, 0x0L, CTEXT, (void*)"This is free software published", 5, 100, 110, 8},
+ {13, 14, 0, 0x0L, CTEXT, (void*)"under the GNU general public.", 5, 108, 110, 8},
+ {14, 0, 0, LASTOBJ, CTEXT, (void*)"license (GPL).", 5, 116, 110, 9}};
+#endif // _WINDOWS
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res;
+
+ if((Dlg = new DlgRoot(AboutDlg))) {
+ Dlg->TextStyle(3, TXS_ITALIC | TXS_BOLD);
+ Dlg->TextFont(3, FONT_TIMES);
+#ifdef _WINDOWS
+ Dlg->TextSize(3, 36);
+#else
+ Dlg->TextSize(3, 32);
+#endif // _WINDOWS
+ Dlg->SetColor(3, 0x00ff0000L);
+ }
+ else return;
+#ifdef _WINDOWS
+ hDlg = CreateDlgWnd("About RLPlot", 50, 50, 240, 280, Dlg, 0x0L);
+#else
+ hDlg = CreateDlgWnd("About RLPlot", 50, 50, 240, 310, Dlg, 0x0L);
+#endif // _WINDOWS
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ if(res == 11) Qt_Box();
+ }while(res <0);
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// change spreadsheet settings
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+DoSpShSize(DataObj *dt)
+{
+ TabSHEET tab1 = {0, 45, 10, "Dimensions"};
+ TabSHEET tab2 = {45, 105, 10, "Width and Height"};
+ char txt1[40], txt2[40];
+ double fw, cw, ch;
+ DlgInfo SSDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 115, 10, 40, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 115, 25, 40, 12},
+ {3, 0, 5, CHECKED | ISPARENT, GROUP, NULL, 138, 40, 55, 12},
+ {5, 6, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 105, 80},
+ {6, 0, 200, ISPARENT, SHEET, &tab2, 5, 10, 105, 80},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"number of columns:", 15, 25, 60, 8},
+ {101, 102, 0, 0x0L, EDTEXT, txt1, 40, 37, 40, 10},
+ {102, 103, 0, 0x0L, LTEXT, (void*)"number of rows:", 15, 52, 60, 8},
+ {103, 0, 0, 0x0L, EDTEXT, txt2, 40, 64, 40, 10},
+ {200, 201, 0, 0x0L, RTEXT, (void*)"row buttons", 10, 34, 40, 8},
+ {201, 202, 0, 0x0L, EDVAL1, &fw, 52, 34, 25, 10},
+ {202, 203, 0, 0x0L, LTEXT, (void*)"[digits]", 79, 34, 20, 8},
+ {203, 204, 0, 0x0L, RTEXT, (void*)"column width", 10, 49, 40, 8},
+ {204, 205, 0, 0x0L, EDVAL1, &cw, 52, 49, 25, 10},
+ {205, 206, 0, 0x0L, LTEXT, (void*)"[digits]", 79, 49, 20, 8},
+ {206, 207, 0, 0x0L, RTEXT, (void*)"text size", 10, 64, 40, 8},
+ {207, 208, 0, 0x0L, EDVAL1, &ch, 52, 64, 25, 10},
+ {208, 0, 0, LASTOBJ, LTEXT, (void *) Units[defs.cUnits].display, 79, 64, 20, 8}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int w1, w2, h1, h2, res, celldim[3];
+ bool bRet = false;
+ double fw1, cw1, ch1;
+
+ if(!dt || !dt->GetSize(&w1, &h1)) return false;
+ dt->Command(CMD_GET_CELLDIMS, &celldim, 0L);
+ fw1 = fw = NiceValue(((double)celldim[0])/((double)(celldim[2]-3)/2.0));
+ cw1 = cw = NiceValue(((double)celldim[1])/((double)(celldim[2]-3)/2.0));
+ switch(defs.cUnits) {
+ case 1: ch = NiceValue(((double)(celldim[2]-2))*0.0259183673); break;
+ case 2: ch = NiceValue(((double)(celldim[2]-2))/98.0); break;
+ default: ch = NiceValue(((double)(celldim[2]-2))*0.259183673); break;
+ }
+ ch1 = ch;
+ sprintf(txt1, "%d", w1);
+ sprintf(txt2, "%d", h1);
+ Dlg = new DlgRoot(SSDlg);
+ hDlg = CreateDlgWnd("Change spread sheet settings", 50, 50, 320, 220, Dlg, 0x0L);
+ Dlg->GetValue(201, &fw1); Dlg->GetValue(204, &cw1); Dlg->GetValue(207, &ch1);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 1: //OK pressed
+ if(Dlg->GetText(101, txt1) && Dlg->GetText(103, txt2)) {
+ w2 = atol(txt1); h2 = atol(txt2);
+ w2 = w2 > 0 ? w2: w1; h2 = h2 > 0 ? h2: h1;
+ }
+ else res = -1;
+ break;
+ }
+ }while(res <0);
+ if(res == 1){
+ Dlg->GetValue(207, &ch);
+ if(ch != ch1 && ch > 0.001) {
+ switch(defs.cUnits) {
+ case 1: celldim[2] = iround(ch/0.0259183673)+2; break;
+ case 2: celldim[2] = iround(ch*98.0)+2; break;
+ default: celldim[2] = iround(ch/0.259183673)+2; break;
+ }
+ dt->Command(CMD_TEXTSIZE, (void*)(& celldim[2]), 0L);
+ }
+ Dlg->GetValue(201, &fw); Dlg->GetValue(204, &cw);
+ if(fw >0.001 && (fw != fw1 || ch != ch1))
+ celldim[0] = iround(fw * ((double)(celldim[2]-3)/2.0));
+ if(cw >0.001 && (cw != cw1 || ch != ch1))
+ celldim[1] = iround(cw * ((double)(celldim[2]-3)/2.0));
+ if(fw != fw1 || cw != cw1 || ch != ch1)
+ dt->Command(CMD_SET_CELLDIMS, &celldim, 0L);
+ if(!dt->ChangeSize(w2, h2, true))
+ ErrorBox("Failed to set new dimensions\nof Spreadsheet.");
+ else bRet = true;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+bool GetCopyRange(RECT *rc, DataObj *d)
+{
+ char text1[80];
+ DlgInfo CopyDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 115, 5, 40, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 115, 20, 40, 12},
+ {3, 4, 0, 0x0L, PUSHBUTTON, (void*)"copy all", 115, 40, 40, 12},
+ {4, 5, 0, 0x0L, LTEXT, (void*)"enter range to copy from:", 10, 10, 80, 9},
+ {5, 0, 0, 0x0L, EDTEXT, text1, 10, 25, 90, 10},
+ {800, 0, 0, LASTOBJ, NONE, 0L, 0, 0, 0, 0}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int r = rc->left, c = rc->top, res, width = 1, height = 1;
+ bool bRet = false;
+ AccRange *rC;
+
+ sprintf(TmpTxt, "%s", Int2ColLabel(rc->right-1, false));
+ sprintf(text1, "%s%d:%s%d", Int2ColLabel(rc->left, false), rc->top+1, TmpTxt, rc->bottom);
+ if(d) d->GetSize(&width, &height);
+ if(!(Dlg = new DlgRoot(CopyDlg))) return false;
+ hDlg = CreateDlgWnd("Copy data", 50, 50, 322, 140, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res){
+ case 3:
+ sprintf(text1, "a1:%s%d", Int2ColLabel(width-1, false), height);
+ Dlg->SetText(5, text1);
+ Dlg->DoPlot(0L);
+ res = -1;
+ break;
+ }
+ }while(res <0);
+ if(res == 1 && Dlg->GetText(5, TmpTxt) && (rC = new AccRange(TmpTxt))) {
+ if(rC->CountItems() >0) {
+ bRet = true; rC->BoundRec(rc);
+ }
+ delete rC;
+ }
+ CloseDlgWnd(hDlg); delete Dlg;
+ return bRet;
+}
+
+bool FillSsRange(DataObj *d, char **range)
+{
+ TabSHEET tab1 = {0, 37, 10, "fill range "};
+ char *ra = range ? *range:0L;
+ double startval = 1.0, stepval = 1.0;
+ static char *formula = 0L;
+ if(!formula && CurrText && CurrText->isFormula()) {
+ if(CurrText->GetText(TmpTxt,TMP_TXT_SIZE)) formula = strdup(TmpTxt);
+ }
+ if(!formula) formula = strdup("=a1");
+ DlgInfo RangeDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 162, 5, 38, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 162, 20, 38, 12},
+ {3, 0, 5, CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {5, 0, 6, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 150, 75},
+ {6, 7, 0, 0x0L, EDTEXT, (void*)ra, 10, 25, 140, 10},
+ {7, 8, 0, CHECKED | TOUCHEXIT, RADIO1, (void*)"with values", 10, 37, 45, 8},
+ {8, 9, 0, TOUCHEXIT, RADIO1, (void*)"with formulas", 60, 37, 60, 8},
+ {9, 10, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
+ {10, 20, 11, CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {11, 12, 0, 0x0L, RTEXT, (void*)"start value=", 10, 60, 35, 8},
+ {12, 13, 0, 0x0L, EDVAL1, &startval, 45, 60, 30, 10},
+ {13, 14, 0, 0x0L, RTEXT, (void*)"increment by", 77, 60, 43, 8},
+ {14, 0, 0, 0x0L, EDVAL1, &stepval, 122, 60, 30, 10},
+ {20, 0, 21, CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
+ {21, 22, 0, 0x0L, RTEXT, (void*)"first cell formula:", 10, 52, 50, 8},
+ {22, 23, 0, 0x0L, EDTEXT, (void*)formula, 60, 52, 90, 10},
+ {23, 24, 0, 0x0L, LTEXT, (void*)"For a list with available funtions see:", 10, 65, 90, 8},
+ {24, 0, 0, HREF | LASTOBJ | TOUCHEXIT, LTEXT, (void*)"http://rlplot.sourceforge.net/Docs/parser.html", 10, 72, 90, 8}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, res, row, col, r1, c1;
+ bool bRet = false, bContinue = false;
+ AccRange *rF;
+
+ if(!d || !range) return false;
+ if(!(Dlg = new DlgRoot(RangeDlg))) return false;
+#ifdef _WINDOWS
+ for(i = 23; i <= 24; i++) Dlg->TextSize(i, 12);
+#else
+ for(i = 23; i <= 24; i++) Dlg->TextSize(i, 10);
+#endif
+ hDlg = CreateDlgWnd("Fill Spreadsheet Range", 50, 50, 414, 206, Dlg, 0x0L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res){
+ case 0:
+ if(bContinue) {
+ bContinue = false; res = -1;
+ }
+ else if(Dlg->GetCheck(9)) res = -1;
+ break;
+ case 1:
+ ra = 0L;
+ if(!Dlg->GetText(6, TmpTxt)) {
+ InfoBox("Range not specified\nor not valid.");
+ bContinue = true; res = -1;
+ }
+ else ra = strdup(TmpTxt);
+ break;
+ case 7:
+ Dlg->ShowItem(10, true); Dlg->ShowItem(20, false);
+ Dlg->Command(CMD_REDRAW, 0L, 0L); res = -1;
+ break;
+ case 8:
+ Dlg->ShowItem(10, false); Dlg->ShowItem(20, true);
+ Dlg->Command(CMD_REDRAW, 0L, 0L); res = -1;
+ break;
+ case 24:
+ bContinue=true;
+ res = -1;
+ break;
+ }
+ }while(res <0);
+ if(res == 1 && ra) {
+ if(Dlg->GetCheck(7)) {
+ Dlg->GetValue(12, &startval); Dlg->GetValue(14, &stepval);
+ if((rF = new AccRange(ra)) && rF->GetFirst(&col, &row)) {
+ for( ; rF->GetNext(&col, &row); startval += stepval) {
+ d->SetValue(row, col, startval);
+ }
+ delete rF; bRet = true;
+ }
+ }
+ else if(Dlg->GetCheck(8)) {
+ if(formula) free(formula); formula = 0L;
+ if((rF = new AccRange(ra)) && rF->GetFirst(&col, &row) &&
+ Dlg->GetText(22, TmpTxt) && (formula = strdup(TmpTxt))){
+ r1 = row; c1 = col;
+ for( ; rF->GetNext(&col, &row); startval += stepval) {
+ MoveFormula(d, formula, TmpTxt, col-c1, row-r1);
+ d->SetText(row, col, TmpTxt);
+ }
+ delete rF; bRet = true;
+ }
+ }
+ free(ra);
+ }
+ CloseDlgWnd(hDlg); delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get resolution and size for exported bitmap
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool GetBitmapRes(double *dpi, double *width, double *height, char *header)
+{
+ DlgInfo ResDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 105, 10, 35, 12},
+ {2, 100, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 105, 25, 35, 12},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"Image properties:", 10, 10, 50, 9},
+ {101, 102, 0, 0x0L, RTEXT, (void*)"width", 10, 22, 35, 9},
+ {102, 103, 0, 0x0L, EDVAL1, width, 47, 22, 30, 10},
+ {103, 104, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 79, 22, 20, 8},
+ {104, 105, 0, 0x0L, RTEXT, (void*)"height", 10, 34, 35, 9},
+ {105, 106, 0, 0x0L, EDVAL1, height, 47, 34, 30, 10},
+ {106, 107, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 79, 34, 20, 8},
+ {107, 108, 0, 0x0L, RTEXT, (void*)"resolution", 10, 46, 35, 9},
+ {108, 109, 0, 0x0L, EDVAL1, dpi, 47, 46, 30, 10},
+ {109, 110, 0, LASTOBJ, LTEXT, (void *) "dpi", 79, 46, 20, 8}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ bool bRet = false;
+ int res;
+
+ if(!(Dlg = new DlgRoot(ResDlg))) return false;
+ if(!(hDlg = CreateDlgWnd(header, 50, 50, 300, 160, Dlg, 0x0L)))return false;
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ if(res==1) {
+ Dlg->GetValue(102, width); Dlg->GetValue(105, height);
+ Dlg->GetValue(108, dpi);
+ }
+ }while (res < 0);
+ if(res == 1) {
+ bRet = true;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Execute schemes dialog as owner drawn button
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static LineDEF Sch0_LINE = {.1, 1.0, 0x0L, 0x0L};
+static LineDEF Sch3_LINE = {.1, 1.0, 0x0L, 0x0L};
+static FillDEF Scheme0 = {FILL_NONE, 0x00ffffffL, 1.0, &Sch0_LINE, 0x00ffffffL};
+static DWORD Scheme1[] = {0x000000ffL, 0x0000ff00L, 0x00ff0000L, 0x0000ffffL,
+ 0x00ff00ffL, 0x00ffff00L, 0x00000000L, 0x00ffffffL};
+static DWORD Scheme2[] = {0x00ffffffL, 0x00e0e0e0L, 0x00c0c0c0L, 0x00808080L,
+ 0x000000L, 0x00808080L, 0x00c0c0c0L, 0x00e0e0e0L};
+static FillDEF Scheme3[] = {
+ {FILL_HLINES, 0x00ffffffL, 1.0, &Sch3_LINE}, {FILL_VLINES, 0x00ffffffL, 1.0, &Sch3_LINE, 0x00ffffffL},
+ {FILL_HVCROSS, 0x00ffffffL, 1.0, &Sch3_LINE}, {FILL_DLINEU, 0x00ffffffL, 1.0, &Sch3_LINE, 0x00ffffffL},
+ {FILL_DLINED, 0x00ffffffL, 1.0, &Sch3_LINE}, {FILL_DCROSS, 0x00ffffffL, 1.0, &Sch3_LINE, 0x00ffffffL},
+ {FILL_BRICKH, 0x00ffffffL, 1.0, &Sch3_LINE}, {FILL_BRICKV, 0x00ffffffL, 1.0, &Sch3_LINE, 0x00ffffffL}};
+static DlgInfo SchBase[] = {
+ {0, 0, 5, CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {5, 6, 0, 0x0L, RADIO1, (void*)"constant fill", 0, 0, 50, 8},
+ {6, 7, 0, 0x0L, RADIO1, (void*)"colors 1", 0, 10, 50, 8},
+ {7, 8, 0, 0x0L, RADIO1, (void*)"colors 2", 0, 28, 50, 8},
+ {8, 10, 0, 0x0L, RADIO1, (void*)"hatches", 0, 46, 50, 8},
+ {10, 20, 0, OWNDIALOG | TOUCHEXIT, FILLBUTTON, (void*)&Scheme0, 56, 0, 20, 8}};
+
+static int CurrScheme = 1;
+
+void OD_scheme(int cmd, void *par, RECT *rec, anyOutput *o,
+ void *data, int id)
+{
+ int x = rec ? rec->left/xbase :0, y = rec ? rec->top/ybase:0;
+ static DlgRoot *Dlg = 0L;
+ POINT *mpos;
+ MouseEvent mev;
+ int i, j, k, res;
+ static DlgInfo *ComSchDlg = 0L;
+
+ switch(cmd) {
+ case OD_CREATE:
+ Dlg = 0L;
+ //set line width: internationalization may be different
+ Sch0_LINE.width = Sch3_LINE.width = defs.GetSize(SIZE_HAIRLINE);
+ ComSchDlg = (DlgInfo*)calloc(40, sizeof(DlgInfo));
+ if(ComSchDlg) {
+ memcpy(ComSchDlg, SchBase, 6 * sizeof(DlgInfo));
+ for (i = 1; i < 6; i++) {
+ ComSchDlg[i].x += x; ComSchDlg[i].y += y;
+ }
+ for (k = 20, j = 6; k < 50; k += 10) {
+ for(i = 0; i < 8; i++) {
+ ComSchDlg[j].id = i+k; ComSchDlg[j].next = i+k+1;
+ ComSchDlg[j].type = k < 40 ? COLBUTTON : FILLBUTTON;
+ ComSchDlg[j].flags = OWNDIALOG | TOUCHEXIT;
+ switch(k) {
+ case 20: ComSchDlg[j].ptype = (void *)Scheme1[i]; break;
+ case 30: ComSchDlg[j].ptype = (void *)Scheme2[i]; break;
+ case 40: ComSchDlg[j].ptype = (void *)&Scheme3[i]; break;
+ }
+ ComSchDlg[j].x = 5 + i*9 + x; ComSchDlg[j].y = 18*(k-10)/10 + y;
+ ComSchDlg[j].w = ComSchDlg[j].h = 8;
+ j++;
+ }
+ ComSchDlg[j-1].next = k+10;
+ }
+ ComSchDlg[j-1].next = 0; ComSchDlg[j-1].flags |= LASTOBJ;
+ Dlg = new DlgRoot(ComSchDlg);
+ }
+ if(Dlg){
+ if(CurrScheme < 4) Dlg->SetCheck(5+CurrScheme, 0L, true);
+ mev.x = mev.y = 0; //activate RootDlg !
+ mev.Action = MOUSE_LBDOWN;
+ mev.StateFlags = 0L;
+ Dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, o); //fake
+ }
+ break;
+ case OD_DELETE:
+ if(Dlg) delete Dlg;
+ Dlg = 0L;
+ if(ComSchDlg) free(ComSchDlg);
+ ComSchDlg = 0L;
+ break;
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ if(Dlg && o) Dlg->DoPlot(o);
+ break;
+ case OD_SELECT:
+ mpos = (POINT*)data;
+ mev.x = mpos->x; mev.y = mpos->y;
+ mev.Action = MOUSE_LBUP;
+ mev.StateFlags = 0L;
+ if(Dlg){
+ ((Dialog*)par)->Command(CMD_CONTINUE, 0L, o);
+ Dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, o);
+ res = Dlg->GetResult();
+ if(res >= 10) Dlg->SetCheck(4 + res/10, 0L, true);
+ if(Dlg->GetCheck(5)) CurrScheme = 0;
+ else if(Dlg->GetCheck(7)) CurrScheme = 2;
+ else if(Dlg->GetCheck(8)) CurrScheme = 3;
+ else CurrScheme = 1;
+ for(i = 0; i < 8; i++) {
+ Dlg->GetColor(i+20, &Scheme1[i]);
+ Dlg->GetColor(i+30, &Scheme2[i]);
+ }
+ }
+ break;
+ case OD_MBTRACK:
+ if(Dlg) Dlg->Command(CMD_MOUSE_EVENT, data, o);
+ break;
+ }
+}
+
+FillDEF *GetSchemeFill(int *i)
+{
+ FillDEF curfill = {FILL_NONE, 0x00c0c0c0L, 1.0, 0L};
+ static FillDEF RetFill;
+
+ switch(CurrScheme) {
+ case 0:
+ memcpy(&RetFill, &Scheme0, sizeof(FillDEF));
+ break;
+ default:
+ case 1:
+ curfill.color = Scheme1[*i&0x07];
+ memcpy(&RetFill, &curfill, sizeof(FillDEF));
+ break;
+ case 2:
+ curfill.color = Scheme2[*i&0x07];
+ memcpy(&RetFill, &curfill, sizeof(FillDEF));
+ break;
+ case 3:
+ memcpy(&RetFill, &Scheme3[*i&0x07], sizeof(FillDEF));
+ break;
+ }
+ *i += 1;
+ return &RetFill;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Execute common line properties as owner drawn dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static LineDEF EditLine = {0.0f, 6.0f, 0x0, 0x0};
+static DlgInfo LinePropBase[] = {
+ {100, 101, 0, 0x0L, RTEXT, (void*)"line width", 0, 0, 45, 8},
+ {101, 102, 0, TOUCHEXIT, INCDECVAL1, &EditLine.width, 50, 0, 32, 10},
+ {102, 103, 0, 0x0L, LTEXT, 0L, 84, 0, 20, 8},
+ {103, 104, 0, 0x0L, RTEXT, (void*)"line color", 0, 12, 45, 8},
+ {104, 105, 0, TOUCHEXIT | OWNDIALOG, COLBUTTON, (void *)EditLine.color, 50, 12, 25, 10},
+ {105, 106, 0, 0x0L, LTEXT, (void*)"pattern:", 0, 24, 25, 8},
+ {106, 107, 0, TOUCHEXIT, LINEPAT, (void *)&EditLine, 0, 34, 128, 4},
+ {107, 108, 0, 0x0L, RTEXT, (void*)"pattern length", 0, 47, 45, 8},
+ {108, 109, 0, TOUCHEXIT, INCDECVAL1, &EditLine.patlength, 50, 47, 32, 10},
+ {109, 110, 0, 0x0L, LTEXT, 0L, 84, 47, 20, 8},
+ {110, 0, 0, LASTOBJ | TOUCHEXIT, LINEBUTT, (void *)&EditLine, 0, 67, 128, 20}};
+
+void OD_linedef(int cmd, void *par, RECT *rec, anyOutput *o,
+ void *data, int id)
+{
+ int x = rec ? rec->left/xbase :0, y = rec ? rec->top/ybase:0;
+ int i, res;
+ POINT *mpos;
+ MouseEvent mev;
+ static DlgRoot *Dlg = 0L;
+ static DlgInfo *LinePropDlg= 0L;
+
+ switch(cmd) {
+ case OD_CREATE:
+ Dlg = 0L;
+ LinePropDlg = (DlgInfo*)calloc(40, sizeof(DlgInfo));
+ if(LinePropDlg) {
+ memcpy(LinePropDlg, LinePropBase, 11 * sizeof(DlgInfo));
+ LinePropDlg[2].ptype = LinePropDlg[9].ptype =
+ (void *)Units[defs.cUnits].display;
+ for (i = 0; i < 11; i++) {
+ LinePropDlg[i].x += x; LinePropDlg[i].y += y;
+ }
+ Dlg = new DlgRoot(LinePropDlg);
+ }
+ if(Dlg){
+ Dlg->SetColor(104, EditLine.color);
+ mev.x = mev.y = 0; //activate RootDlg !
+ mev.Action = MOUSE_LBDOWN;
+ mev.StateFlags = 0L;
+ Dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, o); //fake
+ }
+ break;
+ case OD_DELETE:
+ if(Dlg) delete Dlg;
+ Dlg = 0L;
+ if(LinePropDlg) free(LinePropDlg);
+ LinePropDlg = 0L;
+ break;
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ if(Dlg && o) Dlg->DoPlot(o);
+ break;
+ case OD_SELECT:
+ mpos = (POINT*)data;
+ mev.x = mpos->x; mev.y = mpos->y;
+ mev.Action = MOUSE_LBUP;
+ mev.StateFlags = 0L;
+ if(Dlg){
+ ((Dialog*)par)->Command(CMD_CONTINUE, 0L, o);
+ Dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, o);
+ res = Dlg->GetResult();
+ switch (res) {
+ case 101: //line width changed
+ case 108: //pattern length changed
+ case 110: //preview button
+ Dlg->GetValue(101, &EditLine.width);
+ Dlg->GetValue(108, &EditLine.patlength);
+ case 104: //color button
+ Dlg->GetColor(104, &EditLine.color);
+ case 106: //line pattern
+ Dlg->DoPlot(0);
+ break;
+ }
+ }
+ break;
+ case OD_MBTRACK:
+ if(Dlg) Dlg->Command(CMD_MOUSE_EVENT, data, o);
+ break;
+ case OD_SETLINE:
+ if(data) {
+ memcpy(&EditLine, data, sizeof(LineDEF));
+ if(Dlg && LinePropDlg) Dlg->DoPlot(0);
+ }
+ break;
+ case OD_GETLINE:
+ if(Dlg) {
+ Dlg->GetValue(101, &EditLine.width);
+ Dlg->GetValue(108, &EditLine.patlength);
+ }
+ if(data) memcpy(data, &EditLine, sizeof(LineDEF));
+ break;
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Execute common FILL properties as owner drawn button
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static LineDEF ODLine = {0.0f, 6.0f, 0x0, 0x0};
+static LineDEF ODFillLine = {0.0f, 6.0f, 0x0, 0x0};
+static FillDEF ODFill = {FILL_NONE, 0x00ffffffL, 1.0f, &ODFillLine, 0x00ffffffL};
+static DlgInfo FillPropBase[] = {
+ {100, 101, 0, 0x0L, RTEXT, (void*)"outline width", 0, 0, 40, 8},
+ {101, 102, 0, 0x0L, EDVAL1, &ODLine.width, 42, 0, 25, 10},
+ {102, 103, 0, 0x0L, LTEXT, 0L, 69, 0, 20, 8},
+ {103, 104, 0, 0x0L, RTEXT, (void*)"outline color", 0, 12, 40, 8},
+ {104, 105, 0, OWNDIALOG, COLBUTTON, (void *)ODLine.color, 42, 12, 25, 10},
+ {105, 106, 0, 0x0L, RTEXT,(void*)"fill color" , 0, 24, 40, 8},
+ {106, 107, 0, TOUCHEXIT | OWNDIALOG, COLBUTTON, (void *)ODFill.color, 42, 24, 25, 10},
+ {107, 108, 0, 0x0L, RTEXT, (void*)"pattern", 0, 36, 40, 8},
+ {108, 0, 0, LASTOBJ | TOUCHEXIT | OWNDIALOG, FILLBUTTON, (void*)&ODFill, 42, 36, 25, 10}};
+
+void OD_filldef(int cmd, void *par, RECT *rec, anyOutput *o,
+ void *data, int id)
+{
+ int x = rec ? rec->left/xbase :0, y = rec ? rec->top/ybase:0;
+ int i, res;
+ POINT *mpos;
+ MouseEvent mev;
+ static DlgRoot *Dlg = 0L;
+ static DlgInfo *FillPropDlg= 0L;
+
+ switch(cmd) {
+ case OD_CREATE:
+ Dlg = 0L;
+ FillPropDlg = (DlgInfo*)calloc(9, sizeof(DlgInfo));
+ if(FillPropDlg) {
+ memcpy(FillPropDlg, FillPropBase, 9 * sizeof(DlgInfo));
+ FillPropDlg[2].ptype = (void *) Units[defs.cUnits].display;
+ for (i = 0; i < 9; i++) {
+ FillPropDlg[i].x += x; FillPropDlg[i].y += y;
+ }
+ Dlg = new DlgRoot(FillPropDlg);
+ }
+ if(Dlg){
+ Dlg->SetColor(104, ODLine.color);
+ Dlg->SetColor(106, ODFill.color);
+ mev.x = mev.y = 0; //activate RootDlg !
+ mev.Action = MOUSE_LBDOWN;
+ mev.StateFlags = 0L;
+ Dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, o); //fake
+ }
+ break;
+ case OD_DELETE:
+ if(Dlg) delete Dlg;
+ Dlg = 0L;
+ if(FillPropDlg) free(FillPropDlg);
+ FillPropDlg = 0L;
+ break;
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ if(Dlg && o) Dlg->DoPlot(o);
+ break;
+ case OD_SELECT:
+ mpos = (POINT*)data;
+ mev.x = mpos->x; mev.y = mpos->y;
+ mev.Action = MOUSE_LBUP;
+ mev.StateFlags = 0L;
+ if(Dlg){
+ ((Dialog*)par)->Command(CMD_CONTINUE, 0L, o);
+ Dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, o);
+ res = Dlg->GetResult();
+ switch (res) {
+ case 106: //fill color changed
+ Dlg->GetColor(106, &ODFill.color);
+ Dlg->DoPlot(NULL);
+ break;
+ case 108: //copy color from pattern dialog
+ Dlg->SetColor(106, ODFill.color);
+ break;
+ }
+ }
+ break;
+ case OD_MBTRACK:
+ if(Dlg) Dlg->Command(CMD_MOUSE_EVENT, data, o);
+ break;
+ case OD_SETLINE:
+ if(data) {
+ memcpy(&ODLine, data, sizeof(LineDEF));
+ if(Dlg && FillPropDlg) Dlg->DoPlot(0);
+ }
+ break;
+ case OD_GETLINE:
+ if(Dlg) {
+ Dlg->GetValue(101, &ODLine.width);
+ Dlg->GetColor(104, &ODLine.color);
+ }
+ if(data) memcpy(data, &ODLine, sizeof(LineDEF));
+ break;
+ case OD_SETFILL:
+ if(data) {
+ memcpy(&ODFill, data, sizeof(FillDEF));
+ if(ODFill.hatch) memcpy(&ODFillLine, ((FillDEF*)data)->hatch, sizeof(LineDEF));
+ ODFill.hatch = &ODFillLine;
+ if(Dlg) Dlg->SetColor(106, ODFill.color);
+ }
+ break;
+ case OD_GETFILL:
+ Dlg->GetColor(106, &ODFill.color);
+ if(data) memcpy(data, &ODFill, sizeof(FillDEF));
+ break;
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Execute paper size properiteis as owner drawn button
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+typedef struct{
+ char *name;
+ double mwidth; double mheight;
+ double iwidth; double iheight;
+}paper;
+
+static paper p_formats[] = {
+ {"A0", 841, 1189, 33.11, 46.81}, {"A1", 594, 841, 23.39, 33.11},
+ {"A2", 420, 594, 16.54, 23.39}, {"A3", 297, 420, 11.69, 16.54},
+ {"A4", 210, 297, 8.27, 11.69}, {"A5", 148, 210, 5.83, 8.27},
+ {"A6", 105, 148, 4.13, 5.83}, {"A7", 74, 105, 2.91, 4.13},
+ {"B0", 1030, 1456, 40.55, 57.32}, {"B1", 728, 1030, 28.66, 40.55},
+ {"B2", 515, 728, 20.28, 28.66}, {"B3", 364, 515, 14.33, 20.28},
+ {"B4", 257, 364, 10.12, 14.33}, {"B5", 182, 257, 7.17, 10.12},
+ {"B6", 128, 182, 5.04, 7.17}, {"B7", 91, 128, 3.58, 5.04},
+ {"Executive", 191, 254, 7.52, 10}, {"Folio", 210, 330, 8.27, 12.99},
+ {"Ledger", 432, 279, 17.01, 10.98}, {"Legal", 216, 356, 8.5, 14.02},
+ {"Letter", 216, 279, 8.5, 10.98},
+ {"Custom", 210, 297, 8.27, 11.69}};
+static int cpformats = sizeof(p_formats)/sizeof(paper);
+static double cu_width = 123.0, cu_height = 234.0;
+static int pg_sel = 4;
+
+static DlgInfo PaperDlg[] = {
+ {100, 110, 0, 0x0L, NONE, (void*)0L, 0, 0, 0, 0},
+ {110, 120, 0, TOUCHEXIT, LISTBOX1, (void*)0L, 0, 15, 100, 70},
+ {120, 130, 0, NOEDIT, EDTEXT, (void*)"n.a.", 0, 0, 100, 10},
+ {130, 0, 132, CHECKED, GROUP, 0, 0, 0, 0},
+ {132, 133, 0, 0x0L, EDVAL1, (void*)&cu_width, 27, 0, 25, 10},
+ {133, 134, 0, 0x0L, LTEXT, (void*)"x", 52, 0, 5, 8},
+ {134, 135, 0, 0x0L, EDVAL1, (void*)&cu_height, 58, 0, 25, 10},
+ {135, 0, 0, LASTOBJ, LTEXT, (void*)0L, 83, 0, 14, 8}};
+
+void OD_paperdef(int cmd, void *par, RECT *rec, anyOutput *o,
+ void *data, int id)
+{
+ int x = rec ? rec->left/xbase :0, y = rec ? rec->top/ybase:0;
+ int i, res;
+ POINT *mpos;
+ MouseEvent mev;
+ static DlgRoot *Dlg = 0L;
+ static DlgInfo *PaperPropDlg= 0L;
+ char **dispsize = 0L;
+ double dtmp;
+
+ switch(cmd) {
+ case OD_CREATE:
+ GetPaper(&cu_width, &cu_height);
+ Dlg = 0L;
+ if((PaperPropDlg = (DlgInfo*)calloc(8, sizeof(DlgInfo))) &&
+ (dispsize = (char**)calloc(cpformats+1, sizeof(char*)))) {
+ memcpy(PaperPropDlg, PaperDlg, 8 * sizeof(DlgInfo));
+ for (i = 0; i < cpformats; i++) {
+ if(i < cpformats -1) {
+ switch(defs.cUnits) {
+ case 1:
+ sprintf(TmpTxt, " %s (%.1lf x %.1lf cm)", p_formats[i].name,
+ p_formats[i].mwidth/10.0, p_formats[i].mheight/10.0);
+ break;
+ case 2:
+ sprintf(TmpTxt, " %s (%.2lf x %.2lf inch)", p_formats[i].name,
+ p_formats[i].iwidth, p_formats[i].iheight);
+ break;
+ default:
+ sprintf(TmpTxt, " %s (%.0lf x %.0lf mm)", p_formats[i].name,
+ p_formats[i].mwidth, p_formats[i].mheight);
+ break;
+ }
+ dispsize[i] = strdup(TmpTxt);
+ }
+ else dispsize[i] = strdup(" Custom");
+ }
+ PaperPropDlg[1].ptype = (void*)dispsize;
+ PaperPropDlg[7].ptype = (void*)Units[defs.cUnits].display;
+ if(pg_sel <(cpformats -1))PaperPropDlg[3].flags |= HIDDEN;
+ for (i = 0; i < 8; i++) {
+ PaperPropDlg[i].x += x; PaperPropDlg[i].y += y;
+ }
+ if(Dlg = new DlgRoot(PaperPropDlg)){
+ Dlg->Activate(120, false);
+ if(Dlg->ItemCmd(110, CMD_FINDTEXT, (void*)dispsize[pg_sel])){
+ if(pg_sel < (cpformats-1)) Dlg->SetText(120, dispsize[pg_sel]);
+ else Dlg->SetText(120, dispsize[pg_sel]+1);
+ dtmp = ((double)pg_sel)/((double) cpformats +10.0);
+ Dlg->ItemCmd(110, CMD_SETSCROLL, (void*)&dtmp);
+ }
+ }
+ }
+ break;
+ case OD_DELETE:
+ if(Dlg) delete Dlg;
+ Dlg = 0L;
+ if(PaperPropDlg) free(PaperPropDlg);
+ PaperPropDlg = 0L;
+ if(dispsize) {
+ for (i = 0; i < 20; i++) if(dispsize[i])free(dispsize[i]);
+ free(dispsize);
+ dispsize = 0L;
+ }
+ break;
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ if(Dlg && o) Dlg->DoPlot(o);
+ break;
+ case OD_SELECT:
+ mpos = (POINT*)data;
+ mev.x = mpos->x; mev.y = mpos->y;
+ mev.Action = MOUSE_LBUP;
+ mev.StateFlags = 0L;
+ if(Dlg){
+ ((Dialog*)par)->Command(CMD_CONTINUE, 0L, o);
+ Dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, o);
+ res = Dlg->GetResult();
+ if(res == 110 && Dlg->GetText(110, TmpTxt)){
+ if(Dlg->GetInt(110, &i)) {
+ if(i == cpformats-1){
+ Dlg->ShowItem(130, true);
+ Dlg->SetText(120, TmpTxt+1);
+ }
+ else {
+ Dlg->ShowItem(130, false);
+ Dlg->SetText(120, TmpTxt);
+ }
+ }
+ Dlg->DoPlot(o);
+ }
+ }
+ break;
+ case OD_MBTRACK:
+ if(Dlg) Dlg->Command(CMD_MOUSE_EVENT, data, o);
+ break;
+ case OD_ACCEPT:
+ if(Dlg) {
+ if(Dlg->GetInt(110, &pg_sel) && pg_sel == (i=cpformats-1)){
+ Dlg->GetValue(132, &cu_width);
+ Dlg->GetValue(134, &cu_height);
+ switch(defs.cUnits){
+ case 1:
+ p_formats[i].mwidth = cu_width*10.0;
+ p_formats[i].mheight = cu_height*10.0;
+ p_formats[i].iwidth = cu_width/2.54;
+ p_formats[i].iheight = cu_height/2.54;
+ break;
+ case 2:
+ p_formats[i].mwidth = cu_width*25.4;
+ p_formats[i].mheight = cu_height*25.4;
+ p_formats[i].iwidth = cu_width;
+ p_formats[i].iheight = cu_height;
+ break;
+ default:
+ p_formats[i].mwidth = cu_width;
+ p_formats[i].mheight = cu_height;
+ p_formats[i].iwidth = cu_width/25.4;
+ p_formats[i].iheight = cu_height/25.4;
+ break;
+ }
+ }
+ }
+ break;
+ }
+}
+
+//Find a suitable paper size with width w and height h
+void FindPaper(double w, double h, double tol)
+{
+ int i;
+ double lw, hw, lh, hh;
+
+ lw = w *(1.0-tol); hw = w *(1.0+tol);
+ lh = h *(1.0-tol); hh = h *(1.0+tol);
+ for(i = 0; i < cpformats; i++) {
+ switch(defs.cUnits) {
+ case 1: //units are cm
+ if(p_formats[i].mwidth >= lw*10.0 && p_formats[i].mwidth <= hw*10.0 &&
+ p_formats[i].mheight >= lh*10.0 && p_formats[i].mheight <= hh*10.0){
+ pg_sel = i;
+ return;
+ }
+ break;
+ case 2: //units are inch
+ if(p_formats[i].iwidth >= lw && p_formats[i].iwidth <= hw &&
+ p_formats[i].iheight >= lh && p_formats[i].iheight <= hh){
+ pg_sel = i;
+ return;
+ }
+ break;
+ default: //units are mm
+ if(p_formats[i].mwidth >= lw && p_formats[i].mwidth <= hw &&
+ p_formats[i].mheight >= lh && p_formats[i].mheight <= hh){
+ pg_sel = i;
+ return;
+ }
+ break;
+ }
+ }
+ //The paper format is non standard
+ pg_sel = i = cpformats-1;
+ switch(defs.cUnits){
+ case 1:
+ p_formats[i].mwidth = w*10.0; p_formats[i].mheight = h*10.0;
+ p_formats[i].iwidth = w/2.54; p_formats[i].iheight = h/2.54;
+ break;
+ case 2:
+ p_formats[i].mwidth = w*25.4; p_formats[i].mheight = h*25.4;
+ p_formats[i].iwidth = w; p_formats[i].iheight = h;
+ break;
+ default:
+ p_formats[i].mwidth = w; p_formats[i].mheight = h;
+ p_formats[i].iwidth = w/25.4; p_formats[i].iheight = h/25.4;
+ break;
+ }
+}
+
+//Get (default) paper size
+bool GetPaper(double *w, double *h)
+{
+ switch(defs.cUnits) {
+ case 1: //units are cm
+ *w = p_formats[pg_sel].mwidth/10.0;
+ *h = p_formats[pg_sel].mheight/10.0;
+ break;
+ case 2: //units are inch
+ *w = p_formats[pg_sel].iwidth;
+ *h = p_formats[pg_sel].iheight;
+ break;
+ default: //units are mm
+ *w = p_formats[pg_sel].mwidth;
+ *h = p_formats[pg_sel].mheight;
+ break;
+ }
+ return true;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Select axis for plot as owner drawn button
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static DlgInfo PlotsDlg[] = {
+ {100, 110, 0, 0x0L, NONE, (void*)0L, 0, 0, 0, 0},
+ {110, 150, 0, TOUCHEXIT, LISTBOX1, (void*)0L, 20, 50, 100, 70},
+ {150, 0, 0, LASTOBJ, LTEXT, (void*)"Apply this axis to plot:", 20, 35, 50, 9}};
+static int axisplot_sel = 0;
+
+void OD_axisplot(int cmd, void *par, RECT *rec, anyOutput *o,
+ void *data, int id)
+{
+ static DlgInfo *PlotsPropDlg= 0L;
+ static DlgRoot *Dlg = 0L;
+ int i, res;
+ POINT *mpos;
+ MouseEvent mev;
+ static char **names = 0L;
+
+ switch(cmd) {
+ case OD_CREATE:
+ Dlg = 0L;
+ if(PlotsPropDlg = (DlgInfo*)calloc(3, sizeof(DlgInfo))){
+ memcpy(PlotsPropDlg, PlotsDlg, 3 * sizeof(DlgInfo));
+ PlotsPropDlg[1].ptype = (void*)names;
+ Dlg = new DlgRoot(PlotsPropDlg);
+ }
+ axisplot_sel = 0;
+ break;
+ case OD_DELETE:
+ if(Dlg) delete Dlg;
+ Dlg = 0L;
+ if(PlotsPropDlg) free(PlotsPropDlg);
+ PlotsPropDlg = 0L;
+ break;
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ if(Dlg && o) Dlg->DoPlot(o);
+ break;
+ case OD_SELECT:
+ mpos = (POINT*)data;
+ mev.x = mpos->x; mev.y = mpos->y;
+ mev.Action = MOUSE_LBUP;
+ mev.StateFlags = 0L;
+ if(Dlg){
+ ((Dialog*)par)->Command(CMD_CONTINUE, 0L, o);
+ Dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, o);
+ res = Dlg->GetResult();
+ if(res == 110 && Dlg->GetText(110, TmpTxt)){
+ if(Dlg->GetInt(110, &i)) {
+ //get selection
+ }
+ Dlg->DoPlot(o);
+ }
+ Dlg->GetInt(110, &axisplot_sel);
+ }
+ break;
+ case OD_MBTRACK:
+ if(Dlg) Dlg->Command(CMD_MOUSE_EVENT, data, o);
+ break;
+ case OD_ACCEPT:
+ if(data) names = (char**)data;
+ else Dlg->GetInt(110, &axisplot_sel);
+ if(o) *((int*)o) = axisplot_sel;
+ }
+}
diff --git a/TheDialog.h b/TheDialog.h
new file mode 100755
index 0000000..d3ea251
--- /dev/null
+++ b/TheDialog.h
@@ -0,0 +1,527 @@
+//TheDialog.h, Copyright (c) 2001, 2002, 2003, 2004, 2005 R.Lackner
+//Definitions for TheDialog.cpp
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// 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
+//
+// declarations relevant for user
+typedef struct {
+ unsigned int id; //consecutive number
+ unsigned int next; //id of next object
+ unsigned int first; //number of first child
+ unsigned long flags; //any status flag bits
+ unsigned int type; //identifier of dialog item
+ void *ptype; //pointer to information dependend on type
+ unsigned int x, y, w, h; //start coordinates
+} DlgInfo;
+
+//defining a tab
+typedef struct {
+ unsigned int x1, x2; //relative position to left border
+ unsigned int height; //the height
+ char *text; //descriptor shown on tab
+} TabSHEET;
+
+//types of dialogs
+enum {NONE, PUSHBUTTON, ARROWBUTT, COLBUTTON, FILLBUTTON, SHADE3D, LINEBUTT, SYMBUTT,
+ FILLRADIO, SYMRADIO, CHECKBOX, RADIO0, RADIO1, RADIO2, LTEXT, RTEXT, CTEXT, EDTEXT,
+ EDVAL1, INCDECVAL1, HSCROLL, VSCROLL, TXTHSP, ICON, GROUP,
+ GROUPBOX, SHEET, ODBUTTON, LISTBOX1, TREEVIEW, LINEPAT, TEXTBOX, CHECKPIN, TRASH,
+ CONFIG};
+
+//flags
+#define CHECKED 0x00000001L
+#define TOUCHEXIT 0x00000002L
+#define TOUCHSELEXIT 0x00000004L
+#define ISRADIO 0x00000008L
+#define ISPARENT 0x00000010L
+#define OWNDIALOG 0x00000020L
+#define DEFAULT 0x00000040L
+#define HIDDEN 0x00000080L
+#define NOSELECT 0x00000100L
+#define HREF 0x00000200L
+#define NOEDIT 0x00000400L
+#define LASTOBJ 0x00100000L
+
+//owner draw button commands
+enum {OD_CREATE, OD_DELETE, OD_DRAWNORMAL, OD_DRAWSELECTED, OD_SELECT, OD_MBTRACK,
+ OD_SETLINE, OD_GETLINE, OD_SETFILL, OD_GETFILL, OD_ACCEPT};
+
+class tag_DlgObj{
+public:
+ RECT cr, hcr;
+ int Id, type;
+ unsigned long flags;
+ bool bChecked, bLBdown, bActive;
+
+ virtual bool Command(int cmd, void *tmpl, anyOutput *o){return false;};
+ virtual void DoPlot(anyOutput *o) {return;};
+ virtual bool Select(int x, int y, anyOutput *o) {return false;};
+ virtual bool GetColor(int id, DWORD *color) {return false;};
+ virtual void SetColor(int id, DWORD color) {return;};
+ virtual bool GetValue(int id, double *val) {return false;};
+ virtual bool GetInt(int id, int *val) {return false;};
+ virtual bool SetCheck(int id, anyOutput *o, bool state) {return false;};
+ virtual bool GetCheck(int Id) {return bChecked;};
+ virtual bool GetText(int id, char *txt) {return false;};
+ virtual void MBtrack(MouseEvent *mev, anyOutput *o) {return;};
+ virtual void Activate(int id, bool active){return;};
+};
+
+class Dialog:public tag_DlgObj {
+public:
+ tag_DlgObj *parent;
+ LineDEF Line;
+ FillDEF Fill;
+ TextDEF TextDef;
+
+ Dialog(tag_DlgObj *par, DlgInfo * desc, RECT rec);
+ virtual bool Select(int x, int y, anyOutput *o);
+ bool SetCheck(int id, anyOutput *o, bool state);
+ void MBtrack(MouseEvent *mev, anyOutput *o);
+ virtual void Activate(int id, bool active);
+};
+
+typedef struct {
+ unsigned int id; //consecutive number
+ unsigned int next; //id of next object
+ unsigned int first; //number of first child
+ unsigned long flags; //any status flag bits
+ Dialog *dialog; //pointer to dialog object
+} DlgTmpl;
+
+class DlgRoot:public tag_DlgObj {
+public:
+ anyOutput *CurrDisp;
+
+ DlgRoot(DlgInfo *tmpl);
+ ~DlgRoot();
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void DoPlot(anyOutput *o);
+ bool CurUpDown(int cmd);
+ bool GetColor(int id, DWORD *color);
+ void SetColor(int id, DWORD color);
+ bool GetValue(int id, double *val);
+ bool GetInt(int id, int *val);
+ bool SetCheck(int id, anyOutput *o, bool state);
+ bool GetCheck(int Id);
+ void Activate(int id, bool active);
+ bool GetText(int id, char *txt);
+ bool SetText(int id, char *txt);
+ bool TextStyle(int id, int style);
+ bool TextFont(int id, int font);
+ bool TextSize(int id, int size);
+ bool ShowItem(int id, bool show);
+ int GetResult();
+ int FindIndex(unsigned short id);
+ void ForEach(int cmd, int start, anyOutput *o);
+ bool ItemCmd(int id, int cmd, void *tmpl);
+ anyOutput *GetOutputClass(){return CurrDisp;};
+
+private:
+ int cDlgs, Result, cContinue;
+ Dialog *oldFocus, *oldDefault, *oldTabStop;
+ bool bActive;
+ Dialog **tabstops;
+ DlgTmpl **dlg;
+ MouseEvent *mev;
+};
+
+class PushButton:public Dialog {
+public:
+ PushButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text);
+ ~PushButton();
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+
+private:
+ char *Text;
+};
+
+class TextBox:public Dialog {
+public:
+ TextBox(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text);
+ ~TextBox();
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+ bool GetText(int id, char *txt);
+
+private:
+ mLabel *cont;
+};
+
+class ArrowButton:public Dialog {
+public:
+ ArrowButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, int *which);
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+
+private:
+ int direct;
+};
+
+class ColorButton:public Dialog {
+public:
+ ColorButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, unsigned long color);
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+ bool GetColor(int id, DWORD *color) {*color = col; return true;};
+ void SetColor(int id, DWORD color) {col = color; return;};
+
+private:
+ unsigned long col;
+};
+
+class FillButton:public Dialog {
+public:
+ FillButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, FillDEF *fill);
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+ bool GetColor(int id, DWORD *color) {*color = CurrFill->color; return true;};
+
+private:
+ FillDEF *CurrFill;
+};
+
+class Shade3D:public Dialog {
+public:
+ Shade3D(tag_DlgObj *par, DlgInfo * desc, RECT rec, FillDEF *fill);
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+ bool GetColor(int id, DWORD *color) {*color = CurrFill->color; return true;};
+
+private:
+ FillDEF *CurrFill;
+};
+
+class LineButton:public Dialog {
+public:
+ LineButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, LineDEF *line);
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+
+private:
+ LineDEF *CurrLine;
+ POINT pts[2];
+};
+
+class SymButton:public Dialog {
+public:
+ SymButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, Symbol **sym);
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+
+private:
+ Symbol **symbol;
+};
+
+class FillRadioButt:public Dialog {
+public:
+ FillRadioButt(tag_DlgObj *par, DlgInfo * desc, RECT rec, unsigned int pattern);
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+};
+
+class SymRadioButt:public Dialog {
+public:
+ SymRadioButt(tag_DlgObj *par, DlgInfo * desc, RECT rec, int *type);
+ ~SymRadioButt();
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+
+private:
+ Symbol *Sym;
+};
+
+class CheckBox:public Dialog {
+public:
+ CheckBox(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text);
+ ~CheckBox();
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+
+private:
+ char *Text;
+};
+
+class CheckPin:public Dialog {
+public:
+ CheckPin(tag_DlgObj *par, DlgInfo * desc, RECT rec);
+ ~CheckPin();
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+};
+
+class Trash:public Dialog {
+public:
+ Trash(tag_DlgObj *par, DlgInfo * desc, RECT rec);
+ ~Trash();
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+};
+
+class Config:public Dialog {
+public:
+ Config(tag_DlgObj *par, DlgInfo * desc, RECT rec);
+ ~Config();
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+};
+
+class RadioButton:public Dialog {
+public:
+ RadioButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text);
+ ~RadioButton();
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+ void SetColor(int id, DWORD color);
+
+private:
+ char *Text;
+};
+
+class Text:public Dialog {
+public:
+ Text(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text);
+ ~Text();
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+ void SetColor(int id, DWORD color);
+
+private:
+ char *txt;
+};
+
+class InputText:public Dialog {
+public:
+ EditText *Text;
+
+ InputText(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text);
+ ~InputText();
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ virtual void DoPlot(anyOutput *o);
+ virtual bool Select(int x, int y, anyOutput *o);
+ bool GetValue(int id, double *val);
+ bool GetInt(int id, int *val);
+ bool GetText(int id, char *txt);
+ virtual void MBtrack(MouseEvent *mev, anyOutput *o);
+ void Activate(int id, bool active);
+
+private:
+ anyOutput *Disp;
+};
+
+class InputValue:public InputText {
+public:
+ InputValue(tag_DlgObj *par, DlgInfo * desc, RECT rec, double *value);
+ ~InputValue();
+};
+
+class IncDecValue:public InputText {
+public:
+ IncDecValue(tag_DlgObj *par, DlgInfo * desc, RECT rec, double *value);
+ ~IncDecValue();
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+ void MBtrack(MouseEvent *mev, anyOutput *o);
+
+private:
+ ArrowButton *butts[2];
+};
+
+class TxtHSP:public Dialog {
+public:
+ TxtHSP(tag_DlgObj *par, DlgInfo *desc, RECT rec, int *align);
+ ~TxtHSP();
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+ bool GetInt(int id, int *val);
+ void MBtrack(MouseEvent *mev, anyOutput *o);
+
+private:
+ TextDEF txt;
+ RadioButton *butts[9];
+ DlgInfo *d2;
+};
+
+class SlideRect:public Dialog{
+public:
+ int sLine;
+
+ SlideRect(tag_DlgObj *par, DlgInfo *desc, RECT rec, bool isVert);
+ ~SlideRect();
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+ bool GetValue(int id, double *val);
+ void MBtrack(MouseEvent *mev, anyOutput *o);
+
+private:
+ int dx, dy, w, h;
+ bool bV, puSel, pdSel;
+ RECT buttrc, puRC, pdRC;
+};
+
+class ScrollBar:public Dialog{
+public:
+ int sLine, sPage;
+
+ ScrollBar(tag_DlgObj *par, DlgInfo *desc, RECT rec, bool isVert);
+ ~ScrollBar();
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+ bool GetValue(int id, double *val);
+ void MBtrack(MouseEvent *mev, anyOutput *o);
+
+private:
+ ArrowButton *butts[3];
+ SlideRect *slrc;
+};
+
+class Icon:public Dialog {
+public:
+ Icon(tag_DlgObj *par, DlgInfo * desc, RECT rec, int *ico);
+ void DoPlot(anyOutput *o);
+
+private:
+ int icon;
+};
+
+class Group:public Dialog {
+public:
+ Group(tag_DlgObj *par, DlgInfo * desc, RECT rec);
+ ~Group();
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+ void MBtrack(MouseEvent *mev, anyOutput *o);
+
+ InputText *TextFocus;
+ Dialog **Children;
+ int numChildren;
+};
+
+class GroupBox:public Group {
+public:
+ GroupBox(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *txt);
+ ~GroupBox();
+ void DoPlot(anyOutput *o);
+
+private:
+ char *Text;
+};
+
+class TabSheet:public Group {
+public:
+ TabSheet(tag_DlgObj *par, DlgInfo * desc, RECT rec, TabSHEET *sh);
+ ~TabSheet();
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+
+private:
+ RECT rctab;
+ char *Text;
+};
+
+class ODbutton:public Dialog {
+public:
+ ODbutton(tag_DlgObj *par, DlgInfo *des, RECT rec, void*proc);
+ ~ODbutton();
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+ void MBtrack(MouseEvent *mev, anyOutput *o);
+
+private:
+ void (*ODexec)(int cmd, void *par, RECT *rec, anyOutput *o,
+ void *data, int id);
+};
+
+class Listbox:public Dialog {
+public:
+ Listbox(tag_DlgObj *par, DlgInfo *des, RECT rec, char **list);
+ ~Listbox();
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+ bool GetInt(int id, int *val);
+ bool GetText(int id, char *txt);
+ void MBtrack(MouseEvent *mev, anyOutput *o);
+
+private:
+ ScrollBar *sb;
+ anyOutput *bmp;
+ char **strings;
+ double spos;
+ int ns, bmh, startY, cl;
+
+ bool CreateBitMap(anyOutput *tmpl);
+};
+
+class Treeview:public Dialog {
+public:
+ Treeview(tag_DlgObj *par, DlgInfo *des, RECT rec, GraphObj *g);
+ ~Treeview();
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+ bool GetInt(int id, int *val);
+ void MBtrack(MouseEvent *mev, anyOutput *o);
+
+private:
+ ScrollBar *sb;
+ anyOutput *bmp;
+ double spos;
+ int ns, bmh, bmw, startY, cl;
+ GraphObj *go;
+ ObjTree *ot;
+};
+
+class LinePat:public Dialog {
+public:
+ LinePat(tag_DlgObj *par, DlgInfo *desc, RECT rec, LineDEF *Line);
+ void DoPlot(anyOutput *o);
+ void MBtrack(MouseEvent *mev, anyOutput *o);
+
+private:
+ bool bDraw;
+ DWORD *pPattern;
+};
+
+//prototypes ODbutton.cpp
+void OD_DrawOrder(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id);
+int ExecDrawOrderButt(GraphObj *parent, GraphObj *obj, int id);
+void OD_LineStyleTempl(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id);
+void OD_ErrBarTempl(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id);
+void OD_WhiskerTempl(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id);
+void OD_PolarTempl(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id);
+void OD_PieTempl(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id);
+void OD_AxisDesc3D(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id);
+void OD_BreakTempl(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id);
+void OD_PlotTempl(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id);
+void OD_AxisTempl(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id);
+void OD_AxisTempl3D(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id);
+void OD_NewAxisTempl(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id);
diff --git a/UtilObj.cpp b/UtilObj.cpp
new file mode 100755
index 0000000..c604c25
--- /dev/null
+++ b/UtilObj.cpp
@@ -0,0 +1,2950 @@
+//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.0f, 1.0f, 0x00d8d8d8L, 0L};
+static LineDEF ETbgna = {0.0f, 1.0f, 0x00ffffffL, 0L};
+static LineDEF ETbgmn = {0.0f, 1.0f, 0x00000000L, 0L};
+static LineDEF ETbgma = {0.0f, 1.0f, 0x00ffff00L, 0L};
+extern const LineDEF BlackLine = {0.0f, 1.0f, 0x00000000L, 0L};
+
+static FillDEF ETfbnn = {FILL_NONE, 0x00d8d8d8L, 1.0f, NULL, 0x00ffffffL};
+static FillDEF ETfbna = {FILL_NONE, 0x00ffffffL, 1.0f, NULL, 0x00ffffffL};
+static FillDEF ETfbmn = {FILL_NONE, 0x00000000L, 1.0f, NULL, 0x00ffffffL};
+static FillDEF ETfbma = {FILL_NONE, 0x00ffff00L, 1.0f, NULL, 0x00ffffffL};
+
+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, POINT where, POINT right, char *msg)
+{
+ loc.x = where.x; loc.y = where.y;
+ crb.x = rb.x = right.x; crb.y = rb.y = right.y;
+ if(msg && msg[0]) text = strdup(msg);
+ else text = 0L; Value = 0.0;
+ CursorPos = length = Align = 0; type = ET_UNKNOWN; TextCol=0x00000000L;
+ bgLine = &ETbgnn; bgFill = &ETfbnn; parent = par;
+ FindType();
+ m1 = m2 = -1; //cursor positions track marks
+}
+
+EditText::EditText(void *par, char *msg)
+{
+ loc.x = loc.y = crb.x = rb.x = crb.y = rb.y = 0; Value = 0.0;
+ if(msg && msg[0]) text = strdup(msg);
+ else text = 0L;
+ CursorPos = length = Align = 0; type = ET_UNKNOWN; TextCol=0x00000000L;
+ bgLine = &ETbgnn; bgFill = &ETfbnn; parent = par;
+ FindType();
+ m1 = m2 = -1; //cursor positions track marks
+}
+
+EditText::~EditText()
+{
+ if(CurrText == this) CurrText = 0L;
+ if(text) free(text); text = 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;
+ Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
+ 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;
+ if(parent) ((DataObj*)parent)->Command(CMD_MRK_DIRTY, 0L, 0L);
+ byte1 = byte2 = 0;
+ //replace mark by character if mark exists
+ if(m1 > -1 && m2 > -1) Command(CMD_DELETE, (anyOutput *)0L, (DataObj *)0L);
+ byte1 = text[CursorPos];
+ i = CursorPos;
+ text[i++] = c;
+ while(byte1) {
+ byte2 = byte1; byte1 = text[i]; text[i++] = byte2;
+ }
+ text[i] = byte1;
+ CursorPos++;
+ 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);
+ return true;
+}
+
+void
+EditText::Update(int select, anyOutput *Out, POINT *MousePos)
+{
+ POINT MyPos;
+
+ 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_VTOP | TXA_HLEFT;
+ case 1: //active spread sheet cell with cursor
+ if((type & 0xff) == ET_FORMULA) Align = TXA_VTOP | TXA_HLEFT;
+ if(!text && !(text = (char *) calloc(2, sizeof(char))))return;
+ if(CursorPos > (int)strlen(text)) CursorPos = (int)strlen(text);
+ bgLine = &ETbgna; bgFill = &ETfbna; TextCol = 0x00000000L;
+ Redraw(Out, true);
+ MyPos.y = loc.y;
+ MyPos.x = Align & TXA_HRIGHT ? crb.x - 2 : loc.x + 2;
+ 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);
+ break;
+ case 2: //inactive spreadsheet cell
+ if((type & 0xff) == ET_FORMULA) Align = TXA_VTOP | 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;
+ Redraw(Out, true);
+ break;
+ case 10: //value filled in by external app.
+ if(text && text[0]) {
+ type = ET_VALUE;
+ Align = TXA_VTOP | 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 i, j, w, h, o_crbx;
+ bool b_clip = false;
+ anyOutput *opc;
+ anyResult *fmres;
+
+ o_crbx = crb.x; crb.x = rb.x; crb.y = rb.y;
+ if (Out) {
+ 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; rc.bottom = crb.y;
+ Out->oRectangle(loc.x, loc.y, crb.x-1, crb.y-1);
+ if(!text && (type & 0xff) == ET_VALUE){
+ sprintf(tmptxt, "%g", Value);
+ text = strdup(tmptxt);
+ }
+ if(text && text[0]){
+ if((type & 0xff) == ET_FORMULA && (bgLine == &ETbgnn || bgLine == &ETbgmn)) {
+ Out->TxtSet.Align = TXA_HLEFT;
+ if(type & ET_CIRCULAR) strcpy (tmptxt, "#CIRC.");
+ else if((fmres = do_formula((DataObj*)parent, text+1)) && fmres->type != ET_ERROR) {
+ b_clip = false; //DEBUG: assume column wide enough for number
+ if(fmres->type == ET_VALUE) {
+ sprintf(tmptxt, "%g", Value = fmres->value);
+ for(i=j=0; i < 20; i++) {
+ while(i>3 && tmptxt[i] == '0' && tmptxt[j-2] == 'e') i++;
+ tmptxt[j++] = tmptxt[i];
+ }
+ tmptxt[j] = 0;
+ Out->TxtSet.Align = TXA_HRIGHT;
+ }
+ else if(fmres->type == ET_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 txt = text;
+ MyPos.y = loc.y;
+ if(Out->TxtSet.Align & TXA_HRIGHT) { //right justified text
+ MyPos.x = crb.x-2;
+ }
+ else { //left justified text
+ MyPos.x = loc.x +2;
+ }
+ if(b_clip && (opc = NewBitmapClass(w+22, h+2, 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_VTOP;
+ opc->oTextOut(2, 0, 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-2, rc.bottom-rc.top-2, false);
+ DelBitmapClass(opc);
+ }
+ else {
+ scroll_dist = 0;
+ Out->oTextOut(MyPos.x, loc.y, txt, 0);
+ }
+ }
+ if(display) {
+ if(!(Out->UpdateRect(&rc, false))) return false;
+ if(m1 != m2 && m1 >=0 && m2 >=0) {
+ if (m1 >m2) Swap(m1, m2);
+ rc.left = mx1; rc.right = mx2;
+ Out->ShowMark(&rc, MRK_INVERT);
+ 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;
+ 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 = 0x00ffffffL;
+ break;
+ case 3: //mark active
+ bgLine = &ETbgma; bgFill = &ETfbma; TextCol = 0x00ff0000L;
+ break;
+ }
+ Redraw(Out, true);
+ 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;
+
+ MyPos.y = loc.y;
+ MyPos.x = Align & TXA_HRIGHT ? crb.x - 2 : loc.x + 2;
+ if(!(text)) return false;
+ 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);
+ case CMD_SETFONT:
+ if (!text || !text[0]) return false;
+ type = ET_TEXT;
+ if(m1 > -1 && m2 > -1) {
+ 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);
+ free(text); text = strdup(TmpTxt);
+ Command(CMD_REDRAW, Out, 0L);
+ return true;
+ }
+ return false;
+ case CMD_SETSTYLE:
+ if (!text || !text[0]) return false;
+ type = ET_TEXT;
+ if(m1 > -1 && m2 > -1) {
+ 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);
+ free(text); text = strdup(TmpTxt);
+ Command(CMD_REDRAW, Out, 0L);
+ return true;
+ }
+ return false;
+ case CMD_BACKSP:
+ if(CursorPos <=0){
+ Out->TextCursor(text, MyPos, (POINT *) NULL, &CursorPos,
+ scroll_et == this ? scroll_dist : scroll_dist=0);
+ return false;
+ }
+ Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
+ CursorPos--; //continue as if delete
+ case CMD_DELETE:
+ if(cmd == CMD_DELETE) Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
+ bRet = false;
+ if(m1 > -1 && m2 > -1) { //delete marked part of text
+ if (!text || !text[0]) return false;
+ if(m1 > m2) Swap(m1, m2);
+ if(parent) ((DataObj*)parent)->Command(CMD_MRK_DIRTY, 0L, 0L);
+ if(m2 >= (short int)strlen(text)) text[m1] = 0;
+ else strcpy(text+m1, text+m2);
+ CursorPos = m1;
+ m1 = m2 = -1;
+ if(Out) Redraw(Out, (bRet = true));
+ }
+ else if(text[CursorPos]) {
+ if(parent) ((DataObj*)parent)->Command(CMD_MRK_DIRTY, 0L, 0L);
+ strcpy(text + CursorPos, text + CursorPos + 1);
+ if(Out)Redraw(Out, (bRet = true));
+ }
+ if(Out)Out->TextCursor(text, MyPos, (POINT *) NULL, &CursorPos,
+ scroll_et == this ? scroll_dist : scroll_dist=0);
+ return bRet;
+ case CMD_SHIFTRIGHT:
+ if(CursorPos == m1 && text[m1]) m1++;
+ else if(CursorPos == m2 && text[m2]) m2++;
+ else if(text[CursorPos]){
+ m1 = CursorPos; m2 = CursorPos+1;
+ }
+ if(text[CursorPos]) CursorPos++;
+ else return false;
+ case CMD_SHIFTLEFT:
+ if (!(CursorPos)) return false;
+ case CMD_REDRAW:
+ if(cmd == CMD_SHIFTLEFT) {
+ if(CursorPos == m1 && m1 >0) m1--;
+ else if(CursorPos == m2 && m2 >0) m2--;
+ else if(CursorPos > 0){
+ m1 = CursorPos; m2 = CursorPos-1;
+ }
+ if(CursorPos >0) CursorPos--;
+ }
+ if(m1 >=0 && m2 >= 0 && m1 != m2 && Out) {
+ if(m1 > m2) Swap(m1, m2);
+ w = h = 0;
+ if(Align & TXA_HRIGHT) { //right justified text
+ Out->oGetTextExtent(text, 0, &w, &h);
+ mx1 = crb.x-2 - w;
+ }
+ else { //left justified text
+ mx1 = loc.x +2;
+ }
+ Out->oGetTextExtent(text, m1, &w, &h);
+ mx1 += (m1 ? w : 0);
+ Out->oGetTextExtent(text+m1, m2-m1, &w, &h);
+ mx2 = mx1 + w;
+ }
+ HideTextCursor(); Redraw(Out, true);
+ Out->TextCursor(text, MyPos, (POINT *) NULL, &CursorPos,
+ scroll_et == this ? scroll_dist : scroll_dist=0);
+ return true;
+ case CMD_CURRLEFT:
+ m1 = m2 = -1;
+ if(CursorPos >0) {
+ CursorPos--;
+ if(Redraw(Out, true) && Out->TextCursor(text, MyPos, (POINT *) NULL,
+ &CursorPos, scroll_et == this ? scroll_dist : scroll_dist=0)) return true;
+ else return false;
+ }
+ else if (data_obj) {
+ MyPos.x = loc.x-2; MyPos.y = (rb.y+loc.y)/2;
+ if(((DataObj*)data_obj)->Select(&MyPos))return true;
+ MyPos.x = loc.x+2;
+ ((DataObj*)data_obj)->Select(&MyPos);
+ }
+ return false;
+ case CMD_CURRIGHT:
+ m1 = m2 = -1;
+ if(text[CursorPos]){
+ CursorPos++;
+ if(Redraw(Out, true) && Out->TextCursor(text, MyPos, (POINT *) NULL,
+ &CursorPos, scroll_et == this ? scroll_dist : scroll_dist=0)) return true;
+ else return false;
+ }
+ else if (data_obj) {
+ MyPos.x = rb.x+2; MyPos.y = (rb.y+loc.y)/2; crb.x = rb.x;
+ if(((DataObj*)data_obj)->Select(&MyPos)) return true;
+ MyPos.x = rb.x-2;
+ ((DataObj*)data_obj)->Select(&MyPos);
+ }
+ return false;
+ case CMD_POS_FIRST: case CMD_POS_LAST:
+ CursorPos = (cmd == CMD_POS_LAST && text && text[0]) ? strlen(text) : 0;
+ m1 = m2 = -1;
+ Redraw(Out, true);
+ Out->TextCursor(text, MyPos, (POINT *) NULL, &CursorPos,
+ scroll_et == this ? scroll_dist : scroll_dist=0);
+ return true;
+ case CMD_CURRDOWN: case CMD_CURRUP:
+ if (data_obj) {
+ //the following calculation of the cursor position is crude
+ //it is based on a aspect of 2:1 for digits
+ if(Align & TXA_HRIGHT) //right justified text
+ MyPos.x = rb.x-2-((rb.y-loc.y-4)*(strlen(text)-CursorPos))/2;
+ else MyPos.x = loc.x+2+((rb.y-loc.y-4)*CursorPos)/2;
+ MyPos.y = (cmd == CMD_CURRUP) ? loc.y-2 : rb.y+2;
+ if(MyPos.x < loc.x) MyPos.x = loc.x +2;
+ if(MyPos.x > rb.x) MyPos.x = rb.x -2;
+ if(((DataObj*)data_obj)->Select(&MyPos))return true;
+ MyPos.y = rb.y;
+ ((DataObj*)data_obj)->Select(&MyPos);
+ }
+ return false;
+ case CMD_MOUSE_EVENT: //track left mouse button
+ mev = (MouseEvent*) data_obj;
+ if(!text || !text[0]) return false;
+ if(mev->x <loc.x || mev->x >crb.x || mev->y <loc.y || mev->y >rb.y)return false;
+ if(mev->Action == MOUSE_LBDOWN) {
+ m1 = m2 = -1;
+ return true;
+ }
+ if(mev->Action == MOUSE_LBDOUBLECLICK) {
+ rMark.top = loc.y; rMark.bottom = rb.y;
+ if(!Out->oGetTextExtent(text, strlen(text), &w, &h)) return false;
+ m1 = 0; m2 = strlen(text);
+ if(Align & TXA_HRIGHT) { //right justfied text
+ rMark.right = crb.x -2; rMark.left = crb.x - w - 2;
+ }
+ else { //left justified text
+ rMark.left = loc.x +2; rMark.right = rMark.left +w;
+ }
+ Out->UpdateRect(&rMark,true);
+ return true;
+ }
+ MyPos.x = Align & TXA_HRIGHT ? mev->x + 2 : mev->x - 2;
+ MyPos.y = mev->y;
+ Out->TxtSet.Align = Align;
+ j = Out->CalcCursorPos(text, Align & TXA_HRIGHT ? crb :loc, &MyPos);
+ if(j == m1 || j == m2) return true;
+ if(Align & TXA_HRIGHT) { //right justfied text
+ if((i = strlen(text)-j)){
+ if(!Out->oGetTextExtent(text+j, i, &w, &h)) return false;
+ w = crb.x - w - 2;
+ }
+ else w = crb.x-1;
+ }
+ else { //left justified text
+ if(!j) w = 0;
+ else if(!Out->oGetTextExtent(text, j, &w, &h))return false;
+ w += (loc.x+2);
+ }
+ if(m1 == m2 && m1 == -1) {
+ mx1 = (short)(rMark.left = w);
+ m1 = j;
+ }
+ else if(j != m2){
+ m2 = j;
+ if(m2 >= 0)Out->UpdateRect(&rMark, false);
+ mx2 = (short)(rMark.right = w);
+ rMark.top = loc.y;
+ rMark.bottom = rb.y;
+ if(rMark.right < crb.x && rMark.right > loc.x &&
+ rMark.left > loc.x && rMark.left < crb.x)
+ Out->UpdateRect(&rMark,true);
+ }
+ if(m1 >= 0 && m2 >= 0 && m1 != m2 && parent)
+ //remove range-mark of data
+ ((DataObj*)parent)->Command(CMD_UNLOCK, 0L, 0L);
+ return true;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// return the value (i.e. the floating point equivalent) of text
+bool
+EditText::GetValue(double *v)
+{
+ anyResult * res;
+
+ if(((type & 0xff) == ET_UNKNOWN) && (text)) FindType();
+ if(!text || !text[0]) {
+ if((type & 0xff) == ET_VALUE) {
+ *v = Value; return true;
+ }
+ return false;
+ }
+ if(CurrText == this && !(type & ET_BUSY)) FindType();
+ if((type & 0xff) == ET_VALUE){
+ *v = Value; return true;
+ }
+ if((type & 0xff) == ET_FORMULA && text && text[0]){
+ if(!(type & ET_BUSY)){
+ type |= ET_BUSY;
+ if(res = do_formula((DataObj*)parent, text+1)) {
+ if(res->type == ET_VALUE) Value = res->value;
+ else Value = 0.0;
+ *v = Value; type &= ~ET_BUSY;
+ return res->type == ET_VALUE;
+ }
+ type &= ~ET_BUSY;
+ return false;
+ }
+ else if(parent) {
+ ((DataObj*)parent)->Command(CMD_ERROR, (void*)"circular reference in formula", 0L);
+ type |= ET_CIRCULAR;
+ }
+ *v = Value;
+ return true;
+ }
+ return false;
+}
+
+bool
+EditText::GetText(char *t, int size)
+{
+ if(text) {
+ if((int)strlen(text) < size) strcpy(t, text);
+ else {
+ memcpy(t, &text, size-1); t[size-1] = 0;
+ }
+ return true;
+ }
+ if((type & 0xff) == ET_VALUE) {
+ sprintf(TmpTxt, "%lf", Value);
+ text = strdup(TmpTxt);
+ return GetText(t, size);
+ }
+ return false;
+}
+
+bool
+EditText::GetResult(anyResult *r)
+{
+ anyResult * res;
+
+ if(!text || !text[0]) {
+ r->text = 0L;
+ if((type & 0xff) == ET_VALUE) {
+ r->value = Value; r->type = ET_VALUE;
+ }
+ else {
+ r->value = 0.0; r->type = ET_UNKNOWN;
+ }
+ return true;
+ }
+ if((type & 0xff) == ET_UNKNOWN) FindType();
+ if((type & 0xff) == ET_VALUE) {
+ r->text = 0L; r->value = Value; r->type = ET_VALUE;
+ return true;
+ }
+ if((type & 0xff) == ET_TEXT) {
+ r->text = text; r->value = 0.0; r->type = ET_TEXT;
+ return true;
+ }
+ if((type & 0xff) == ET_FORMULA){
+ if(!(type & ET_BUSY)){
+ type |= ET_BUSY;
+ if(res = do_formula((DataObj*)parent, text+1)) {
+ if(res->type == ET_VALUE) Value = res->value;
+ else Value = 0.0;
+ type &= ~ET_BUSY;
+ memcpy(r, res, sizeof(anyResult));
+ return true;
+ }
+ type &= ~ET_BUSY;
+ return false;
+ }
+ else if(parent) {
+ ((DataObj*)parent)->Command(CMD_ERROR, (void*)"circular reference in formula", 0L);
+ r->text = "#CIRC."; r->value = 0.0; r->type = ET_TEXT;
+ return true;
+ }
+ return false;
+ }
+ return false;
+}
+
+bool
+EditText::SetValue(double v)
+{
+ if(text){
+ free(text); text = 0L;
+ }
+ Value = v; type = ET_VALUE;
+ return true;
+}
+
+bool
+EditText::SetText(char *t)
+{
+ if(text){
+ free(text); text = 0L;
+ }
+ Value = 0.0; type = ET_UNKNOWN;
+ if(t && t[0]) text = strdup(t);
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// return the ASCII reprentation of value of text if applicable. If not return
+// the text with double quotes: comma separated file syntax.
+bool
+EditText::GetItem(char *dest, int size)
+{
+ char tmp[50];
+ int i;
+
+ if(!text || !text[0] || !dest || size < 3) return false;
+ if((type & 0xff) == ET_UNKNOWN) FindType();
+ if(CurrText == this) FindType();
+ //its a value
+ if((type & 0xff) == ET_VALUE){
+ if(text && strlen(text) < (sizeof(tmp)-1)){
+ strcpy(tmp, text);
+ if(defs.DecPoint[0] != '.') {
+ for(i = 0; tmp[i]; i++)
+ if(tmp[i] == defs.DecPoint[0]) tmp[i]='.';
+ }
+ }
+ else {
+ sprintf(tmp, "%f", Value); RmTrail(tmp);
+ }
+ for(i = 0; i < (size-1) && tmp[i]; i++) dest[i] = tmp[i];
+ dest[i] = 0;
+ }
+ //else its a string
+ else {
+ dest[0] = '"';
+ for(i = 1; i < (size-2) && text[i-1]; i++) dest[i] = text[i-1];
+ dest[i++] = '"';
+ dest[i] = 0;
+ }
+ return true;
+}
+
+void
+EditText::SetRec(RECT *rc)
+{
+ loc.x = rc->left; loc.y = rc->top;
+ crb.x = rb.x = rc->right; crb.y = rb.y = rc->bottom;
+}
+
+
+bool
+EditText::isValue()
+{
+ if((type & 0xff)==ET_UNKNOWN) FindType();
+ return (type == ET_VALUE || type == ET_FORMULA);
+}
+
+bool
+EditText::isFormula()
+{
+ if((type & 0xff)==ET_UNKNOWN) FindType();
+ return (type == ET_FORMULA);
+}
+
+void
+EditText::FindType()
+{
+ if(text && text[0] == '=') {
+ Align = TXA_VTOP | TXA_HRIGHT;
+ type = ET_FORMULA;
+ }
+ else if(text && (Txt2Flt(text, &Value))) {
+ Align = TXA_VTOP | TXA_HRIGHT;
+ type = ET_VALUE;
+ }
+ else if (text && text[0]) {
+ Align = TXA_VTOP | TXA_HLEFT;
+ type = ET_TEXT;
+ }
+ else if ((type && 0xff) == ET_VALUE) {
+ Align = TXA_VTOP | TXA_HRIGHT;
+ type = ET_VALUE;
+ }
+ else {
+ Align = TXA_VTOP | TXA_HRIGHT;
+ type = ET_UNKNOWN;
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// output formated text - style and font changes
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+typedef struct _tag_info {
+ char *tag;
+ int and_style, or_style;
+ int font, op;
+}tag_info;
+
+static tag_info tags[] = {
+ {"<i>", ~TXS_NORMAL, TXS_ITALIC, -1, 0},
+ {"</i>", ~TXS_ITALIC, TXS_NORMAL, -1, 0},
+ {"<b>", ~TXS_NORMAL, TXS_BOLD, -1, 0},
+ {"</b>", ~TXS_BOLD, TXS_NORMAL, -1, 0},
+ {"<u>", ~TXS_NORMAL, TXS_UNDERLINE, -1, 0},
+ {"</u>", ~TXS_UNDERLINE, TXS_NORMAL, -1, 0},
+ {"<sup>", ~TXS_NORMAL, TXS_SUPER, -1, 0},
+ {"</sup>", ~TXS_SUPER, TXS_NORMAL, -1, 0},
+ {"<sub>", ~TXS_NORMAL, TXS_SUB, -1, 0},
+ {"</sub>", ~TXS_SUB, TXS_NORMAL, -1, 0},
+ {"<face=helvetica>", 0, 0, FONT_HELVETICA, 0},
+ {"<face=times>", 0, 0, FONT_TIMES, 0},
+ {"<face=courier>", 0, 0, FONT_COURIER, 0},
+ {"<face=greek>", 0, 0, FONT_GREEK, 0},
+ {"</face>", 0, 0, -2, 0},
+ {"<bullet1>", 0, 0, -1, 1}, {"<bullet2>", 0, 0, -1, 2},
+ {"<bullet3>", 0, 0, -1, 3}, {"<bullet4>", 0, 0, -1, 4},
+ {"<bullet5>", 0, 0, -1, 5}, {"<bullet6>", 0, 0, -1, 6},
+ {"<bullet7>", 0, 0, -1, 7}, {"<bullet8>", 0, 0, -1, 8},
+ {"<white>", 0, 0, -1, 100}, {"<black>", 0, 0, -1, 101},
+ {"<red>", 0, 0, -1, 102}, {"<blue>", 0, 0, -1, 103},
+ {"<green>", 0, 0, -1, 104}, {"<yellow>", 0, 0, -1, 105},
+ {"<cyan>", 0, 0, -1, 106}, {"<purple>", 0, 0, -1, 107},
+ {"<smaller>", 0, 0, -1, 200}, {"<larger>", 0, 0, -1, 201},
+ {0L, 0, 0, 0, 0}};
+
+static int font_buff[256];
+static unsigned font_idx=0;
+
+fmtText::fmtText(anyOutput *o, int x, int y, char *txt)
+{
+ if(txt && txt[0]) src=strdup(txt);
+ else src=0L; split_text=0L; n_split=0;
+ pos.x = x; pos.y = y; if(src)Parse();
+ if(o) DrawText(o);
+}
+
+fmtText::~fmtText()
+{
+ SetText(0L, 0L, 0L, 0L);
+}
+
+bool
+fmtText::StyleAt(int idx, TextDEF *txt_def, int *style, int *font)
+{
+ TextDEF td;
+ int i, j, n;
+
+ if(!src || !split_text || (idx > (int)strlen(src))) return false;
+ memcpy(&td, txt_def, sizeof(TextDEF));
+ for(i = j = 0; i < n_split; i++) {
+ if((n=split_text[i].tag) >= 0 && SetTextDef(&td, n)) j += strlen(tags[n].tag);
+ if(j > idx) break;
+ if(split_text[i].txt && split_text[i].txt[0]) j += strlen(split_text[i].txt);
+ if(j >= idx) break;
+ }
+ if(style) *style = td.Style; if(font) *font = td.Font;
+ return true;
+}
+
+
+int
+fmtText::rightTag(char *txt, int cb)
+{
+ int i, j;
+
+ for(i = 0; tags[i].tag; i++) {
+ for(j=1; tags[i].tag[j] && txt[cb+j]; j++) if(tags[i].tag[j] != txt[cb+j]) break;
+ if(!tags[i].tag[j]) return i;
+ }
+ return -1;
+}
+
+int
+fmtText::leftTag(char *txt, int cb)
+{
+ int i, j, k;
+
+ for(i = 0; tags[i].tag; i++) {
+ for(j = 0, k=strlen(tags[i].tag)-1; tags[i].tag[j] && k <=cb; j++, k--) {
+ if(tags[i].tag[j] != txt[cb-k]) break;
+ }
+ if(!tags[i].tag[j]) return i;
+ }
+ return -1;
+}
+
+void
+fmtText::cur_right(int *pos)
+{
+ int n;
+
+ if(!src || !pos || !src[*pos]) return;
+ if(src[*pos] == '<' && (n=rightTag(src, *pos)) >= 0) {
+ *pos += strlen(tags[n].tag);
+ cur_right(pos);
+ }
+ else (*pos)++;
+}
+
+void
+fmtText::cur_left(int *pos)
+{
+ int n;
+
+ if(!src || !pos || !(*pos)) return;
+ (*pos)--;
+ while (src[*pos] == '>' && (n=leftTag(src, *pos)) >= 0) {
+ *pos -= strlen(tags[n].tag);
+ }
+}
+
+bool
+fmtText::oGetTextExtent(anyOutput *o, int *width, int *height, int cb)
+{
+ TextDEF td1, td2;
+ int i, n, l, l1, w, w1, h, h1;
+
+ if(!o || !width || !height) return false;
+ if(!cb) cb = strlen(src);
+ if(!split_text) return o->oGetTextExtent(src, cb, width, height);
+ memcpy(&td1, &o->TxtSet, sizeof(TextDEF)); memcpy(&td2, &o->TxtSet, sizeof(TextDEF));
+ for(i = w = h = l = l1 = 0; i < n_split; i++){
+ if((n=split_text[i].tag) >= 0 && SetTextDef(&td2, n)) {
+ o->SetTextSpec(&td2);
+ l += strlen(tags[n].tag);
+ }
+ if(split_text[i].txt){
+ l1 = l; l += strlen(split_text[i].txt);
+ if (l1 >= cb) break;
+ o->oGetTextExtent(split_text[i].txt, l >= cb ? cb-l1 : 0, &w1, &h1);
+ w += w1; if(!i) h = h1;
+ if (l >= cb) break;
+ }
+ }
+ *width = w; *height = h; o->SetTextSpec(&td1);
+ return true;
+}
+
+void
+fmtText::SetText(anyOutput *o, char *txt, int *px, int *py)
+{
+ int i;
+
+ if(px) pos.x = *px; if(py) pos.y = *py;
+ if(src && txt && !strcmp(src, txt)) {
+ if(o) DrawText(o);
+ return;
+ }
+ if(src) free(src); src = 0L;
+ if(split_text) {
+ for(i = 0; i < n_split; i++) if(split_text[i].txt) free(split_text[i].txt);
+ free(split_text); split_text = 0L; n_split = 0;
+ }
+ if(txt && txt[0]) src=strdup(txt); if(src)Parse();
+ if(o) DrawText(o);
+}
+
+void
+fmtText::DrawText(anyOutput *o)
+{
+ if(!o || !src) return;
+ if(split_text)DrawFormatted(o);
+ else o->oTextOut(pos.x, pos.y, src, 0);
+}
+
+bool
+fmtText::SetTextDef(TextDEF *td, int idx)
+{
+ if(tags[idx].and_style != tags[idx].or_style) {
+ td->Style &= tags[idx].and_style; td->Style |= tags[idx].or_style;
+ }
+ else if(tags[idx].font >= 0) {
+ font_buff[font_idx & 0xff] = td->Font; font_idx++;
+ td->Font = tags[idx].font;
+ }
+ else if(tags[idx].font == -2) {
+ font_idx--; td->Font=font_buff[font_idx & 0xff];
+ }
+ else return false;
+ return true;
+}
+
+bool
+fmtText::Parse()
+{
+ int i, li, j, n;
+ char *tmp;
+
+ if(!src || !(tmp = strdup(src))) return false;
+ for(i = li = 0; src[i]; i++) {
+ if(src[i] == '<' && (n=rightTag(src, i))>=0) {
+ if(split_text) { //more tags in text
+ if(!(split_text = (fmt_txt_info *)realloc(split_text, (n_split+1)*sizeof(fmt_txt_info)))){
+ free(tmp); return false;
+ }
+ for(j = li; j < i; j++) tmp[j-li]= src[j]; tmp[j-li]=0;
+ split_text[n_split-1].txt = strdup(tmp);
+ i += strlen(tags[n].tag); split_text[n_split].tag = n;
+ split_text[n_split++].txt = 0L;
+ }
+ else { //first tag of text
+ if(!(split_text = (fmt_txt_info *)calloc(2, sizeof(fmt_txt_info)))){
+ free(tmp); return false;
+ }
+ for(j = 0; j < i; j++) tmp[j]= src[j]; tmp[j]=0;
+ split_text[0].tag = -1; split_text[0].txt = strdup(tmp);
+ i += strlen(tags[n].tag); split_text[1].tag = n;
+ n_split = 2;
+ }
+ li = i; i--;
+ }
+ }
+ if(split_text && n_split && li < i && src[li]) split_text[n_split-1].txt = strdup(src+li);
+ free(tmp);
+ return true;
+}
+
+void
+fmtText::DrawBullet(anyOutput *o, int x, int y, int type, double size, DWORD lc, DWORD fc)
+{
+ int is;
+ POINT pts[5];
+ static FillDEF fd = {0, 0x00ffffff, 1.0, 0L, 0x00ffffff};
+ static LineDEF ld = {defs.GetSize(SIZE_SYM_LINE), 1.0, 0x00000000L, 0x00000000};
+
+ switch (type) {
+ case 3: case 4:
+ is = o->un2ix(size/4.1);
+ break;
+ case 5: case 6: case 7: case 8:
+ is = o->un2ix(size/3.7);
+ break;
+ default:
+ is = o->un2ix(size/4.0);
+ break;
+ }
+ fd.color = fc; ld.color = lc;
+ switch(type) {
+ case 1:
+ o->SetLine(&ld); o->SetFill(&fd);
+ o->oCircle(x-is, y-is, x+is, y+is);
+ break;
+ case 2:
+ fd.color = ld.color;
+ o->SetLine(&ld); o->SetFill(&fd);
+ o->oCircle(x-is, y-is, x+is, y+is);
+ break;
+ case 3:
+ o->SetLine(&ld); o->SetFill(&fd);
+ o->oRectangle(x-is, y-is, x+is, y+is);
+ break;
+ case 4:
+ fd.color = ld.color;
+ o->SetLine(&ld); o->SetFill(&fd);
+ o->oRectangle(x-is, y-is, x+is, y+is);
+ break;
+ case 5: case 6: case 7: case 8:
+ if(type == 6 || type == 8) fd.color = ld.color;
+ pts[0].x = pts[3].x = x - is; pts[1].x = x; pts[2].x = x+is;
+ if(type == 5 || type == 6) {
+ pts[0].y = pts[2].y = pts[3].y = y+o->un2iy(size*0.19439);
+ pts[1].y = y-o->un2iy(size*0.38878);
+ }
+ else {
+ pts[0].y = pts[2].y = pts[3].y = y-o->un2iy(size*0.19439);
+ pts[1].y = y+o->un2iy(size*0.38878);
+ }
+ o->SetLine(&ld); o->SetFill(&fd);
+ o->oPolygon(pts, 4);
+ break;
+ }
+}
+
+void
+fmtText::DrawFormatted(anyOutput *o)
+{
+ int i, n, x, y, x1, y1, w, h;
+ TextDEF td1, td2;
+ double si, csi, fx, fy;
+
+ if(!o || !split_text) return;
+ memcpy(&td1, &o->TxtSet, sizeof(TextDEF)); memcpy(&td2, &o->TxtSet, sizeof(TextDEF));
+ si = sin(td1.RotBL *0.01745329252); csi = cos(td1.RotBL *0.01745329252);
+ fx = pos.x; fy = pos.y;
+ oGetTextExtent(o, &w, &h, 0);
+ if(td2.Align & TXA_HRIGHT) {
+ fx -= w*csi; fy += w*si;
+ }
+ else if(td2.Align & TXA_HCENTER){
+ fx -= (w>>1)*csi; fy += (w>>1)*si;
+ }
+ x = iround(fx); y = iround(fy);
+ td2.Align &= ~(TXA_HRIGHT | TXA_HCENTER); o->SetTextSpec(&td2);
+ for(i = 0; i < n_split; i++) if(split_text[i].txt) {
+ if((n=split_text[i].tag) >= 0 && SetTextDef(&td2, n)) o->SetTextSpec(&td2);
+ else if(n >= 0 && tags[n].op) {
+ x1 = x + iround(o->un2fix(td2.fSize*0.25)*csi);
+ y1 = y - iround(o->un2fiy(td2.fSize*0.25)*si);
+ if((td2.Align & TXA_VTOP) == TXA_VTOP){
+ y1 += iround(o->un2fiy(td2.fSize*0.5)*csi);
+ x1 += iround(o->un2fix(td2.fSize*0.5)*si);
+ }
+ if((td2.Align & TXA_VCENTER) == TXA_VCENTER){
+ y1 -= iround(o->un2fiy(td2.fSize*0.5)*csi);
+ x1 -= iround(o->un2fix(td2.fSize*0.5)*si);
+ }
+ if((td2.Align & TXA_VBOTTOM) == TXA_VBOTTOM){
+ y1 -= iround(o->un2fiy(td2.fSize)*csi);
+ x1 -= iround(o->un2fix(td2.fSize)*si);
+ }
+ switch (tags[n].op) {
+ case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8:
+ DrawBullet(o, x1, y1, tags[n].op, td2.fSize, td2.ColTxt, 0x00ffffff);
+ w = o->un2ix(td2.fSize/2.0);
+ x = iround(fx += (w*csi)); y = iround(fy -= (w*si));
+ break;
+ case 100: td2.ColTxt = 0x00ffffffL; break;
+ case 101: td2.ColTxt = 0x00000000L; break;
+ case 102: td2.ColTxt = 0x000000ffL; break;
+ case 103: td2.ColTxt = 0x00ff0000L; break;
+ case 104: td2.ColTxt = 0x0000ff00L; break;
+ case 105: td2.ColTxt = 0x0000ffffL; break;
+ case 106: td2.ColTxt = 0x00ffff00L; break;
+ case 107: td2.ColTxt = 0x00ff00ffL; break;
+ case 200: td2.fSize *= 0.81; td2.iSize = 0; break;
+ case 201: td2.fSize /= 0.81; td2.iSize = 0; break;
+ }
+ o->SetTextSpec(&td2);
+ }
+ if(split_text[i].txt){
+ o->oTextOut(x, y, split_text[i].txt, 0);
+ o->oGetTextExtent(split_text[i].txt, 0, &w, &h);
+ x = iround(fx += (w*csi)); y = iround(fy -= (w*si));
+ }
+ }
+ o->SetTextSpec(&td1);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// the basic data object
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+DataObj::DataObj()
+{
+ cRows = cCols = 0;
+ etRows = 0L;
+}
+
+DataObj::~DataObj()
+{
+ FlushData();
+}
+
+bool
+DataObj::Init(int nR, int nC)
+{
+ int i, j;
+
+ if(etRows)FlushData();
+ if(!(etRows = (EditText ***)calloc (cRows = nR, sizeof(EditText **)))) return false;
+ for(i = 0, cCols = nC; i < cRows; i++) {
+ if(!(etRows[i] = (EditText **)calloc(cCols, sizeof(EditText *)))) {
+ FlushData(); return false;
+ }
+ if(etRows[i]) for(j = 0; j < cCols; j++) {
+ etRows[i][j] = new EditText(this, 0L);
+ }
+ }
+ return true;
+}
+
+bool
+DataObj::SetValue(int row, int col, double val)
+{
+ if(row < 0 || row >= cRows || col < 0 || col >= cCols) return false;
+ if(etRows[row][col]) return etRows[row][col]->SetValue(val);
+ return false;
+}
+
+bool
+DataObj::SetText(int row, int col, char *txt)
+{
+ if(row < 0 || row >= cRows || col < 0 || col >= cCols) return false;
+ if(etRows[row][col]) return etRows[row][col]->SetText(txt);
+ return false;
+}
+
+bool
+DataObj::GetValue(int row, int col, double *v)
+{
+ if(row < 0 || row >= cRows || col < 0 || col >= cCols) return false;
+ if(etRows[row][col]) return etRows[row][col]->GetValue(v);
+ return false;
+}
+
+bool
+DataObj::GetText(int row, int col, char *txt, int len)
+{
+ if(row < 0 || row >= cRows || col < 0 || col >= cCols) return false;
+ if(txt && etRows[row][col]) return etRows[row][col]->GetText(txt, len);
+ return false;
+}
+
+char **
+DataObj::GetTextPtr(int row, int col)
+{
+ if(row < 0 || row >= cRows || col < 0 || col >= cCols) return 0L;
+ if(etRows[row][col]) return &etRows[row][col]->text;
+ return 0L;
+}
+
+bool
+DataObj::GetResult(anyResult *r, int row, int col)
+{
+ if(row < 0 || row >= cRows || col < 0 || col >= cCols) return false;
+ if(etRows[row][col]) return etRows[row][col]->GetResult(r);
+ return false;
+}
+
+bool
+DataObj::GetSize(int *width, int *height)
+{
+ if(width)*width = cCols; if(height)*height = cRows;
+ return true;
+}
+
+void
+DataObj::FlushData()
+{
+ int i, j;
+
+ if(etRows){
+ for(i = 0; i < cRows; i++) if(etRows[i]) {
+ for (j = 0; j< cCols; j++) if(etRows[i][j]) delete etRows[i][j];
+ free(etRows[i]);
+ }
+ free(etRows);
+ }
+ etRows = 0L;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Store Data Object as strings: less memory required than with DataObj
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+StrData::StrData(DataObj *par)
+{
+ int r, c;
+ char *tx;
+
+ pw = ph = w = h = 0; str_data = 0L;
+ if(src = par) {
+ src->GetSize(&pw, & ph);
+ if(!(str_data = (char***)calloc(ph, sizeof(char**))))return;
+ for (r = 0; r < ph; r++) {
+ if(!(str_data[r] = (char**)malloc(pw * sizeof(char*)))) break;
+ for(c = 0; c < pw; c++) {
+ str_data[r][c] = (tx = *(src->GetTextPtr(r, c))) && tx[0] ? strdup(tx) : 0L;
+ }
+ }
+ }
+ w = pw; h = ph;
+}
+
+StrData::~StrData()
+{
+ int r, c;
+
+ if(str_data) for (r = 0; r < h; r++) {
+ if(str_data[r]) {
+ for(c = 0; c < w; c++) if(str_data[r][c]) free(str_data[r][c]);
+ free(str_data[r]);
+ }
+ }
+ if(str_data) free(str_data);
+}
+
+bool
+StrData::GetSize(int *uw, int *uh)
+{
+ if(uw) *uw = pw; if(uh) *uh = ph;
+ return true;
+}
+
+void
+StrData::RestoreData(DataObj *dest)
+{
+ int r, c;
+
+ if(!dest || !str_data || !w || ! h) return;
+ for (r = 0; r < h; r++) {
+ if(str_data[r]) {
+ for(c = 0; c < w; c++) dest->SetText(r, c, str_data[r][c]);
+ }
+ }
+ return;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// The notary class handles different types of supervision and indexing
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+notary::notary()
+{
+ gObs = 0L;
+ goStack = 0L;
+ NextPopGO = NextPushGO = NextRegGO = 0L;
+}
+
+notary::~notary()
+{
+ FreeStack();
+}
+
+unsigned long
+notary::RegisterGO(GraphObj *go)
+{
+ int i, j;
+
+ if(!go) return 0L;
+ if(!gObs) {
+ gObs = (GraphObj ***)calloc(0x2000L, sizeof(GraphObj **));
+ gObs[0] = (GraphObj **)calloc(0x2000L, sizeof(GraphObj *));
+ if(gObs && gObs[0]) {
+ gObs[0][0] = go;
+ return 1L;
+ }
+ return 0L;
+ }
+ i = (int)(NextRegGO >> 13);
+ j = (int)(NextRegGO & 0x1fff)+1;
+ if(j >=0x2000){
+ i++; j = 0;
+ }
+ if(gObs[i] && gObs[i][j] && gObs[i][j] == go) {
+ NextRegGO = ((i << 13) | j);
+ return (unsigned long)i*0x2000L+j+1;
+ }
+ if(gObs && gObs[0]) {
+ for(i = 0; i < 0x2000; i++) {
+ for(j = 0; j < 0x2000L; j++) {
+ if(gObs[i][j] == go) {
+ NextRegGO = ((i << 13) | j);
+ return (unsigned long)i*0x2000L+j+1;
+ }
+ if(!gObs[i][j]) {
+ gObs[i][j] = go;
+ NextRegGO = ((i << 13) | j);
+ return (unsigned long)i*0x2000L+j+1;
+ }
+ }
+ if(i < 0x1fffL && !gObs[i+1])
+ gObs[i+1] = (GraphObj **)calloc(0x2000L, sizeof(GraphObj *));
+ if(i < 0x1fffL && !gObs[i+1]) return 0L;
+ }
+ }
+ return 0L;
+}
+
+void
+notary::AddRegGO(GraphObj *go)
+{
+ int i, j;
+
+ if(!go) return;
+ if(!gObs) {
+ gObs = (GraphObj ***)calloc(0x2000L, sizeof(GraphObj **));
+ gObs[0] = (GraphObj **)calloc(0x2000L, sizeof(GraphObj *));
+ if(gObs && gObs[0]) {
+ gObs[0][0] = go;
+ return;
+ }
+ return;
+ }
+ i = (int)(NextRegGO >> 13);
+ j = (int)(NextRegGO & 0x1fff)+1;
+ if(j >=0x2000){
+ i++;
+ j = 0;
+ }
+ if(!gObs[i]) gObs[i] = (GraphObj **)calloc(0x2000L, sizeof(GraphObj *));
+ if(gObs[i] && !gObs[i][j]) {
+ gObs[i][j] = go;
+ NextRegGO = ((i << 13) | j);
+ }
+ else RegisterGO(go);
+}
+
+bool
+notary::PushGO(unsigned long id, GraphObj *go)
+{
+ int i, j;
+
+ NextPopGO = 0L;
+ if(!go) return true;
+ go->Id = id;
+ if(!goStack) {
+ goStack = (GraphObj ***)calloc(8192, sizeof(GraphObj **));
+ goStack[0] = (GraphObj **)calloc(8192, sizeof(GraphObj *));
+ if(goStack && goStack[0]) {
+ goStack[0][0] = go;
+ return true;
+ }
+ return false;
+ }
+ i = (int)(NextPushGO >> 13);
+ j = (int)(NextPushGO & 0x1fff)+1;
+ if(j >=0x2000){
+ i++;
+ j = 0;
+ }
+ if(!goStack || !goStack[0]) return false;
+ if(goStack[i] && !goStack[i][j]) {
+ goStack[i][j] = go;
+ NextPushGO = ((i << 13) | j);
+ return true;
+ }
+ for(i = 0; i < 0x2000; i++) {
+ for(j = 0; j < 0x2000; j++) {
+ if(!goStack[i][j]) {
+ goStack[i][j] = go;
+ NextPushGO = ((i << 13) | j);
+ return true;
+ }
+ }
+ if(i < 0x1fff && !goStack[i+1] && !(goStack[i+1] =
+ (GraphObj **)calloc(0x2000, sizeof(GraphObj *)))) return false;
+ }
+ return false;
+}
+
+GraphObj *
+notary::PopGO(unsigned long id)
+{
+ int i, j;
+ GraphObj *go;
+
+ NextPushGO = 0L;
+ if(!id || !goStack || !goStack[0]) return 0L;
+ i = (int)(NextPopGO >> 13);
+ j = (int)(NextPopGO & 0x1fff)+1;
+ if(j >=0x2000){
+ i++;
+ j = 0;
+ }
+ if(goStack[i] && goStack[i][j] && goStack[i][j]->Id == id) {
+ go = goStack[i][j];
+ goStack[i][j] = 0L;
+ go->Id = 0L;
+ NextPopGO = ((i << 13) | j);
+ return go;
+ }
+ for(i = 0; i < 0x2000; i++) {
+ for(j = 0; j < 0x2000; j++) {
+ if(goStack[i][j] && goStack[i][j]->Id == id) {
+ go = goStack[i][j];
+ goStack[i][j] = 0L;
+ go->Id = 0L;
+ NextPopGO = ((i << 13) | j);
+ return go;
+ }
+ }
+ if(i < 0x1fff && !goStack[i+1]) return 0L;
+ }
+ return 0L;
+}
+
+void
+notary::FreeStack()
+{
+ int i, j, k;
+
+ if(gObs) {
+ for(i = 0; gObs[i] && i <8192; i++) free(gObs[i]);
+ free(gObs);
+ gObs = 0L;
+ }
+ if(goStack) {
+ for(i = 0; goStack[i] && i <8192; i++){
+ for(j = k = 0; j < 8192; j++){
+ if(goStack[i][j]) {
+ goStack[i][j]->Id = 0L;
+ DeleteGO(goStack[i][j]);
+ k++;
+ }
+ }
+ free(goStack[i]);
+ }
+ free(goStack);
+ if(k){
+ sprintf(TmpTxt,"%d objects deleted\nby notary", k);
+ ErrorBox(TmpTxt);
+ }
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Calculate continuous index to a range given by an ASCII string
+// string examples include "a1:a12" or "a1:a4;a12:a24"
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+AccRange::AccRange(char *asc)
+{
+ int i, j;
+
+ if(asc && *asc){
+ i = strlen(asc)+2;
+ txt = (char *)malloc(i);
+ for(i = j = 0; i< (int)strlen(asc); i++)
+ if(asc[i] > 32) txt[j++] = asc[i];
+ txt[j] = 0;
+ }
+ else txt = 0L;
+ x1 = y1 = x2 = y2 = 0;
+}
+
+AccRange::~AccRange()
+{
+ if(txt) free(txt);
+}
+
+int
+AccRange::CountItems()
+{
+ int RetVal;
+
+ RetVal = 0;
+ if(txt && Reset()) do {
+ RetVal += ((x2-x1+1)*(y2-y1+1));
+ } while((curridx < (int)strlen(txt)) && Parse(curridx));
+ return RetVal;
+}
+
+bool
+AccRange::GetFirst(int *x, int *y)
+{
+ if(txt && Reset()) {
+ if(x && y) {*x = x1; *y = y1;}
+ return true;
+ }
+ return false;
+}
+
+bool
+AccRange::GetNext(int *x, int *y)
+{
+ if(txt && x && y) {
+ if(cx <= x2) {*x = cx; *y = cy; cx++; return true;}
+ else {
+ cx = x1; cy++;
+ if(cy <= y2) return GetNext(x, y);
+ else if(txt[curridx]){
+ if(Parse(curridx)) return GetNext(x, y);
+ return false;
+ }
+ }
+ }
+ return false;
+}
+
+bool
+AccRange::IsInRange(int x, int y)
+{
+ if(txt && Reset()) do {
+ if(x >= x1 && x <= x2 && y >= y1 && y <= y2) return true;
+ } while((curridx < (int)strlen(txt)) && Parse(curridx));
+ return false;
+}
+
+bool
+AccRange::BoundRec(RECT *rec)
+{
+ if(txt && Reset()){
+ SetMinMaxRect(rec, x1, y1, x2, y2);
+ while((curridx < (int)strlen(txt)) && Parse(curridx)) {
+ UpdateMinMaxRect(rec, x1, y1); UpdateMinMaxRect(rec, x2, y2);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool
+AccRange::Reset()
+{
+ curridx = 0;
+ return Parse(curridx);
+}
+
+bool
+AccRange::Parse(int start)
+{
+ int i, step, *v;
+
+ i = start;
+ if(!txt) return false;
+ if(txt[i] == ';') i++;
+ if(!txt[i]) return false;
+ step = x1 = y1 = x2 = y2 = 0;
+ v = &x1;
+ for ( ; i < (int)strlen(txt)+1; i++) {
+ if(txt[i] == '$') i++;
+ switch(step) {
+ case 0:
+ case 2:
+ if((txt[i] >= 'a') && (txt[i] <= 'z')){
+ *v *= 26;
+ *v += (txt[i]-'a'+1);
+ }
+ else if((txt[i] >= 'A') && (txt[i] <= 'Z')){
+ *v *= 26;
+ *v += (txt[i]-'A'+1);
+ }
+ else if((txt[i] >= '0') && (txt[i] <= '9')){
+ v = step == 0 ? &y1 : &y2;
+ *v = txt[i]-'0';
+ step++;
+ }
+ else return false;
+ break;
+ case 1:
+ case 3:
+ if((txt[i] >= '0') && (txt[i] <= '9')){
+ *v *= 10;
+ *v += (txt[i]-'0');
+ }
+ else if((txt[i] >= 'a') && (txt[i] <= 'z') ||
+ (txt[i] >= 'A') && (txt[i] <= 'Z')){
+ if(step == 1) v = &x2;
+ else return false;
+ *v = txt[i] >='a' && txt[i] <= 'z' ?
+ txt[i]-'a' : txt[i]-'A';
+ step++;
+ }
+ else if(step == 1 && (txt[i] == ':')) {
+ v = &x2;
+ step++;
+ }
+ else if((txt[i] == ';') || (txt[i] == ',') || (txt[i] == 0)) {
+ if(step == 1) { //one single cell selected
+ x2 = x1; y2 = y1;
+ }
+ if(x2<x1) Swap(x1,x2); if(y2<y1) Swap(y1,y2);
+ if(y1 >0) y1--; if(y2 >0) y2--;
+ if(x1 >0) x1--; if(x2 >0) x2--;
+ curridx = i;
+ cx = x1; cy = y1;
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Default data vault
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Default::Default()
+{
+ dUnits = cUnits = 0;
+ strcpy(DecPoint, "."); strcpy(ColSep, ",");
+ Line_0.width = .4; Line_1.width = .04, Line_2.width = 0.016;
+ Line_0.patlength = 6.0; Line_1.patlength = 0.6; Line_2.patlength = 0.24;
+ Line_0.color = Line_1.color = Line_2.color = 0x00000000L; //black
+ Line_0.pattern = Line_1.pattern = Line_2.pattern = 0L; //solid line
+ FillLine_0.width = FillLine_1.width = FillLine_2.width = 0.0;
+ FillLine_0.patlength = 6.0; FillLine_1.patlength = 0.6; FillLine_2.patlength = 0.24;
+ Line_0.color = Line_1.color = Line_2.color = 0x00000000L; //black
+ Line_0.pattern = Line_1.pattern = Line_2.pattern = 0L; //solid line
+ Fill_0.type = Fill_1.type = Fill_2.type = FILL_NONE;
+ Fill_0.color = Fill_1.color = Fill_2.color = 0x00ffffffL; //white background
+ Fill_0.scale = Fill_1.scale = Fill_2.scale = 1.0; //size = 100%
+ Fill_0.hatch = &FillLine_0; Fill_1.hatch = &FillLine_1; Fill_2.hatch = &FillLine_2;
+ Fill_0.color2 = Fill_1.color2 = Fill_2.color2 = 0x00ffffffL; //white background
+ OutLine_0.width = .2; OutLine_1.width = .1; OutLine_2.width = 0.008;
+ OutLine_0.patlength = 6.0; OutLine_1.patlength = 0.6; OutLine_2.patlength = 0.24;
+ OutLine_0.color = OutLine_1.color = OutLine_2.color = 0x00000000L;
+ OutLine_0.pattern = OutLine_1.pattern = OutLine_2.pattern = 0L;
+ pl = pgl = 0L; pg = 0L; pg_fl = 0L; rrect_rad = 0L;
+ cdisp = 0L; min4log = 0.000001;
+ axis_color = 0x0L;
+ svgAttr = svgScript = currPath = IniFile = 0L;
+ File1 = File2 = File3 = File4 = File5 = File6 = 0L;
+}
+
+Default::~Default()
+{
+ if(svgAttr) free(svgAttr); if(svgScript) free(svgScript);
+ if(currPath) free(currPath); if(IniFile) free(IniFile);
+ svgAttr = svgScript = currPath = 0L;
+ if(pl) free(pl); if(pgl) free(pgl);
+ if(pg_fl) free(pg_fl); if(pg) free(pg);
+ if(rrect_rad) free(rrect_rad);
+ if(File1) free(File1); if(File2) free(File2);
+ if(File3) free(File3); if(File4) free(File4);
+ if(File5) free(File5); if(File6) free(File6);
+}
+
+void
+Default::SetDisp(anyOutput *o)
+{
+ if(o && o != cdisp) {
+ Undo.SetDisp(o);
+ cdisp = o;
+ }
+}
+
+double
+Default::GetSize(int select)
+{
+ double RetVal = 0.0;
+
+ switch (select){
+ case SIZE_SYMBOL: RetVal = 3.0; break;
+ case SIZE_SYM_LINE: RetVal = 0.2; break;
+ case SIZE_DATA_LINE:
+ switch(cUnits) {
+ case 1: return Line_1.width;
+ case 2: return Line_2.width;
+ default: return Line_0.width;
+ }
+ case SIZE_TEXT: RetVal = 4.0; break;
+ case SIZE_GRECT_TOP: RetVal = 0.0; break;
+ case SIZE_GRECT_BOTTOM: RetVal = 110.0; break;
+ case SIZE_GRECT_LEFT: RetVal = 0.0; break;
+ case SIZE_GRECT_RIGHT: RetVal = 160.0; break;
+ case SIZE_DRECT_TOP: RetVal = 10.0; break;
+ case SIZE_DRECT_BOTTOM: RetVal = 90.0; break;
+ case SIZE_DRECT_LEFT: RetVal = 25.0; break;
+ case SIZE_DRECT_RIGHT: RetVal = 140.0; break;
+ case SIZE_PATLENGTH:
+ case SIZE_DATA_LINE_PAT:
+ switch(cUnits) {
+ case 1: return Line_1.patlength;
+ case 2: return Line_2.patlength;
+ default: return Line_0.patlength;
+ }
+ case SIZE_AXIS_TICKS: RetVal = 2.0; break;
+ case SIZE_TICK_LABELS: RetVal = 4.0; break;
+ case SIZE_WHISKER:
+ case SIZE_ERRBAR: RetVal = 3.0; break;
+ case SIZE_WHISKER_LINE:
+ case SIZE_AXIS_LINE:
+ case SIZE_BAR_LINE:
+ case SIZE_ERRBAR_LINE:
+ switch(cUnits) {
+ case 1: return OutLine_1.width;
+ case 2: return OutLine_2.width;
+ default: return OutLine_0.width;
+ }
+ case SIZE_BOX:
+ case SIZE_BAR: RetVal = 10.0; break;
+ case SIZE_BUBBLE_LINE: RetVal = 0.4; break;
+ case SIZE_BUBBLE_HATCH_LINE: RetVal = 0.1; break;
+ case SIZE_ARROW_LINE: RetVal = 0.4; break;
+ case SIZE_ARROW_CAPWIDTH: RetVal = 3.0; break;
+ case SIZE_ARROW_CAPLENGTH: RetVal = 4.0; break;
+ case SIZE_HAIRLINE: RetVal = 0.1; break;
+ case SIZE_SEGLINE: RetVal = 0.4; break;
+ case SIZE_CELLWIDTH: RetVal = 20.0; break;
+ case SIZE_CELLTEXT: RetVal = 4.5; break;
+ case SIZE_RRECT_RAD:
+ return rrect_rad ? *rrect_rad : GetSize(SIZE_SYMBOL)/2.0;
+ default: return 0.0;
+ }
+ switch(cUnits) {
+ case 1: RetVal /= 10.0; break;
+ case 2: RetVal = NiceValue(RetVal/25.4); break;
+ }
+ return RetVal;
+}
+
+DWORD
+Default::Color(int select)
+{
+ switch (select){
+ case COL_ERROR_LINE:
+ case COL_WHISKER:
+ case COL_SYM_LINE: return 0x00000000L;
+ case COL_SYM_FILL: return 0x00ffffffL;
+ case COL_ARROW:
+ case COL_DATA_LINE: return Line_0.color;
+ case COL_TEXT: return 0x00000000L;
+ case COL_BG: return 0x00ffffffL;
+ case COL_AXIS: return axis_color;
+ case COL_BAR_LINE: return OutLine_0.color;
+ case COL_BAR_FILL: return 0x00ffffffL;
+ case COL_BUBBLE_LINE:
+ case COL_BUBBLE_FILLLINE: return 0x00ff0000L;
+ case COL_BUBBLE_FILL: return 0x00ffc0c0L;
+ case COL_DRECT: return 0x00ffffffL;
+ case COL_GRECT: return 0x00ffffffL;
+ case COL_GRECTLINE: return 0x00e0e0e0L;
+ case COL_POLYLINE: return pl ? pl->color : OutLine_0.color;
+ case COL_POLYGON: return pgl ? pgl->color : OutLine_0.color;
+ default: return 0x00C0C0C0L; //Error
+ }
+}
+
+LineDEF *
+Default::GetLine()
+{
+ switch (cUnits) {
+ case 1: return &Line_1;
+ case 2: return &Line_2;
+ default: return &Line_0;
+ }
+}
+
+void
+Default::SetLine(int u, LineDEF *l, int which)
+{
+ double lw, pl;
+ LineDEF *l1, *l2, *l3;
+
+ switch (which) {
+ case 0: l1 = &Line_0; l2 = &Line_1; l3 = &Line_2; break;
+ case 1: l1 = &FillLine_0; l2 = &FillLine_1; l3 = &FillLine_2; break;
+ case 2: l1 = &OutLine_0; l2 = &OutLine_1; l3 = &OutLine_2; break;
+ default: return;
+ }
+ l1->color = l2->color = l3->color = l->color;
+ l1->pattern = l2->pattern = l3->pattern = l->pattern;
+ switch (u) {
+ case 1:
+ lw = l->width*10.0; pl = l->patlength*10.0;
+ l1->width = lw; l1->patlength = pl;
+ l2->width = l->width; l2->patlength = l->patlength;
+ l3->patlength = NiceValue(pl/25.4);
+ l3->patlength = NiceValue(pl/25.4);
+ break;
+ case 2:
+ lw = NiceValue(l->width*25.4); pl = NiceValue(l->patlength*25.4);
+ l1->width = lw; l1->patlength = pl;
+ l2->width = lw/10.0; l2->patlength = pl/10.0;
+ l3->width = l->width; l3->patlength = l->patlength;
+ break;
+ default:
+ lw = l->width; pl = l->patlength;
+ l1->width = l->width; l1->patlength = l->patlength;
+ l2->width = lw/10.0; l2->patlength = pl/10.0;
+ l3->patlength = NiceValue(pl/25.4);
+ l3->patlength = NiceValue(pl/25.4);
+ break;
+ }
+}
+
+FillDEF *
+Default::GetFill()
+{
+ switch (cUnits) {
+ case 1: return &Fill_1;
+ case 2: return &Fill_2;
+ default: return &Fill_0;
+ }
+}
+
+void
+Default::SetFill(int u, FillDEF *fd)
+{
+ memcpy(&Fill_0, fd, sizeof(FillDEF));
+ memcpy(&Fill_1, fd, sizeof(FillDEF));
+ memcpy(&Fill_2, fd, sizeof(FillDEF));
+ if(fd->hatch) SetLine(u, fd->hatch, 1);
+ Fill_0.hatch = &FillLine_0;
+ Fill_1.hatch = &FillLine_1;
+ Fill_2.hatch = &FillLine_2;
+}
+
+LineDEF *
+Default::GetOutLine()
+{
+ switch (cUnits) {
+ case 1: return &OutLine_1;
+ case 2: return &OutLine_2;
+ default: return &OutLine_0;
+ }
+}
+
+LineDEF *
+Default::plLineDEF(LineDEF *ld)
+{
+ if(ld) {
+ if(pl) free(pl);
+ if(pl = (LineDEF *)malloc(sizeof(LineDEF))) memcpy(pl, ld, sizeof(LineDEF));
+ }
+ if(pl) return pl;
+ else return GetOutLine();
+}
+
+LineDEF *
+Default::pgLineDEF(LineDEF *ol)
+{
+ if(ol) {
+ if(pgl) free(pgl);
+ if(pgl = (LineDEF *)malloc(sizeof(LineDEF))) memcpy(pgl, ol, sizeof(LineDEF));
+ }
+ if(pgl) return pgl;
+ else return GetOutLine();
+}
+
+FillDEF *
+Default::pgFillDEF(FillDEF *fd)
+{
+ if(fd) {
+ if(pg) free(pg);
+ if(pg = (FillDEF *)malloc(sizeof(FillDEF))){
+ memcpy(pg, fd, sizeof(FillDEF));
+ if(pg->hatch) {
+ if(pg_fl) free(pg_fl);
+ if(pg_fl = (LineDEF *)malloc(sizeof(LineDEF)))
+ memcpy(pg_fl, pg->hatch, sizeof(LineDEF));
+ pg->hatch = pg_fl;
+ }
+ }
+ }
+ if(pg) return pg;
+ else return GetFill();
+}
+
+double
+Default::rrectRad(double rad)
+{
+ if(!rrect_rad)rrect_rad=(double*)malloc(sizeof(double));
+ if(rrect_rad) return (*rrect_rad = rad);
+ return 0.0;
+}
+
+void
+Default::FileHistory(char *path)
+{
+ char *tmp_path = 0L, *tmp;
+ char **history[] = {&File1, &File2, &File3, &File4, &File5, &File6};
+ int i;
+
+ if(path && (tmp_path=strdup(path))){
+ for(i=strlen(path); i > 0 && tmp_path[i] != '/' && tmp_path[i] != '\\'; i--);
+ tmp_path[i] = 0;
+ if(currPath) free(currPath);
+ if(strlen(tmp_path)) currPath = strdup(tmp_path);
+ else currPath = 0L;
+ strcpy(tmp_path, path);
+ if(File1 && strcmp(File1, tmp_path)) {
+ for(i = 0; i < 6 && tmp_path; i++) {
+ if(i && *history[i] && !strcmp(File1, *history[i])){
+ free(*history[i]);
+ *history[i] = tmp_path;
+ tmp_path = 0L;
+ break;
+ }
+ if(*history[i]) {
+ if(strcmp(tmp_path, *history[i])){
+ tmp = *history[i];
+ *history[i] = tmp_path;
+ tmp_path = tmp;
+ }
+ else {
+ free(tmp_path);
+ tmp_path = 0L;
+ }
+ }
+ else{
+ tmp = *history[i];
+ *history[i] = tmp_path;
+ tmp_path = tmp;
+ }
+ }
+ }
+ if(!(*history[0])) {
+ *history[0] = tmp_path;
+ tmp_path = 0L;
+ }
+ }
+ if(tmp_path) free(tmp_path);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Chache file input for read operations
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#define CharCacheSize 1024
+ReadCache::ReadCache()
+{
+ Cache = 0L;
+ idx = max = 0;
+ eof = true;
+}
+
+ReadCache::~ReadCache()
+{
+ if(Cache) free(Cache);
+ Cache = 0L;
+}
+
+bool
+ReadCache::Open(char *name)
+{
+ idx = max = 0;
+ eof = true;
+ if(!name) iFile = 0; //use stdin
+ else if(-1 ==(iFile = open(name, O_BINARY))) return false;
+ Cache = (unsigned char *)malloc((unsigned)(CharCacheSize + 1));
+ if(Cache) return true;
+ return false;
+}
+
+void
+ReadCache::Close()
+{
+ close(iFile);
+ if(Cache) free(Cache);
+ Cache = 0L;
+}
+
+unsigned char
+ReadCache::Getc()
+{
+ if(Cache){
+ if(idx < max) return (last = Cache[idx++]);
+ else {
+ do {
+ max = read(iFile, Cache, CharCacheSize);
+ if(max <=0) {
+ eof = true;
+ return 0;
+ }
+ else eof = false;
+ }while(max == 0);
+ idx = 1;
+ return(last = Cache[0]);
+ }
+ }
+ return 0;
+}
+
+unsigned char *
+ReadCache::GetField()
+{
+ int i;
+ static unsigned char *ret;
+
+ if(Cache && max) {
+ while(idx < max && Cache[idx] < 43) idx++;
+ if(idx == max){
+ if(max == CharCacheSize) {
+ max = read(iFile, Cache, CharCacheSize);
+ idx = 0;
+ return GetField();
+ }
+ else return 0L;
+ }
+ i = idx;
+ while(i < max && Cache[i] > 32 && Cache[i] <= 'z') i++;
+ if(i == max) {
+ for(i = 0; (Line[i] = Getc()) >32 && Line[i] <= 'z' && i < 4096; i++);
+ Line[i] = 0;
+ return Line;
+ }
+ else {
+ ret = Cache+idx;
+ idx = i;
+ return ret;
+ }
+ }
+ return 0L;
+}
+
+void
+ReadCache::ReadLine(char *dest, int size)
+{
+ int i=0;
+ unsigned char c;
+
+ dest[0] = 0;
+ do {
+ c = Getc();
+ if(c == 0x09) c = 0x32; // tab to space
+ if(c > 31) dest[i++] = (char)c;
+ }while(c && c != 0x0a && i < size);
+ dest[i] = 0;
+}
+
+bool
+ReadCache::GetInt(long *in)
+{
+ unsigned char *field;
+
+ field = GetField();
+ if(field && field[0]) {
+ *in = atol((char*)field);
+ if(*in == 0 && field[0] == '}') return false;
+ return true;
+ }
+ return false;
+}
+
+bool
+ReadCache::GetFloat(double *fn)
+{
+ unsigned char *field;
+
+ field = GetField();
+ if(field && field[0]) {
+ *fn = atof((char*)field);
+ if(*fn == 0.0 && field[0] == '}') return false;
+ return true;
+ }
+ return false;
+}
+
+unsigned char
+ReadCache::Lastc()
+{
+ return last;
+}
+
+bool
+ReadCache::IsEOF()
+{
+ return eof;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Process memory block as if file input
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+MemCache::MemCache(unsigned char *ptr)
+:ReadCache()
+{
+ if(ptr) {
+ Cache = (unsigned char*) strdup((char*)ptr);
+ max = strlen((char*)Cache);
+ eof = false;
+ }
+}
+
+MemCache::~MemCache()
+{
+ if(Cache) free(Cache);
+ Cache = 0L;
+}
+
+unsigned char
+MemCache::Getc()
+{
+ if(Cache){
+ if(idx < max) return (last = Cache[idx++]);
+ else {
+ eof = true;
+ return 0;
+ }
+ }
+ return 0;
+}
+
+unsigned char *
+MemCache::GetField()
+{
+ int i;
+ static unsigned char *ret;
+
+ if(Cache && max) {
+ while(idx < max && Cache[idx] < 43) idx++;
+ i = idx;
+ while(i < max && Cache[i] > 32 && Cache[i] <= 'z') i++;
+ ret = Cache+idx;
+ idx = i;
+ return ret;
+ }
+ return 0L;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Process Undo
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#define UNDO_RING_SIZE 0x100
+#define UNDO_IDX_MASK 0xff
+UndoObj::UndoObj()
+{
+ buff = buff0 = (UndoInfo**)calloc(UNDO_RING_SIZE, sizeof(UndoInfo*));
+ stub1 = ndisp = 0;
+ pcb = &stub1; cdisp = ldisp = 0L; buffers = 0L;
+}
+
+UndoObj::~UndoObj()
+{
+ Flush();
+ if(buff0) free(buff0);
+}
+
+//free all resources associated with undo operations
+void
+UndoObj::Flush()
+{
+ int i, j;
+
+ if(!buffers) return;
+ for(i = 0; i < ndisp; i++) if(buffers[i]) {
+ if(buffers[i]->buff) {
+ for(j = 0; j < UNDO_RING_SIZE; j++) {
+ if(buffers[i]->buff[j]) FreeInfo(&buffers[i]->buff[j]);
+ }
+ free(buffers[i]->buff);
+ }
+ free(buffers[i]);
+ }
+ free(buffers);
+ stub1 = ndisp = 0;
+ pcb = &stub1; cdisp = 0L; buffers = 0L;
+}
+
+//select buffers associated with the current window/widget,
+//create new buffers if called for the first time
+void
+UndoObj::SetDisp(anyOutput *o)
+{
+ int i;
+ void *ptmp;
+
+ if(o && o != cdisp) {
+ ldisp = cdisp;
+ if(buffers) {
+ for(i = 0; i < ndisp; i++) {
+ if(buffers[i] && buffers[i]->disp == o){
+ cdisp = o;
+ buff = buffers[i]->buff; pcb = &buffers[i]->count;
+ return;
+ }
+ else if(!buffers[i] && (buffers[i] = (UndoBuff*)calloc(1, sizeof(UndoBuff)))) {
+ buffers[i]->buff = (UndoInfo**)calloc(UNDO_RING_SIZE, sizeof(UndoInfo*));
+ buffers[i]->disp = cdisp = o;
+ buff = buffers[i]->buff; pcb = &buffers[i]->count;
+ return;
+ }
+ }
+ if(ptmp = memdup(buffers, sizeof(UndoBuff*) *(ndisp+1), 0)){
+ free(buffers); buffers = (UndoBuff**)ptmp;
+ if(buffers[ndisp] = (UndoBuff*)calloc(1, sizeof(UndoBuff))) {
+ buffers[ndisp]->buff = (UndoInfo**)calloc(UNDO_RING_SIZE, sizeof(UndoInfo*));
+ buffers[ndisp]->disp = cdisp = o;
+ buff = buffers[ndisp]->buff; pcb = &buffers[ndisp]->count;
+ ndisp++;
+ }
+ }
+ }
+ else if(buffers = (UndoBuff**)calloc(1, sizeof(UndoBuff*))){
+ if(buffers[0] = (UndoBuff*)calloc(1, sizeof(UndoBuff))) {
+ buffers[0]->buff = (UndoInfo**)calloc(UNDO_RING_SIZE, sizeof(UndoInfo*));
+ buffers[0]->disp = cdisp = o;
+ ndisp = 1;
+ buff = buffers[0]->buff; pcb = &buffers[0]->count;
+ }
+ }
+ }
+}
+
+//free memory for a closed output
+void
+UndoObj::KillDisp(anyOutput *o)
+{
+ int i, j, c_buf;
+
+ if(o && buffers) {
+ for(i = c_buf = 0; i < ndisp; i++) {
+ if(buffers[i] && buffers[i]->disp == o) c_buf = i; break;
+ }
+ if(!(c_buf)) return;
+ if(buffers[c_buf]->buff) {
+ for(j = 0; j < UNDO_RING_SIZE; j++) {
+ if(buffers[c_buf]->buff[j]) FreeInfo(&buffers[c_buf]->buff[j]);
+ }
+ free(buffers[c_buf]->buff);
+ }
+ free(buffers[i]); buffers[i] = 0L;
+ }
+ if(o == cdisp) SetDisp(ldisp);
+}
+
+//remove references to an invalid (probabbly deleted) object
+void
+UndoObj::InvalidGO(GraphObj *go)
+{
+ int i, i1, i2;
+
+ if(*pcb >10) {
+ if(*pcb < UNDO_RING_SIZE){
+ i1 = 0; i2 = *pcb;
+ }
+ else {
+ i1 = ((*pcb) & UNDO_IDX_MASK);
+ i2 = (((*pcb)-UNDO_RING_SIZE) & UNDO_IDX_MASK);
+ if(i1 > i2) Swap(i1, i2);
+ }
+ }
+ else {
+ i1 = 0; i2 = *pcb;
+ }
+ for(i = i1; i < i2; i++) {
+ if(buff[i] && buff[i]->owner == go) FreeInfo(&buff[i]);
+ if(buff[i]) switch(buff[i]->cmd) {
+// case UNDO_OBJCONF:
+ case UNDO_OBJCONF_1:
+ if(buff[i]->loc == (void**)go) FreeInfo(&buff[i]);
+ break;
+ }
+ }
+}
+
+void
+UndoObj::Pop()
+{
+ int idx;
+
+ if(*pcb < 1) return;
+ idx = ((*pcb-1) & UNDO_IDX_MASK);
+ if(buff[idx]) FreeInfo(&buff[idx]);
+ (*pcb)--;
+}
+
+void
+UndoObj::Restore(bool redraw, anyOutput*o)
+{
+ int i, j, idx;
+ DWORD flags;
+ UndoList *ul;
+ GraphObj **gol;
+ unsigned char *savbuf, *target;
+
+ if(o) SetDisp(o);
+ else if(cdisp) o = cdisp;
+ CurrGO = 0L;
+ if(*pcb < 1){
+ InfoBox("The UNDO-cache is empty");
+ return;
+ }
+ do {
+ idx = ((*pcb-1) & UNDO_IDX_MASK);
+ if(!buff[idx] && *pcb > 0) (*pcb)--;
+ } while(!buff[idx] && *pcb > 0);
+ if(!buff[idx]) return;
+ if(buff[idx]->zd.org.fx != cdisp->VPorg.fx ||
+ buff[idx]->zd.org.fy != cdisp->VPorg.fy || buff[idx]->zd.scale != cdisp->VPscale){
+ cdisp->VPorg.fx = buff[idx]->zd.org.fx;
+ cdisp->VPorg.fy = buff[idx]->zd.org.fy;
+ cdisp->VPscale = buff[idx]->zd.scale;
+ if(cdisp->VPscale > 100.0) cdisp->VPscale = 100.0;
+ if(cdisp->VPscale < 0.05) cdisp->VPscale = 0.05;
+ if(buff[idx]->owner)
+ if(buff[idx]->owner->Id < GO_PLOT) CurrGO = buff[idx]->owner;
+ if(!((buff[idx]->owner)->Command(CMD_SETSCROLL, 0L, cdisp)))
+ (buff[idx]->owner)->Command(CMD_REDRAW, 0L, cdisp);
+ return;
+ }
+ (*pcb)--;
+ if(buff[idx]) {
+ flags = buff[idx]->flags;
+ switch(buff[idx]->cmd) {
+ case UNDO_DATA:
+ RestoreData(buff[idx]);
+ break;
+ case UNDO_ET:
+ if(buff[idx]->loc && buff[idx]->data) {
+ if(((EtBuff*)buff[idx]->data)->DaO){
+ buff[idx]->loc = (void**)((EtBuff*)buff[idx]->data)->DaO->
+ etRows[((EtBuff*)buff[idx]->data)->row][((EtBuff*)buff[idx]->data)->col];
+ }
+ ((EditText*)buff[idx]->loc)->SetText(((EtBuff*)buff[idx]->data)->txt);
+ if(((EtBuff*)buff[idx]->data)->txt) free(((EtBuff*)buff[idx]->data)->txt);
+ *(((EtBuff*)buff[idx]->data)->cur) = ((EtBuff*)buff[idx]->data)->vcur;
+ *(((EtBuff*)buff[idx]->data)->m1) = ((EtBuff*)buff[idx]->data)->vm1;
+ *(((EtBuff*)buff[idx]->data)->m2) = ((EtBuff*)buff[idx]->data)->vm2;
+ ((EditText*)buff[idx]->loc)->Command(CMD_MRK_DIRTY, cdisp, 0L);
+ }
+ break;
+ case UNDO_MUTATE:
+ case UNDO_DEL_GO:
+ ((GraphObj*)(buff[idx]->data))->parent = buff[idx]->owner;
+ if(buff[idx]->cmd == UNDO_MUTATE && *(buff[idx]->loc))
+ ::DeleteGO((GraphObj*)*(buff[idx]->loc));
+ else CurrGO = (GraphObj*) buff[idx]->data;
+ *(buff[idx]->loc) = buff[idx]->data;
+ (buff[idx]->owner)->Command(CMD_MRK_DIRTY, 0L, 0L);
+ break;
+ case UNDO_DROPGOLIST:
+ if((ul = (UndoList *)(buff[idx]->data)) && (ul->array)){
+ gol = (GraphObj**)(*(ul->loc_arr));
+ if(gol) for (i = 0; i < *(ul->loc_count); i++) if(gol[i]) ::DeleteGO(gol[i]);
+ *(ul->loc_count) = ul->count; free(gol);
+ *(ul->loc_arr) = ul->array; free(ul);
+ }
+ break;
+ case UNDO_GOLIST:
+ if((ul = (UndoList *)(buff[idx]->data)) && (ul->array)){
+ memcpy(*(ul->loc_arr), ul->array, ul->count * sizeof(GraphObj*));
+ *(ul->loc_count) = ul->count; free(ul->array);
+ free(ul);
+ }
+ break;
+ case UNDO_DROPMEM:
+ *(buff[idx]->loc) = buff[idx]->data; break;
+ case UNDO_SAVVAR:
+ if(!(savbuf = (unsigned char *)buff[idx]->data))break;
+ for(i = 0; ; ) {
+ memcpy(&target, savbuf+i, sizeof(unsigned char*)); i += sizeof(unsigned char*);
+ memcpy(&j, savbuf+i, sizeof(int)); i += sizeof(int);
+ if(!target) break;
+ memcpy(target, savbuf+i, j); i += j;
+ }
+ if(buff[idx]->owner)(buff[idx]->owner)->Command(CMD_MRK_DIRTY, 0L, 0L);
+ free(savbuf);
+ break;
+ case UNDO_VALDWORD:
+ *((DWORD*)(buff[idx]->loc)) = *((DWORD*)(buff[idx]->data));
+ free(buff[idx]->data); break;
+ case UNDO_VALINT:
+ *((int*)(buff[idx]->loc)) = *((int*)(buff[idx]->data));
+ free(buff[idx]->data); break;
+ case UNDO_OBJCONF_1: //single object restore
+ UpdGOfromMem((GraphObj *)buff[idx]->loc, (unsigned char *)buff[idx]->data);
+ free(buff[idx]->data); break;
+ case UNDO_OBJCONF: //tree of objects to restore
+ RestoreConf(buff[idx]);
+ if(buff[idx] && buff[idx]->data) free(buff[idx]->data); break;
+ case UNDO_LFP:
+ memcpy(buff[idx]->loc, buff[idx]->data, sizeof(lfPOINT));
+ free(buff[idx]->data); break;
+ case UNDO_MOVE:
+ (buff[idx]->owner)->Command(CMD_UNDO_MOVE, buff[idx]->data, 0L);
+ free(buff[idx]->data); break;
+ case UNDO_RECT:
+ memcpy(buff[idx]->loc, buff[idx]->data, sizeof(fRECT));
+ free(buff[idx]->data); break;
+ case UNDO_STRING:
+ if(*(buff[idx]->loc)) free(*(buff[idx]->loc));
+ CurrGO = buff[idx]->owner;
+ *(buff[idx]->loc) = buff[idx]->data; break;
+ case UNDO_ROTDEF:
+ memcpy(*(buff[idx]->loc), buff[idx]->data, 6 * sizeof(double));
+ free(buff[idx]->data); break;
+ case UNDO_SETGO:
+ ::DeleteGO(*((GraphObj**)(buff[idx]->loc)));
+ *((GraphObj**)(buff[idx]->loc)) = 0L; break;
+ case UNDO_LINEDEF:
+ memcpy(buff[idx]->loc, buff[idx]->data, sizeof(LineDEF));
+ free(buff[idx]->data); break;
+ case UNDO_FILLDEF:
+ memcpy(buff[idx]->loc, buff[idx]->data, sizeof(FillDEF) - (sizeof(LineDEF*) + sizeof(DWORD)));
+ ((FillDEF*)(buff[idx]->loc))->color2 = ((FillDEF*)(buff[idx]->data))->color2;
+ free(buff[idx]->data); break;
+ case UNDO_AXISDEF:
+ if(((AxisDEF*)(buff[idx]->loc))->breaks) free(((AxisDEF*)(buff[idx]->loc))->breaks);
+ memcpy(buff[idx]->loc, buff[idx]->data, sizeof(AxisDEF));
+ free(buff[idx]->data); break;
+ case UNDO_TEXTDEF:
+ if(((TextDEF*)(buff[idx]->loc))->text) free(((TextDEF*)(buff[idx]->loc))->text);
+ memcpy(buff[idx]->loc, buff[idx]->data, sizeof(TextDEF));
+ free(buff[idx]->data); break;
+ case UNDO_LFP3D:
+ memcpy(buff[idx]->loc, buff[idx]->data, sizeof(fPOINT3D));
+ free(buff[idx]->data); break;
+ case UNDO_FLOAT:
+ *((double*)(buff[idx]->loc)) = *((double*)(buff[idx]->data));
+ free(buff[idx]->data); break;
+ case UNDO_MEM:
+ if((ul = (UndoList *)(buff[idx]->data)) && (ul->array)){
+ memcpy(*(ul->loc_arr), ul->array, ul->size);
+ *(ul->loc_count) = ul->count;
+ free(ul->array);
+ if(buff[idx]->owner->Id < GO_PLOT) CurrGO = (GraphObj*) buff[idx]->owner;
+ if(buff[idx]->owner)(buff[idx]->owner)->Command(CMD_MRK_DIRTY, 0L, 0L);
+ }
+ break;
+ }
+ if(flags & UNDO_CONTINUE){
+ free(buff[idx]); buff[idx] = 0L;
+ Restore(redraw, cdisp);
+ }
+ else {
+ if(o) o->MrkMode = MRK_NONE;
+ if(redraw && buff[idx] && buff[idx]->owner){
+ (buff[idx]->owner)->Command(CMD_MRK_DIRTY, 0L, 0L);
+ (buff[idx]->owner)->Command(CMD_REDRAW, 0L, 0L);
+ }
+ if(buff[idx]) free(buff[idx]); buff[idx] = 0L;
+ }
+ }
+ else {
+ InfoBox("The UNDO-cache is empty");
+ }
+}
+
+void
+UndoObj::ListGOmoved(GraphObj **oldlist, GraphObj **newlist, long size)
+{
+ long i;
+ int c;
+
+ if(!oldlist || !newlist || oldlist == newlist) return;
+ for(i = 0; i < size; i++) if(oldlist[i] == newlist[i]) {
+ for(c = 0; c < UNDO_RING_SIZE; c++) {
+ if(buff[c]) switch(buff[c]->cmd) {
+ case UNDO_DEL_GO:
+ case UNDO_SETGO:
+ case UNDO_OBJCONF_1:
+ case UNDO_OBJCONF:
+ if(buff[c]->loc == (void**) &oldlist[i]){
+ buff[c]->loc = (void**) &newlist[i];
+ }
+ break;
+ }
+ }
+ }
+}
+
+void
+UndoObj::DeleteGO(GraphObj **go, DWORD flags, anyOutput *o)
+{
+ if(!go || !(*go)) return;
+ if(o){
+ SetDisp(o); o->HideMark();
+ }
+ if(CurrGO == *go) CurrGO = 0L;
+ if((*go)->Id == GO_POLYLINE || (*go)->Id == GO_POLYGON){
+ if(CurrHandle && CurrHandle->parent==*go) {
+ if((*go)->Command(CMD_DELOBJ, CurrHandle, 0l)) return;
+ }
+ }
+ NewItem(UNDO_DEL_GO, flags, (*(go))->parent, *(go), (void**)go);
+ (*(go))->parent->Command(CMD_MRK_DIRTY, 0L, 0L);
+ (*(go))->parent = 0L;
+ *(go) = CurrGO = 0L;
+}
+
+void
+UndoObj::MutateGO(GraphObj **old, GraphObj *repl, DWORD flags, anyOutput *o)
+{
+ if(!old || !(*old)) return;
+ if(o){
+ SetDisp(o); o->HideMark();
+ }
+ if(!(*old))return; //HideMark might delete object: should never happen
+ if(CurrGO == *old) CurrGO = 0L;
+ NewItem(UNDO_MUTATE, flags, (*(old))->parent, *(old), (void**)old);
+ repl->parent = (*(old))->parent;
+ (*(old))->parent = 0L;
+ *(old) = repl;
+ repl->parent->Command(CMD_REDRAW, 0L, o);
+}
+
+void
+UndoObj::StoreListGO(GraphObj *parent, GraphObj ***go, long *count, DWORD flags)
+{
+ UndoList *ul;
+
+ if(ul = (UndoList *)malloc(sizeof(UndoList))) {
+ if(ul->array = memdup(*go, *count * sizeof(GraphObj*), 0)){
+ ul->loc_arr = (void **)go;
+ ul->count = *count;
+ ul->loc_count = count;
+ if(0 > NewItem(UNDO_GOLIST, flags, parent, ul, 0L)) {
+ free(ul->array); free(ul);
+ }
+ }
+ else free(ul);
+ }
+}
+
+void
+UndoObj::DropListGO(GraphObj *parent, GraphObj ***go, long *count, DWORD flags)
+{
+ UndoList *ul;
+
+ if(ul = (UndoList *)malloc(sizeof(UndoList))) {
+ if(ul->array = memdup(*go, *count * sizeof(GraphObj*), 0)){
+ ul->loc_arr = (void **)go; *go = 0L;
+ ul->count = *count; *count = 0;
+ ul->loc_count = count;
+ if(0 > NewItem(UNDO_DROPGOLIST, flags, parent, ul, 0L)) {
+ free(ul->array); free(ul);
+ }
+ }
+ else free(ul);
+ }
+}
+
+void
+UndoObj::DropMemory(GraphObj *parent, void **mem, DWORD flags)
+{
+ NewItem(UNDO_DROPMEM, flags, parent, *(mem), mem);
+ *mem = 0L;
+}
+
+void
+UndoObj::SavVarBlock(GraphObj *parent, void **mem, DWORD flags)
+{
+ NewItem(UNDO_SAVVAR, flags, parent, *(mem), mem);
+ *mem = 0L;
+}
+
+void
+UndoObj::ValDword(GraphObj *parent, DWORD *val, DWORD flags)
+{
+ void *ptr;
+
+ if(!(ptr = memdup(val, sizeof(DWORD), 0))) return;
+ if(0 > NewItem(UNDO_VALDWORD, flags, parent, ptr, (void**)val)) free(ptr);
+}
+
+void
+UndoObj::ValInt(GraphObj *parent, int *val, DWORD flags)
+{
+ void *ptr;
+
+ if(!(ptr = memdup(val, sizeof(int), 0))) return;
+ if(0 > NewItem(UNDO_VALINT, flags, parent, ptr, (void**)val)) free(ptr);
+}
+
+void
+UndoObj::ObjConf(GraphObj *go, DWORD flags)
+{
+ long sz;
+ int idx;
+
+ InvalidGO(go);
+ if(0<=(idx = NewItem(UNDO_OBJCONF, flags, go->parent, GraphToMem(go, &sz), (void**)go))){
+ if(cObsW == 1) buff[idx]->cmd = UNDO_OBJCONF_1;
+ (buff[idx]->owner)->Command(CMD_MRK_DIRTY, 0L, 0L);
+ }
+}
+
+int
+UndoObj::SaveLFP(GraphObj *go, lfPOINT *lfp, DWORD flags)
+{
+ int idx;
+ void *ptr;
+
+ if(!(ptr = memdup(lfp, sizeof(lfPOINT), 0))) return -1;
+ if(0 > (idx = NewItem(UNDO_LFP, flags, go, ptr, (void**)lfp))) free(ptr);
+ return idx;
+}
+
+void
+UndoObj::MoveObj(GraphObj *go, lfPOINT *lfp, DWORD flags)
+{
+ int idx;
+ lfPOINT dsp;
+
+ if(!lfp) return;
+ dsp.fx = -1.0 * lfp->fx; dsp.fy = -1.0 * lfp->fy;
+ if((idx = SaveLFP(go, &dsp, flags)) <0) return;
+ buff[idx]->cmd = UNDO_MOVE;
+}
+
+void
+UndoObj::ValRect(GraphObj *go, fRECT *rec, DWORD flags)
+{
+ void *ptr;
+
+ if(!(ptr = memdup(rec, sizeof(fRECT), 0))) return;
+ if(0 > NewItem(UNDO_RECT, flags, go, ptr, (void**)rec)) free(ptr);
+}
+
+void
+UndoObj::String(GraphObj *go, char **s, DWORD flags)
+{
+ char *ptr;
+
+ ptr = (s && *s && *(*s)) ? strdup(*(s)):0L;
+ if(0 > NewItem(UNDO_STRING, flags, go, ptr, (void**)s)) if(ptr) free(ptr);
+}
+
+void
+UndoObj::RotDef(GraphObj *go, double **d, DWORD flags)
+{
+ void *ptr;
+
+ if(!(ptr = memdup(*d, 6 * sizeof(double), 0))) return;
+ if(0 > NewItem(UNDO_ROTDEF, flags, go, ptr, (void**)d)) free(ptr);
+}
+
+void
+UndoObj::SetGO(GraphObj *parent, GraphObj **where, GraphObj *go, DWORD flags)
+{
+ *where = go;
+ NewItem(UNDO_SETGO, flags, parent, 0L, (void**)where);
+}
+
+void
+UndoObj::Line(GraphObj *go, LineDEF *ld, DWORD flags)
+{
+ void *ptr;
+
+ if(!(ptr = memdup(ld, sizeof(LineDEF), 0))) return;
+ if(0 > NewItem(UNDO_LINEDEF, flags, go, ptr, (void**)ld)) free(ptr);
+}
+
+void
+UndoObj::Fill(GraphObj *go, FillDEF *fd, DWORD flags)
+{
+ void *ptr;
+
+ if(!(ptr = memdup(fd, sizeof(FillDEF), 0))) return;
+ if(0 > NewItem(UNDO_FILLDEF, flags, go, ptr, (void**)fd)) free(ptr);
+}
+
+void
+UndoObj::AxisDef(GraphObj *go, AxisDEF *ad, DWORD flags)
+{
+ AxisDEF *ptr;
+
+ if(!(ptr = (AxisDEF*) memdup(ad, sizeof(AxisDEF), 0))) return;
+ if(ptr->nBreaks && ptr->breaks) ptr->breaks =
+ (lfPOINT*)memdup(ad->breaks, ad->nBreaks * sizeof(lfPOINT), 0);
+ if(0 > NewItem(UNDO_AXISDEF, flags, go, ptr, (void**)ad)) free(ptr);
+}
+
+void
+UndoObj::TextDef(GraphObj *go, TextDEF *td, DWORD flags)
+{
+ TextDEF *ptr;
+
+ if(!(ptr = (TextDEF*) memdup(td, sizeof(TextDEF), 0))) return;
+ if(td->text) ptr->text = strdup(td->text);
+ if(0 > NewItem(UNDO_TEXTDEF, flags, go, ptr, (void**)td)) free(ptr);
+}
+
+void
+UndoObj::ValLFP3D(GraphObj *go, fPOINT3D *lfp, DWORD flags)
+{
+ void *ptr;
+
+ if(!(ptr = memdup(lfp, sizeof(fPOINT3D), 0))) return;
+ if(0 > NewItem(UNDO_LFP3D, flags, go, ptr, (void**)lfp)) free(ptr);
+}
+
+void
+UndoObj::ValFloat(GraphObj *parent, double *val, DWORD flags)
+{
+ void *ptr;
+
+ if(!(ptr = memdup(val, sizeof(double), 0))) return;
+ if(0 > NewItem(UNDO_FLOAT, flags, parent, ptr, (void**)val)) free(ptr);
+}
+
+void
+UndoObj::DataMem(GraphObj *go, void **mem, int size, long *count, DWORD flags)
+{
+ UndoList *ul;
+
+ if(ul = (UndoList *)malloc(sizeof(UndoList))) {
+ if(ul->array = memdup(*mem, size, 0)){
+ ul->loc_arr = (void **)mem;
+ ul->size = size;
+ ul->count = *count;
+ ul->loc_count = count;
+ if(0 > NewItem(UNDO_MEM, flags, go, ul, 0L)) {
+ free(ul->array); free(ul);
+ }
+ }
+ else free(ul);
+ }
+}
+
+void
+UndoObj::DataObject(GraphObj *go, anyOutput *o, DataObj *d, DWORD flags)
+{
+ int w, h;
+ StrData *save;
+
+ if(!go || !d) return;
+ if(o) SetDisp(o);
+ if(!(d->GetSize(&w, &h)) || !(save = new StrData(d))) return;
+ if(0 > NewItem(UNDO_DATA, flags, go, save, (void**)d)) if(save) delete(save);
+}
+
+void
+UndoObj::TextCell(EditText *et, anyOutput *o, char *text, int *cur, int *m1, int *m2, void* DaO, DWORD flags)
+{
+ anyOutput *o_save;
+ EtBuff *ptr;
+ POINT cpos = {-1, -1};
+
+ if(o) {
+ o_save = cdisp; SetDisp(o);
+ if(ptr = (EtBuff*) calloc(1, sizeof(EtBuff))) {
+ if(text && text[0]) ptr->txt = strdup(text);
+ ptr->cur = cur; ptr->m1 = m1; ptr->m2 = m2;
+ ptr->vcur = *cur; ptr->vm1 = *m1; ptr->vm2 = *m2;
+ ptr->row = 0; ptr->col = 0;
+ if(ptr->DaO = (DataObj*)DaO) {
+ if(ptr->DaO->Command(CMD_CURRPOS, &cpos, 0L)){
+ ptr->row = cpos.y; ptr->col = cpos.x;
+ }
+ }
+ if(0 > NewItem(UNDO_ET, flags, 0L, ptr, (void**)et)) {
+ if(ptr->txt)free (ptr->txt); free(ptr);
+ }
+ }
+ SetDisp(o_save);
+ }
+}
+
+int
+UndoObj::NewItem(int cmd, DWORD flags, GraphObj *owner, void *data, void **loc)
+{
+ UndoInfo *tmp;
+ int idx;
+
+ if(!buff || !cdisp) return -1;
+ if(!(tmp = (UndoInfo *)malloc(sizeof(UndoInfo))))return -1;
+ tmp->cmd = cmd; tmp->flags = flags;
+ tmp->owner = owner; tmp->data = data;
+ tmp->loc = loc;
+ tmp->zd.org.fx = cdisp->VPorg.fx;
+ tmp->zd.org.fy = cdisp->VPorg.fy;
+ tmp->zd.scale = cdisp->VPscale;
+ idx = (*pcb & UNDO_IDX_MASK);
+ if(buff[idx]) FreeInfo(&buff[idx]);
+ buff[idx] = tmp;
+ (*pcb)++;
+ return idx;
+}
+
+void
+UndoObj::FreeInfo(UndoInfo** inf)
+{
+ int i;
+ UndoList *ul;
+ GraphObj *go, **gol;
+
+ if(!inf || !(*inf)) return;
+ switch((*inf)->cmd) {
+ case UNDO_SETGO:
+ break;
+ case UNDO_DATA:
+ delete ((StrData*)((*inf)->data));
+ break;
+ case UNDO_ET:
+ if(((EtBuff*)((*inf)->data))->txt) free(((EtBuff*)((*inf)->data))->txt);
+ break;
+ case UNDO_MUTATE:
+ case UNDO_DEL_GO:
+ go = (GraphObj*)((*inf)->data);
+ (*inf)->data = 0L; ::DeleteGO(go);
+ break;
+ case UNDO_DROPGOLIST:
+ if((ul = (UndoList *)((*inf)->data)) && (ul->array)) {
+ gol = (GraphObj**)(ul->array);
+ for (i = 0; i < ul->count; i++) if(gol[i]) ::DeleteGO(gol[i]);
+ free(ul->array); free(ul);
+ }
+ break;
+ case UNDO_GOLIST: case UNDO_MEM:
+ if((ul = (UndoList *)((*inf)->data)) && (ul->array)) {
+ free(ul->array); free(ul);
+ }
+ break;
+ case UNDO_AXISDEF:
+ if(((AxisDEF*)(*inf)->data)->breaks) free(((AxisDEF*)(*inf)->data)->breaks);
+ free((*inf)->data);
+ break;
+ case UNDO_TEXTDEF:
+ if(((TextDEF*)(*inf)->data)->text) free(((TextDEF*)(*inf)->data)->text);
+ free((*inf)->data);
+ break;
+ case UNDO_DROPMEM: case UNDO_VALDWORD: case UNDO_VALINT:
+ case UNDO_OBJCONF: case UNDO_OBJCONF_1: case UNDO_LFP:
+ case UNDO_MOVE: case UNDO_RECT: case UNDO_STRING:
+ case UNDO_ROTDEF: case UNDO_LINEDEF: case UNDO_FILLDEF:
+ case UNDO_LFP3D: case UNDO_FLOAT: case UNDO_SAVVAR:
+ free((*inf)->data);
+ break;
+ }
+ free(*inf);
+ *inf = 0L;
+}
+
+class UndoUtil:public GraphObj {
+public:
+ GraphObj *res;
+
+ UndoUtil(GraphObj *p, GraphObj *old):GraphObj(0L, 0L){root = p; optr = old; res = 0L;};
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+
+private:
+ GraphObj *root, *optr;
+};
+
+bool
+UndoUtil::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ GraphObj *xch[2];
+
+ switch(cmd){
+ case CMD_DROP_GRAPH:
+ //we come here if conversion of undo-information is
+ // successfully converted into a tree of graphic objects.
+ // Now ask the parent object to replace the modified
+ // object with a previous version (i.e. undo modifications).
+ xch[0] = optr;
+ xch[1] = res = (GraphObj*)tmpl;
+ if(root) return root->Command(CMD_REPL_GO, xch, o);
+ break;
+ }
+ return false;
+}
+
+void
+UndoObj::RestoreConf(UndoInfo *inf)
+{
+ UndoUtil *proc;
+ int i;
+
+ //Create a message object which will accept the translated graphic
+ // object or tree of objects, and which will forward it to the parent
+ // of the tree finalizing undo.
+ if(!inf->data) return;
+ if(!(proc = new UndoUtil(inf->owner, (GraphObj*)inf->loc))) return;
+ OpenGraph(proc, 0L, (unsigned char *)inf->data);
+ if(proc->res) for(i = 0; i < UNDO_RING_SIZE; i++) {
+ if(buff[i] && buff[i]->owner == (GraphObj*)inf->loc) FreeInfo(&buff[i]);
+ if(buff[i] && buff[i]->cmd == UNDO_OBJCONF){
+ if(buff[i]->loc == inf->loc) buff[i]->loc = (void**)proc->res;
+ }
+ }
+ delete proc;
+}
+
+void
+UndoObj::RestoreData(UndoInfo *inf)
+{
+ DataObj *od;
+ StrData *nd;
+ int w, h;
+
+ if(!(nd = (StrData*)inf->data) || !(od = (DataObj*)inf->loc)){
+ if(nd) delete(nd); return;
+ }
+ nd->GetSize(&w, &h); od->ChangeSize(w, h, false);
+ nd->RestoreData(od); delete(nd);
+}
+
+#undef UNDO_RING_SIZE
+#undef UNDO_IDX_MASK
diff --git a/Utils.cpp b/Utils.cpp
new file mode 100755
index 0000000..33fc5b2
--- /dev/null
+++ b/Utils.cpp
@@ -0,0 +1,1946 @@
+//Utils.cpp, Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005 R.Lackner
+//Collection of utility functions and classes for RLPlot
+//
+// 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 <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "rlplot.h"
+
+extern GraphObj *CurrGO; //Selected Graphic Objects
+extern Label *CurrLabel;
+extern Default defs;
+extern UndoObj Undo;
+
+char TmpTxt[TMP_TXT_SIZE];
+
+//----------------------------------------------------------------------------
+// Get the rectanpular part of bitmap. Used for screen updates
+//----------------------------------------------------------------------------
+anyOutput *GetRectBitmap(RECT *rc, anyOutput *src)
+{
+ RECT cr;
+ anyOutput *bm;
+
+ if(!rc || !src) return 0L;
+ src->ActualSize(&cr);
+ if(rc->left < cr.left) rc->left = cr.left;
+ if(rc->right > cr.right) rc->right = cr.right;
+ if(rc->top < cr.top) rc->top = cr.top;
+ if(rc->bottom > cr.bottom) rc->bottom = cr.bottom;
+ if(rc->left == rc->right) return 0L;
+ if(rc->top == rc->bottom) return 0L;
+ if(!(bm = NewBitmapClass(rc->right - rc->left, rc->bottom - rc->top,
+ src->hres, src->vres)))return 0L;
+ bm->CopyBitmap(0, 0, src, rc->left, rc->top, rc->right - rc->left,
+ rc->bottom - rc->top, false);
+ return bm;
+}
+
+void RestoreRectBitmap(anyOutput **pmo, RECT *mrc, anyOutput *o)
+{
+ if(pmo && *pmo && o && mrc) {
+ o->CopyBitmap(mrc->left, mrc->top, *pmo, 0, 0, mrc->right - mrc->left,
+ mrc->bottom - mrc->top, false);
+ DelBitmapClass(*pmo); *pmo = 0L;
+ o->UpdateRect(mrc, false);
+ }
+}
+
+//----------------------------------------------------------------------------
+// Axis utility functions
+//----------------------------------------------------------------------------
+void NiceAxis(AxisDEF *axis, int nTick)
+{
+ double diff, logStep, Step, Magn, LoVal, HiVal;
+ int i;
+
+ axis->Start = axis->min;
+ axis->Step = (axis->max - axis->min)/((double)nTick);
+ diff = axis->max - axis->min;
+ if(axis->breaks) for(i = 0; i < axis->nBreaks; i++) {
+ diff -= fabs(axis->breaks[i].fy - axis->breaks[i].fx);
+ }
+ if(diff <= 0.0) return;
+ logStep = log10(diff/(double)nTick);
+ Magn = floor(logStep);
+ logStep -= Magn;
+ Step = 1.0;
+ if(logStep > 0.301) Step = 2.0;
+ if(logStep > 0.699) Step = 5.0;
+ Step *= pow(10.0, Magn);
+ HiVal = LoVal = Step * floor(axis->min/Step);
+ axis->max *=1.05f;
+ while(HiVal < axis->max) HiVal += Step;
+ axis->min = LoVal;
+ axis->max = HiVal;
+ axis->Start = axis->min;
+ axis->Step = Step;
+}
+
+void NiceStep(AxisDEF *axis, int nTick)
+{
+ double diff, logStep, Step, Magn;
+ int i;
+
+ diff = axis->max - axis->min;
+ if(axis->breaks) for(i = 0; i < axis->nBreaks; i++) {
+ diff -= fabs(axis->breaks[i].fy - axis->breaks[i].fx);
+ }
+ if(diff < 0.0) return;
+ logStep = log10(diff/(double)nTick);
+ Magn = floor(logStep);
+ logStep -= Magn;
+ Step = 1.0;
+ if(logStep > 0.301) Step = 2.0;
+ if(logStep > 0.699) Step = 5.0;
+ Step *= pow(10.0, Magn);
+ axis->Step = Step;
+}
+
+double base4log(AxisDEF *axis, int direc)
+{
+ double lv, Step = 1.0, Magn;
+ int cmd;
+
+ switch (direc) {
+ case 0: cmd = SIZE_BOUNDS_XMIN; break;
+ case 1: cmd = SIZE_BOUNDS_YMIN; break;
+ case 2: cmd = SIZE_BOUNDS_ZMIN; break;
+ default: return 1.0;
+ }
+ if(axis->min > defs.min4log) lv = axis->min;
+ else lv = ((GraphObj*)axis->owner)->GetSize(cmd);
+ if(lv <= defs.min4log) return defs.min4log;
+ lv = log10(lv);
+ lv -= (Magn = floor(lv));
+ if(lv > 0.301) Step = 2.0;
+ if(lv > 0.699) Step = 5.0;
+ Step *= pow(10.0, Magn);
+ return Step > defs.min4log ? Step : 1.0;
+}
+
+double TransformValue(AxisDEF *axis, double val, bool transform)
+{
+ int i;
+ double f1, f2, RetVal = val;
+
+ if(!axis) return val;
+ if(axis->breaks) {
+ for (i = 0; i < axis->nBreaks; i++) {
+ f1 = axis->breaks[i].fx; f2 = axis->breaks[i].fy;
+ if(val > f2) RetVal -= (f2-f1);
+ else if(val > f1 && val <= f2) RetVal -= (val-f1);
+ }
+ }
+ else (axis->nBreaks = 0);
+ if(transform) {
+ switch(axis->flags & 0x7000L) {
+ case AXIS_LINEAR: break;
+ case AXIS_LOG:
+ if(axis->flags & AXIS_RADIAL) RetVal = fabs(RetVal);
+ RetVal = RetVal > defs.min4log ? log10(RetVal): log10(defs.min4log);
+ break;
+ case AXIS_RECI: RetVal = RetVal > defs.min4log || RetVal < - defs.min4log ?
+ 1.0/RetVal : 0.0; break;
+ case AXIS_SQR: RetVal = RetVal >= 0.0 ? sqrt(RetVal) : 0.0; break;
+ }
+ }
+ return RetVal;
+}
+
+void SortAxisBreaks(AxisDEF *axis)
+{
+ int i, j;
+ double ftmp;
+ bool sorted;
+
+ if(!axis || !axis->nBreaks || !axis->breaks) return;
+ //low values first
+ for(i = 0; i < axis->nBreaks; i++) {
+ if(axis->breaks[i].fy < axis->breaks[i].fx) {
+ ftmp = axis->breaks[i].fx;
+ axis->breaks[i].fx = axis->breaks[i].fy;
+ axis->breaks[i].fy = ftmp;
+ }
+ }
+ //a simple bubble sort should do
+ if(axis->nBreaks >1) do {
+ sorted = true;
+ for(i = 1; i < axis->nBreaks; i++) {
+ if(axis->breaks[i-1].fx > axis->breaks[i].fx) {
+ ftmp = axis->breaks[i-1].fx;
+ axis->breaks[i-1].fx = axis->breaks[i].fx;
+ axis->breaks[i].fx = ftmp;
+ ftmp = axis->breaks[i-1].fy;
+ axis->breaks[i-1].fy = axis->breaks[i].fy;
+ axis->breaks[i].fy = ftmp;
+ sorted = false;
+ }
+ }
+ }while(!sorted);
+ //combine overlapping ranges
+ if((j = axis->nBreaks) >1) for(i = j = 1; i < axis->nBreaks; i++) {
+ if(axis->breaks[i].fx > axis->breaks[j-1].fy) {
+ axis->breaks[j].fx = axis->breaks[i].fx;
+ axis->breaks[j].fy = axis->breaks[i].fy;
+ j++;
+ }
+ else {
+ j--;
+ axis->breaks[j++].fy = axis->breaks[i].fy;
+ }
+ }
+ axis->nBreaks = j;
+}
+
+double GetAxisFac(AxisDEF *axis, double delta, int direc)
+{
+ double da, v1, v2;
+
+ switch(axis->flags & 0x7000L) {
+ case AXIS_LOG:
+ axis->max = axis->max > defs.min4log ? log10(axis->max): log10(defs.min4log);
+ axis->min = axis->min > defs.min4log ? log10(axis->min):
+ log10(base4log(axis, direc));
+ if(axis->max <= axis->min) axis->max = axis->min +1.0;
+ break;
+ case AXIS_RECI:
+ v1 = fabs(axis->min) >defs.min4log ? axis->min :
+ base4log(axis, direc);
+ if(fabs(v1) > defs.min4log) v1 = 1.0/v1;
+ else v1 = 1.0e+34;
+ if(fabs(axis->max) >defs.min4log) v2 = 1.0/axis->max;
+ else v2 = 0.0;
+ if(fabs(v2) < fabs(v1/10.0)) v2 = 0.0;
+ axis->min = v2; axis->max = v1;
+ break;
+ case AXIS_SQR:
+ axis->max = axis->max > defs.min4log ? sqrt(axis->max) : 0.0;
+ axis->min = axis->min > defs.min4log ? sqrt(axis->min) : 0.0;
+ break;
+ }
+ v2 = TransformValue(axis, axis->max, false); //process breaks
+ v1 = TransformValue(axis, axis->min, false);
+ da = v2 != v1 ? v2 - v1 : 1.0;
+ return delta / da;
+}
+
+//----------------------------------------------------------------------------
+// Text utility functions: internationalization and formats
+//----------------------------------------------------------------------------
+// restyle formula
+void ReshapeFormula(char **text)
+{
+ int i, j, l;
+
+ if(!text || !*text || !**text) return;
+ l = strlen(*text);
+ for(i = j = 0; i < l; i++) {
+ if((*text)[i] == ';') {
+ if((*text)[i+1] == ';' || (*text)[i+1] == '\n') i++;
+ }
+ TmpTxt[j++] = (*text)[i];
+ }
+ TmpTxt[j] = 0;
+ if((int)strlen(TmpTxt) < l && TmpTxt[0]) {
+ free(*text); *text = strdup(TmpTxt);
+ }
+}
+
+void CleanTags(char *txt, int *i1, int *i2, int *i3)
+{
+ char *no_tags[] = {"<b></b>", "</b><b>", "<b><b>", "</b></b>",
+ "<i></i>", "</i><i>", "<i><i>", "</i></i>", "<u></u>",
+ "</u><u>", "<u><u>", "</u></u>", "<sub></sub>",
+ "</sub><sub>", "<sup></sup>", "</sup><sup>",
+ 0L};
+ int i, j, k, l, w;
+ bool na;
+
+ for(i = j = 0; txt[i]; i++) {
+ if(txt[i] != '<') txt[j++] = txt[i];
+ else {
+ for(k = 0, na = true; no_tags[k]; k++) {
+ for(l=1; no_tags[k][l] && txt[i+l]; l++)
+ if(no_tags[k][l] != txt[i+l]) break;
+ if(!no_tags[k][l]){
+ na = false;
+ i += ((w=strlen(no_tags[k]))-1);
+ if(i1 && *i1 > i) *i1 -= w;
+ if(i2 && *i2 > i) *i2 -= w;
+ if(i3 && *i3 > i) *i3 -= w;
+ break;
+ }
+ }
+ if(na) txt[j++] = txt[i];
+ }
+ }
+ txt[j++] = 0;
+}
+
+//replace one character in string
+void ChangeChar(char *text, char c1, char c2) //replace one char in string
+{
+ int i;
+
+ for(i = 0; text[i]; i++) if (text[i] == c1) text[i] = c2;
+}
+
+char *Int2Nat(char *text) //format ASCII number to locale format
+{
+ int i;
+
+ for(i = 0; text[i]; i++) if (text[i] == '.') text[i] = defs.DecPoint[0];
+ return text;
+}
+
+char *Nat2Int(char *text) //format locale number to intranational notation
+{
+ int i;
+
+ for(i = 0; text[i]; i++) if (text[i] == defs.DecPoint[0]) text[i] = '.';
+ return text;
+}
+
+void WriteNatFloatToBuff(char *buff, double val)
+{
+ WriteFloatToBuff(buff, val);
+ Int2Nat(buff);
+}
+
+bool Txt2Flt(char *txt, double *val)
+{
+ char *tmp = 0L;
+
+ if(txt && txt[0] && val) {
+ if(!txt[1] && (txt[0] == defs.DecPoint[0] || txt[0] < '0' ||
+ txt[0] > '9'))return false;
+ if(txt && txt[0] && (tmp = strdup(txt))){
+ Nat2Int(tmp);
+ //the return value of sscanf only roughly identifies a number
+ if(!sscanf(tmp,"%lf", val)){
+ free(tmp);
+ return false;
+ }
+ free(tmp);
+ return true;
+ }
+ }
+ return false;
+}
+
+void RmTrail(char *txt)
+{
+ int i;
+
+ i = strlen(txt);
+ while(i >0 && (txt[i-1] == '0' || txt[i-1] < 32)) txt[--i] = 0;
+ if(i > 1 && txt[i-1] == '.') txt[i-1] = 0;
+}
+
+double NiceValue(double fv)
+{
+ double sign = fv > 0.0f ? 1.0 : -1.0;
+ double fa = fabs(fv);
+ double magn = floor(log10(fa));
+ int i = iround(fa/pow(10.0, magn-1.0));
+
+ return sign*pow(10.0, magn-1.0) *(double)i;
+}
+
+char *Int2ColLabel(int nr1, bool uc)
+{
+ static char RetTxt[10];
+ int i, j, nr = nr1;
+ char base = uc ? 'A' : 'a';
+
+ sprintf(RetTxt+8, "%c\0", base + (nr %26));
+ nr /= 26;
+ for (i = 7; nr && i>=0; i--) {
+ j = nr %27;
+ RetTxt[i] = base + (j ? j-1 : j);
+ if (nr == 26) nr = 0;
+ else nr = nr/26;
+ }
+ return RetTxt+i+1;
+}
+
+//convert strings to XML specifications
+//this offers a limited support for special characters
+char *str2xml(char *str)
+{
+ int i, j;
+ wchar_t wc;
+
+ if(!str) return 0L;
+ for(i = j = 0; str[i] && j < 4090; i++) {
+ switch(str[i]) {
+ case '"':
+ j += sprintf(TmpTxt+j, """);
+ break;
+ case '&':
+ j += sprintf(TmpTxt+j, "&");
+ break;
+ case '<':
+ j += sprintf(TmpTxt+j, "<");
+ break;
+ case '>':
+ j += sprintf(TmpTxt+j, ">");
+ break;
+ default:
+ if((unsigned char)str[i] <= 127) TmpTxt[j++]=str[i];
+ else {
+ if(mbtowc(&wc, str+i, 1) >0) j += sprintf(TmpTxt+j,
+ "&#%d;", ((unsigned short)wc));
+ }
+ }
+ }
+ TmpTxt[j] = 0;
+ return(TmpTxt);
+}
+
+// split string str into array of strings using sep as separator
+// return number of lines created in nl
+char **split(char *str, char sep, int *nl)
+{
+ int i, j, k, l, ns;
+ char **ptr, *txt;
+
+ if(!str || !sep) return 0L;
+ if(!(txt = strdup(str))) return 0L;
+ k = (int)strlen(txt);
+ for(i = ns = 0; i < k; i++) if(txt[i] == sep) ns++;
+ if(!(ptr = (char**)calloc(ns+2, sizeof(char*)))){
+ free(txt); return 0L;
+ }
+ for(i = j = l = 0; i < k; i++) {
+ if(txt[i] == sep) {
+ txt[i] = 0; ptr[l++] = strdup(txt+j); j = i+1;
+ }
+ }
+ ptr[l++] = strdup(txt+j); if(nl) *nl = l; free(txt);
+ return ptr;
+}
+
+//----------------------------------------------------------------------------
+// bounding rectangle utilities
+//----------------------------------------------------------------------------
+void SetMinMaxRect(RECT *rc, int x1, int y1, int x2, int y2)
+{
+ if(x1 > x2) {
+ rc->left = x2; rc->right = x1;
+ }
+ else {
+ rc->left = x1; rc->right = x2;
+ }
+ if(y1 > y2) {
+ rc->top = y2; rc->bottom = y1;
+ }
+ else {
+ rc->top = y1; rc->bottom = y2;
+ }
+}
+
+void UpdateMinMaxRect(RECT *rc, int x, int y)
+{
+ if(x < rc->left) rc->left = x;
+ if(x > rc->right) rc->right = x;
+ if(y < rc->top) rc->top = y;
+ if(y > rc->bottom) rc->bottom = y;
+}
+
+void IncrementMinMaxRect(RECT *rc, int i)
+{
+ rc->left -= i; rc->right += i;
+ rc->top -= i; rc->bottom += i;
+}
+
+bool IsInRect(RECT *rc, int x, int y)
+{
+ if(x < rc->left || x > rc->right ||
+ y < rc->top || y > rc->bottom) return false;
+ return true;
+}
+
+//----------------------------------------------------------------------------
+// test if point (e.g. mouse position) is close to or iside a shape
+//----------------------------------------------------------------------------
+bool IsCloseToLine(POINT *p1, POINT *p2, int x, int y)
+{
+ bool bFound = false;
+ int tmp, dx, dy;
+
+ //do not process single point
+ if(p1->x == p2->x && p1->y == p2->y) return false;
+ //point must be bracketed by p1:p2
+ if((x-2) > p1->x && (x-2) > p2->x) return false;
+ if((x+2) < p1->x && (x+2) < p2->x) return false;
+ if((y-2) > p1->y && (y-2) > p2->y) return false;
+ if((y+2) < p1->y && (y+2) < p2->y) return false;
+ if(abs(dx = (p2->x - p1->x)) < abs(dy = (p2->y - p1->y))) { //y dominant
+ tmp = (p1->x + ((y - p1->y) * dx)/dy);
+ if(x > (tmp-3) && x < (tmp+3)) bFound = true;
+ }
+ else { // x dominant
+ tmp = (p1->y + ((x - p1->x) * dy)/dx);
+ if(y > (tmp-3) && y < (tmp+3)) bFound = true;
+ }
+ return bFound;
+}
+
+bool IsCloseToPL(POINT p, POINT *pts, int cp)
+{
+ int i;
+
+ for( i = 1; i < cp; i++) if(IsCloseToLine(pts+i-1, pts+i, p.x, p.y)) return true;
+ return false;
+}
+
+//test if poitn p is within the polygon pts of size cp
+//note: the last point of the polypon should be equal to the first point,
+// i.e. the polygon must be closed
+int idx_point_on_line;
+bool IsInPolygon(POINT *p, POINT *pts, int cp)
+{
+ int tmp1 = 0, tmp2 = 0, tmp3, i;
+
+ for(i = 1; i < cp; i++) {
+ if((pts[i-1].x <= p->x && pts[i].x > p->x) || (pts[i-1].x > p->x && pts[i].x <= p->x)) {
+ tmp3 = ((p->x - pts[i-1].x)*(pts[i].y -pts[i-1].y))/(pts[i].x - pts[i-1].x);
+ tmp3 += pts[i-1].y;
+ if(p->y > tmp3) tmp1++;
+ else if(p->y < tmp3) tmp2++;
+ else return false; //ignore points on the line
+ }
+ }
+ return((tmp1 & 0x1) && (tmp2 & 0x1));
+}
+
+bool IsInPolygon3D(double x, double y, POINT3D *pts, int cp, int *us, int *ls)
+{
+ int tmp1 = 0, tmp2 = 0, i, idx1, idx2;
+ double tmp3;
+
+ for(i = 1, idx1 = idx2 = -1; i < cp; i++) {
+ if((pts[i-1].x <= x && pts[i].x > x) || (pts[i-1].x > x && pts[i].x <= x)) {
+ tmp3 = ((x - pts[i-1].x)*(pts[i].y -pts[i-1].y))/(pts[i].x - pts[i-1].x);
+ tmp3 += pts[i-1].y;
+ if(y > tmp3){
+ tmp1++; idx1 = i;
+ }
+ else if(y < tmp3) {
+ tmp2++; idx2 = i;
+ }
+ else { //points is on the line
+ idx1 = idx2 = idx_point_on_line = i;
+ if(us) *us = idx1; if(ls) *ls = idx2;
+ return true;
+ }
+ }
+ }
+ //return an index to the bracketing sgments of the polygon
+ if(us) *us = idx1; if(ls) *ls = idx2;
+ return((tmp1 & 0x1) && (tmp2 & 0x1));
+}
+
+//return true if two rectangles overlap
+bool OverlapRect(RECT *rc1, RECT *rc2)
+{
+ if((rc1->left < rc2->right && rc1->right > rc2->left) ||
+ (rc2->left < rc1->right && rc2->right > rc1->left)) {
+ if((rc1->top < rc2->bottom && rc1->bottom > rc2->top) ||
+ (rc2->top < rc1->bottom && rc2->bottom > rc1->top))
+ return true;
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------------
+// collect points to a polygon
+// keep number of points low by extrapolation
+//----------------------------------------------------------------------------
+void AddToPolygon(long *cp, POINT *pts, POINT *np)
+{
+ int ix, iy;
+ long i = *cp;
+
+ if(i && pts[i-1].x == np->x && pts[i-1].y == np->y) return;
+ if(i < 2) { //accept first points of polygon
+ pts[i].x = np->x; pts[i].y = np->y; *cp = i+1;
+ return;
+ }
+ if(pts[i-1].x == pts[i-2].x && pts[i-1].x == np->x) {
+ if(np->y == pts[i-1].y) return;
+ if((np->y > pts[i-1].y && pts[i-1].y > pts[i-2].y) ||
+ (np->y < pts[i-1].y && pts[i-1].y < pts[i-2].y)) {
+ pts[i-1].x = np->x;
+ pts[i-1].y = np->y;
+ return;
+ }
+ }
+ if(pts[i-1].y == pts[i-2].y && pts[i-1].y == np->y) {
+ if(np->x == pts[i-1].x) return;
+ if((np->x > pts[i-1].x && pts[i-1].x > pts[i-2].x) ||
+ (np->x < pts[i-1].x && pts[i-1].x < pts[i-2].x)) {
+ pts[i-1].x = np->x;
+ pts[i-1].y = np->y;
+ return;
+ }
+ }
+ //try linear extrapolation
+ if((pts[i-1].x > pts[i-2].x && np->x > pts[i-1].x) ||
+ (pts[i-1].x < pts[i-2].x && np->x < pts[i-1].x)) {
+ ix = (pts[i-1].y != pts[i-2].y) ? (pts[i-2].x + ((np->y - pts[i-2].y) *
+ (pts[i-1].x - pts[i-2].x))/(pts[i-1].y - pts[i-2].y)) : 0;
+ iy = (pts[i-1].x != pts[i-2].x) ? (pts[i-2].y + ((np->x - pts[i-2].x) *
+ (pts[i-1].y - pts[i-2].y))/(pts[i-1].x - pts[i-2].x)) : 0;
+ if((ix && ix == np->x) || (iy && iy == np->y)) {
+ pts[i-1].x = np->x;
+ pts[i-1].y = np->y;
+ return;
+ }
+ }
+ //not explained by extrapolation, accept new point
+ pts[i].x = np->x;
+ pts[i].y = np->y;
+ *cp = i+1;
+ return;
+}
+
+//----------------------------------------------------------------------------
+// create a circular polygon
+//use circular Bresenham's algorithm to draw arcs
+//Ref: C. Montani, R. Scopigno (1990) "Speres-To-Voxel Conversion", in:
+// Graphic Gems (A.S. Glassner ed.) Academic Press, Inc.;
+// ISBN 0-12-288165-5
+//----------------------------------------------------------------------------
+POINT *MakeArc(int ix, int iy, int r, int qad, long *npts)
+{
+ int i, x, y, di, de, lim;
+ static POINT *pts, *rpts;
+ POINT np;
+
+ if(r < 1) return 0L;
+ if(!(pts = (POINT*) malloc((r+1)*8*sizeof(POINT))))return 0L;
+ for(i = *npts = 0; i < 4; i++) {
+ x = lim = 0; y = r; di = 2*(1-r);
+ if(qad & (1<<i))while (y >= lim){
+ if(di < 0) {
+ de = 2*di + 2*y -1;
+ if(de > 0) {
+ x++; y--; di += (2*x -2*y +2);
+ }
+ else {
+ x++; di += (2*x +1);
+ }
+ }
+ else {
+ de = 2*di -2*x -1;
+ if(de > 0) {
+ y--; di += (-2*y +1);
+ }
+ else {
+ x++; y--; di += (2*x -2*y +2);
+ }
+ }
+ switch(i) {
+ case 0: np.x = ix-y; np.y = iy+x; break;
+ case 1: np.x = ix+x; np.y = iy+y; break;
+ case 2: np.x = ix+y; np.y = iy-x; break;
+ case 3: np.x = ix-x; np.y = iy-y; break;
+ }
+ AddToPolygon(npts, pts, &np);
+ }
+ }
+ if(*npts < 3) return 0L;
+ if(rpts = (POINT*)realloc(pts, sizeof(POINT)*(*npts))) return rpts;
+ return pts;
+}
+
+//----------------------------------------------------------------------------
+// display a marked polygon by displaying it with complement colors
+//----------------------------------------------------------------------------
+void InvertPolygon(POINT *pts, int nPts, LineDEF *Line, FillDEF *Fill, RECT *rc,
+ anyOutput *o, bool mark)
+{
+ LineDEF *FillLine;
+
+ if(!Line || !Fill || !rc || !o) return;
+ FillLine = Fill->hatch;
+ if(mark) {
+ if(FillLine)FillLine->color ^= 0x00ffffffL;
+ Fill->color ^= 0x00ffffffL;
+ Line->color ^= 0x00ffffffL;
+ o->SetLine(Line);
+ o->SetFill(Fill);
+ o->oPolygon(pts, nPts);
+ Fill->color ^= 0x00ffffffL;
+ if(FillLine)FillLine->color ^= 0x00ffffffL;
+ Line->color ^= 0x00ffffffL;
+ InvertLine(pts, nPts, Line, 0L, o, mark);
+ }
+ else {
+ InvertLine(pts, nPts, Line, 0L, o, mark);
+ o->SetLine(Line);
+ o->SetFill(Fill);
+ o->oPolygon(pts, nPts);
+ }
+ if(rc) o->UpdateRect(rc, false);
+}
+
+//----------------------------------------------------------------------------
+// display a marked line using complement colors
+//----------------------------------------------------------------------------
+void InvertLine(POINT *pts, int nPts, LineDEF *Line, RECT *rc,
+ anyOutput *o, bool mark)
+{
+ LineDEF OldLine;
+ double minw = defs.GetSize(SIZE_DATA_LINE);
+
+ memcpy(&OldLine, Line, sizeof(LineDEF));
+ if(OldLine.width <= 0.001) memcpy(&OldLine, defs.GetLine(), sizeof(LineDEF));
+ OldLine.color = mark ? Line->color : 0x00ffffffL;
+ OldLine.width = OldLine.width < minw ? minw * 3.0 : OldLine.width *3.0;
+ o->SetLine(&OldLine);
+ o->oPolyline(pts, nPts);
+ OldLine.width = Line->width;
+ OldLine.color = mark ? Line->color ^ 0x00ffffffL : Line->color;
+ o->SetLine(&OldLine);
+ o->oPolyline(pts, nPts);
+ if(rc) o->UpdateRect(rc, false);
+}
+
+//----------------------------------------------------------------------------
+// color utilitis
+//----------------------------------------------------------------------------
+// calculate distance between two colors
+unsigned int ColDiff(DWORD col1, DWORD col2)
+{
+ int ret = 0, d;
+
+ d = (col1 & 0xff) - (col2 & 0xff);
+ ret = isqr(d*d);
+ d = ((col1>>8) & 0xff) - ((col2>>8) & 0xff);
+ ret += isqr(d*d);
+ d = ((col1>>16) & 0xff) - ((col2>>16) & 0xff);
+ ret += isqr(d*d);
+ return ret;
+}
+
+//----------------------------------------------------------------------------
+// interpolate between two colors
+DWORD IpolCol(DWORD color1, DWORD color2, double fact)
+{
+ DWORD col1, col2, col3, c1;
+ int i;
+
+ col1 = color1; col2 = color2; col3 = 0x0L;
+ for(i = 0; i < 3; i++) {
+ c1 = iround(fabs(((col1 & 0xff0000)>>16) * fact));
+ c1 += iround(fabs(((col2 & 0xff0000)>>16) *(1.0-fact)));
+ col3 |= c1 < 0xff ? c1 : 0xff;
+ col1 <<= 8; col2 <<= 8;
+ if(i < 2) col3 <<= 8;
+ }
+ return col3;
+}
+
+//----------------------------------------------------------------------------
+// Random number generator with low sequential correlations.
+// ran2 returns a number betwee 0.0f and 1.0f;
+// Ref: W.H. Press, B.P. Flannery, S.A. Teukolsky, W.T. Veterling
+// Numerical Recipe in C, The Art of Scientific Computing
+// Cambridge University Press 1988, ISBN 0-521-35465-X
+//----------------------------------------------------------------------------
+#define M 714025
+#define IA 1366
+#define IC 150889
+double ran2(long *idum)
+{
+ static long iy, ir[98];
+ static int iff = 0;
+ int j;
+
+ if(*idum < 0 || iff == 0) {
+ iff = 1;
+ if((*idum = (IC-(*idum)) % M) < 0) *idum = -(*idum);
+ for(j = 1; j <= 97; j++) {
+ *idum = (IA*(*idum)+IC) % M;
+ ir[j] = (*idum);
+ }
+ *idum=(IA*(*idum)+IC) % M;
+ iy=(*idum);
+ }
+ j = 1+97 * iy/M;
+ if(j > 97 || j< 1) return 0.0f; //impossible
+ iy = ir[j];
+ *idum = (IA*(*idum)+IC) % M;
+ ir[j] = (*idum);
+ return (float) iy/M;
+}
+#undef IC
+#undef IA
+#undef M
+
+//----------------------------------------------------------------------------
+// integer square root
+// calculate the largest number <= sqr(n)
+// Christopher J. Musial in Graphics Gems II, page 37ff, page 610
+// Academic Press, 1991
+// modified
+//----------------------------------------------------------------------------
+
+unsigned long int isqr(unsigned long int n)
+{
+ unsigned long int nextTrial, decrement;
+
+ if (nextTrial = n>>1) {
+ for ( ; ; ){
+ if(decrement = (nextTrial - n/nextTrial)>>1) nextTrial -= decrement;
+ else if(nextTrial * nextTrial > n) return nextTrial-1;
+ else return nextTrial;
+ }
+ }
+ return n;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// multiply two rotation matrices
+// see: Graphic Gems, A.S. Glassner ed.; Academic Press Inc.
+// ISBN 0-12-286165-5, p.640
+//
+bool MatMul(double a[3][3], double b[3][3], double c[3][3])
+{
+ int i, j, k;
+ bool success = true;
+
+ for(i = 0; i < 3; i++) {
+ for (j = 0; j < 3; j++) {
+ c[i][j] = 0.0;
+ for(k = 0; k < 3; k++) c[i][j] += a[i][k] * b[k][j];
+ if(c[i][j] < -.99999 || c[i][j] > .99999) success = false;
+ }
+ }
+ return success;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//Return a format string depending on the range
+//
+char *GetNumFormat(double Magn)
+{
+ if(Magn < -3.0) return("%0.2le");
+ if(Magn == -3.0) return("%0.4lf");
+ if(Magn == -2.0) return("%0.3lf");
+ if(Magn == -1.0) return("%0.2lf");
+ if(Magn == 0.0) return("%0.1lf");
+ if(Magn >= 5.0) return("%0.2le");
+ return("%0.0lf");
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//Delete a graphic object using the Id member of the class to select the
+// the proper destructor
+void DeleteGO(GraphObj *go)
+{
+ if(!go) return;
+ if(!go->Id) {
+ //this will also set the Id member of the class
+ go->Command(CMD_SET_DATAOBJ, 0L, 0L);
+ }
+ if(go == CurrGO) CurrGO = 0L;
+ switch(go->Id) {
+ case GO_AXIS: delete((Axis*)go); break;
+ case GO_TICK: delete((Tick*)go); break;
+ case GO_GRIDLINE: delete((GridLine*)go); break;
+ case GO_GRIDLINE3D: delete((GridLine3D*)go); break;
+ case GO_SYMBOL: delete((Symbol*)go); break;
+ case GO_BUBBLE: delete((Bubble*)go); break;
+ case GO_BAR: delete((Bar*)go); break;
+ case GO_ERRBAR: delete((ErrorBar*)go); break;
+ case GO_ARROW: delete((Arrow*)go); break;
+ case GO_BOX: delete((Box*)go); break;
+ case GO_WHISKER: delete((Whisker*)go); break;
+ case GO_DROPLINE: delete((DropLine*)go); break;
+ case GO_DATALINE:
+ //we call ~DataLine for ~DataPolygon because variables are
+ // initialized in DataLine ??!!??!!
+ // otherwise we would crash with ~DataPolygon.
+ case GO_DATAPOLYGON: delete((DataLine*)go); break;
+ case GO_SPHERE: delete((Sphere*)go); break;
+ case GO_PLANE: delete((plane*)go); break;
+ case GO_BRICK: delete((Brick*)go); break;
+ case GO_LINE3D: delete((Line3D*)go); break;
+ case GO_LABEL: delete((Label*)go); break;
+ case GO_MLABEL: delete((mLabel*)go); break;
+ case GO_SEGMENT: delete((segment*)go); break;
+ case GO_POLYGON:
+ case GO_POLYLINE: delete((polyline*)go); break;
+ case GO_REGLINE: delete((RegLine*)go); break;
+ case GO_SDELLIPSE: delete((SDellipse*)go); break;
+ case GO_ELLIPSE:
+ case GO_ROUNDREC:
+ case GO_RECTANGLE: delete((rectangle*)go); break;
+ case GO_DRAGHANDLE: delete((dragHandle*)go); break;
+ case GO_DRAGRECT: delete((dragRect*)go); break;
+ case GO_DRAG3D: delete((Drag3D*)go); break;
+ case GO_FRAMERECT: delete((FrmRect*)go); break;
+ case GO_PLOT: delete((Plot*)go); break;
+ case GO_BARCHART:
+ case GO_PLOTSCATT: delete((PlotScatt*)go); break;
+ case GO_REGRESSION: delete((Regression*)go); break;
+ case GO_BUBBLEPLOT: delete((BubblePlot*)go); break;
+ case GO_BOXPLOT: delete((BoxPlot*)go); break;
+ case GO_DENSDISP: delete((DensDisp*)go); break;
+ case GO_STACKBAR:
+ case GO_WATERFALL:
+ case GO_STACKPG: delete((StackBar*)go); break;
+ case GO_POLARPLOT: delete((PolarPlot*)go); break;
+ case GO_RINGCHART:
+ case GO_PIECHART: delete((PieChart*)go); break;
+ case GO_GROUP:
+ case GO_STARCHART: delete((GoGroup*)go); break;
+ case GO_SCATT3D: delete((Scatt3D*)go); break;
+ case GO_PLOT3D: delete((Plot3D*)go); break;
+ case GO_PAGE:
+ case GO_GRAPH: delete((Graph*)go); break;
+ case GO_SVGOPTIONS: delete((svgOptions*)go); break;
+ case GO_DROPL3D: delete((DropLine3D*)go); break;
+ case GO_ARROW3D: delete((Arrow3D*)go); break;
+ case GO_LIMITS: delete((Limits*)go); break;
+ case GO_GRIDRADIAL: delete((GridRadial*)go); break;
+ case GO_DEFRW: delete((DefsRW*)go); break;
+ case GO_PLANE3D: delete((Plane3D*)go); break;
+ case GO_RIBBON: delete((Ribbon*)go); break;
+ case GO_FUNCTION: delete((Function*)go); break;
+ case GO_FITFUNC: delete((FitFunc*)go); break;
+ case GO_LEGITEM: delete((LegItem*)go); break;
+ case GO_LEGEND: delete((Legend*)go); break;
+ case GO_OBJTREE: delete((ObjTree*)go); break;
+ case GO_FREQDIST: delete((FreqDist*)go); break;
+ case GO_GRID3D: delete((Grid3D*)go); break;
+ default:
+ sprintf(TmpTxt, "Cannot delete Object\nwith Id %ld", go->Id);
+ ErrorBox(TmpTxt);
+ //we do not delete the object, probably we recover
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//backup file before writing a new one
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool BackupFile(char *FileName)
+{
+ int i;
+ FILE *TheFile;
+ char TmpFileName[512], Name[512], ext[6];
+
+ //no backup necessary if file does not exist
+ if(!(FileExist(FileName))) return true;
+ strcpy(Name, FileName);
+ i = strlen(Name)-1;
+ if(Name[--i] == '.') Name[i] = 0;
+ else if(Name[--i] == '.') Name[i] = 0;
+ else if(Name[--i] == '.') Name[i] = 0;
+ else return false;
+ i = 1;
+ do {
+ sprintf(ext, ".%03d", i);
+ sprintf(TmpFileName, "%s%s", Name, ext);
+ if((TheFile = fopen(TmpFileName, "r"))) fclose(TheFile);
+ i++;
+ } while (i < 999 && TheFile);
+ if(i >= 999) { //too many backups exist already
+ ErrorBox("Too many backup\files exist already.");
+ return false;
+ }
+ if(-1 == rename(FileName, TmpFileName)) {
+ ErrorBox("Error accessing file.");
+ return false;
+ }
+ return true;
+}
+
+bool IsRlpFile(char *FileName)
+{
+ FILE *TheFile;
+ char Line[10];
+ bool bRet = false;
+
+ if(0L ==(TheFile = fopen(FileName, "r"))) return false;
+ fread(Line, 1, 8, TheFile);
+ Line[5] = 0;
+ if(0 == strcmp(Line, ";RLP "))bRet = true;
+ fclose(TheFile);
+ return bRet;
+}
+
+bool IsXmlFile(char *FileName)
+{
+ FILE *TheFile;
+ char Line[10];
+ bool bRet = false;
+
+ if(0L ==(TheFile = fopen(FileName, "r"))) return false;
+ fread(Line, 1, 8, TheFile);
+ Line[6] = 0;
+ if(0 == strcmp(Line, "<?xml "))bRet = true;
+ fclose(TheFile);
+ return bRet;
+}
+
+bool FileExist(char *FileName)
+{
+ FILE *TheFile;
+
+ if(0L ==(TheFile = fopen(FileName, "r"))) return false;
+ fclose(TheFile);
+ return true;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//duplicate a block of memory
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void *memdup(void *ptr, int cb_old, int cb_new)
+{
+ void *p;
+
+ if(cb_new > cb_old) {
+ if((p = calloc(cb_new, 1)) && ptr) memcpy(p, ptr, cb_old);
+ }
+ else {
+ if((p = malloc(cb_old)) && ptr) memcpy(p, ptr, cb_old);
+ }
+ return p;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//calculate angle from sin(angle)
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+double trig2deg(double si, double csi)
+{
+ double ang;
+
+ ang = acos(csi);
+ if(si < 0.0) ang *= -1.0;
+ return floor(ang * 57.29577951 +0.5);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//replace graphic object with new: typically used for undo
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool ReplaceGO(GraphObj **oldobj, GraphObj **newobj)
+{
+ newobj[1]->parent = newobj[0]->parent;
+ newobj[1]->Command(CMD_SET_DATAOBJ, newobj[0]->data, 0L);
+ *oldobj = newobj[1];
+ newobj[0]->parent = 0L; //disable messaging
+ Undo.InvalidGO(newobj[0]);
+ DeleteGO(newobj[0]);
+ return true;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//calculate a 'unique' hash value for a string
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+unsigned int HashValue(unsigned char *str)
+{
+ unsigned int i = 0, ret=0;
+
+ if(!str) return 0;
+ do {
+ if(str[i] > 32) ret = ((str[i]-32) + (ret <<2));
+ i++;
+ }while(str[i]);
+ return ret;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//compare data structures: return true if changed or save undo info
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool cmpLineDEF(LineDEF *l1, LineDEF *l2)
+{
+ if(!l1 || !l2 || l1 == l2) return false; //oh, oh !
+ if(l1->width != l2->width) return true;
+ if(l1->patlength != l2->patlength) return true;
+ if(l1->color != l2->color) return true;
+ if(l1->pattern != l2->pattern) return true;
+ return false;
+}
+
+bool cmpFillDEF(FillDEF *f1, FillDEF *f2)
+{
+ if(!f1 || !f2 || f1 == f2) return false; //oh, oh!
+ if(f1->type != f2->type || f1->color != f2->color ||
+ f1->scale != f2->scale || f1->color2 != f2->color2) return true;
+ //the hatch line is subject to a separate call to cmpLineDEF
+ return false;
+}
+
+bool cmpAxisDEF(AxisDEF *a1, AxisDEF *a2)
+{
+ int i;
+
+ if(!a1 || !a2 || a1 == a2) return false; //oh, oh!
+ if(a1->flags != a2->flags || a1->min != a2->min || a1->max != a2->max ||
+ a1->loc[0].fx != a2->loc[0].fx || a1->loc[0].fy != a2->loc[0].fy ||
+ a1->loc[0].fz != a2->loc[0].fz || a1->loc[1].fx != a2->loc[1].fx ||
+ a1->loc[1].fy != a2->loc[1].fy || a1->loc[1].fz != a2->loc[1].fz ||
+ a1->Start != a2->Start || a1->Step != a2->Step || a1->Radius != a2->Radius ||
+ a1->Center.fx != a2->Center.fx || a1->Center.fy != a2->Center.fy ||
+ a1->nBreaks != a2->nBreaks) return true;
+ for(i = 0; i < a1->nBreaks; i++) {
+ if(a1->breaks[i].fx != a2->breaks[i].fx ||
+ a1->breaks[i].fy != a2->breaks[i].fy) return true;
+ }
+ return false;
+}
+
+bool cmpTextDEF(TextDEF *t1, TextDEF *t2)
+{
+ if(!t1 || !t2) return false;
+ if(t1->ColTxt != t2->ColTxt || t1->ColBg != t2->ColBg || t1->fSize != t2->fSize ||
+ t1->RotBL != t2->RotBL || t1->RotCHAR != t2->RotCHAR || t1->iSize != t2->iSize ||
+ t1->Align != t2->Align || t1->Mode != t2->Mode || t1->Style != t2->Style ||
+ t1->Font != t2->Font) return true;
+ if((!(t1->text) && (t2->text)) || (!(t2->text) && (t1->text))) return true;
+ if(t1->text && t2->text && strcmp(t1->text, t2->text)) return true;
+ return false;
+}
+
+// Dialog Undo utilitites
+DWORD CheckNewFloat(double *loc, double old_v, double new_v, GraphObj *par, DWORD flags)
+{
+ if(loc && old_v != new_v) {
+ Undo.ValFloat(par, loc, flags);
+ *loc = new_v; return (flags | UNDO_CONTINUE);
+ }
+ return flags;
+}
+
+DWORD CheckNewInt(int *loc, int old_v, int new_v, GraphObj *par, DWORD flags)
+{
+ if(loc && old_v != new_v) {
+ Undo.ValInt(par, loc, flags);
+ *loc = new_v; return (flags | UNDO_CONTINUE);
+ }
+ return flags;
+}
+
+DWORD CheckNewDword(DWORD *loc, DWORD old_v, DWORD new_v, GraphObj *par, DWORD flags)
+{
+ if(loc && old_v != new_v) {
+ Undo.ValDword(par, loc, flags);
+ *loc = new_v; return (flags | UNDO_CONTINUE);
+ }
+ return flags;
+}
+
+DWORD CheckNewLFPoint(lfPOINT *loc, lfPOINT *old_v, lfPOINT *new_v, GraphObj *par, DWORD flags)
+{
+ if(loc && old_v && new_v && (old_v->fx != new_v->fx || old_v->fy != new_v->fy)) {
+ Undo.SaveLFP(par, loc, flags);
+ loc->fx = new_v->fx; loc->fy = new_v->fy; return (flags | UNDO_CONTINUE);
+ }
+ return flags;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//execute clipping of 3D objects
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+typedef struct { //structure required by 3D Bresenhan's algorithm
+ int d, a, s, *r, l;
+ }moveDEF;
+
+long sph_r2;
+int sph_x, sph_y, sph_z, nclp_pg, seg_x_seg;
+POINT3D *clp_pg, *sphlim1, *sphlim2;
+double *vclp_pg = 0L;
+
+int test_sphere(int x, int y, int z)
+{
+ int d;
+ long ld;
+
+ ld = (d = x-sph_x) * d; ld += (d = y-sph_y) * d;
+ ld += (d = z-sph_z) * d;
+ return (ld > sph_r2) ? 1 : 0;
+}
+
+//use a 3D Bresenham alorithm to find z coordinates where x == lx or y == ly
+bool line3D_z(POINT3D *p1, POINT3D *p2, int lx, int ly, int *cx, int *cy, int *cz)
+{
+ moveDEF mx, my, mz, *m1, *m2, *m3;
+ int x, y, z, d1, d2;
+
+ mx.d = p2->x - p1->x; mx.a = mx.d >= 0 ? mx.d : -mx.d;
+ mx.s = mx.d >= 0 ? 1 : -1; mx.r = &x; mx.l = p2->x; x = p1->x;
+ my.d = p2->y - p1->y; my.a = my.d >= 0 ? my.d : -my.d;
+ my.s = my.d >= 0 ? 1 : -1; my.r = &y; my.l = p2->y; y = p1->y;
+ mz.d = p2->z - p1->z; mz.a = mz.d >= 0 ? mz.d : -mz.d;
+ mz.s = mz.d >= 0 ? 1 : -1; mz.r = &z; mz.l = p2->z; z = p1->z;
+ if(mx.a > my.a) {
+ if(mz.a > mx.a) {
+ m1 = &mz; m2 = &mx; m3 = &my;
+ }
+ else if(mz.a > my.a) {
+ m1 = &mx; m2 = &mz; m3 = &my;
+ }
+ else {
+ m1 = &mx; m2 = &my; m3 = &mz;
+ }
+ }
+ else {
+ if(mz.a > my.a) {
+ m1 = &mz; m2 = &my; m3 = &mx;
+ }
+ else if(mz.a > mx.a) {
+ m1 = &my; m2 = &mz; m3 = &mx;
+ }
+ else {
+ m1 = &my; m2 = &mx; m3 = &mz;
+ }
+ }
+ d1 = m2->a - (m1->a >>1); d2 = m3->a - (m1->a >>1);
+ for(; ;) {
+ //process point at (m1.r, m2.r, m3.r);
+ if(x == lx || y == ly) {
+ *cx = x; *cy = y; *cz = z;
+ return true;
+ }
+ if(*(m1->r) == m1->l) return false;
+ if(d1 >= 0) {
+ *(m2->r) += m2->s; d1 -= m1->a;
+ }
+ if(d2 >= 0) {
+ *(m3->r) += m3->s; d2 -= m1->a;
+ }
+ *(m1->r) += m1->s; d1 += m2->a; d2 += m3->a;
+ }
+}
+
+//test if point is 1) outside, 2) above, 3) on the line, or 0) hidden by a plane
+int test_plane(int x, int y, int z)
+{
+ int us, ls, us1, ls1, x1, y1, z1, x2, y2, z2;
+ static int last = 0;
+ POINT3D p1, p2;
+
+ if(IsInPolygon3D(x, y, clp_pg, nclp_pg, &us, &ls)) {
+ if(us == ls){
+ seg_x_seg = us;
+ return last = 3; //point is on line: visible
+ }
+ if(vclp_pg) {
+ if(iround((x * vclp_pg[0] + y * vclp_pg[1] - vclp_pg[3])/vclp_pg[2]) < z)
+ return last = 2;
+ else return last = 0;
+ }
+ if(us < 1) us1 = nclp_pg -1; else us1 = us -1;
+ if(ls < 1) ls1 = nclp_pg -1; else ls1 = ls -1;
+ if(z < clp_pg[us1].z && z < clp_pg[us].z && z < clp_pg[ls1].z &&
+ z < clp_pg[ls].z) return last = 0; //far below plane
+ if(z > clp_pg[us1].z && z > clp_pg[us].z && z > clp_pg[ls1].z &&
+ z > clp_pg[ls].z) return last = 2; //far above plane
+ if(line3D_z(&clp_pg[us1], &clp_pg[us], x, -1, &x1, &y1, &z1) &&
+ line3D_z(&clp_pg[ls1], &clp_pg[ls], x, -1, &x2, &y2, &z2)){
+ if(z1 < z && z2 < z) return last = 2;
+ if(z1 >= z && z2 >= z) return last = 0;
+ p1.x = x1; p1.y = y1; p1.z = z1; p2.x = x2; p2.y = y2; p2.z = z2;
+ if(line3D_z(&p1, &p2, -1, y, &x1, &y1, &z1)) {
+ if(z > z1) return last = 2;
+ else return last = 0;
+ }
+ }
+ return last;
+ }
+ return last = 1;
+}
+
+int test_planeandline(int x, int y, int z)
+{
+ int ret;
+
+ ret = test_plane(x, y, z);
+ if(ret == 3 && clp_pg && nclp_pg && idx_point_on_line < nclp_pg) {
+ if(vclp_pg) {
+ if(iround((x * vclp_pg[0] + y * vclp_pg[1] - vclp_pg[3])/vclp_pg[2]) < z)
+ return 2;
+ else return 0;
+ }
+ else {
+ // no equation for plane available
+ }
+ }
+ return ret;
+}
+
+
+void proc_polygon(int vis, POINT3D *pnt, POINT3D * last); //prototype
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//use a 3D Bresenham algorithm to clip lines
+void clip_line_3D(GraphObj *go, POINT3D *p1, POINT3D *p2, int(*proc)(int, int, int))
+{
+ moveDEF mx, my, mz, *m1, *m2, *m3;
+ int x, y, z, d1, d2, vis;
+ bool bVisible, bDrawLater = false;
+ POINT3D p, lp;
+
+ if(p1->x == p2->x && p1->y == p2->y && p1->z == p2->z) return;
+ mx.d = p2->x - p1->x; mx.a = mx.d >= 0 ? mx.d : -mx.d;
+ mx.s = mx.d >= 0 ? 1 : -1; mx.r = &x; mx.l = p2->x; x = p1->x;
+ my.d = p2->y - p1->y; my.a = my.d >= 0 ? my.d : -my.d;
+ my.s = my.d >= 0 ? 1 : -1; my.r = &y; my.l = p2->y; y = p1->y;
+ mz.d = p2->z - p1->z; mz.a = mz.d >= 0 ? mz.d : -mz.d;
+ mz.s = mz.d >= 0 ? 1 : -1; mz.r = &z; mz.l = p2->z; z = p1->z;
+ if(mx.a > my.a) {
+ if(mz.a > mx.a) {
+ m1 = &mz; m2 = &mx; m3 = &my;
+ }
+ else if(mz.a > my.a) {
+ m1 = &mx; m2 = &mz; m3 = &my;
+ }
+ else {
+ m1 = &mx; m2 = &my; m3 = &mz;
+ }
+ }
+ else {
+ if(mz.a > my.a) {
+ m1 = &mz; m2 = &my; m3 = &mx;
+ }
+ else if(mz.a > mx.a) {
+ m1 = &my; m2 = &mz; m3 = &mx;
+ }
+ else {
+ m1 = &my; m2 = &mx; m3 = &mz;
+ }
+ }
+ bVisible = (0 != (vis = (*proc)(x, y, z)));
+ if((bDrawLater = (vis == 2)) && go) go->Command(CMD_DRAW_LATER, 0L, 0L);
+ lp.x = p1->x; lp.y = p1->y; lp.z = p1->z;
+ if(!go && vis) proc_polygon(vis, p1, p1);
+ d1 = m2->a - (m1->a >>1); d2 = m3->a - (m1->a >>1);
+ for(; ;) {
+ //process point at (m1.r, m2.r, m3.r);
+ vis = (*proc)(x, y, z);
+ if(!bDrawLater && vis == 2){
+ if(go) go->Command(CMD_DRAW_LATER, 0L, 0L);
+ bDrawLater = true;
+ }
+ if(bVisible) {
+ if(!vis) {
+ p.x = x; p.y = y; p.z = z;
+ if(go) go->Command(CMD_ADDTOLINE, &lp, 0L);
+ else proc_polygon(vis, &p, &lp);
+ bVisible = false;
+ }
+ }
+ else if(vis){
+ p.x = x; p.y = y; p.z = z;
+ if(go) go->Command(CMD_STARTLINE, &p, 0L);
+ else proc_polygon(vis, &p, &lp);
+ bVisible = true;
+ }
+ if(*(m1->r) == m1->l){
+ if(vis){
+ p.x = x; p.y = y; p.z = z;
+ if(go) go->Command(CMD_ADDTOLINE, &p, 0L);
+ else proc_polygon(vis, &p, &lp);
+ }
+ return;
+ }
+ lp.x = x; lp.y = y; lp.z = z;
+ if(d1 >= 0) {
+ *(m2->r) += m2->s; d1 -= m1->a;
+ }
+ if(d2 >= 0) {
+ *(m3->r) += m3->s; d2 -= m1->a;
+ }
+ *(m1->r) += m1->s; d1 += m2->a; d2 += m3->a;
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//use circular Bresenham's algorithm to clip a spherical scanline
+//Ref: C. Montani, R. Scopigno (1990) "Speres-To-Voxel Conversion", in:
+// Graphic Gems (A.S. Glassner ed.) Academic Press, Inc.;
+// ISBN 0-12-288165-5
+void clip_spher_line(GraphObj *go, POINT3D *cent, int r, bool bVert, int(*proc)(int, int, int))
+{
+ int x, y, q, di, de, lim;
+ int vis = 0, o_vis;
+ POINT3D cpos;
+
+ if(r < 1) return;
+ cpos.x = cent->x; cpos.y = cent->y; cpos.z = cent->z;
+ if(bVert) cpos.y -= r;
+ else cpos.x -= r;
+ for(q = 0; q < 2; q++) {
+ x = lim = 0; y = r; di = 2*(1-r);
+ while (y >= lim){
+ o_vis = vis;
+ if(bVert && (cpos.x < sphlim1->x || cpos.x > sphlim2->x)) vis = 0;
+ else if (cpos.y < sphlim1->y || cpos.y > sphlim2->y) vis = 0;
+ else if (cpos.x > 0 && cpos.y >0) vis = (*proc)(cpos.x, cpos.y, cpos.z);
+ if(vis != o_vis) {
+ if(vis) go->Command(CMD_STARTLINE, &cpos, 0L);
+ else go->Command(CMD_ADDTOLINE, &cpos, 0L);
+ }
+ if(di < 0) {
+ de = 2*di + 2*y -1;
+ if(de > 0) {
+ x++; y--; di += (2*x -2*y +2);
+ }
+ else {
+ x++; di += (2*x +1);
+ }
+ }
+ else {
+ de = 2*di -2*x -1;
+ if(de > 0) {
+ y--; di += (-2*y +1);
+ }
+ else {
+ x++; y--; di += (2*x -2*y +2);
+ }
+ }
+ switch(q) {
+ case 0:
+ if(bVert) cpos.y = cent->y - y;
+ else cpos.x = cent->x - y;
+ cpos.z = cent->z + x;
+ break;
+ case 1:
+ if(vis && y < lim) go->Command(CMD_ADDTOLINE, &cpos, 0L);
+ if(bVert) cpos.y = cent->y + x;
+ else cpos.x = cent->x + x;
+ cpos.z = cent->z + y;
+ break;
+ }
+ }
+ }
+ return;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//come here to process polygon clipping events
+int ppg_vis, ppg_level, ppg_reason, ppg_firstvis, ppg_nact, ppg_nmask;
+bool ppg_nowvis;
+POINT *ppg_mask;
+POINT3D ppg_first, *ppg_act;
+GraphObj *ppg_par;
+double *ppg_vec = 0L;
+
+// test if point is on line of 3D polygon
+//Ref: P.S. Heckbert (1990) "Digital Line Drawing", in: Graphic Gems
+// (A.S. Glassner, ed.); Academic Press, Inc.,
+// ISBN 0-12-286165-5
+// void AddToPolygon(long *cp, POINT *pts, POINT *np);
+bool IsOnLine(POINT *p1, POINT *p2, int x, int y)
+{
+ int d, ax, ay, sx, sy, dx, dy;
+ POINT tr;
+
+ dx = p2->x - p1->x;
+ if ( p2->x < p1->x) { ax = (-dx)<<1; sx = -1; }
+ else { ax = dx <<1; sx = 1; }
+ dy = p2->y - p1->y;
+ if (p2->y < p1->y) { ay = (-dy)<<1; sy = -1; }
+ else { ay = dy<<1; sy = 1; }
+ tr.x = p1->x; tr.y = p1->y;
+ if (ax > ay) { // x dominant
+ d = ay - (ax >>1);
+ for ( ; ; ) {
+ if(tr.y == y && tr.x == x) return true; //match
+ if(tr.x == p2->x) return false;
+ if (d >= 0) {tr.y += sy; d -= ax;}
+ tr.x += sx; d += ay;
+ }
+ }
+ else { // y dominant
+ d = ax - (ay >>1);
+ for ( ; ; ) {
+ if(tr.x == x && tr.y == y) return true; //match
+ if (tr.y == p2->y) return false;
+ if (d >= 0) {tr.x += sx; d -= ay;}
+ tr.y += sy; d += ax;
+ }
+ }
+}
+
+//use Bresenham's algorithm to complete a partially hidden polygon
+// by the shadow of the above surface
+//Ref: P.S. Heckbert (1990) "Digital Line Drawing", in: Graphic Gems
+// (A.S. Glassner, ed.); Academic Press, Inc.,
+// ISBN 0-12-286165-5
+// void AddToPolygon(long *cp, POINT *pts, POINT *np);
+bool ShadowPolygon(POINT *p1, POINT *p2, POINT *tp, int ntp, POINT *pts, long *cp, POINT *lim)
+{
+ int d, ax, ay, sx, sy, dx, dy;
+ bool bPen, vis;
+ POINT tr, mp;
+ long d1, ndist, dist = 99999;
+
+ dx = p2->x - p1->x;
+ if ( p2->x < p1->x) { ax = (-dx)<<1; sx = -1; }
+ else { ax = dx <<1; sx = 1; }
+ dy = p2->y - p1->y;
+ if (p2->y < p1->y) { ay = (-dy)<<1; sy = -1; }
+ else { ay = dy<<1; sy = 1; }
+ tr.x = p1->x; tr.y = p1->y;
+ bPen = IsInPolygon(&tr, tp, ntp) || IsCloseToPL(tr, tp, ntp);
+ AddToPolygon(cp, pts, p1); //first Point is always visible
+ if (ax > ay) { // x dominant
+ d = ay - (ax >>1);
+ for ( ; ; ) {
+ if(abs(tr.y - lim->y) < 3 && abs(tr.x - lim->x) < 3) {
+ ndist = (d1=(tr.y - lim->y))*d1;
+ ndist += ((d1=(tr.x - lim->x))*d1);
+ if(ndist <= dist) {
+ mp.x = tr.x; mp.y = tr.y; dist = ndist;
+ }
+ else {
+ //mp is the closest point
+ AddToPolygon(cp, pts, &mp);
+ return false;
+ }
+ }
+ vis = IsInPolygon(&tr, tp, ntp) || IsCloseToPL(tr, tp, ntp);
+ if(bPen && !vis) {
+ AddToPolygon(cp, pts, &tr);
+ return false; //now leaving the polygon
+ }
+ if(tr.x == p2->x) return true; //still inside
+ if (d >= 0) {tr.y += sy; d -= ax;}
+ bPen = vis; tr.x += sx; d += ay;
+ }
+ }
+ else { // y dominant
+ d = ax - (ay >>1);
+ for ( ; ; ) {
+ if(abs(tr.x - lim->x) < 3 && abs(tr.y - lim->y) < 3) {
+ ndist = (d1=(tr.y - lim->y))*d1;
+ ndist += ((d1=(tr.x - lim->x))*d1);
+ if(ndist <= dist) {
+ mp.x = tr.x; mp.y = tr.y; dist = ndist;
+ }
+ else {
+ //mp is the closest point
+ AddToPolygon(cp, pts, &mp);
+ return false;
+ }
+ }
+ vis = IsInPolygon(&tr, tp, ntp) || IsCloseToPL(tr, tp, ntp);
+ if(bPen && !vis) {
+ AddToPolygon(cp, pts, &tr);
+ return false; //now leaving the polygon
+ }
+ if (tr.y == p2->y) return true; //still inside
+ if (d >= 0) {tr.x += sx; d -= ay;}
+ bPen = vis; tr.y += sy; d += ax;
+ }
+ }
+}
+
+//find sepment which is closest to point
+int FindClosestSeg(POINT3D *pg, int npg, int x, int y, int start)
+{
+ int i, i1, j, tmp, idx = -2, dx, dy, d, dist = 10000;
+ POINT p1, p2;
+
+ if(start < 1) start = 1;
+ for(j = start + npg, i1 = start; i1 < j; i1++) {
+ i = ((i1-1)%npg)+1;
+ if( i == npg) {
+ p1.x = pg[i-1].x; p1.y = pg[i-1].y;
+ p2.x = pg[0].x; p2.y = pg[0].y;
+ }
+ else {
+ p1.x = pg[i-1].x; p1.y = pg[i-1].y;
+ p2.x = pg[i].x; p2.y = pg[i].y;
+ }
+ if(p1.x != p2.x || p1.y != p2.y) {
+ d = dist;
+ if(abs(dx = (p2.x - p1.x)) < abs(dy = (p2.y - p1.y))) { //y dominant
+ if(dy && ((p1.y >= y && p2.y < y) || (p2.y > y && p1.y <= y))) {
+ tmp = (p1.x + ((y - p1.y) * dx)/dy); d = abs(x-tmp);
+ }
+ }
+ else { // x dominant
+ if(dx && ((p1.x >= x && p2.x < x) || (p2.x > x && p1.x <= x))) {
+ tmp = (p1.y + ((x - p1.x) * dy)/dx); d = abs(y-tmp);
+ }
+ }
+ if(d < dist) {
+ dist = d; idx = i;
+ }
+ }
+ if(dist < 3) break;
+ }
+ return idx;
+}
+
+//finish a partially visible 3D polygon by its shadow of the above
+// 3D polygon
+bool AddShadowPolygon(POINT3D *pnt, POINT3D *ep, int cidx) {
+ int us, ls, i, j, k, x1, x2, y1, y2, z1, z2, idx_clppg_line;
+ long cpg1 = 0, d, d1, d2, ntp=0, ntp1=0, ntp2=0;
+ POINT *pg1 = 0L, np, *tp=0L, *tp1, *tp2, lim;
+ POINT3D nep;
+ bool bRet = false;
+
+ d = ((d1 = (ep->x - pnt->x))*d1);
+ d += ((d1 = (ep->y - pnt->y))*d1);
+ if(d < 4) { //propably too close
+ if(d) ppg_par->Command(CMD_ADDTOLINE, ep, 0L);
+ return true; //connect
+ }
+ lim.x = ep->x; lim.y = ep->y;
+ idx_clppg_line = FindClosestSeg(clp_pg, nclp_pg, pnt->x, pnt->y, cidx);
+ //create track from hiding polygon
+ //the ppoint 'pnt' is expected to be on the line
+ // clp_pg[idx_clpgg_line] and clp_pg[idx_clpgg_line - 1]
+ if(!(pg1 = (POINT*)calloc(nclp_pg +4, sizeof(POINT))))return true;
+ np.x = pnt->x; np.y = pnt->y; AddToPolygon(&cpg1, pg1, &np);
+ j = idx_clppg_line + nclp_pg;
+ for(i = idx_clppg_line; i < j; i++) {
+ np.x = clp_pg[k = (i%nclp_pg)].x; np.y = clp_pg[k].y;
+ AddToPolygon(&cpg1, pg1, &np);
+ }
+ //close polygon
+ np.x = pnt->x; np.y = pnt->y; AddToPolygon(&cpg1, pg1, &np);
+ //calculate two possible solutions
+ tp1 = (POINT*)calloc(nclp_pg+4, sizeof(POINT));
+ tp2 = (POINT*)calloc(nclp_pg+4, sizeof(POINT));
+ if(!tp1 || !tp2) { //memory allocation error
+ free(pg1); free(ppg_mask); return false;
+ }
+ ShadowPolygon(&pg1[0], &pg1[1], ppg_mask, (int)ppg_nmask, tp1, &ntp1, &lim);
+ if(ntp1 == 1){ //more than one segment
+ for(i = 2; i < cpg1; i++) {
+ if(!ShadowPolygon(&pg1[i-1], &pg1[i], ppg_mask, (int)ppg_nmask, tp1, &ntp1, &lim))
+ break;
+ }
+ }
+ if(i == cpg1) { //last segment required
+ ShadowPolygon(&pg1[i-1], &pg1[0], ppg_mask, (int)ppg_nmask, tp1, &ntp1, &lim);
+ }
+ ShadowPolygon(&pg1[0], &pg1[cpg1-1], ppg_mask, (int)ppg_nmask, tp2, &ntp2, &lim);
+ if(ntp2 == 1){ //more than one segment
+ for(i = cpg1-1; i > 1; i--) {
+ if(!ShadowPolygon(&pg1[i], &pg1[i-1], ppg_mask, (int)ppg_nmask, tp2, &ntp2, &lim))
+ break;
+ }
+ }
+ //find better solution
+ d1 = ((d = (ep->x - tp1[ntp1-1].x))*d); d1 += ((d = (ep->y - tp1[ntp1-1].y))*d);
+ d2 = ((d = (ep->x - tp2[ntp2-1].x))*d); d2 += ((d = (ep->y - tp2[ntp2-1].y))*d);
+ if(d1 < d2 && d1 < 5) { //use solution 1
+ tp = tp1; ntp = ntp1;
+ }
+ else if(d2 < d1 && d2 < 5) { //use solution 2
+ tp = tp2; ntp = ntp2;
+ }
+ else if (d1 == d2 && d1 < 5) { //ambiguous result: connect stright
+ if(d) ppg_par->Command(CMD_ADDTOLINE, ep, 0L);
+ }
+ else { //no valid solution;
+ if(cidx >= 0) return AddShadowPolygon(pnt, ep, -2);
+ bRet = false;
+ }
+ if(tp && ntp>1) { //create shadow line
+ bRet = true;
+ for(i = 1; i < ntp; i++) {
+ if(i == ntp -1) {
+ d = ((d1 = tp[i].x - ep->x) * d1);
+ d += ((d1 = tp[i].y - ep->y) * d1);
+ if(d < 2){ //too close to end point
+ nep.x = ep->x = tp[i].x; nep.y = ep->y = tp[i].y;
+ nep.z = ep->z;
+ break;
+ }
+ }
+ np.x = nep.x = tp[i].x; np.y = nep.y = tp[i].y;
+ nep.z = pnt->z > ep->z ? ep->z : pnt->z;
+ if(IsInPolygon(&np, ppg_mask, ppg_nmask) ||
+ IsCloseToPL(np, ppg_mask, ppg_nmask)){
+ if(ppg_vec) { //valid plane eqation
+ nep.z = iround((nep.x * ppg_vec[0] + nep.y * ppg_vec[1] - ppg_vec[3])/ppg_vec[2]);
+ ppg_par->Command(CMD_ADDTOLINE, &nep, 0L);
+ }
+ else if(IsInPolygon3D(nep.x, nep.y, ppg_act, ppg_nact, &us, &ls)) {
+ if(us == ls) if(ls){ //point is on the line
+ j = nep.z;
+ if(ppg_act[ls].x == ppg_act[ls-1].x && ppg_act[ls].y == ppg_act[ls-1].y){
+ nep.z = (ppg_act[ls].z + ppg_act[ls-1].z)>>1; //impropable
+ }
+ else if(abs(ppg_act[ls].x - ppg_act[ls-1].x) >
+ abs(ppg_act[ls].y - ppg_act[ls-1].y)){ // x dominant
+ line3D_z(&ppg_act[ls-1], &ppg_act[ls], nep.x, -1, &k, &k, &j);
+ }
+ else { // y dominant
+ line3D_z(&ppg_act[ls-1], &ppg_act[ls], -1, nep.y, &k, &k, &j);
+ }
+ nep.z = j;
+ }
+ else {
+ if(line3D_z(&ppg_act[ls-1], &ppg_act[ls], nep.x, -1, &x1, &y1, &z1) &&
+ line3D_z(&ppg_act[us-1], &ppg_act[us], nep.x, -1, &x2, &y2, &z2)){
+ nep.z = (z1 + z2)>>1; //impropable
+ }
+ }
+ ppg_par->Command(CMD_ADDTOLINE, &nep, 0L);
+ }
+ else {
+ //point is inside by one algorithm but outside with another
+ //try without this point
+ }
+ }
+ }
+ if(nep.x != ep->x || nep.y != ep->y) ppg_par->Command(CMD_ADDTOLINE, ep, 0L);
+ }
+ free(pg1); free(tp1); free(tp2);
+ return bRet;
+}
+
+//calculate the clipping line between two planes
+bool CuttingEdge(POINT3D* pt, POINT3D* np)
+{
+ int i, j, us1, ls1, us2, ls2;
+ long d, di[2];
+ POINT3D res[2];
+ double v[3], s[2][3];
+
+ if(!vclp_pg || !ppg_vec) return false;
+ v[0] = vclp_pg[1]*ppg_vec[2] - vclp_pg[2]*ppg_vec[1];
+ v[1] = vclp_pg[2]*ppg_vec[0] - vclp_pg[0]*ppg_vec[2];
+ v[2] = vclp_pg[0]*ppg_vec[1] - vclp_pg[1]*ppg_vec[0];
+ if(fabs(v[0]) < 1e-5 || fabs(v[1]) < 1e-5 || fabs(v[2]) < 1e-5) return false;
+ v[0] *= (v[2]*2048.0); v[1] *= (v[2]*2048.0); v[2] *= (v[2]*2048.0);
+ //find two solutions +/- vector
+ for(i = 0; i < 2; i++) {
+ s[i][0] = (double)(pt->x); s[i][1] = (double)(pt->y); s[i][2] = (double)(pt->z);
+ for(j = 0; j < 5; j++) {
+ do {
+ s[i][0] += v[0]; s[i][1] += v[1]; s[i][2] += v[2];
+ }while(IsInPolygon3D(s[i][0], s[i][1], ppg_act, ppg_nact, &us1, &ls1)
+ && IsInPolygon3D(s[i][0], s[i][1], clp_pg, nclp_pg, &us2, &ls2));
+ s[i][0] -= v[0]; s[i][1] -= v[1]; s[i][2] -= v[2];
+ v[0] /= 4.0; v[1] /= 4.0; v[2] /= 4.0;
+ }
+ s[i][0] += v[0]; s[i][1] += v[1]; s[i][2] += v[2];
+ v[0] *= -1024.0; v[1] *= -1024.0; v[2] *= -1024.0;
+ res[i].x = iround(s[i][0]); res[i].y = iround(s[i][1]); res[i].z = iround(s[i][2]);
+ di[i] = (d=(res[i].x - pt->x))*d; di[i] += ((d=(res[i].y - pt->y))*d);
+ }
+ if(di[0] > 1 && di[0] > di[1]) {
+ //first solution has longer projection
+ np->x = res[0].x; np->y = res[0].y; np->z = res[0].z;
+ return true;
+ }
+ if(di[1] > 1 && di[1] > di[0]) {
+ //second solution has longer projection
+ np->x = res[1].x; np->y = res[1].y; np->z = res[1].z;
+ return true;
+ }
+ return false;
+}
+
+//come here from clip_line_3D to process changes in visibility when
+// clipping one polygon with another
+void proc_polygon(int vis, POINT3D *pnt, POINT3D *last)
+{
+ static POINT3D np, lp;
+ long d, d1;
+ bool spg_valid;
+
+ switch(ppg_level){
+ case 0: //searching first visible point of polygon
+ if(vis == 3) vis = 1; //on line is visible
+ if(!ppg_vis && vis && !ppg_nowvis){ //found it !
+ ppg_nowvis = true; ppg_first.x = pnt->x;
+ ppg_first.y = pnt->y; ppg_first.z = pnt->z;
+ ppg_reason = vis;
+ }
+ else if(!vis && ppg_nowvis) { //check if too short
+ d = (d1 = pnt->x - ppg_first.x) * d1;
+ d += (d1 = pnt->y - ppg_first.y) * d1;
+ if(d < 3) ppg_nowvis = false; //cancel first point
+ }
+ ppg_vis = vis;
+ break;
+ case 1:
+ if(vis == 3) vis = 1; //on line: visible
+ if(ppg_first.x < 0 && ppg_first.y < 0 && vis) {
+ memcpy(&ppg_first, pnt, sizeof(POINT3D));
+ ppg_firstvis = vis; lp.x = pnt->x;
+ lp.y = pnt->y; lp.z = pnt->z;
+ ppg_par->Command(CMD_STARTLINE, pnt, 0L);
+ }
+ else if (ppg_vis) { //leaving visibility or continue
+ spg_valid = false;
+ if(lp.x == pnt->x && lp.y == pnt->y && lp.z == pnt->z) break;
+ if(vis) ppg_par->Command(CMD_ADDTOLINE, pnt, 0L);
+ else ppg_par->Command(CMD_ADDTOLINE, last, 0L);
+ if(!vis){ //leaving visibility
+ ppg_vis = test_plane(last->x, last->y, last->z);
+ if(ppg_vis == 3) ppg_vis = 1;
+ if(ppg_firstvis == 1 && ppg_vis == 1) {
+ //from below surface to below surface
+ spg_valid = AddShadowPolygon(last, &ppg_first, -2);
+ }
+ else if(ppg_firstvis == 1 && ppg_vis == 2) {
+ //from below surface enter inside surface
+ if(CuttingEdge(last, &np)){
+ ppg_par->Command(CMD_ADDTOLINE, &np, 0L);
+ spg_valid = AddShadowPolygon(&np, &ppg_first, seg_x_seg);
+ }
+ else spg_valid = AddShadowPolygon(last, &ppg_first, seg_x_seg);
+ }
+ else if(ppg_firstvis == 2 && ppg_vis == 1) {
+ //from inside surface to below surface
+ if(CuttingEdge(&ppg_first, &np)){
+ if(!(spg_valid = AddShadowPolygon(last, &np, seg_x_seg)))
+ ppg_par->Command(CMD_REQ_POINT, &ppg_first, 0L);
+ ppg_par->Command(CMD_ADDTOLINE, &np, 0L);
+ }
+ else spg_valid = AddShadowPolygon(last, &ppg_first, seg_x_seg);
+ }
+ else if(ppg_firstvis == 2 && ppg_vis == 2) {
+ //from inside surface to inside surface
+ // nothing to do: connect straight
+ spg_valid = true;
+ }
+ //prepare for new polygon
+ if(spg_valid) {
+ ppg_first.x = ppg_first.y = ppg_first.z = -1;
+ }
+ else {
+ //we could not find a proper connection between the two points
+ // probably due to high complexity of graph or shape.
+ // We ignore part of the polygon and continue with the
+ // started shape.
+ vis = ppg_vis;
+ }
+ }
+ }
+ ppg_vis = vis; lp.x = pnt->x;
+ lp.y = pnt->y; lp.z = pnt->z;
+ break;
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//test if line is available in 3D-polygons: determine shared edges
+bool LineInPolgon(POINT3D *p1, POINT3D *p2, POINT3D *tpg, int ntpg)
+{
+ int i;
+
+ for(i = 1; i < ntpg; i++) {
+ if(p2->x == tpg[i].x && p2->y == tpg[i].y && p2->z == tpg[i].z) {
+ if(p1->x == tpg[i-1].x && p1->y == tpg[i-1].y && p1->z == tpg[i-1].z) return true;
+ }
+ if(p1->x == tpg[i].x && p1->y == tpg[i].y && p1->z == tpg[i].z) {
+ if(p2->x == tpg[i-1].x && p2->y == tpg[i-1].y && p2->z == tpg[i-1].z) return true;
+ }
+ }
+ i = ntpg -1;
+ if(p1->x == tpg[i].x && p1->y == tpg[i].y && p1->z == tpg[i].z &&
+ p2->x == tpg[0].x && p2->y == tpg[0].y && p2->z == tpg[0].z) return true;
+ if(p2->x == tpg[i].x && p2->y == tpg[i].y && p2->z == tpg[i].z &&
+ p1->x == tpg[0].x && p1->y == tpg[0].y && p1->z == tpg[0].z) return true;
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//entry points for clipping requests
+
+void clip_line_sphere(GraphObj *par, POINT3D **li, int r, int cx, int cy, int cz)
+{
+ sph_r2 = r*r; sph_x = cx; sph_y = cy; sph_z = cz;
+ if(test_sphere(li[0]->x, li[0]->y, li[0]->z)) par->Command(CMD_STARTLINE, li[0], 0L);
+ clip_line_3D(par, &li[0][0], &li[0][1], test_sphere);
+}
+
+void clip_line_plane(GraphObj *par, POINT3D **li, POINT3D *pg, int np, double *vec)
+{
+ nclp_pg = np; clp_pg = pg; vclp_pg = vec;
+ if(test_plane(li[0]->x, li[0]->y, li[0]->z)) par->Command(CMD_STARTLINE, li[0], 0L);
+ clip_line_3D(par, &li[0][0], &li[0][1], test_plane);
+ vclp_pg = 0L;
+}
+
+void clip_sphline_sphere(GraphObj *par, POINT3D *lim1, POINT3D *lim2, POINT3D *cent,
+ int r1, int r2, int cx, int cy, int cz)
+{
+ sphlim1 = lim1; sphlim2 = lim2;
+ sph_r2 = r2*r2; sph_x = cx; sph_y = cy; sph_z = cz;
+ clip_spher_line(par, cent, r1, lim1->x == lim2->x, test_sphere);
+}
+
+void clip_sphline_plane(GraphObj *par, POINT3D *lim1, POINT3D *lim2, POINT3D *cent,
+ int r1, POINT3D *pg, int np, double *vec)
+{
+ sphlim1 = lim1; sphlim2 = lim2; nclp_pg = np;
+ clp_pg = pg; vclp_pg = vec;
+ clip_spher_line(par, cent, r1, lim1->x == lim2->x, test_planeandline);
+ vclp_pg = 0L;
+}
+
+void clip_plane_plane(GraphObj *par, POINT3D *pg1, int n1, double *v1, POINT3D *pg2,
+ int n2, double *v2, POINT *mask, int nmask)
+{
+ int i, j;
+ POINT3D sp;
+
+ nclp_pg = n2; clp_pg = pg2; ppg_level = 0; ppg_nowvis = false;
+ ppg_reason = 0; vclp_pg = v2;
+ ppg_vis = test_plane(pg1[0].x, pg1[0].y, pg1[0].z);
+ ppg_act = pg1; ppg_nact = n1; ppg_vec = v1;
+ for(i = 1; i < n1 && !ppg_nowvis; i++){ //assume first pnt == last pnt
+ if(!LineInPolgon(&pg1[i-1], &pg1[i], pg2, n2))
+ clip_line_3D(0L, &pg1[i-1], &pg1[i], test_plane);
+ }
+ if(!ppg_nowvis && !ppg_vis) { //complete pg hidden
+ ppg_vec = vclp_pg = 0L; return;
+ }
+ if(ppg_nowvis) { //clip this polygon
+ ppg_mask = mask; ppg_nmask = nmask;
+ ppg_level = 1; ppg_par = par;
+ sp.x = ppg_first.x; sp.y = ppg_first.y;
+ sp.z = ppg_first.z; ppg_first.x = ppg_first.y = ppg_first.z = -1;
+ ppg_vis = test_plane(sp.x, sp.y, sp.z);
+ proc_polygon(ppg_vis, &sp, &sp);
+ clip_line_3D(0L, &sp, &pg1[i-1], test_plane);
+ for(j = i+n1-1; i < j; i++) {
+ seg_x_seg = -2;
+ clip_line_3D(0L, &pg1[(i-1)%n1], &pg1[i%n1], test_plane);
+ }
+ clip_line_3D(0L, &pg1[(i-1)%n1], &sp, test_plane);
+ }
+ else { //all visible
+ par->Command(CMD_STARTLINE, pg1, 0L);
+ for(i = 1; i < n1; i++) {
+ par->Command(CMD_ADDTOLINE, &pg1[i], 0L);
+ }
+ }
+ ppg_vec = vclp_pg = 0L;
+}
diff --git a/Version.h b/Version.h
new file mode 100755
index 0000000..5289724
--- /dev/null
+++ b/Version.h
@@ -0,0 +1,20 @@
+//RLPlot.h, Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005 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
+//
+#define SZ_VERSION "0.99.14b"
+
diff --git a/WinSpec.cpp b/WinSpec.cpp
new file mode 100755
index 0000000..fb917e7
--- /dev/null
+++ b/WinSpec.cpp
@@ -0,0 +1,2422 @@
+//WinSpec.cpp, Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005 R.Lackner
+//the entire code of this module is highly specific to Windows!
+//
+// 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 <stdio.h>
+#include <math.h>
+#include "rlplot.h"
+#include "WinSpec.h"
+#include "rlplot.rc"
+#include "TheDialog.h"
+
+extern int dlgtxtheight;
+
+HINSTANCE hInstance;
+HWND MainWnd = 0L;
+HACCEL accel;
+bool isWIN95 = false;
+extern tag_Units Units[];
+extern GraphObj *CurrGO; //Selected Graphic Objects
+extern Graph *CurrGraph;
+extern char *WWWbrowser;
+extern char *LoadFile;
+extern Default defs;
+extern char TmpTxt[];
+extern UndoObj Undo;
+
+const char name[] = "RLPLOT1";
+
+static unsigned int cf_rlpgraph = RegisterClipboardFormat("rlp_graph");
+static unsigned int cf_rlpobj = RegisterClipboardFormat("rlp_obj");
+static unsigned int cf_rlpxml = RegisterClipboardFormat("rlp_xml");
+
+long FAR PASCAL WndProc(HWND, UINT, UINT, LONG);
+PrintWin *Printer = 0L;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// I/O File name dialogs
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get a new file name to store data in
+char *SaveDataAsName(char *oldname)
+{
+ static char szFile[500], szFileTitle[256];
+ static char szFilter[] = "RLPlot workbook (*.rlw)\0*.rlw\0data files (*.csv)\0*.csv\0tab separated (*tsv)\0"
+ "*.tsv\0XML (*.xml)\0*.xml\0";
+ OPENFILENAME ofn;
+
+ szFile[0] = '\0';
+ if(oldname)strcpy(szFile, oldname);
+ memset(&ofn, 0, sizeof(OPENFILENAME));
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = GetFocus();
+ ofn.lpstrFilter = szFilter;
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFile = szFile;
+ ofn.nMaxFile = sizeof(szFile);
+ ofn.lpstrFileTitle = szFileTitle;
+ ofn.nMaxFileTitle = sizeof(szFileTitle);
+ ofn.lpstrInitialDir = defs.currPath;
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;
+ ofn.lpstrTitle = "Save Data As";
+
+ if(GetSaveFileName(&ofn)){
+ defs.FileHistory(szFile);
+ return szFile;
+ }
+ else return NULL;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get a new file name to store graph
+char *SaveGraphAsName(char *oldname)
+{
+ static char szFile[500], szFileTitle[256];
+ static char szFilter[] = "RLPlot Graph (*.RLP)\0*.rlp\0";
+ OPENFILENAME ofn;
+
+ szFile[0] = '\0';
+ if(oldname)strcpy(szFile, oldname);
+ memset(&ofn, 0, sizeof(OPENFILENAME));
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = GetFocus();
+ ofn.lpstrFilter = szFilter;
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFile = szFile;
+ ofn.nMaxFile = sizeof(szFile);
+ ofn.lpstrFileTitle = szFileTitle;
+ ofn.nMaxFileTitle = sizeof(szFileTitle);
+ ofn.lpstrInitialDir = defs.currPath;
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;
+ ofn.lpstrTitle = "Save Graph As";
+
+ if(GetSaveFileName(&ofn)){
+ defs.FileHistory(szFile);
+ return szFile;
+ }
+ else return NULL;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get file name to read graph
+char *OpenGraphName(char *oldname)
+{
+ static char szFile[500], szFileTitle[256];
+ static char szFilter[] = "RLPlot Graph (*.RLP)\0*.rlp\0";
+ OPENFILENAME ofn;
+
+ szFile[0] = '\0';
+ if(oldname)strcpy(szFile, oldname);
+ memset(&ofn, 0, sizeof(OPENFILENAME));
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = GetFocus();
+ ofn.lpstrFilter = szFilter;
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFile = szFile;
+ ofn.nMaxFile = sizeof(szFile);
+ ofn.lpstrFileTitle = szFileTitle;
+ ofn.nMaxFileTitle = sizeof(szFileTitle);
+ ofn.lpstrInitialDir = defs.currPath;
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+ ofn.lpstrTitle = "Open Graph";
+
+ if(GetOpenFileName(&ofn)){
+ defs.FileHistory(szFile);
+ return szFile;
+ }
+ else return NULL;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get a file name to load data
+char *OpenDataName(char *oldname)
+{
+ static char szFile[500], szFileTitle[256];
+ static char szFilter[] = "RLPlot workbook (*rlw)\0*.rlw\0data files (*.csv)\0*.csv\0"
+ "tab separated file (*.tsv)\0*.tsv\0"
+ "RLPlot Graph (*.rlp)\0*.rlp\0all files (*.*)\0*.*\0";
+ OPENFILENAME ofn;
+
+ szFile[0] = '\0';
+ if(oldname)strcpy(szFile, oldname);
+ memset(&ofn, 0, sizeof(OPENFILENAME));
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = GetFocus();
+ ofn.lpstrFilter = szFilter;
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFile = szFile;
+ ofn.nMaxFile = sizeof(szFile);
+ ofn.lpstrFileTitle = szFileTitle;
+ ofn.nMaxFileTitle = sizeof(szFileTitle);
+ ofn.lpstrInitialDir = defs.currPath;
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+ ofn.lpstrTitle = "Open Data File";
+
+ if(GetOpenFileName(&ofn)){
+ defs.FileHistory(szFile);
+ return szFile;
+ }
+ else return NULL;
+}
+
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get a file name to export graph
+void OpenExportName(GraphObj *g, char *oldname)
+{
+ static char szFile[500], szFileTitle[256];
+ static char szFilter[] = "Scalable Vector Graphics (*.svg)\0*.svg\0"
+ "Encapsulated Post Script (*.eps)\0*.eps\0"
+ "MSWindows MetaFile(*.wmf)\0*.wmf\0Tag Image File Format (*.tif)\0*.tif\0";
+ OPENFILENAME ofn;
+ int i;
+
+ szFile[0] = '\0';
+ if(!g) return;
+ if(oldname)strcpy(szFile, oldname);
+ memset(&ofn, 0, sizeof(OPENFILENAME));
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = GetFocus();
+ ofn.lpstrFilter = szFilter;
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFile = szFile;
+ ofn.nMaxFile = sizeof(szFile);
+ ofn.lpstrFileTitle = szFileTitle;
+ ofn.nMaxFileTitle = sizeof(szFileTitle);
+ ofn.lpstrInitialDir = defs.currPath;
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;
+ ofn.lpstrTitle = "Export Graph";
+
+ if(g && GetSaveFileName(&ofn)){
+ i = strlen(szFile);
+ g->Command(CMD_BUSY, 0L, 0L);
+ if(0==stricmp(".svg", szFile+i-4)) {
+ DoExportSvg(g, szFile, 0L);
+ }
+ else if(0==stricmp(".wmf", szFile+i-4)) {
+ DoExportWmf(g, szFile, 600.0f, 0L);
+ }
+ else if(0==stricmp(".eps", szFile+i-4)) {
+ DoExportEps(g, szFile, 0L);
+ }
+ else if(0==stricmp(".tif", szFile+i-4)) {
+ DoExportTif(g, szFile, 0L);
+ }
+ else if(0==stricmp(".tiff", szFile+i-5)) {
+ DoExportTif(g, szFile, 0L);
+ }
+ else ErrorBox("Unknown file extension or format");
+ g->Command(CMD_MOUSECURSOR, 0L, 0L);
+ }
+}
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Common alert boxes
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void InfoBox(char *Msg)
+{
+ MessageBox(0, Msg, "Info", MB_OK | MB_ICONINFORMATION);
+}
+
+void ErrorBox(char *Msg)
+{
+ MessageBox(0, Msg, "ERROR", MB_OK | MB_ICONSTOP);
+}
+
+bool YesNoBox(char *Msg)
+{
+ if(IDYES == MessageBox(0, Msg, "RLPlot", MB_YESNO | MB_ICONQUESTION)) return true;
+ return false;
+}
+
+void Qt_Box()
+{
+ MessageBox(0, "No Qt installed\nunder Windows", "Error", MB_OK | MB_ICONQUESTION);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Display blinking text cursor
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+anyOutput *oTxtCur = 0L, *oCopyMark = 0L;
+RECT rTxtCur, rCopyMark;
+bool bTxtCur = false, bTxtCurIsVis = false;
+DWORD cTxtCur = 0x0L;
+HWND hwndTxtCur = 0L;
+int iTxtCurCount = 0;
+POINT ptTxtCurLine[2];
+BitMapWin *bmCopyMark = 0L;
+
+void HideTextCursor()
+{
+ if(oTxtCur) {
+ bTxtCur = false;
+ oTxtCur->UpdateRect(&rTxtCur, false);
+ }
+ oTxtCur = 0L;
+}
+
+void HideTextCursorObj(anyOutput *out)
+{
+ if(oTxtCur && oTxtCur == out) HideTextCursor();
+}
+
+void ShowTextCursor(anyOutput *out, RECT *disp, DWORD color)
+{
+ HWND wnd = GetFocus();
+
+ cTxtCur = color;
+ HideTextCursor();
+ oTxtCur = out;
+ iTxtCurCount = -2;
+ memcpy(&rTxtCur, disp, sizeof(RECT));
+ ptTxtCurLine[0].x = rTxtCur.left; ptTxtCurLine[0].y = rTxtCur.top;
+ ptTxtCurLine[1].x = rTxtCur.right; ptTxtCurLine[1].y = rTxtCur.bottom;
+ rTxtCur.bottom++; rTxtCur.right++;
+ oTxtCur->ShowLine(ptTxtCurLine, 2, cTxtCur);
+ bTxtCurIsVis = bTxtCur = true;
+}
+
+void HideCopyMark()
+{
+ if(bmCopyMark && oCopyMark) {
+ oCopyMark->UpdateRect(&rCopyMark, false);
+ delete bmCopyMark;
+ }
+ bmCopyMark = 0L; oCopyMark = 0L;
+}
+
+void ShowCopyMark(anyOutput *out, RECT *mrk, int nRec)
+{
+ int i;
+
+ HideCopyMark();
+ if(!out || !mrk || !nRec) return;
+ oCopyMark = out;
+ rCopyMark.left = mrk[0].left; rCopyMark.right = mrk[0].right;
+ rCopyMark.top = mrk[0].top; rCopyMark.bottom = mrk[0].bottom;
+ for(i = 1; i < nRec; i++) {
+ UpdateMinMaxRect(&rCopyMark, mrk[i].left, mrk[i].top);
+ UpdateMinMaxRect(&rCopyMark, mrk[i].right, mrk[i].bottom);
+ }
+ bmCopyMark = new BitMapWin(rCopyMark.right - rCopyMark.left,
+ rCopyMark.bottom - rCopyMark.top, out->hres, out->vres);
+}
+
+LineDEF liCopyMark1 = {0.0f, 1.0f, 0x00ffffffL, 0L};
+LineDEF liCopyMark2 = {0.0f, 6.0f, 0x0L, 0xf0f0f0f0L};
+
+long FAR PASCAL TimerWndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
+{
+ static POINT line[5];
+ static int cp_mark = 0;
+
+ switch(message) {
+ case WM_TIMER:
+ if(bmCopyMark && oCopyMark) {
+ bmCopyMark->CopyBitmap(0, 0, oCopyMark, rCopyMark.left, rCopyMark.top,
+ rCopyMark.right - rCopyMark.left, rCopyMark.bottom - rCopyMark.top, false);
+ bmCopyMark->SetLine(&liCopyMark1);
+ line[0].x = line[1].x = line[4].x = 0;
+ line[0].y = line[3].y = line[4].y = 0;
+ line[1].y = line[2].y = rCopyMark.bottom-rCopyMark.top-1;
+ line[2].x = line[3].x = rCopyMark.right-rCopyMark.left-1;
+ bmCopyMark->oPolyline(line, 5);
+ bmCopyMark->SetLine(&liCopyMark2);
+ bmCopyMark->RLP.finc = 1.0; bmCopyMark->RLP.fp = (cp_mark & 0x7);
+ bmCopyMark->oPolyline(line, 5);
+ oCopyMark->ShowBitmap(rCopyMark.left, rCopyMark.top, bmCopyMark);
+ cp_mark++;
+ if(bTxtCurIsVis && oTxtCur && ptTxtCurLine[0].y != ptTxtCurLine[1].y &&
+ oTxtCur == oCopyMark && OverlapRect(&rCopyMark, &rTxtCur)){
+ oTxtCur->ShowLine(ptTxtCurLine, 2, cTxtCur);
+ }
+ }
+ if(!oTxtCur || (ptTxtCurLine[0].x == ptTxtCurLine[1].x &&
+ ptTxtCurLine[0].y == ptTxtCurLine[1].y)) return 0;
+ iTxtCurCount++;
+ if(iTxtCurCount<0) oTxtCur->ShowLine(ptTxtCurLine, 2, cTxtCur);
+ if(iTxtCurCount < 4) return 0;
+ iTxtCurCount = 0;
+ if(bTxtCur && oTxtCur) {
+ if(!bTxtCurIsVis) {
+ oTxtCur->ShowLine(ptTxtCurLine, 2, cTxtCur);
+ bTxtCurIsVis = true;
+ }
+ else {
+ oTxtCur->UpdateRect(&rTxtCur, false);
+ bTxtCurIsVis = false;
+ }
+ }
+ return 0;
+ case WM_QUERYOPEN:
+ case WM_SIZE:
+ return 0;
+ case WM_DESTROY:
+ KillTimer(hwnd, 1);
+ break;
+ }
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+void InitTextCursor(bool init)
+{
+ WNDCLASS wndclass;
+
+ if (init) {
+ wndclass.style = CS_BYTEALIGNWINDOW | CS_DBLCLKS;
+ wndclass.lpfnWndProc = TimerWndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = 0;
+ wndclass.hInstance = hInstance;
+ wndclass.hIcon = 0L;
+ wndclass.hCursor = 0L;
+ wndclass.hbrBackground = NULL;
+ wndclass.lpszMenuName = 0L;
+ wndclass.lpszClassName = "RLP_TIMER";
+ RegisterClass(&wndclass);
+ if((hwndTxtCur = CreateWindow("RLP_TIMER", 0L, WS_OVERLAPPEDWINDOW,
+ 0, 0, 0, 0, NULL, NULL, hInstance, NULL))){
+ SetTimer(hwndTxtCur, 1, 150, 0L);
+ }
+ }
+ else if(hwndTxtCur) {
+ DestroyWindow(hwndTxtCur);
+ hwndTxtCur = 0L;
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Process paste command: check for clipboard contents
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void TestClipboard(GraphObj *g)
+{
+ HANDLE hmem = 0;
+ unsigned char *ptr;
+
+ if(!g) return;
+ OpenClipboard(MainWnd);
+ if(g->Id == GO_SPREADDATA) {
+ if((hmem = GetClipboardData(cf_rlpxml)) &&
+ (ptr = (unsigned char*) GlobalLock(hmem))) g->Command(CMD_PASTE_XML, ptr, 0L);
+ else if((hmem = GetClipboardData(CF_TEXT)) &&
+ (ptr = (unsigned char*) GlobalLock(hmem))) ProcMemData(g, ptr, true);
+ else if((hmem = GetClipboardData(cf_rlpobj)) &&
+ (ptr = (unsigned char*) GlobalLock(hmem))) OpenGraph(g, 0L, ptr);
+ else if((hmem = GetClipboardData(cf_rlpgraph)) &&
+ (ptr = (unsigned char*) GlobalLock(hmem))) OpenGraph(g, 0L, ptr);
+ }
+ else if(g->Id == GO_PAGE) {
+ if((hmem = GetClipboardData(cf_rlpobj)) &&
+ (ptr = (unsigned char*) GlobalLock(hmem))) OpenGraph(g, 0L, ptr);
+ else if((hmem = GetClipboardData(cf_rlpgraph)) &&
+ (ptr = (unsigned char*) GlobalLock(hmem))) OpenGraph(g, 0L, ptr);
+ }
+ else if(g->Id == GO_GRAPH) TestClipboard(g->parent);
+ if(hmem) GlobalUnlock(hmem);
+ CloseClipboard();
+}
+
+void EmptyClip()
+{
+ HideCopyMark();
+ OpenClipboard(MainWnd);
+ EmptyClipboard();
+ CloseClipboard();
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get display (desktop) size
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void GetDesktopSize(int *width, int *height)
+{
+ RECT rc;
+
+ GetClientRect(GetDesktopWindow(), &rc);
+ *width = rc.right;
+ *height = rc.bottom;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Common code for any Windows output class
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool com_oTextOut(int x, int y, char *txt, int cb,
+ HFONT *hFont, HDC *dc, TextDEF *td, bool win95mode, anyOutput *o)
+{
+ XFORM xf;
+ w_char *uc;
+ int i, ix, iy, align;
+
+ if(!*hFont || !txt || !txt[0]) return false;
+ SelectObject(*dc, *hFont);
+ SetTextColor(*dc, td->ColTxt);
+ SetBkColor(*dc, td->ColBg);
+ align = ((td->Align & TXA_HRIGHT) ? TA_RIGHT : (td->Align &
+ TXA_HCENTER) ? TA_CENTER : TA_LEFT) | ((td->Align & TXA_VBOTTOM) ?
+ TA_BOTTOM : TA_TOP);
+ SetTextAlign(*dc, align);
+ SetBkMode(*dc, td->Mode ? TRANSPARENT : OPAQUE);
+ ix = iy = 0;
+ if(td->Style & TXS_SUB) {
+ if((td->Align & TXA_VCENTER) == TXA_VCENTER) iy += o->un2iy(td->fSize*0.4);
+ else if((td->Align & TXA_VBOTTOM) == TXA_VBOTTOM) iy += o->un2iy(td->fSize*0.2);
+ else if((td->Align & TXA_VTOP) == TXA_VTOP) iy += o->un2iy(td->fSize*.6);
+ }
+ else if(td->Style & TXS_SUPER) {
+ if((td->Align & TXA_VCENTER) == TXA_VCENTER) iy -= o->un2iy(td->fSize*0.4);
+ else if((td->Align & TXA_VBOTTOM) == TXA_VBOTTOM) iy -= o->un2iy(td->fSize*0.6);
+ else if((td->Align & TXA_VTOP) == TXA_VTOP) iy += o->un2iy(td->fSize*.0);
+ }
+ if(!win95mode && (fabs(td->RotBL) >.01 || fabs(td->RotCHAR) >.01)) {
+ SetGraphicsMode(*dc, GM_ADVANCED);
+ xf.eM11 = xf.eM22 = (float)cos(td->RotBL *0.01745329252);
+ xf.eM12 = (float)-sin(td->RotBL *0.01745329252);
+ xf.eM21 = -xf.eM12;
+ xf.eDx = (float)x;
+ xf.eDy = (float)y;
+ SetWorldTransform(*dc, &xf);
+ if(td->Font==FONT_GREEK && (uc=(w_char*)calloc(strlen(txt)+1, sizeof(w_char)))) {
+ for(i = 0; txt[i]; i++) {
+ if((txt[i] >= 'A' && txt[i] <= 'Z')) uc[i] = txt[i] - 'A' + 0x391;
+ else if((txt[i] >= 'a' && txt[i] <= 'z')) uc[i] = txt[i] - 'a' + 0x3B1;
+ else uc[i] = txt[i];
+ }
+ TextOutW(*dc, ix, iy+((td->Align & TXA_VCENTER) ? - td->iSize/2 : 0), uc,
+ (cb > 0) ? cb : strlen(txt));
+ free(uc);
+ }
+ else {
+ TextOut(*dc, ix, iy+((td->Align & TXA_VCENTER) ? - td->iSize/2 : 0), txt,
+ (cb > 0) ? cb : strlen(txt));
+ }
+// DrawText(*dc, txt, (cb> 0)? cb : strlen(txt), 0L /*LPRECT*/, uFormat);
+ ModifyWorldTransform(*dc, &xf, MWT_IDENTITY);
+ SetGraphicsMode(*dc, GM_COMPATIBLE);
+ return true;
+ }
+ else {
+ if(!win95mode && td->Font==FONT_GREEK && (uc=(w_char*)calloc(strlen(txt)+1, sizeof(w_char)))) {
+ for(i = 0; txt[i]; i++) {
+ if((txt[i] >= 'A' && txt[i] <= 'Z')) uc[i] = txt[i] - 'A' + 0x391;
+ else if((txt[i] >= 'a' && txt[i] <= 'z')) uc[i] = txt[i] - 'a' + 0x3B1;
+ else uc[i] = txt[i];
+ }
+ TextOutW(*dc, x+ix, iy + ((td->Align & TXA_VCENTER) ? y - td->iSize/2 : y), uc,
+ (cb > 0) ? cb : strlen(txt));
+ free(uc);
+ return true;
+ }
+ else if(TextOut(*dc, x+ix, iy + ((td->Align & TXA_VCENTER) ? y - td->iSize/2 : y), txt,
+ (cb > 0) ? cb : strlen(txt))) return true;
+ }
+ return false;
+}
+
+bool com_SetTextSpec(TextDEF *set, anyOutput *o, HFONT *hFont, TextDEF *TxtSet,
+ HDC *dc, bool win95mode)
+{
+ bool IsModified, RetVal;
+ LOGFONT FontRec;
+ HFONT newFont;
+
+ if(!set->iSize && set->fSize > 0.001f) set->iSize = o->un2iy(set->fSize);
+ if(!set->iSize) return false;
+ if(!*hFont || TxtSet->iSize != set->iSize || TxtSet->Style != set->Style ||
+ TxtSet->RotBL != set->RotBL || TxtSet->RotCHAR != set->RotCHAR ||
+ TxtSet->Font != set->Font || TxtSet->fSize != set->fSize) IsModified = true;
+ else IsModified = false;
+ RetVal = o->anyOutput::SetTextSpec(set);
+ if (IsModified && RetVal) {
+ // create font
+ if((TxtSet->Style & TXS_SUPER) || (TxtSet->Style & TXS_SUB))
+ FontRec.lfHeight = o->un2iy(set->fSize*0.71);
+ else FontRec.lfHeight = TxtSet->iSize;
+ if(FontRec.lfHeight <8) FontRec.lfHeight = 8;
+ FontRec.lfWidth = 0;
+ if(win95mode) { //Win 95, 98
+ FontRec.lfEscapement = iround(TxtSet->RotBL*10); //text angle
+ FontRec.lfOrientation = iround(TxtSet->RotBL*10); //base line angle
+ }
+ else { //Win NT, 2000, XP
+ FontRec.lfEscapement = 0; //text angle
+ FontRec.lfOrientation = 0; //base line angle
+ }
+ FontRec.lfWeight = (TxtSet->Style & TXS_BOLD) ? FW_BOLD : FW_NORMAL;
+ FontRec.lfItalic = (TxtSet->Style & TXS_ITALIC) ? TRUE : FALSE;
+ FontRec.lfUnderline = (TxtSet->Style & TXS_UNDERLINE) ? TRUE : FALSE;
+ FontRec.lfStrikeOut = 0;
+ FontRec.lfOutPrecision = OUT_DEFAULT_PRECIS;
+ FontRec.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ FontRec.lfQuality = PROOF_QUALITY;
+ switch(TxtSet->Font){
+ case FONT_HELVETICA:
+ default:
+ FontRec.lfCharSet = ANSI_CHARSET;
+ FontRec.lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
+ strcpy(FontRec.lfFaceName, "Arial");
+ break;
+ case FONT_GREEK: case FONT_TIMES:
+ FontRec.lfCharSet = ANSI_CHARSET;
+ FontRec.lfPitchAndFamily = VARIABLE_PITCH | FF_ROMAN;
+ strcpy(FontRec.lfFaceName, "Times New Roman");
+ break;
+ case FONT_COURIER:
+ FontRec.lfCharSet = ANSI_CHARSET;
+ FontRec.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
+ strcpy(FontRec.lfFaceName, "Courier New");
+ break;
+ }
+ newFont = CreateFontIndirect(&FontRec);
+ SelectObject(*dc, newFont);
+ if(*hFont)DeleteObject(*hFont);
+ *hFont = newFont;
+ if(!(*hFont)) return false;
+ }
+ return RetVal;
+}
+
+bool com_Arc(HDC dc, int x1, int y1, int x2, int y2, int quads)
+{
+ int bx, by, ex, ey;
+
+ if(x1 > x2) Swap(x1, x2); if(y1 > y2) Swap(y1, y2);
+ switch (quads) {
+ case 1:
+ bx = (x1+x2)>>1; by = y2;
+ ex = x2; ey = (y1 +y2)>>1;
+ break;
+ case 2:
+ bx = x1; ex = x2; by = ey = (y1 +y2)>>1;
+ break;
+ case 3:
+ bx = (x1+x2)>>1; by = y1;
+ ex = x2; ey = (y1 +y2)>>1;
+ break;
+ case 4:
+ bx = ex = x2; by = ey = (y1 +y2)>>1;
+ break;
+ default: return false;
+ }
+ if(Arc(dc, x1, y1, x2, y2, bx, by, ex, ey)) return true;
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Output to windows bitmap
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+BitMapWin::BitMapWin(GraphObj *g, HWND hw):anyOutput()
+{
+ HDC dc;
+ HWND hwndDesk;
+
+ memDC = 0L; hgo = 0L; go = g;
+ dc = GetDC(hwndDesk = GetDesktopWindow());
+ hres = (double)GetDeviceCaps(dc, LOGPIXELSX);
+ vres = (double)GetDeviceCaps(dc, LOGPIXELSY);
+ if(hw) GetClientRect(hw, &DeskRect);
+ else GetClientRect(hwndDesk, &DeskRect);
+ Box1.Xmin = DeskRect.left; Box1.Xmax = DeskRect.right;
+ Box1.Ymin = DeskRect.top; Box1.Ymax = DeskRect.bottom;
+ scr = CreateCompatibleBitmap(dc, DeskRect.right, DeskRect.bottom);
+ memDC = CreateCompatibleDC(NULL);
+ SelectObject(memDC, scr);
+ ReleaseDC(hwndDesk, dc);
+ hPen = CreatePen(PS_SOLID, 1, dLineCol = 0x00ffffffL);
+ hBrush = CreateSolidBrush(dFillCol =dBgCol = 0x00ffffffL);
+ dPattern = 0L;
+ if(memDC) {
+ oldPen = (HPEN)SelectObject(memDC, hPen);
+ oldBrush = (HBRUSH)SelectObject(memDC, hBrush);
+ }
+ else {
+ oldBrush = 0L;
+ oldPen = 0L;
+ }
+ hFont = 0L;
+}
+
+BitMapWin::BitMapWin(int w, int h, double hr, double vr)
+{
+ HDC dc;
+ HWND hwndDesk;
+
+ memDC = 0L; hgo = 0L; go = 0L;
+ hres = hr; vres = vr;
+ units = defs.cUnits;
+ DeskRect.right = w; DeskRect.bottom = h;
+ DeskRect.left = DeskRect.top = 0;
+ VPorg.fx = VPorg.fy = 0.0;
+ dc = GetDC(hwndDesk = GetDesktopWindow());
+ scr = CreateCompatibleBitmap(dc, DeskRect.right, DeskRect.bottom);
+ memDC = CreateCompatibleDC(NULL);
+ ReleaseDC(hwndDesk, dc);
+ SelectObject(memDC, scr);
+ hPen = CreatePen(PS_SOLID, 1, dLineCol = 0x00ffffffL);
+ hBrush = CreateSolidBrush(dFillCol =dBgCol = 0x00ffffffL);
+ dPattern = 0L;
+ if(memDC) {
+ SelectObject(memDC, hPen);
+ SelectObject(memDC, hBrush);
+ }
+ hFont = 0L;
+}
+
+BitMapWin::BitMapWin(GraphObj *g):anyOutput()
+{
+ HDC dc;
+ HWND hwndDesk;
+
+ memDC = 0L; hgo = 0L; go = g;
+ dc = GetDC(hwndDesk = GetDesktopWindow());
+ hres = vres = 300.0;
+ units = defs.cUnits;
+ DeskRect.right = un2ix(go->GetSize(SIZE_GRECT_RIGHT) - go->GetSize(SIZE_GRECT_LEFT));
+ DeskRect.bottom = un2iy(go->GetSize(SIZE_GRECT_BOTTOM) - go->GetSize(SIZE_GRECT_TOP));
+ DeskRect.top = DeskRect.left = 0;
+ VPorg.fy = -co2fiy(go->GetSize(SIZE_GRECT_TOP));
+ VPorg.fx = -co2fix(go->GetSize(SIZE_GRECT_LEFT));
+ scr = CreateCompatibleBitmap(dc, DeskRect.right, DeskRect.bottom);
+ memDC = CreateCompatibleDC(NULL);
+ SelectObject(memDC, scr);
+ ReleaseDC(hwndDesk, dc);
+ hPen = CreatePen(PS_SOLID, 1, dLineCol = 0x00ffffffL);
+ hBrush = CreateSolidBrush(dFillCol =dBgCol = 0x00ffffffL);
+ dPattern = 0L;
+ if(memDC) {
+ SelectObject(memDC, hPen);
+ SelectObject(memDC, hBrush);
+ }
+ hFont = 0L;
+}
+
+BitMapWin::~BitMapWin()
+{
+ if(go) {
+ go->Command(CMD_CAN_DELETE, 0L, 0L);
+ }
+ Undo.KillDisp(this);
+ if(hgo) delete hgo;
+ if(hFont) DeleteObject(hFont);
+ if(scr) DeleteObject(scr);
+ SelectObject(memDC, oldPen);
+ SelectObject(memDC, oldBrush);
+ if(memDC) DeleteDC(memDC);
+ if(hPen) DeleteObject(hPen);
+ if(hBrush) DeleteObject(hBrush);
+ hgo = 0L; hFont = 0L; scr = 0L;
+ memDC = 0L; hPen = 0L; hBrush = 0L;
+}
+
+bool
+BitMapWin::SetLine(LineDEF *lDef)
+{
+ int iw;
+ HPEN newPen;
+
+ if(!hPen || lDef->width != LineWidth || lDef->width != LineWidth ||
+ lDef->pattern != dPattern || lDef->color != dLineCol) {
+ LineWidth = lDef->width;
+ iw = iround(un2fix(lDef->width));
+ dPattern = lDef->pattern;
+ RLP.finc = 256.0/un2fix(lDef->patlength*8.0);
+ RLP.fp = 0.0;
+ if(iLine == iw && dLineCol == lDef->color && hPen) return true;
+ iLine = iw;
+ dLineCol = lDef->color;
+ newPen = CreatePen(PS_SOLID, iw > 0 ? iw : 1, dLineCol);
+ SelectObject(memDC, newPen);
+ if(hPen) DeleteObject(hPen);
+ hPen = newPen;
+ }
+ return true;
+}
+
+bool
+BitMapWin::SetFill(FillDEF *fill)
+{
+ HBRUSH newBrush;
+
+ if(!fill) return false;
+ if((fill->type & 0xff) != FILL_NONE) {
+ if(!hgo) hgo = new HatchOut(this);
+ if(hgo) hgo->SetFill(fill);
+ }
+ else {
+ if(hgo) delete hgo;
+ hgo = NULL;
+ }
+ if(dFillCol != fill->color) {
+ newBrush = CreateSolidBrush(dFillCol = fill->color);
+ SelectObject(memDC, newBrush);
+ if(hBrush) DeleteObject(hBrush);
+ hBrush = newBrush;
+ }
+ dFillCol = fill->color;
+ dFillCol2 = fill->color2;
+ return true;
+}
+
+bool
+BitMapWin::SetTextSpec(TextDEF *set)
+{
+ return com_SetTextSpec(set, this, &hFont, &TxtSet, &memDC, isWIN95);
+}
+
+bool
+BitMapWin::Erase(DWORD Color)
+{
+ HPEN hBGpen, hOldPen;
+ HBRUSH hBGbrush, hOldBrush;
+
+ hBGpen = CreatePen(PS_SOLID, 1, Color);
+ hBGbrush = CreateSolidBrush(Color);
+ if(hBGpen && memDC) {
+ if(hBGbrush) {
+ hOldBrush = (HBRUSH)SelectObject(memDC, hBGbrush);
+ hOldPen = (HPEN)SelectObject(memDC, hBGpen);
+ Rectangle(memDC, 0, 0, DeskRect.right, DeskRect.bottom);
+ SelectObject(memDC, hOldBrush);
+ SelectObject(memDC, hOldPen);
+ DeleteObject(hBGbrush);
+ DeleteObject(hBGpen);
+ return true;
+ }
+ if(hBGpen) DeleteObject(hBGpen);
+ }
+ return false;
+}
+
+bool
+BitMapWin::CopyBitmap(int x, int y, anyOutput* sr, int sx, int sy,
+ int sw, int sh, bool invert)
+{
+ BitMapWin *src = (BitMapWin*)sr;
+
+ return(0 != BitBlt(memDC, x, y, sw, sh, src->memDC, sx, sy,
+ invert ? DSTINVERT : SRCCOPY));
+}
+
+bool
+BitMapWin::oGetTextExtent(char *text, int cb, int *width, int *height)
+{
+ SIZE TextExtent;
+ double si, csi, d;
+
+ if(!text) return false;
+ if(!GetTextExtentPoint32(memDC, text, cb ? cb : strlen(text), &TextExtent))return false;
+ if(fabs(TxtSet.RotBL) >0.01) {
+ si = fabs(sin(TxtSet.RotBL * 0.01745329252)); csi = fabs(cos(TxtSet.RotBL * 0.01745329252));
+ d = si > csi ? 1.0/si : 1.0/csi;
+ d = (TextExtent.cx * ((7.0 + d)/8.0));
+ TextExtent.cx = iround(d);
+ }
+ *width = TextExtent.cx;
+ *height = TextExtent.cy;
+ return true;
+}
+
+bool
+BitMapWin::oGetPix(int x, int y, DWORD *col)
+{
+ DWORD pix;
+
+ if(x >= DeskRect.left && x < DeskRect.right &&
+ y >= DeskRect.top && y < DeskRect.bottom) {
+ pix = GetPixel(memDC, x, y);
+ *col = pix;
+ return true;
+ }
+ else return false;
+}
+
+bool
+BitMapWin::oDrawIcon(int type, int x, int y)
+{
+ HICON icon = 0L;
+
+ switch(type) {
+ case ICO_INFO:
+ icon = LoadIcon(0L, IDI_ASTERISK);
+ break;
+ case ICO_ERROR:
+ icon = LoadIcon(0L, IDI_HAND);
+ break;
+ case ICO_RLPLOT:
+ icon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_EVAL));
+ break;
+ }
+ if(icon){
+ DrawIcon(memDC, x, y, icon);
+ return true;
+ }
+ return false;
+}
+
+bool
+BitMapWin::oCircle(int x1, int y1, int x2, int y2, char *nam)
+{
+ BOOL RetVal;
+
+ RetVal = Ellipse(memDC, x1, y1, x2, y2);
+ if(RetVal && hgo) return hgo->oCircle(x1, y1, x2, y2);
+ else if(RetVal) return true;
+ return false;
+}
+
+bool
+BitMapWin::oPolyline(POINT * pts, int cp, char *nam)
+{
+ int i;
+
+ if(cp < 1) return false;
+ if (dPattern) {
+ for (i = 1; i < cp; i++) PatLine(pts[i-1], pts[i]);
+ return true;
+ }
+ else {
+ if(Polyline(memDC, pts, cp))return true;
+ else return false;
+ }
+}
+
+bool
+BitMapWin::oRectangle(int x1, int y1, int x2, int y2, char *name)
+{
+ BOOL RetVal;
+
+ RetVal = Rectangle(memDC, x1, y1, x2, y2);
+ if(RetVal && hgo) return hgo->oRectangle(x1, y1, x2, y2, 0L);
+ else if (RetVal) return true;
+ return false;
+}
+
+bool
+BitMapWin::oSolidLine(POINT *p)
+{
+ if(Polyline(memDC, p, 2)) return true;
+ return false;
+}
+
+bool
+BitMapWin::oTextOut(int x, int y, char *txt, int cb)
+{
+ return com_oTextOut(x, y, txt, cb, &hFont, &memDC, &TxtSet, isWIN95, this);
+}
+
+bool
+BitMapWin::oPolygon(POINT *pts, int cp, char *nam)
+{
+ BOOL RetVal;
+
+ RetVal = Polygon(memDC, pts, cp);
+ if(RetVal && hgo) return hgo->oPolygon(pts, cp);
+ else if (RetVal) return true;
+ return false;
+}
+
+bool
+BitMapWin::oArc(int x1, int y1, int x2, int y2, int quads)
+{
+ return com_Arc(memDC, x1, y1, x2, y2, quads);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Output to windows window
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+OutputWin::OutputWin(GraphObj *g, HWND hw):BitMapWin(g, hw)
+{
+ hdc = 0L;
+ if(g) {
+ if(!hw) CreateNewWindow(g);
+ else hWnd = hw;
+ }
+ else { //its a dialog window
+ hWnd = hw;
+ yAxis.flags = AXIS_INVERT; //drawing origin upper left corner
+ }
+}
+
+OutputWin::~OutputWin()
+{
+ HideTextCursorObj(this);
+ SendMessage(hWnd, WM_CLOSE, 0, 0L);
+ //Note: HGDI objects are deleted by the BitMapWin destructor
+}
+
+bool
+OutputWin::ActualSize(RECT *rc)
+{
+ if(GetClientRect(hWnd, rc)) return true;
+ return false;
+}
+
+void
+OutputWin::Caption(char *txt)
+{
+ SetWindowText(hWnd, txt);
+}
+
+unsigned char hand_bits[] = { //hand cursor bitmap
+ 0x01, 0x80, 0x1b, 0xf0, 0x3f, 0xf8, 0x3f, 0xfa,
+ 0x1f, 0xff, 0x1f, 0xff, 0x6f, 0xff, 0xff, 0xff,
+ 0xff, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x3f, 0xfc,
+ 0x1f, 0xfc, 0x0f, 0xf8, 0x07, 0xf8, 0x07, 0xf8};
+
+unsigned char hand_mask[] = { //hand cursor mask
+ 0xff, 0xff, 0xfe, 0x7f, 0xe6, 0x4f, 0xe6, 0x4f,
+ 0xf2, 0x4d, 0xf2, 0x49, 0x78, 0x09, 0x98, 0x01,
+ 0x88, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xe0, 0x07,
+ 0xf0, 0x07, 0xf8, 0x0f, 0xfc, 0x0f, 0xfc, 0x0f};
+
+unsigned char zoom_bits[] = { //zoom cursor bitmap
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0xa0, 0x06, 0x30,
+ 0x08, 0x08, 0x10, 0x84, 0x10, 0x84, 0x20, 0x02,
+ 0x26, 0x32, 0x20, 0x02, 0x10, 0x84, 0x10, 0x84,
+ 0x08, 0x08, 0x06, 0x30, 0x01, 0xa0, 0x00, 0x00};
+
+unsigned char zoom_mask[] = { //zoom cursor mask
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+void
+OutputWin::MouseCursor(int cid, bool force)
+{
+ HCURSOR hc, hoc = 0L;
+
+ if(cid == cCursor && !force) return;
+ if(cid == MC_LAST) cid = cCursor;
+ switch(cid) {
+ case MC_ARROW:
+ hoc = SetCursor(LoadCursor(NULL, IDC_ARROW)); break;
+ case MC_CROSS: hoc = SetCursor(LoadCursor(NULL, IDC_CROSS)); break;
+ case MC_WAIT:
+ hoc = SetCursor(LoadCursor(NULL, IDC_WAIT)); break;
+ case MC_TEXT: hoc = SetCursor(LoadCursor(NULL, IDC_IBEAM)); break;
+ case MC_NORTH: hoc = SetCursor(LoadCursor(NULL, IDC_SIZENS)); break;
+ case MC_NE: hoc = SetCursor(LoadCursor(NULL, IDC_SIZENESW));break;
+ case MC_EAST: hoc = SetCursor(LoadCursor(NULL, IDC_SIZEWE)); break;
+ case MC_SE: hoc = SetCursor(LoadCursor(NULL, IDC_SIZENWSE));break;
+ case MC_SALL: hoc = SetCursor(LoadCursor(NULL, IDC_SIZEALL)); break;
+ case MC_MOVE:
+ hc = CreateCursor(hInstance, 8, 8, 16, 16, hand_mask, hand_bits);
+ hoc = SetCursor(hc);
+ break;
+ case MC_ZOOM:
+ hc = CreateCursor(hInstance, 8, 8, 16, 16, zoom_mask, zoom_bits);
+ hoc = SetCursor(hc);
+ break;
+ default: return;
+ }
+ if(hoc) DestroyCursor(hoc);
+ cCursor = cid;
+}
+
+bool
+OutputWin::SetScroll(bool isVert, int iMin, int iMax, int iPSize, int iPos)
+{
+ SCROLLINFO si;
+
+ if(iPos < iMin) return false;
+ si.cbSize = sizeof(SCROLLINFO);
+ si.fMask = SIF_ALL;
+ si.nMin = iMin;
+ si.nMax = iMax;
+ si.nPage = iPSize < iMax ? iPSize : iMax;
+ si.nPos = iPos;
+ si.nTrackPos = 0;
+ SetScrollInfo(hWnd, isVert ? SB_VERT : SB_HORZ, &si, TRUE);
+ return true;
+}
+
+bool
+OutputWin::Erase(DWORD Color)
+{
+ bool bRet;
+ RECT ClientRect;
+
+ if(bRet = BitMapWin::Erase(Color)) {
+ GetClientRect(hWnd, &ClientRect);
+ InvalidateRect(hWnd, &ClientRect, FALSE);
+ }
+ return bRet;
+}
+
+bool
+OutputWin::StartPage()
+{
+ MrkMode = MRK_NONE;
+ MrkRect = 0L;
+ hdc = memDC;
+ if(hgo && hdc) hgo->StartPage();
+ return true;
+}
+
+bool
+OutputWin::EndPage()
+{
+ RECT ClientRect;
+
+ hdc = NULL;
+ GetClientRect(hWnd, &ClientRect);
+ return UpdateRect(&ClientRect, false);
+}
+
+bool
+OutputWin::UpdateRect(RECT *rc, bool invert)
+{
+ HDC dc;
+ BOOL RetVal = FALSE;
+
+ if(dc = GetDC(hWnd)) {
+ RetVal = BitBlt(dc, rc->left, rc->top, rc->right - rc->left,
+ rc->bottom - rc->top, memDC, rc->left, rc->top, invert ? DSTINVERT : SRCCOPY);
+ ReleaseDC(hWnd, dc);
+ }
+ return (RetVal != 0);
+}
+
+bool
+OutputWin::UpdateRect(HDC dc, RECT rc)
+{
+ if(BitBlt(dc, rc.left, rc.top, rc.right - rc.left,
+ rc.bottom - rc.top, memDC, rc.left, rc.top, SRCCOPY))return true;
+ return false;
+}
+
+void
+OutputWin::ShowBitmap(int x, int y, anyOutput* src)
+{
+ int w, h;
+ HDC dc;
+ BitMapWin *sr;
+
+ if(!src) return;
+ sr = (BitMapWin *) src;
+ w = sr->DeskRect.right - sr->DeskRect.left;
+ h = sr->DeskRect.bottom - sr->DeskRect.top;
+ if(dc = GetDC(hWnd)) {
+ BitBlt(dc, x, y, w, h, sr->memDC, 0, 0, SRCCOPY);
+ ReleaseDC(hWnd, dc);
+ }
+}
+
+void
+OutputWin::ShowLine(POINT * pts, int cp, DWORD color)
+{
+ HDC dc;
+ HPEN hP, oP;
+
+ if((hP = CreatePen(PS_SOLID, 0, color))&& (dc = GetDC(hWnd))) {
+ oP = (HPEN)SelectObject(dc, hP);
+ Polyline(dc, pts, cp);
+ SelectObject(dc, oP);
+ DeleteObject(hP);
+ ReleaseDC(hWnd, dc);
+ }
+}
+
+void
+OutputWin::ShowEllipse(POINT p1, POINT p2, DWORD color)
+{
+ HDC dc;
+ HPEN hP, oP;
+
+ if((hP = CreatePen(PS_SOLID, 0, color)) && (dc = GetDC(hWnd))) {
+ oP = (HPEN)SelectObject(dc, hP);
+ Arc(dc, p1.x, p1.y, p2.x, p2.y, 0, 0, 0, 0);
+ SelectObject(dc, oP);
+ DeleteObject(hP);
+ ReleaseDC(hWnd, dc);
+ }
+}
+
+bool
+OutputWin::SetMenu(int type)
+{
+ HMENU hMenu = 0L;
+
+ switch(type) {
+ case MENU_NONE:
+ break;
+ case MENU_SPREAD:
+ hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(MENU_2));
+ break;
+ case MENU_GRAPH:
+ hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(MENU_1));
+ break;
+ case MENU_PAGE:
+ hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(MENU_3));
+ }
+ ::SetMenu(hWnd, hMenu);
+ return true;
+}
+
+void
+OutputWin::CheckMenu(int mid, bool check)
+{
+ HMENU hMenu = GetMenu(hWnd);
+
+ if(mid < CM_T_STANDARD) switch(mid){ //tool mode identifier
+ case TM_STANDARD: mid = CM_T_STANDARD; break;
+ case TM_DRAW: mid = CM_T_DRAW; break;
+ case TM_POLYLINE: mid = CM_T_POLYLINE; break;
+ case TM_POLYGON: mid = CM_T_POLYGON; break;
+ case TM_RECTANGLE: mid = CM_T_RECTANGLE; break;
+ case TM_ROUNDREC: mid = CM_T_ROUNDREC; break;
+ case TM_ELLIPSE: mid = CM_T_ELLIPSE; break;
+ case TM_ARROW: mid = CM_T_ARROW; break;
+ case TM_TEXT: mid = CM_T_TEXT; break;
+ default: return;
+ }
+ if(hMenu) CheckMenuItem(hMenu, mid, check ? MF_CHECKED : MF_UNCHECKED);
+}
+
+void
+OutputWin::FileHistory()
+{
+ HMENU hSubMenu;
+ char **history[] = {&defs.File1, &defs.File2, &defs.File3, &defs.File4, &defs.File5, &defs.File6};
+ int i, j, k;
+
+ if(!hasHistMenu || !defs.File1) return;
+ if(!(hSubMenu = GetSubMenu(GetMenu(hWnd), 0))) return;
+ if(!HistMenuSize) AppendMenu(hSubMenu, MF_SEPARATOR, 0L, 0L);
+ for(i = 0; i < 6 && *history[i]; i++) {
+ k = strlen(*history[i]);
+ for (j = 0; j < k && defs.currPath[j] == (*history[i])[j]; j++);
+ if((*history[i])[j] == '\\' || (*history[i])[j] == '/') j++;
+ if(i < HistMenuSize) {
+ ModifyMenu(hSubMenu, CM_FILE1+i, MF_BYCOMMAND | MF_STRING, CM_FILE1+i, *history[i]+j);
+ }
+ else {
+ AppendMenu(hSubMenu, MF_STRING, CM_FILE1+i, *history[i]+j);
+ }
+ }
+ HistMenuSize = i;
+}
+
+void
+OutputWin::CreateNewWindow(void *g)
+{
+ hWnd = CreateWindow(name, "RLPlot",
+ WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
+ SetWindowLong(hWnd, 0, (long)g); // g is the parent graphic obj
+ SetWindowLong(hWnd, GWL_USERDATA, (long)this);
+ ShowWindow(hWnd, SW_SHOW);
+ UpdateWindow(hWnd);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Copy to Clipboard
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Create Windows Meta File for clipboard
+WinCopyWMF::WinCopyWMF(GraphObj *g)
+{
+ DeskRect.left = DeskRect.top = 0;
+ DeskRect.right = DeskRect.bottom = 0x4fffffffL;
+ hPen = CreatePen(PS_SOLID, 1, dLineCol = 0x00ffffffL);
+ hBrush = CreateSolidBrush(dFillCol =dBgCol = 0x00ffffffL);
+ dPattern = 0L;
+ go = g;
+ hgo = 0L;
+ hres = vres = 1000.0;
+}
+
+WinCopyWMF::~WinCopyWMF()
+{
+ if(hgo) delete hgo;
+ if(hFont) DeleteObject(hFont);
+ if(hBrush) DeleteObject(hBrush);
+ if(hPen) DeleteObject(hPen);
+}
+
+bool
+WinCopyWMF::SetLine(LineDEF *lDef)
+{
+ int iw;
+ HPEN newPen;
+
+ if(!hPen || lDef->width != LineWidth || lDef->width != LineWidth ||
+ lDef->pattern != dPattern || lDef->color != dLineCol) {
+ LineWidth = lDef->width;
+ iw = iround(un2fix(lDef->width));
+ dPattern = lDef->pattern;
+ RLP.finc = 256.0/un2fix(lDef->patlength*8.0);
+ RLP.fp = 0.0;
+ if(iLine == iw && dLineCol == lDef->color && hPen) return true;
+ iLine = iw;
+ dLineCol = lDef->color;
+ newPen = CreatePen(PS_SOLID, iw > 0 ? iw : 1, dLineCol);
+ SelectObject(hdc, newPen);
+ if(hPen) DeleteObject(hPen);
+ hPen = newPen;
+ }
+ return true;
+}
+
+bool
+WinCopyWMF::SetFill(FillDEF *fill)
+{
+ HBRUSH newBrush;
+
+ if(!fill) return false;
+ if((fill->type & 0xff) != FILL_NONE) {
+ if(!hgo) hgo = new HatchOut(this);
+ if(hgo) hgo->SetFill(fill);
+ }
+ else {
+ if(hgo) delete hgo;
+ hgo = NULL;
+ }
+ if(dFillCol != fill->color) {
+ newBrush = CreateSolidBrush(dFillCol = fill->color);
+ SelectObject(hdc, newBrush);
+ if(hBrush) DeleteObject(hBrush);
+ hBrush = newBrush;
+ }
+ dFillCol = fill->color;
+ dFillCol2 = fill->color2;
+ return true;
+}
+
+bool
+WinCopyWMF::SetTextSpec(TextDEF *set)
+{
+ return com_SetTextSpec(set, this, &hFont, &TxtSet, &hdc, true);
+}
+
+bool
+WinCopyWMF::StartPage()
+{
+ int w, h;
+
+
+ if(!go) return false;
+ w = un2ix(go->GetSize(SIZE_GRECT_RIGHT) - go->GetSize(SIZE_GRECT_LEFT));
+ h = un2iy(go->GetSize(SIZE_GRECT_BOTTOM) - go->GetSize(SIZE_GRECT_TOP));
+ w++; h++;
+ if(!(hdc = CreateMetaFile(NULL))) return false;
+ if(hPen)SelectObject(hdc, hPen);
+ if(hBrush) SelectObject(hdc, hBrush);
+ VPorg.fy = -co2fiy(go->GetSize(SIZE_GRECT_TOP));
+ VPorg.fx = -co2fix(go->GetSize(SIZE_GRECT_LEFT));
+ SetMapMode(hdc, MM_HIENGLISH);
+ SetWindowExtEx(hdc, w, h, 0L);
+ SetWindowOrgEx(hdc, 0, 0, 0L);
+ return true;
+}
+
+bool
+WinCopyWMF::EndPage()
+{
+ HMETAFILE hmf;
+ HGLOBAL hGMem;
+ LPMETAFILEPICT pMFP;
+
+ hmf = CloseMetaFile(hdc);
+ hGMem = GlobalAlloc(GHND, sizeof(METAFILEPICT));
+ pMFP = (LPMETAFILEPICT)GlobalLock(hGMem);
+ pMFP->mm = MM_ANISOTROPIC;
+ pMFP->xExt = (long)(Box1.Xmax+Box1.Xmin);
+ pMFP->yExt = (long)(Box1.Ymax+Box1.Ymin);
+ pMFP->hMF = hmf;
+ GlobalUnlock(hGMem);
+ // We do not open the Clipboard because we are responding to WM_RENDERFORMAT
+ SetClipboardData(CF_METAFILEPICT, hGMem);
+ return true;
+}
+
+bool
+WinCopyWMF::oCircle(int x1, int y1, int x2, int y2, char* nam)
+{
+ BOOL RetVal;
+
+ RetVal = Ellipse(hdc, x1, y1, x2, y2);
+ if(RetVal && hgo) return hgo->oCircle(x1, y1, x2, y2);
+ else if(RetVal) return true;
+ return false;
+}
+
+bool
+WinCopyWMF::oPolyline(POINT * pts, int cp, char *nam)
+{
+ int i;
+
+ if(cp < 1) return false;
+ if (dPattern) {
+ for (i = 1; i < cp; i++) PatLine(pts[i-1], pts[i]);
+ return true;
+ }
+ else {
+ if(Polyline(hdc, pts, cp))return true;
+ else return false;
+ }
+ return false;
+}
+
+bool
+WinCopyWMF::oRectangle(int x1, int y1, int x2, int y2, char *name)
+{
+ BOOL RetVal;
+
+ RetVal = Rectangle(hdc, x1, y1, x2, y2);
+ if(RetVal && hgo) return hgo->oRectangle(x1, y1, x2, y2, 0L);
+ else if (RetVal) return true;
+ return false;
+}
+
+bool
+WinCopyWMF::oSolidLine(POINT *p)
+{
+ if(Polyline(hdc, p, 2)) return true;
+ return false;
+}
+
+bool
+WinCopyWMF::oTextOut(int x, int y, char *txt, int cb)
+{
+ return com_oTextOut(x, y, txt, cb, &hFont, &hdc, &TxtSet, true, this);
+}
+
+bool
+WinCopyWMF::oPolygon(POINT *pts, int cp, char *nam)
+{
+ BOOL RetVal;
+
+ RetVal = Polygon(hdc, pts, cp);
+ if(RetVal && hgo) return hgo->oPolygon(pts, cp);
+ else if (RetVal) return true;
+ return false;
+}
+
+bool
+WinCopyWMF::oArc(int x1, int y1, int x2, int y2, int quads)
+{
+ return com_Arc(hdc, x1, y1, x2, y2, quads);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Print
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+PrintWin::PrintWin()
+{
+ int i, j;
+ double pw, ph;
+
+ PrintDriver = PrintDevice = PrintPort = 0L;
+ hPen = 0L;
+ hBrush = 0L;
+ hFont = 0L;
+ hDC = 0L;
+ hgo = 0L;
+ units = defs.cUnits;
+ i = j = 0;
+ GetProfileString("windows", "device", "", TmpTxt, 4096);
+ while(TmpTxt[i] && TmpTxt[i] != ',') i++;
+ TmpTxt[i] = 0;
+ if (i >2) {
+ PrintDevice = strdup(TmpTxt);
+ i++;
+ j = i;
+ while(TmpTxt[i] && TmpTxt[i] != ',') i++;
+ if(i-j > 2) {
+ TmpTxt[i] = 0;
+ PrintDriver = strdup(TmpTxt+j);
+ i++;
+ j = i;
+ while(TmpTxt[i] && TmpTxt[i] != ',') i++;
+ if(i-j > 2) {
+ TmpTxt[i] = 0;
+ PrintPort = strdup(TmpTxt+j);
+ //Get default paper setup
+ if(hDC = CreateDC(PrintDriver, PrintDevice, PrintPort, 0L)) {
+ pw = GetDeviceCaps(hDC, PHYSICALWIDTH);
+ pw /= (double)GetDeviceCaps(hDC, LOGPIXELSX);
+ ph = GetDeviceCaps(hDC, PHYSICALHEIGHT);
+ ph /= (double)GetDeviceCaps(hDC, LOGPIXELSY);
+ switch (defs.cUnits){
+ case 1: pw *= 2.54; ph *= 2.54; break;
+ case 2: break;
+ default: pw *= 25.4; ph *= 25.4; break;
+ }
+ FindPaper(pw, ph, 0.01);
+ DeleteDC(hDC);
+ }
+ hDC = 0L;
+ }
+ }
+ }
+}
+
+PrintWin::~PrintWin()
+{
+ if(PrintDriver) free(PrintDriver);
+ if(PrintDevice) free(PrintDevice);
+ if(PrintPort) free(PrintPort);
+ if(hPen) DeleteObject(hPen);
+ if(hBrush) DeleteObject(hBrush);
+ if(hFont) DeleteObject(hFont);
+}
+
+bool
+PrintWin::SetLine(LineDEF *lDef)
+{
+ int iw;
+ HPEN newPen;
+
+ if(!hPen || lDef->width != LineWidth || lDef->width != LineWidth ||
+ lDef->pattern != dPattern || lDef->color != dLineCol) {
+ LineWidth = lDef->width;
+ iw = iround(un2ix(lDef->width));
+ dPattern = lDef->pattern;
+ RLP.finc = 256.0/un2fix(lDef->patlength*8.0);
+ RLP.fp = 0.0;
+ if(iLine == iw && dLineCol == lDef->color && hPen) return true;
+ iLine = iw;
+ dLineCol = lDef->color;
+ newPen = CreatePen(PS_SOLID, iw > 0 ? iw : 1, dLineCol);
+ SelectObject(hDC, newPen);
+ if(hPen) DeleteObject(hPen);
+ hPen = newPen;
+ }
+ return true;
+}
+
+bool
+PrintWin::SetFill(FillDEF *fill)
+{
+ HBRUSH newBrush;
+
+ if(!fill) return false;
+ if((fill->type & 0xff) != FILL_NONE) {
+ if(!hgo) hgo = new HatchOut(this);
+ if(hgo) hgo->SetFill(fill);
+ }
+ else {
+ if(hgo) delete hgo;
+ hgo = NULL;
+ }
+ newBrush = CreateSolidBrush(fill->color);
+ SelectObject(hDC, newBrush);
+ if(hBrush) DeleteObject(hBrush);
+ hBrush = newBrush;
+ dFillCol = fill->color;
+ dFillCol2 = fill->color2;
+ return true;
+}
+
+bool
+PrintWin::SetTextSpec(TextDEF *set)
+{
+ return com_SetTextSpec(set, this, &hFont, &TxtSet, &hDC, isWIN95);
+}
+
+bool
+PrintWin::StartPage()
+{
+ DOCINFO DocInfo;
+ bool bRet = false;
+
+ if(hDC = CreateDC(PrintDriver, PrintDevice, PrintPort, 0L)) {
+ hPen = CreatePen(PS_SOLID, 1, dLineCol = 0x00ffffffL);
+ hBrush = CreateSolidBrush(dFillCol =dBgCol = 0x00ffffffL);
+ dPattern = 0L;
+ SelectObject(hDC, hPen);
+ SelectObject(hDC, hBrush);
+ memset(&DocInfo, 0, sizeof(DOCINFO));
+ DocInfo.lpszDocName = "RLPlot graph";
+ DocInfo.cbSize = sizeof(DOCINFO);
+ DeskRect.left = DeskRect.top = 0;
+ DeskRect.right = GetDeviceCaps(hDC, HORZRES);
+ DeskRect.bottom = GetDeviceCaps(hDC, VERTRES);
+ hres = (double)GetDeviceCaps(hDC, LOGPIXELSX);
+ vres = (double)GetDeviceCaps(hDC, LOGPIXELSY);
+ if(StartDoc(hDC, &DocInfo) >= 0) {
+ if(::StartPage(hDC)>0) bRet = true;
+ }
+ }
+ return bRet;
+}
+
+bool
+PrintWin::EndPage()
+{
+
+ if(hDC) {
+ ::EndPage(hDC); EndDoc(hDC); DeleteDC(hDC);
+ }
+ hDC = 0L;
+ return true;
+}
+
+bool
+PrintWin::Eject()
+{
+ if(hDC) {
+ ::EndPage(hDC); ::StartPage(hDC); return true;
+ }
+ return false;
+}
+
+bool
+PrintWin::oCircle(int x1, int y1, int x2, int y2, char* nam)
+{
+ BOOL RetVal;
+
+ RetVal = Ellipse(hDC, x1, y1, x2, y2);
+ if(RetVal && hgo) return hgo->oCircle(x1, y1, x2, y2);
+ else if(RetVal) return true;
+ return false;
+}
+
+bool
+PrintWin::oPolyline(POINT * pts, int cp, char *nam)
+{
+ int i;
+
+ if(cp < 1) return FALSE;
+ if (dPattern) {
+ for (i = 1; i < cp; i++) PatLine(pts[i-1], pts[i]);
+ return true;
+ }
+ else {
+ if(Polyline(hDC, pts, cp))return true;
+ else return false;
+ }
+}
+
+bool
+PrintWin::oRectangle(int x1, int y1, int x2, int y2, char *name)
+{
+ BOOL RetVal;
+
+ RetVal = Rectangle(hDC, x1, y1, x2, y2);
+ if(RetVal && hgo) return hgo->oRectangle(x1, y1, x2, y2, 0L);
+ else if (RetVal) return true;
+ return false;
+}
+
+bool
+PrintWin::oSolidLine(POINT *p)
+{
+ if(Polyline(hDC, p, 2)) return true;
+ return false;
+}
+
+bool
+PrintWin::oTextOut(int x, int y, char *txt, int cb)
+{
+ return com_oTextOut(x, y, txt, cb, &hFont, &hDC, &TxtSet, isWIN95, this);
+}
+
+bool
+PrintWin::oPolygon(POINT *pts, int cp, char *nam)
+{
+ BOOL RetVal;
+
+ RetVal = Polygon(hDC, pts, cp);
+ if(RetVal && hgo) return hgo->oPolygon(pts, cp);
+ else if (RetVal) return true;
+ return false;
+}
+
+bool
+PrintWin::oArc(int x1, int y1, int x2, int y2, int quads)
+{
+ return com_Arc(hDC, x1, y1, x2, y2, quads);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Find a suitable www browser
+void FindBrowser()
+{
+ char text[600];
+ long size = 599;
+ HDC dc;
+ HKEY hdl;
+ HWND hwnd;
+ int i;
+
+ //find the default browser
+ if(ERROR_SUCCESS == RegQueryValue(HKEY_CLASSES_ROOT, "http\\shell\\open\\command",
+ text, &size) && size > 7) {
+ if(text[0] == '"') {
+ for(i = size-2; i >3; i--) {
+ if(text[i+1] == '"') {
+ text[i+1] = 0;
+ break;
+ }
+ else text[i+1] = 0;
+ }
+ WWWbrowser = strdup(text+1);
+ }
+ else {
+ for(i = size-1; i >5; i--) {
+ if(0 == stricmp(text+i-3, ".exe")) break;
+ else text[i] = 0;
+ }
+ WWWbrowser = strdup(text);
+ }
+ }
+ //find user default data directory
+ if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, "Environment", NULL,
+ KEY_READ, &hdl)) {
+ text[0] = 0; size=599;
+ RegQueryValueEx(hdl, "HOMEDRIVE", 0, 0, (unsigned char*)text, (unsigned long*)&size);
+ size= 599;
+ RegQueryValueEx(hdl, "HOMEPATH", 0, 0, (unsigned char*)(text+strlen(text)),
+ (unsigned long*)&size);
+ defs.currPath = strdup(text);
+ }
+ //find user application data directory
+ if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER,
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", NULL,
+ KEY_READ, &hdl)) {
+ text[0] = 0; size=599;
+ RegQueryValueEx(hdl, "AppData", 0, 0, (unsigned char*)text, (unsigned long*)&size);
+ strcat(text, "\\RLPlot");
+ defs.IniFile = strdup(text);
+ }
+ //find country specific information
+ // its not a perfect place to do it, but a good one
+ GetProfileString("intl", "sDecimal", ".", text, 2);
+ if(text[0]) defs.DecPoint[0] = text[0];
+ GetProfileString("intl", "sList", ".", text, 2);
+ if(text[0]) defs.ColSep[0] = text[0];
+ if(GetProfileInt("intl", "iMeasure", 0)) defs.dUnits = defs.cUnits = 2;
+ //test if windows95
+ dc = GetDC(hwnd = GetDesktopWindow());
+ isWIN95 = (0 == SetGraphicsMode(dc, GM_ADVANCED));
+ SetGraphicsMode(dc, GM_COMPATIBLE);
+ ReleaseDC(hwnd, dc);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Shutdown or reboot windows
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void HardExit(bool reboot)
+{
+ int tpsize;
+ HANDLE hProcess, hAccessToken;
+ TOKEN_PRIVILEGES *tp;
+
+ hProcess = GetCurrentProcess();
+ tpsize = sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES);
+ tp = (TOKEN_PRIVILEGES *)malloc(tpsize);
+ if(tp){
+ tp->PrivilegeCount = 1;
+ tp->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ if(LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tp->Privileges[0].Luid)) {
+ if(OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hAccessToken))
+ AdjustTokenPrivileges(hAccessToken, FALSE, tp, tpsize, NULL, NULL);
+ }
+ free(tp);
+ }
+ if(reboot) ExitWindowsEx(EWX_REBOOT | EWX_FORCE, NULL);
+ else ExitWindowsEx(EWX_POWEROFF | EWX_FORCE, NULL);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Windos entry point
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine, int nCmdShow )
+{
+ WNDCLASS wndclass;
+ MSG msg;
+ DefsRW *drw;
+
+ //OS dependent initialization
+ dlgtxtheight = 16;
+
+ if(lpCmdLine && lpCmdLine[0] && FileExist(lpCmdLine)) LoadFile = strdup(lpCmdLine);
+ hInstance = hInst;
+ wndclass.style = CS_BYTEALIGNWINDOW | CS_DBLCLKS;
+ wndclass.lpfnWndProc = WndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = sizeof(GraphObj*);
+ wndclass.hInstance = hInstance;
+ wndclass.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_EVAL));
+ wndclass.hCursor = 0L;
+ wndclass.hbrBackground = NULL;
+ wndclass.lpszMenuName = 0L;
+ wndclass.lpszClassName = name;
+
+ RegisterClass(&wndclass);
+ ShowBanner(true);
+ InitTextCursor(true);
+ Printer = new PrintWin();
+ accel = LoadAccelerators(hInstance, MAKEINTRESOURCE(ACCELERATORS_1));
+ while(GetMessage(&msg, NULL, 0, 0)){
+ TranslateMessage(&msg);
+ TranslateAccelerator(msg.hwnd, accel, &msg);
+ DispatchMessage(&msg);
+ }
+ if(defs.IniFile) {
+ if(drw = new DefsRW()){
+ drw->FileIO(FILE_WRITE); delete drw;
+ }
+ }
+ if(WWWbrowser) free(WWWbrowser);
+ if(LoadFile) free(LoadFile);
+ SpreadMain(false);
+ if(Printer) delete Printer;
+ InitTextCursor(false);
+ UnregisterClass(name, hInstance);
+ return msg.wParam;
+}
+
+void CopyData(GraphObj *g, unsigned int cf)
+{
+ HGLOBAL hmem;
+ long cb;
+ unsigned char *dt = 0L;
+ unsigned char *buf;
+
+ if(!g || g->Id != GO_SPREADDATA) return;
+ switch(cf) {
+ case CF_TEXT:
+ if(!g->Command(CMD_COPY_TSV, &dt, 0L))return;
+ break;
+ case CF_SYLK:
+ if(!g->Command(CMD_COPY_SYLK, &dt, 0L))return;
+ break;
+ default:
+ if(cf == cf_rlpxml && g->Command(CMD_COPY_XML, &dt, 0L)) break;
+ else return;
+ }
+ cb = strlen((char*)dt);
+ if(hmem = GlobalAlloc(GMEM_MOVEABLE, cb+2)) {
+ if(buf = (unsigned char *)GlobalLock(hmem)) {
+ memcpy(buf, dt, cb+1);
+ GlobalUnlock(hmem);
+ SetClipboardData(cf, hmem);
+ }
+ }
+}
+
+void CopyGraph(GraphObj *g, unsigned int cf)
+{
+ HGLOBAL hmem;
+ char *dt, *buf;
+ long cb;
+
+ if(!(dt = GraphToMem(g, &cb)))return;
+ if(hmem = GlobalAlloc(GMEM_MOVEABLE, cb+1)) {
+ if(buf = (char *)GlobalLock(hmem)) {
+ memcpy(buf, dt, cb);
+ buf[cb] = 0;
+ GlobalUnlock(hmem);
+ SetClipboardData(cf, hmem);
+ }
+ }
+ free(dt);
+}
+
+void ScrollEvent(bool bVert, HWND hwnd, UINT type, GraphObj *g, OutputWin *w)
+{
+ SCROLLINFO si;
+ int LineStep, cmd, pos;
+
+ if(hwnd && g && w) {
+ cmd = bVert ? CMD_SETVPOS : CMD_SETHPOS;
+ LineStep = g->Id == GO_GRAPH ? 8 : 1;
+ si.fMask = SIF_ALL;
+ si.cbSize = sizeof(SCROLLINFO);
+ if(!(GetScrollInfo(hwnd, bVert ? SB_VERT : SB_HORZ, &si)))return;
+ switch(type){
+ case SB_LINEUP:
+ pos = si.nPos - LineStep;
+ break;
+ case SB_LINEDOWN:
+ pos = si.nPos + LineStep;
+ break;
+ case SB_PAGEUP:
+ pos = (si.nPos - (int)si.nPage) >= si.nMin ?
+ (si.nPos - si.nPage) : si.nMin;
+ break;
+ case SB_PAGEDOWN:
+ pos = ((unsigned)si.nPos + si.nPage*2) < (unsigned)si.nMax ?
+ (si.nPos + si.nPage) : (si.nMax - si.nPage+1);
+ break;
+ case SB_THUMBTRACK:
+ case SB_THUMBPOSITION:
+ pos = si.nTrackPos;
+ break;
+ default:
+ return;
+ }
+ g->Command(cmd, (void*)(& pos), w);
+ }
+}
+
+long OpenFileFromHistory(OutputWin *w, GraphObj *g, int id)
+{
+ char *name = 0L;
+
+ switch (id) {
+ case 0: name = defs.File1; break;
+ case 1: name = defs.File2; break;
+ case 2: name = defs.File3; break;
+ case 3: name = defs.File4; break;
+ case 4: name = defs.File5; break;
+ case 5: name = defs.File6; break;
+ }
+ if(name && FileExist(name)) {
+ g->Command(CMD_DROPFILE, name, w);
+ defs.FileHistory(name);
+ w->FileHistory();
+ }
+ return 0;
+}
+
+static GraphObj *copy_obj;
+
+long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
+{
+ static WinCopyWMF *CopyWMF = NULL;
+ static BitMapWin *CopyBMP = NULL;
+ static bool CtrlDown = false;
+ PAINTSTRUCT ps;
+ OutputWin *w;
+ GraphObj *g;
+ MouseEvent mev;
+ HDC dc;
+ int cc;
+
+ g = (GraphObj *) GetWindowLong(hwnd, 0);
+ w = (OutputWin *) GetWindowLong(hwnd, GWL_USERDATA);
+ if(g && w) switch(message) {
+ case WM_SETFOCUS:
+ if(g->Id == GO_GRAPH) CurrGraph = (Graph*)g;
+ else CurrGraph = 0L;
+ break;
+ case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:
+ HideTextCursor();
+ case WM_MOUSEMOVE: case WM_RBUTTONUP: case WM_LBUTTONUP:
+ mev.x = LOWORD(lParam);
+ mev.y = HIWORD(lParam);
+ mev.StateFlags = 0;
+ if(wParam & MK_LBUTTON) mev.StateFlags |= 1;
+ if(wParam & MK_MBUTTON) mev.StateFlags |= 2;
+ if(wParam & MK_RBUTTON) mev.StateFlags |= 4;
+ if(wParam & MK_SHIFT) mev.StateFlags |= 8;
+ if(wParam & MK_CONTROL) mev.StateFlags |= 16;
+ if(message == WM_LBUTTONUP) mev.Action = MOUSE_LBUP;
+ else if(message == WM_RBUTTONUP) mev.Action = MOUSE_RBUP;
+ else if(message == WM_LBUTTONDBLCLK) mev.Action = MOUSE_LBDOUBLECLICK;
+ else if(message == WM_LBUTTONDOWN) mev.Action = MOUSE_LBDOWN;
+ else if(message == WM_MOUSEMOVE)mev.Action = MOUSE_MOVE;
+ g->Command(CMD_MOUSE_EVENT, (void *)&mev, w);
+ break;
+ case WM_KEYDOWN:
+ if(g && w && (GetKeyState(VK_LCONTROL) || GetKeyState(VK_RCONTROL))){
+ cc = (wParam & 0xff);
+ if(cc == 0xbb || cc == 0x6b ) g->Command(CMD_ZOOM, &"+", w);
+ else if(cc == 0xbd || cc == 0x6d ) g->Command(CMD_ZOOM, &"-", w);
+ else break;
+ return 0;
+ }
+ break;
+ case WM_CHAR:
+ cc = (wParam & 0xff);
+ g->Command(CMD_ADDCHAR, (void *)(& cc), w);
+ return 0;
+ case WM_VSCROLL: case WM_HSCROLL:
+ ScrollEvent(message == WM_VSCROLL, hwnd, wParam & 0xffff, g, w);
+ return 0;
+ }
+
+ switch(message) {
+ case WM_CREATE:
+ //assume that the first window created is the main window
+ if(!MainWnd) MainWnd = hwnd;
+ break;
+ case WM_SIZE:
+ if(g && w) g->Command(CMD_SETSCROLL, 0L, w);
+ break;
+ case WM_INITMENUPOPUP: case WM_NCMOUSEMOVE:
+ SetCursor(LoadCursor(NULL, IDC_ARROW));
+ break;
+ case WM_SETCURSOR:
+ if(w) w->MouseCursor(MC_LAST, true);
+ return TRUE;
+ case WM_SETFOCUS:
+ if(g && w) if(!g->Command(message == WM_SETFOCUS ?
+ CMD_SETFOCUS : CMD_KILLFOCUS, NULL, w))
+ SetCursor(LoadCursor(NULL, IDC_ARROW));
+ return 0;
+ case WM_DESTROYCLIPBOARD:
+ return 0;
+ case WM_RENDERALLFORMATS:
+ // we do not support leaving data on the clipboard after exit
+ OpenClipboard(hwnd);
+ EmptyClipboard();
+ CloseClipboard();
+ return 0;
+ case WM_RENDERFORMAT:
+ if(g && w) switch(wParam){
+ case CF_METAFILEPICT:
+ CopyWMF = new WinCopyWMF(copy_obj);
+ if(CopyWMF && CopyWMF->StartPage()) {
+ copy_obj->DoPlot(CopyWMF);
+ CopyWMF->EndPage();
+ }
+ delete CopyWMF;
+ CopyWMF = NULL;
+ if(copy_obj->Id == GO_GRAPH || copy_obj->Id == GO_PAGE) copy_obj->DoPlot(0L);
+ break;
+ case CF_BITMAP:
+ if((CopyBMP = new BitMapWin(copy_obj)) && CopyBMP->StartPage()) {
+ copy_obj->DoPlot(CopyBMP);
+ CopyBMP->EndPage();
+ SetClipboardData(CF_BITMAP, CopyBMP->scr);
+ CopyBMP->scr = 0L;
+ }
+ delete CopyBMP;
+ CopyBMP = NULL;
+ if(copy_obj->Id == GO_GRAPH || copy_obj->Id == GO_PAGE) copy_obj->DoPlot(0L);
+ break;
+ case CF_SYLK: case CF_TEXT:
+ if(g->Id == GO_SPREADDATA) CopyData(g, wParam);
+ break;
+ default:
+ if(wParam == cf_rlpgraph) CopyGraph(copy_obj, wParam);
+ if(wParam == cf_rlpxml) CopyData(g, wParam);
+ break;
+ }
+ if(w->Erase(defs.Color(COL_BG))) g->DoPlot(w);
+ return 0;
+ case WM_COMMAND:
+ wParam &= 0xffff;
+ if(g && w) switch(wParam) {
+ case CM_EXIT:
+ g->Command(CMD_CAN_DELETE, 0L, 0L);
+ SetWindowLong(hwnd, 0, 0L);
+ SetWindowLong(hwnd, GWL_USERDATA, 0L);
+ w->go = 0L;
+ DestroyWindow(hwnd);
+ return 0;
+ case CM_PASTE:
+ w->MouseCursor(MC_WAIT, true);
+ if(g->Id == GO_SPREADDATA || g->Id == GO_PAGE ||
+ g->Id == GO_GRAPH)TestClipboard(g);
+ w->MouseCursor(MC_ARROW, true);
+ return 0;
+ case CM_COPY: case CM_CUT:
+ EmptyClip();
+ OpenClipboard(hwnd);
+ if(g->Id == GO_SPREADDATA && g->Command(wParam == CM_CUT ? CMD_CUT : CMD_QUERY_COPY, 0L, w)) {
+ SetClipboardData(CF_TEXT, NULL);
+ SetClipboardData(CF_SYLK, NULL);
+ SetClipboardData(cf_rlpxml, NULL);
+ }
+ CloseClipboard();
+ return 0;
+ case CM_UPDATE:
+ g->Command(CMD_UPDATE, 0L, w);
+ return 0;
+ case CM_COPYGRAPH:
+ EmptyClip();
+ OpenClipboard(GetFocus());
+ SetClipboardData(CF_METAFILEPICT, NULL);
+ SetClipboardData(CF_BITMAP, NULL);
+ SetClipboardData(cf_rlpgraph, NULL);
+ if(g->Id == GO_PAGE && CurrGraph) CopyGraph(CurrGraph, cf_rlpobj);
+ copy_obj = g;
+ CloseClipboard();
+ return 0;
+ case CM_OPEN:
+ g->Command(CMD_OPEN, (void *)NULL, w);
+ return 0;
+ case CM_FILE1: case CM_FILE2: case CM_FILE3:
+ case CM_FILE4: case CM_FILE5: case CM_FILE6:
+ return OpenFileFromHistory(w, g, wParam - CM_FILE1);
+ case CM_FILLRANGE:
+ g->Command(CMD_FILLRANGE, (void *)NULL, w);
+ return 0;
+ case CM_ABOUT:
+ RLPlotInfo();
+ return 0;
+ case CM_ZOOM25:
+ g->Command(CMD_ZOOM, &"25", w);
+ return 0;
+ case CM_ZOOM50:
+ g->Command(CMD_ZOOM, &"50", w);
+ return 0;
+ case CM_ZOOM100:
+ g->Command(CMD_ZOOM, &"100", w);
+ return 0;
+ case CM_ZOOM200:
+ g->Command(CMD_ZOOM, &"200", w);
+ return 0;
+ case CM_ZOOM400:
+ g->Command(CMD_ZOOM, &"400", w);
+ return 0;
+ case CM_ZOOMIN:
+ g->Command(CMD_ZOOM, &"+", w);
+ return 0;
+ case CM_ZOOMOUT:
+ g->Command(CMD_ZOOM, &"-", w);
+ return 0;
+ case CM_ZOOMFIT:
+ g->Command(CMD_ZOOM, &"fit", w);
+ return 0;
+ case CM_ADDPLOT:
+ g->Command(CMD_ADDPLOT, 0L, w);
+ return 0;
+ case CM_LEGEND:
+ g->Command(CMD_LEGEND, 0L, w);
+ return 0;
+ case CM_LAYERS:
+ g->Command(CMD_LAYERS, 0L, w);
+ return 0;
+ case CM_NEWGRAPH:
+ g->Command(CMD_NEWGRAPH, 0L, w);
+ return 0;
+ case CM_NEWPAGE:
+ g->Command(CMD_NEWPAGE, 0L, w);
+ return 0;
+ case CM_DELGRAPH:
+ g->Command(CMD_DELGRAPH, 0L, w);
+ return 0;
+ case CM_SAVEDATAAS:
+ g->Command(CMD_SAVEDATAAS, 0L, w);
+ return 0;
+ case CM_REDRAW:
+ if(w->Erase(defs.Color(COL_BG))) g->DoPlot(w);
+ return 0;
+ case CM_DELOBJ:
+ if(CurrGO && CurrGO->parent && CurrGO->parent->
+ Command(CMD_DELOBJ, (void*)CurrGO, w)) {
+ CurrGO = 0L;
+ if(w->Erase(defs.Color(COL_BG))) g->DoPlot(w);
+ }
+ else if(!CurrGO) InfoBox("No object selected!");
+ return 0;
+ case CM_SAVEGRAPHAS:
+ SaveGraphAs(g);
+ return 0;
+ case CM_EXPORT:
+ OpenExportName(g, "hello.svg");
+ g->DoPlot(w);
+ return 0;
+ case CM_PRINT:
+ if(g->Id == GO_SPREADDATA){
+ g->Command(CMD_PRINT, 0L, Printer);
+ return 0;
+ }
+ if(Printer && Printer->StartPage()) {
+ SetCursor(LoadCursor(0L, IDC_WAIT));
+ g->DoPlot(Printer);
+ Printer->EndPage();
+ w->Erase(defs.Color(COL_BG));
+ g->DoPlot(w);
+ SetCursor(LoadCursor(0L, IDC_ARROW));
+ }
+ return 0;
+ case CM_ADDROWCOL:
+ g->Command(CMD_ADDROWCOL, (void *)NULL, w);
+ return 0;
+ case CM_REBOOT:
+ HardExit(true);
+ return 0;
+ case CM_SHUTDOWN:
+ HardExit(false);
+ return 0;
+ case CM_DEFAULTS:
+ g->Command(CMD_CONFIG, 0L, w);
+ return 0;
+ case CM_ADDAXIS:
+ g->Command(CMD_ADDAXIS, 0L, w);
+ return 0;
+ case CM_T_STANDARD:
+ cc = TM_STANDARD;
+ g->Command(CMD_TOOLMODE, (void*)(& cc), w);
+ return 0;
+ case CM_T_DRAW:
+ cc = TM_DRAW;
+ g->Command(CMD_TOOLMODE, (void*)(& cc), w);
+ return 0;
+ case CM_T_POLYLINE:
+ cc = TM_POLYLINE;
+ g->Command(CMD_TOOLMODE, (void*)(& cc), w);
+ return 0;
+ case CM_T_POLYGON:
+ cc = TM_POLYGON;
+ g->Command(CMD_TOOLMODE, (void*)(& cc), w);
+ return 0;
+ case CM_T_RECTANGLE:
+ cc = TM_RECTANGLE;
+ g->Command(CMD_TOOLMODE, (void*)(& cc), w);
+ return 0;
+ case CM_T_ROUNDREC:
+ cc = TM_ROUNDREC;
+ g->Command(CMD_TOOLMODE, (void*)(& cc), w);
+ return 0;
+ case CM_T_ELLIPSE:
+ cc = TM_ELLIPSE;
+ g->Command(CMD_TOOLMODE, (void*)(& cc), w);
+ return 0;
+ case CM_T_ARROW:
+ cc = TM_ARROW;
+ g->Command(CMD_TOOLMODE, (void*)(& cc), w);
+ return 0;
+ case CM_T_TEXT:
+ cc = TM_TEXT;
+ g->Command(CMD_TOOLMODE, (void*)(& cc), w);
+ return 0;
+ case CM_DELKEY: case CM_LEFTARRKEY: case CM_RIGHTARRKEY:
+ case CM_UPARRKEY: case CM_DOWNARRKEY: case CM_POS_FIRST:
+ case CM_POS_LAST: case CM_SHLEFT: case CM_SHRIGHT:
+ case CM_SHUP: case CM_SHDOWN: case CM_TAB:
+ case CM_SHTAB:
+ switch(wParam) {
+ case CM_DELKEY: cc = CMD_DELETE; break;
+ case CM_LEFTARRKEY: cc = CMD_CURRLEFT; break;
+ case CM_RIGHTARRKEY: cc = CMD_CURRIGHT; break;
+ case CM_UPARRKEY: cc = CMD_CURRUP; break;
+ case CM_DOWNARRKEY: cc = CMD_CURRDOWN; break;
+ case CM_POS_FIRST: cc = CMD_POS_FIRST; break;
+ case CM_POS_LAST: cc = CMD_POS_LAST; break;
+ case CM_SHLEFT: cc = CMD_SHIFTLEFT; break;
+ case CM_SHRIGHT: cc = CMD_SHIFTRIGHT; break;
+ case CM_SHUP: cc = CMD_SHIFTUP; break;
+ case CM_SHDOWN: cc = CMD_SHIFTDOWN; break;
+ case CM_TAB: cc = CMD_TAB; break;
+ case CM_SHTAB: cc = CMD_SHTAB; break;
+ }
+ g->Command(cc, (void *)NULL, w);
+ return 0;
+ case CM_PGUP: case CM_PGDOWN:
+ g->Command(wParam == CM_PGUP ? CMD_PAGEUP : CMD_PAGEDOWN, 0L, w);
+ return 0;
+ case CM_UNDO:
+ g->Command(CMD_UNDO, 0L, w);
+ return 0;
+ default:
+ sprintf(TmpTxt, "Command 0x%x (%d)\nreceived", wParam & 0xffff,
+ wParam & 0xffff);
+ MessageBox(hwnd, TmpTxt, "Info", MB_OK | MB_ICONINFORMATION);
+ }
+ return 0;
+ case WM_CLOSE:
+ if(g) {
+ g->Command(CMD_CAN_DELETE, 0L, 0L);
+ SetWindowLong(hwnd, 0, 0L);
+ SetWindowLong(hwnd, GWL_USERDATA, 0L);
+ w->go = 0L;
+ }
+ DestroyWindow(hwnd);
+ return 0;
+ case WM_DESTROY:
+ if(hwnd == MainWnd)PostQuitMessage(0);
+ break;
+ case WM_PAINT:
+ dc = BeginPaint(hwnd, &ps);
+ if(w && dc) w->UpdateRect(dc, ps.rcPaint);
+ EndPaint(hwnd, &ps);
+ break;
+ }
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Dialog window: Windows specific
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+const char dlgname[] = "RLDLGWIN";
+
+long FAR PASCAL DlgWndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
+{
+ OutputWin *w;
+ tag_DlgObj *d;
+ PAINTSTRUCT ps;
+ HDC dc;
+ MouseEvent mev;
+ int i, cc;
+
+ d = (tag_DlgObj *) GetWindowLong(hwnd, 0);
+ w = (OutputWin *) GetWindowLong(hwnd, GWL_USERDATA);
+ switch(message) {
+ case WM_CREATE:
+ break;
+ case WM_KILLFOCUS:
+ HideTextCursorObj(w);
+ if(d) d->Command(CMD_ENDDIALOG, NULL, w);
+ return 0;
+ case WM_TIMER:
+ if(d) d->Command(CMD_ENDDIALOG, d, w);
+ return 0;
+ case WM_DESTROY: case WM_CLOSE:
+ if(d) {
+ d->Command(CMD_UNLOCK, 0L, w);
+ d->Command(CMD_ENDDIALOG, 0L, w);
+ SetWindowLong(hwnd, 0, NULL);
+ }
+ if(w) {
+ SetWindowLong(hwnd, GWL_USERDATA, NULL);
+ delete w;
+ }
+ break;
+ case WM_CHAR:
+ if(0x09 == (cc = wParam & 0xff)) break; //ignore Tab
+ if(d && w) d->Command(CMD_ADDCHAR, (void *)(& cc), w);
+ break;
+ case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:
+ HideTextCursor();
+ case WM_RBUTTONUP: case WM_LBUTTONUP: case WM_MOUSEMOVE:
+ mev.x = LOWORD(lParam); mev.y = HIWORD(lParam); mev.StateFlags = 0;
+ if(wParam & MK_LBUTTON) mev.StateFlags |= 1;
+ if(wParam & MK_MBUTTON) mev.StateFlags |= 2;
+ if(wParam & MK_RBUTTON) mev.StateFlags |= 4;
+ if(wParam & MK_SHIFT) mev.StateFlags |= 8;
+ if(wParam & MK_CONTROL) mev.StateFlags |= 16;
+ if(message == WM_MOUSEMOVE) mev.Action = MOUSE_MOVE;
+ else if(message == WM_LBUTTONDOWN) mev.Action = MOUSE_LBDOWN;
+ else if(message == WM_LBUTTONUP) mev.Action = MOUSE_LBUP;
+ else if(message == WM_RBUTTONUP) mev.Action = MOUSE_RBUP;
+ else if(message == WM_LBUTTONDBLCLK) mev.Action = MOUSE_LBDOUBLECLICK;
+ if(d && w) d->Command(CMD_MOUSE_EVENT, (void *)&mev, w);
+ break;
+ case WM_COMMAND:
+ wParam &= 0xffff;
+ i = 0;
+ switch(wParam) {
+ case CM_DELKEY: i = CMD_DELETE; break;
+ case CM_LEFTARRKEY: i = CMD_CURRLEFT; break;
+ case CM_RIGHTARRKEY: i = CMD_CURRIGHT; break;
+ case CM_UPARRKEY: i = CMD_CURRUP; break;
+ case CM_DOWNARRKEY: i = CMD_CURRDOWN; break;
+ case CM_TAB: i = CMD_TAB; break;
+ case CM_SHTAB: i = CMD_SHTAB; break;
+ case CM_POS_FIRST: i = CMD_POS_FIRST; break;
+ case CM_POS_LAST: i = CMD_POS_LAST; break;
+ case CM_SHLEFT: i = CMD_SHIFTLEFT; break;
+ case CM_SHRIGHT: i = CMD_SHIFTRIGHT; break;
+ case CM_UNDO: i = CMD_UNDO; break;
+ }
+ if(i && d && w) d->Command(i, 0L, w);
+ return 0;
+ case WM_PAINT:
+ dc = BeginPaint(hwnd, &ps);
+ if(w && dc){
+ w->HideMark(); w->UpdateRect(dc, ps.rcPaint);
+ }
+ EndPaint(hwnd, &ps);
+ break;
+ }
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+void *CreateDlgWnd(char *title, int x, int y, int width, int height, tag_DlgObj *d, DWORD flags)
+{
+ WNDCLASS wndclass;
+ OutputWin *w;
+ HWND hDlg, hFoc;
+ RECT rec, BoxRec, DeskRect;
+ DWORD ws;
+
+ wndclass.style = CS_BYTEALIGNWINDOW | CS_DBLCLKS;
+ wndclass.lpfnWndProc = DlgWndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = sizeof(tag_DlgObj *);
+ wndclass.hInstance = hInstance;
+ wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_EVAL));
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.hbrBackground = NULL;
+ wndclass.lpszMenuName = NULL;
+ wndclass.lpszClassName = dlgname;
+ RegisterClass(&wndclass);
+ hFoc = GetFocus();
+ if(hFoc) {
+ GetWindowRect(hFoc, &rec);
+ x += rec.left;
+ y += rec.top;
+ }
+ ws = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS;
+ if(!(flags & 0x2)) ws |= WS_CAPTION;
+ hDlg = CreateWindow(dlgname, title, ws,
+ x, y, width, height, GetFocus(), NULL, hInstance, NULL);
+ w = new OutputWin(0L, hDlg);
+ w->units = defs.cUnits;
+ if(hDlg && w && w->Erase(0x00c0c0c0L)) {
+ SetWindowLong(hDlg, GWL_USERDATA, (long)w);
+ SetWindowLong(hDlg, 0, (long)d);
+ ShowWindow(hDlg, SW_SHOW);
+ if(flags & 0x01) { //center on screen
+ GetWindowRect(hDlg, &BoxRec);
+ GetClientRect(GetDesktopWindow(), &DeskRect);
+ SetWindowPos(hDlg, HWND_TOPMOST, (DeskRect.right -DeskRect.left)/2 -
+ (BoxRec.right - BoxRec.left)/2, (DeskRect.bottom -DeskRect.top)/2 -
+ (BoxRec.bottom- BoxRec.top)/2, BoxRec.right - BoxRec.left,
+ BoxRec.bottom - BoxRec.top, 0);
+ }
+ if(flags & 0x04) SetTimer(hDlg, 1, 100, 0L);
+ UpdateWindow(hDlg); d->DoPlot(w);
+ }
+ else {
+ if(w) delete (w); return 0L;
+ }
+ return hDlg;
+}
+
+void LoopDlgWnd() //keep message processing running
+{
+ MSG msg;
+
+ GetMessage(&msg, NULL, 0, 0); TranslateMessage(&msg);
+ TranslateAccelerator(msg.hwnd, accel, &msg);
+ DispatchMessage(&msg);
+}
+
+void CloseDlgWnd(void *hDlg)
+{
+ if(hDlg) SendMessage((HWND)hDlg, WM_CLOSE, 0, 0);
+}
+
+void ShowDlgWnd(void *hDlg)
+{
+ ShowWindow((HWND)hDlg, SW_SHOW);
+ SetFocus((HWND)hDlg);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// OS independent interface to Windows specific classes
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+anyOutput *NewDispClass(GraphObj *g)
+{
+ return new OutputWin(g, 0L);
+}
+
+bool DelDispClass(anyOutput *w)
+{
+ if (w) delete (OutputWin*) w;
+ return true;
+}
+
+anyOutput *NewBitmapClass(int w, int h, double hr, double vr)
+{
+ return new BitMapWin(w, h, hr, vr);
+}
+
+bool DelBitmapClass(anyOutput *w)
+{
+ if (w) delete (BitMapWin*) w;
+ return true;
+}
diff --git a/WinSpec.h b/WinSpec.h
new file mode 100755
index 0000000..f6a6423
--- /dev/null
+++ b/WinSpec.h
@@ -0,0 +1,130 @@
+//WinSpec.h, Copyright (c) 2000, 2001 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
+//
+class BitMapWin:public anyOutput{
+public:
+ HBITMAP scr;
+ GraphObj *go;
+ HDC memDC;
+ HPEN hPen, oldPen;
+ HBRUSH hBrush, oldBrush;
+ HFONT hFont;
+ HatchOut *hgo;
+
+ BitMapWin(GraphObj *g, HWND hw);
+ BitMapWin(int w, int h, double hr, double vr);
+ BitMapWin(GraphObj *g);
+ ~BitMapWin();
+ bool SetLine(LineDEF *lDef);
+ bool SetFill(FillDEF *fill);
+ bool SetTextSpec(TextDEF *set);
+ virtual bool Erase(DWORD Color);
+ virtual bool StartPage() {return true;};
+ bool CopyBitmap(int x, int y, anyOutput* src, int sx, int sy,
+ int sw, int sh, bool invert);
+ bool oGetTextExtent(char *text, int cb, int *width, int *height);
+ bool oGetPix(int x, int y, DWORD *col);
+ bool oDrawIcon(int type, int x, int y);
+ bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L);
+ bool oPolyline(POINT * pts, int cp, char *nam = 0L);
+ bool oRectangle(int x1, int y1, int x2, int y2, char* nam = 0L);
+ bool oSolidLine(POINT *p);
+ bool oTextOut(int x, int y, char *txt, int cb);
+ bool oPolygon(POINT *pts, int cp, char *nam = 0L);
+ bool oArc(int x1, int y1, int x2, int y2, int quads);
+};
+
+class OutputWin:public BitMapWin{
+public:
+ HWND hWnd;
+ HDC hdc;
+
+ OutputWin(GraphObj *g, HWND hw);
+ ~OutputWin();
+ bool ActualSize(RECT *rc);
+ void Caption(char *txt);
+ void MouseCursor(int cid, bool force);
+ bool SetScroll(bool isVert, int iMin, int iMax, int iPSize, int iPos);
+ bool Erase(DWORD Color);
+ bool StartPage();
+ bool EndPage();
+ bool UpdateRect(RECT *rc, bool invert);
+ bool UpdateRect(HDC hdc, RECT rc);
+ void ShowBitmap(int x, int y, anyOutput* src);
+ void ShowLine(POINT * pts, int cp, DWORD color);
+ void ShowEllipse(POINT p1, POINT p2, DWORD color);
+ bool SetMenu(int type);
+ void CheckMenu(int mid, bool check);
+ void FileHistory();
+
+private:
+ void CreateNewWindow(void *g);
+};
+
+class WinCopyWMF:public anyOutput {
+public:
+ WinCopyWMF(GraphObj *g);
+ ~WinCopyWMF();
+ bool SetLine(LineDEF *lDef);
+ bool SetFill(FillDEF *fill);
+ bool SetTextSpec(TextDEF *set);
+ bool StartPage();
+ bool EndPage();
+ bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L);
+ bool oPolyline(POINT * pts, int cp, char *nam = 0L);
+ bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
+ bool oSolidLine(POINT *p);
+ bool oTextOut(int x, int y, char *txt, int cb);
+ bool oPolygon(POINT *pts, int cp, char *nam = 0L);
+ bool oArc(int x1, int y1, int x2, int y2, int quads);
+
+private:
+ GraphObj *go;
+ HDC hdc;
+ HPEN hPen;
+ HBRUSH hBrush;
+ HFONT hFont;
+ HatchOut *hgo;
+};
+
+class PrintWin:public anyOutput{
+public:
+ PrintWin();
+ ~PrintWin();
+ bool SetLine(LineDEF *lDef);
+ bool SetFill(FillDEF *fill);
+ bool SetTextSpec(TextDEF *set);
+ bool StartPage();
+ bool EndPage();
+ bool Eject();
+ bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L);
+ bool oPolyline(POINT * pts, int cp, char *nam = 0L);
+ bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
+ bool oSolidLine(POINT *p);
+ bool oTextOut(int x, int y, char *txt, int cb);
+ bool oPolygon(POINT *pts, int cp, char *nam = 0L);
+ bool oArc(int x1, int y1, int x2, int y2, int quads);
+
+private:
+ HPEN hPen;
+ HBRUSH hBrush;
+ HFONT hFont;
+ HatchOut *hgo;
+ char *PrintDevice, *PrintDriver, *PrintPort;
+ HDC hDC;
+};
diff --git a/exprlp.cpp b/exprlp.cpp
new file mode 100755
index 0000000..b374c7f
--- /dev/null
+++ b/exprlp.cpp
@@ -0,0 +1,532 @@
+//exprlp.cpp, Copyright (c) 2002, 2003, 2004, 2005 R.Lackner
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <unistd.h> //required for unlink()
+#include "Version.h"
+#include "rlplot.h"
+
+int file_fmt = FF_UNKNOWN;
+bool bQuiet = false, bSVGtype = false, bDelete = false;
+char *szFile1 = 0L, *szFile2 = 0L;
+int dlgtxtheight = 12; //stub: not used
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// direct messages to console
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void InfoBox(char *Msg)
+{
+ if(!bQuiet) fprintf(stderr, "exprlp INFO: %s\n", Msg);
+}
+
+void ErrorBox(char *Msg)
+{
+ if(!bQuiet) fprintf(stderr, "exprlp ERROR: %s\n", Msg);
+}
+
+bool YesNoBox(char *Msg)
+{
+return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// STUBS: we do not need dialogs
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool ShowLayers(GraphObj *root)
+{
+ return false;
+}
+
+bool GetBitmapRes(double *res, double *width, double *height, char *header)
+{
+ return false;
+}
+
+bool GetPaper(double *w, double *h)
+{
+ *w = *h = 1.0;
+ return true;
+}
+
+bool Symbol::PropertyDlg()
+{
+ return false;
+}
+
+bool Bubble::PropertyDlg()
+{
+ return false;
+}
+
+bool Bar::PropertyDlg()
+{
+ return false;
+}
+
+bool DataLine::PropertyDlg()
+{
+ return false;
+}
+
+bool DataPolygon::PropertyDlg()
+{
+ return false;
+}
+
+bool RegLine::PropertyDlg()
+{
+ return false;
+}
+
+bool SDellipse::PropertyDlg()
+{
+ return false;
+}
+
+bool ErrorBar::PropertyDlg()
+{
+ return false;
+}
+
+bool Arrow::PropertyDlg()
+{
+ return false;
+}
+
+bool Box::PropertyDlg()
+{
+ return false;
+}
+
+bool Whisker::PropertyDlg()
+{
+ return false;
+}
+
+bool DropLine::PropertyDlg()
+{
+ return false;
+}
+
+bool Sphere::PropertyDlg()
+{
+ return false;
+}
+
+bool Plane3D::PropertyDlg()
+{
+ return false;
+}
+
+bool Brick::PropertyDlg()
+{
+ return false;
+}
+
+bool DropLine3D::PropertyDlg()
+{
+ return false;
+}
+
+bool Arrow3D::PropertyDlg()
+{
+ return false;
+}
+
+bool Line3D::PropertyDlg()
+{
+ return false;
+}
+
+bool Label::PropertyDlg()
+{
+ return false;
+}
+
+bool segment::PropertyDlg()
+{
+ return false;
+}
+
+bool polyline::PropertyDlg()
+{
+ return false;
+}
+
+bool polygon::PropertyDlg()
+{
+ return false;
+}
+
+bool rectangle::PropertyDlg()
+{
+ return false;
+}
+
+bool PlotScatt::PropertyDlg()
+{
+ return false;
+}
+
+bool Regression::PropertyDlg()
+{
+ return false;
+}
+
+bool FreqDist::PropertyDlg()
+{
+ return false;
+}
+
+bool BubblePlot::PropertyDlg()
+{
+ return false;
+}
+
+bool PolarPlot::PropertyDlg()
+{
+ return false;
+}
+
+bool PolarPlot::Config()
+{
+ return false;
+}
+
+bool BoxPlot::PropertyDlg()
+{
+ return false;
+}
+
+bool DensDisp::PropertyDlg()
+{
+ return false;
+}
+
+bool StackBar::PropertyDlg()
+{
+ return false;
+}
+
+bool Waterfall::PropertyDlg()
+{
+ return false;
+}
+
+bool MultiLines::PropertyDlg()
+{
+ return false;
+}
+
+bool PieChart::PropertyDlg()
+{
+ return false;
+}
+
+bool StarChart::PropertyDlg()
+{
+ return false;
+}
+
+bool Function::PropertyDlg()
+{
+ return false;
+}
+
+bool Scatt3D::PropertyDlg()
+{
+ return false;
+}
+
+bool FitFunc::PropertyDlg()
+{
+ return false;
+}
+
+bool Plot3D::PropertyDlg()
+{
+ return false;
+}
+
+bool Plot3D::AddPlot(int)
+{
+ return false;
+}
+
+bool Chart25D::PropertyDlg()
+{
+ return false;
+}
+
+bool Ribbon25D::PropertyDlg()
+{
+ return false;
+}
+
+bool BubblePlot3D::PropertyDlg()
+{
+ return false;
+}
+
+bool GridLine::PropertyDlg()
+{
+ return false;
+}
+
+bool Tick::PropertyDlg()
+{
+ return false;
+}
+
+bool Axis::PropertyDlg()
+{
+ return false;
+}
+
+bool Graph::AddPlot(int family)
+{
+ return false;
+}
+
+bool Graph::PropertyDlg()
+{
+ return false;
+}
+
+bool Graph::Configure()
+{
+ return false;
+}
+
+bool Graph::AddAxis()
+{
+ return false;
+}
+
+bool Page::Configure()
+{
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// some more STUBS .....
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+char *SaveGraphAsName(char *oldname)
+{
+ return 0L;
+}
+
+char *OpenGraphName(char *oldname)
+{
+ return 0L;
+}
+
+void HideTextCursor()
+{
+ return;
+}
+
+void HideTextCursorObj(anyOutput *out)
+{
+ return;
+}
+
+void ShowTextCursor(anyOutput *out, RECT *disp, DWORD color)
+{
+ return;
+}
+
+anyOutput *NewDispClass(GraphObj *g)
+{
+ return 0L;
+}
+
+bool DelDispClass(anyOutput *w)
+{
+ return false;
+}
+
+anyOutput *NewBitmapClass(int w, int h, double hr, double vr)
+{
+ return 0L;
+}
+
+bool DelBitmapClass(anyOutput *w)
+{
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create a root object to handle I/O
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class ExpRoot:public GraphObj{
+public:
+ ExpRoot(char *file1, char *file2);
+ ~ExpRoot();
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+
+private:
+ char *name1, *name2;
+ GraphObj *go;
+};
+
+ExpRoot::ExpRoot(char *file1, char *file2):GraphObj(0L, 0L)
+{
+ if(file1 && strcmp("-", file1)) name1 = file1;
+ else name1 = 0L;
+ if(file2 && strcmp("-", file2)) name2 = file2;
+ else name2 = 0L;
+ go = 0L;
+ OpenGraph(this, name1, 0L);
+ if(bDelete && name1 && name1[0]) unlink(name1);
+}
+
+ExpRoot::~ExpRoot()
+{
+ if(go) {
+ DeleteGO(go);
+ if(!bQuiet)fprintf(stderr, "Object deleted after read\n");
+ }
+}
+
+bool
+ExpRoot::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i;
+
+ switch(cmd) {
+ case CMD_DROP_GRAPH:
+ go = (GraphObj*)tmpl;
+ if(go) {
+ go->Command(CMD_SET_DATAOBJ, 0L, 0L);
+ switch(file_fmt){
+ case FF_SVG:
+ DoExportSvg(go, name2, bSVGtype ? 1L : 0L);
+ break;
+ case FF_WMF:
+ DoExportWmf(go, name2, 600.0f, 0L);
+ break;
+ case FF_EPS:
+ DoExportEps(go, name2, 0L);
+ break;
+ default:
+ ErrorBox("Unknown file extension or format of destination");
+ }
+ DeleteGO(go);
+ go = 0L;
+ }
+ break;
+ }
+ return true;
+}
+
+
+int Usage()
+{
+ printf("______________________________________________________________\n");
+ printf("\nexprlp: RLPlot export utility, version %s.\n", SZ_VERSION);
+ printf("Copyright (C) 2002-2004 R. Lackner\n");
+ printf("This is free software published under the GNU\n");
+ printf("general public licence (GPL).\n");
+ printf("\nUsage: exprlp [options] <input> [options] [<output>]\n");
+ printf("\nOptions:\n");
+ printf(" - use stdin/stdout as input or output file; requires\n");
+ printf(" that file format is set by -e | -s | -w option\n");
+ printf(" not an option in the strict sense\n");
+ printf(" -h print this information\n");
+ printf(" -d delete input file after read\n");
+ printf(" -e output Encapsulated PostScript, *.eps\n");
+ printf(" -s output Scalable Vector Graphics, *.svg\n");
+ printf(" -S like -s, start output with \"Content-Type: image/svg+xml\"\n");
+ printf(" -v print RLPlot version\n");
+ printf(" -w output Windows Meta File, *.wmf\n");
+ printf(" -q quiet mode: suppress output to the console\n");
+ printf("\nExamples:\n");
+ printf(" exprlp foo.rlp foo.svg ;exports Scalable Vector Graphics\n");
+ printf(" exprlp -q foo.rlp foo.eps ;exports Encapsulated PostScript, no messages\n");
+ printf(" exprlp foo.rlp foo.wmf ;exports Windows Meta File\n");
+ printf(" exprlp -sq foo.rlp - ;exports SVG to the console, no messages\n");
+ printf(" exprlp -eq - - ;converts inputfile from stdin to EPS\n");
+ printf(" on stdout: useful for pipes\n");
+ printf("\n switch character is either \'-\' or \'/\'\n");
+ printf("______________________________________________________________\n\n");
+ if(szFile1) free(szFile1); if(szFile2) free(szFile2);
+ szFile1 = szFile2 = 0L;
+ return 1;
+}
+
+int main (int argc, char **argv)
+{
+ ExpRoot *base = 0L;
+ int i, j, k;
+
+ for (i = 1, j = 0; i < argc; i++) {
+ if(argv[i][0] == '-' || (argv[i][0] == '/' && strlen(argv[i]) < 5)) {
+ //check for switch
+ for(k = 1; argv[i][k-1]; k++) {
+ switch(argv[i][k]){
+ case 'h': case 'H': case '?':
+ return Usage();
+ case 'd':
+ bDelete = true;
+ break;
+ case 'S':
+ bSVGtype = true;
+ case 's':
+ file_fmt = FF_SVG;
+ break;
+ case 'e': case 'E':
+ file_fmt = FF_EPS;
+ break;
+ case 'w': case 'W':
+ file_fmt = FF_WMF;
+ break;
+ case 'q': case 'Q':
+ bQuiet = true;
+ break;
+ case 'v': case 'V':
+ printf("RLPlot version %s\n", SZ_VERSION);
+ return 0;
+ case '\0':
+ if(k == 1) {
+ if(j == 0) szFile1 = strdup("-");
+ else if(j == 1) szFile2 = strdup("-");
+ j++;
+ }
+ break;
+ }
+ }
+ }
+ else switch(j) {
+ case 0:
+ szFile1 = strdup(argv[i]);
+ j++;
+ break;
+ case 1:
+ szFile2 = strdup(argv[i]);
+ j++;
+ }
+ }
+ if(file_fmt == FF_UNKNOWN && szFile2 && (i = strlen(szFile2)) > 4) {
+ if(0==strcmp(".svg", szFile2+i-4)) file_fmt = FF_SVG;
+ else if(0==strcmp(".wmf", szFile2+i-4)) file_fmt = FF_WMF;
+ else if(0==strcmp(".eps", szFile2+i-4)) file_fmt = FF_EPS;
+ }
+ if(file_fmt == FF_UNKNOWN) {
+ if(szFile1)printf("\n**** Unknown file extension or format ****\n\n");
+ return Usage();
+ }
+ if(!bQuiet) {
+ fprintf(stderr,"Input file \"%s\"\n", szFile1);
+ fprintf(stderr,"Output file \"%s\"\n", szFile2);
+ }
+ setlocale(LC_ALL, "");
+ if(!szFile1) return Usage();
+ base = new ExpRoot(szFile1, szFile2);
+ if(base) {
+ delete base;
+ }
+ if(szFile1) free(szFile1); if(szFile2) free(szFile2);
+ return 0;
+}
diff --git a/gpl.txt b/gpl.txt
new file mode 100755
index 0000000..5b6e7c6
--- /dev/null
+++ b/gpl.txt
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/mfcalc.cpp b/mfcalc.cpp
new file mode 100755
index 0000000..8f7f943
--- /dev/null
+++ b/mfcalc.cpp
@@ -0,0 +1,2299 @@
+
+/* A Bison parser, made from ../../rlplot/mfcalc.y
+ by GNU Bison version 1.28 */
+
+#define YYBISON 1 /* Identify Bison output. */
+
+#define NUM 257
+#define ARR 258
+#define STR 259
+#define PI 260
+#define E 261
+#define CLVAL 262
+#define VAR 263
+#define FNCT 264
+#define TXT 265
+#define CLAUSE 266
+#define COLR 267
+#define COLC 268
+#define AND 269
+#define OR 270
+#define EQ 271
+#define NE 272
+#define GT 273
+#define GE 274
+#define LT 275
+#define LE 276
+#define NEG 277
+
+
+/*
+ mfcalc.y, mfcalc.cpp, Copyright (c) 2004, 2005 R.Lackner
+ parse string and simple math: based on the bison 'mfcalc' example
+
+ 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 <math.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+#include "rlplot.h"
+
+struct symrec {
+ int type, row, col;
+ unsigned int h_name;
+ char *name, *text;
+ struct {
+ double var;
+ double (*fnctptr)(...);
+ } value;
+ int arg_type;
+ struct symrec *next;
+};
+
+// syntactical information
+struct syntax_info {
+ int last_tok; //resolve ambiguous ':'
+ double clval; //current value for where - clause
+ int cl1, cl2; //limits of clause formula in buffer
+ struct syntax_info *next;
+ };
+static syntax_info *syntax_level = 0L;
+
+
+typedef struct{
+ double val;
+ int type;
+ symrec *tptr;
+ double *a_data;
+ char *text;
+ int a_count;
+
+}YYSTYPE;
+
+static symrec *putsym (unsigned int h_name, int sym_type, int arg_type);
+static symrec *getsym (unsigned int h_name, char *sym_name = 0L);
+static int push(YYSTYPE *res, YYSTYPE *val);
+static void store_res(YYSTYPE *res);
+static char *PushString(char *text);
+static char *add_strings(char *st1, char *st2);
+static char *string_value(YYSTYPE *exp);
+static int get_range(YYSTYPE *res, char *first, char *last);
+static void exec_clause(YYSTYPE *res);
+static YYSTYPE *proc_clause(YYSTYPE *res);
+static void yyerror(char *s);
+static int yylex(void);
+
+static char res_txt[1000];
+static anyResult line_res = {ET_UNKNOWN, 0.0, res_txt};
+static double line_result;
+static DataObj *curr_data;
+
+//the current command buffer
+static char *buffer = 0L;
+static int buff_pos = 0;
+#include <stdio.h>
+
+#ifndef __cplusplus
+#ifndef __STDC__
+#define const
+#endif
+#endif
+
+
+
+#define YYFINAL 79
+#define YYFLAG -32768
+#define YYNTBASE 36
+
+#define YYTRANSLATE(x) ((unsigned)(x) <= 277 ? yytranslate[x] : 40)
+
+static const char yytranslate[] = { 0,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 32,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 34,
+ 35, 28, 27, 13, 26, 2, 29, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 33, 2,
+ 12, 2, 17, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 31, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 1, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 14, 15, 16, 18, 19,
+ 20, 21, 22, 23, 24, 25, 30
+};
+
+#if YYDEBUG != 0
+static const short yyprhs[] = { 0,
+ 0, 1, 4, 7, 10, 13, 16, 19, 22, 24,
+ 28, 32, 36, 38, 40, 42, 44, 46, 48, 52,
+ 57, 61, 65, 69, 73, 77, 81, 85, 89, 93,
+ 97, 101, 105, 109, 113, 116, 120, 124, 128, 134,
+ 140, 146
+};
+
+static const short yyrhs[] = { -1,
+ 36, 37, 0, 32, 33, 0, 39, 32, 0, 39,
+ 33, 0, 38, 32, 0, 38, 33, 0, 1, 32,
+ 0, 5, 0, 38, 27, 39, 0, 39, 27, 38,
+ 0, 38, 27, 38, 0, 3, 0, 11, 0, 8,
+ 0, 6, 0, 7, 0, 9, 0, 9, 12, 39,
+ 0, 10, 34, 39, 35, 0, 39, 18, 39, 0,
+ 39, 19, 39, 0, 39, 20, 39, 0, 39, 21,
+ 39, 0, 39, 22, 39, 0, 39, 23, 39, 0,
+ 39, 24, 39, 0, 39, 25, 39, 0, 39, 27,
+ 39, 0, 39, 26, 39, 0, 39, 28, 39, 0,
+ 39, 29, 39, 0, 39, 13, 39, 0, 9, 15,
+ 9, 0, 26, 39, 0, 39, 31, 39, 0, 39,
+ 14, 39, 0, 34, 39, 35, 0, 39, 17, 39,
+ 16, 39, 0, 39, 17, 5, 16, 5, 0, 39,
+ 17, 5, 16, 39, 0, 39, 17, 39, 16, 5,
+ 0
+};
+
+#endif
+
+#if YYDEBUG != 0
+static const short yyrline[] = { 0,
+ 102, 103, 106, 107, 108, 109, 110, 111, 114, 116,
+ 117, 118, 121, 122, 123, 124, 125, 126, 127, 129,
+ 131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
+ 141, 142, 144, 145, 146, 147, 148, 149, 150, 151,
+ 152, 153
+};
+#endif
+
+
+#if YYDEBUG != 0 || defined (YYERROR_VERBOSE)
+
+static const char * const yytname[] = { "$","error","$undefined.","NUM","ARR",
+"STR","PI","E","CLVAL","VAR","FNCT","TXT","'='","','","CLAUSE","COLR","COLC",
+"'?'","AND","OR","EQ","NE","GT","GE","LT","LE","'-'","'+'","'*'","'/'","NEG",
+"'^'","'\\n'","';'","'('","')'","input","line","str_exp","exp", NULL
+};
+#endif
+
+static const short yyr1[] = { 0,
+ 36, 36, 37, 37, 37, 37, 37, 37, 38, 38,
+ 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+ 39, 39
+};
+
+static const short yyr2[] = { 0,
+ 0, 2, 2, 2, 2, 2, 2, 2, 1, 3,
+ 3, 3, 1, 1, 1, 1, 1, 1, 3, 4,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 2, 3, 3, 3, 5, 5,
+ 5, 5
+};
+
+static const short yydefact[] = { 1,
+ 0, 0, 13, 9, 16, 17, 15, 18, 0, 14,
+ 0, 0, 0, 2, 0, 0, 8, 0, 0, 0,
+ 35, 3, 0, 0, 6, 7, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 4, 5, 19, 34, 0, 0, 38, 12,
+ 10, 33, 37, 0, 0, 21, 22, 23, 24, 25,
+ 26, 27, 28, 30, 11, 29, 31, 32, 36, 20,
+ 29, 0, 0, 40, 41, 42, 39, 0, 0
+};
+
+static const short yydefgoto[] = { 1,
+ 14, 15, 16
+};
+
+static const short yypact[] = {-32768,
+ 33, -31,-32768,-32768,-32768,-32768,-32768, 0, -26,-32768,
+ 115, -19, 115,-32768, -22, 171,-32768, 115, 23, 115,
+ 4,-32768, 133, 42,-32768,-32768, 115, 115, 72, 115,
+ 115, 115, 115, 115, 115, 115, 115, 115, 42, 115,
+ 115, 115,-32768,-32768, 211,-32768, 152, 115,-32768,-32768,
+ 230, 246, 261, 47, 192, 109, 109, 29, 29, 29,
+ 29, 29, 29, -25,-32768, -25, 4, 4, 4,-32768,
+ -25, 81, 94,-32768, 261,-32768, 261, 46,-32768
+};
+
+static const short yypgoto[] = {-32768,
+-32768, 30, -11
+};
+
+
+#define YYLAST 292
+
+
+static const short yytable[] = { 21,
+ 17, 23, 40, 41, 24, 42, 45, 20, 47, 25,
+ 26, 18, 51, 22, 19, 52, 53, 55, 56, 57,
+ 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
+ 69, 46, 78, 2, 42, 3, 71, 4, 5, 6,
+ 7, 8, 9, 10, 3, 79, 4, 5, 6, 7,
+ 8, 9, 10, 50, 38, 48, 40, 41, 11, 42,
+ 75, 77, 72, 0, 12, 0, 13, 11, 65, 0,
+ 0, 0, 0, 0, 3, 13, 54, 5, 6, 7,
+ 8, 9, 10, 3, 0, 74, 5, 6, 7, 8,
+ 9, 10, 0, 0, 0, 0, 3, 11, 76, 5,
+ 6, 7, 8, 9, 10, 13, 11, 0, 0, 0,
+ 0, 0, 0, 0, 13, 0, 0, 3, 0, 11,
+ 5, 6, 7, 8, 9, 10, 0, 13, 32, 33,
+ 34, 35, 36, 37, 38, 48, 40, 41, 0, 42,
+ 11, 0, 0, 0, 0, 27, 28, 0, 13, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 48,
+ 40, 41, 0, 42, 27, 28, 0, 49, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 48, 40,
+ 41, 0, 42, 27, 28, 0, 70, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 0, 42, 43, 44, 27, 28, 0, 73, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 48, 40,
+ 41, 0, 42, 27, 28, 0, 0, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 48, 40, 41,
+ 0, 42, 27, 28, 0, 0, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 0, 40, 41, 28,
+ 42, 0, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 48, 40, 41, 0, 42, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 48, 40, 41,
+ 0, 42
+};
+
+static const short yycheck[] = { 11,
+ 32, 13, 28, 29, 27, 31, 18, 34, 20, 32,
+ 33, 12, 24, 33, 15, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 9, 0, 1, 31, 3, 48, 5, 6, 7,
+ 8, 9, 10, 11, 3, 0, 5, 6, 7, 8,
+ 9, 10, 11, 24, 26, 27, 28, 29, 26, 31,
+ 72, 73, 16, -1, 32, -1, 34, 26, 39, -1,
+ -1, -1, -1, -1, 3, 34, 5, 6, 7, 8,
+ 9, 10, 11, 3, -1, 5, 6, 7, 8, 9,
+ 10, 11, -1, -1, -1, -1, 3, 26, 5, 6,
+ 7, 8, 9, 10, 11, 34, 26, -1, -1, -1,
+ -1, -1, -1, -1, 34, -1, -1, 3, -1, 26,
+ 6, 7, 8, 9, 10, 11, -1, 34, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, -1, 31,
+ 26, -1, -1, -1, -1, 13, 14, -1, 34, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, -1, 31, 13, 14, -1, 35, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+ 29, -1, 31, 13, 14, -1, 35, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ -1, 31, 32, 33, 13, 14, -1, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+ 29, -1, 31, 13, 14, -1, -1, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ -1, 31, 13, 14, -1, -1, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, -1, 28, 29, 14,
+ 31, -1, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, -1, 31, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ -1, 31
+};
+/* -*-C-*- Note some compilers choke on comments on `#line' lines. */
+
+/* This file comes from bison-1.28. */
+
+/* Skeleton output parser for bison,
+ Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
+
+ 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, 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. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* This is the parser code that is written into each bison parser
+ when the %semantic_parser declaration is not specified in the grammar.
+ It was written by Richard Stallman by simplifying the hairy parser
+ used when %semantic_parser is specified. */
+
+#ifndef YYSTACK_USE_ALLOCA
+#ifdef alloca
+#define YYSTACK_USE_ALLOCA
+#else /* alloca not defined */
+#ifdef __GNUC__
+#define YYSTACK_USE_ALLOCA
+#define alloca __builtin_alloca
+#else /* not GNU C. */
+#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386))
+#define YYSTACK_USE_ALLOCA
+#include <alloca.h>
+#else /* not sparc */
+/* We think this test detects Watcom and Microsoft C. */
+/* This used to test MSDOS, but that is a bad idea
+ since that symbol is in the user namespace. */
+#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__)
+#if 0 /* No need for malloc.h, which pollutes the namespace;
+ instead, just don't use alloca. */
+#include <malloc.h>
+#endif
+#else /* not MSDOS, or __TURBOC__ */
+#if defined(_AIX)
+/* I don't know what this was needed for, but it pollutes the namespace.
+ So I turned it off. rms, 2 May 1997. */
+/* #include <malloc.h> */
+ #pragma alloca
+#define YYSTACK_USE_ALLOCA
+#else /* not MSDOS, or __TURBOC__, or _AIX */
+#if 0
+#ifdef __hpux /* haible at ilog.fr says this works for HPUX 9.05 and up,
+ and on HPUX 10. Eventually we can turn this on. */
+#define YYSTACK_USE_ALLOCA
+#define alloca __builtin_alloca
+#endif /* __hpux */
+#endif
+#endif /* not _AIX */
+#endif /* not MSDOS, or __TURBOC__ */
+#endif /* not sparc */
+#endif /* not GNU C */
+#endif /* alloca not defined */
+#endif /* YYSTACK_USE_ALLOCA not defined */
+
+#ifdef YYSTACK_USE_ALLOCA
+#define YYSTACK_ALLOC alloca
+#else
+#define YYSTACK_ALLOC malloc
+#endif
+
+/* Note: there must be only one dollar sign in this file.
+ It is replaced by the list of actions, each action
+ as one case of the switch. */
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY -2
+#define YYEOF 0
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrlab1
+/* Like YYERROR except do call yyerror.
+ This remains here temporarily to ease the
+ transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+#define YYFAIL goto yyerrlab
+#define YYRECOVERING() (!!yyerrstatus)
+#define YYBACKUP(token, value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { yychar = (token), yylval = (value); \
+ yychar1 = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { yyerror ("syntax error: cannot back up"); YYERROR; } \
+while (0)
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+#ifndef YYPURE
+#define YYLEX yylex()
+#endif
+
+#ifdef YYPURE
+#ifdef YYLSP_NEEDED
+#ifdef YYLEX_PARAM
+#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM)
+#else
+#define YYLEX yylex(&yylval, &yylloc)
+#endif
+#else /* not YYLSP_NEEDED */
+#ifdef YYLEX_PARAM
+#define YYLEX yylex(&yylval, YYLEX_PARAM)
+#else
+#define YYLEX yylex(&yylval)
+#endif
+#endif /* not YYLSP_NEEDED */
+#endif
+
+/* If nonreentrant, generate the variables here */
+
+#ifndef YYPURE
+
+int yychar; /* the lookahead symbol */
+YYSTYPE yylval; /* the semantic value of the */
+ /* lookahead symbol */
+
+#ifdef YYLSP_NEEDED
+YYLTYPE yylloc; /* location data for the lookahead */
+ /* symbol */
+#endif
+
+int yynerrs; /* number of parse errors so far */
+#endif /* not YYPURE */
+
+#if YYDEBUG != 0
+int yydebug; /* nonzero means print parse trace */
+/* Since this is uninitialized, it does not stop multiple parsers
+ from coexisting. */
+#endif
+
+/* YYINITDEPTH indicates the initial size of the parser's stacks */
+
+#ifndef YYINITDEPTH
+#define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH is the maximum size the stacks can grow to
+ (effective only if the built-in stack extension method is used). */
+
+#if YYMAXDEPTH == 0
+#undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH 10000
+#endif
+
+/* Define __yy_memcpy. Note that the size argument
+ should be passed with type unsigned int, because that is what the non-GCC
+ definitions require. With GCC, __builtin_memcpy takes an arg
+ of type size_t, but it can handle unsigned int. */
+
+#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */
+#define __yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT)
+#else /* not GNU C or C++ */
+#ifndef __cplusplus
+
+/* This is the most reliable way to avoid incompatibilities
+ in available built-in functions on various systems. */
+static void
+__yy_memcpy (to, from, count)
+ char *to;
+ char *from;
+ unsigned int count;
+{
+ register char *f = from;
+ register char *t = to;
+ register int i = count;
+
+ while (i-- > 0)
+ *t++ = *f++;
+}
+
+#else /* __cplusplus */
+
+/* This is the most reliable way to avoid incompatibilities
+ in available built-in functions on various systems. */
+static void
+__yy_memcpy (char *to, char *from, unsigned int count)
+{
+ register char *t = to;
+ register char *f = from;
+ register int i = count;
+
+ while (i-- > 0)
+ *t++ = *f++;
+}
+
+#endif
+#endif
+
+
+
+/* The user can define YYPARSE_PARAM as the name of an argument to be passed
+ into yyparse. The argument should have type void *.
+ It should actually point to an object.
+ Grammar actions can access the variable by casting it
+ to the proper pointer type. */
+
+#ifdef YYPARSE_PARAM
+#ifdef __cplusplus
+#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL
+#else /* not __cplusplus */
+#define YYPARSE_PARAM_ARG YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
+#endif /* not __cplusplus */
+#else /* not YYPARSE_PARAM */
+#define YYPARSE_PARAM_ARG
+#define YYPARSE_PARAM_DECL
+#endif /* not YYPARSE_PARAM */
+
+/* Prevent warning if -Wstrict-prototypes. */
+#ifdef __GNUC__
+#ifdef YYPARSE_PARAM
+int yyparse (void *);
+#else
+int yyparse (void);
+#endif
+#endif
+
+int
+yyparse(YYPARSE_PARAM_ARG)
+ YYPARSE_PARAM_DECL
+{
+ register int yystate;
+ register int yyn;
+ register short *yyssp;
+ register YYSTYPE *yyvsp;
+ int yyerrstatus; /* number of tokens to shift before error messages enabled */
+ int yychar1 = 0; /* lookahead token as an internal (translated) token number */
+
+ short yyssa[YYINITDEPTH]; /* the state stack */
+ YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */
+
+ short *yyss = yyssa; /* refer to the stacks thru separate pointers */
+ YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */
+
+#ifdef YYLSP_NEEDED
+ YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */
+ YYLTYPE *yyls = yylsa;
+ YYLTYPE *yylsp;
+
+#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--)
+#else
+#define YYPOPSTACK (yyvsp--, yyssp--)
+#endif
+
+ int yystacksize = YYINITDEPTH;
+ int yyfree_stacks = 0;
+
+#ifdef YYPURE
+ int yychar;
+ YYSTYPE yylval;
+ int yynerrs;
+#ifdef YYLSP_NEEDED
+ YYLTYPE yylloc;
+#endif
+#endif
+
+ YYSTYPE yyval; /* the variable used to return */
+ /* semantic values from the action */
+ /* routines */
+
+ int yylen;
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Starting parse\n");
+#endif
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss - 1;
+ yyvsp = yyvs;
+#ifdef YYLSP_NEEDED
+ yylsp = yyls;
+#endif
+
+/* Push a new state, which is found in yystate . */
+/* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks. */
+yynewstate:
+
+ *++yyssp = yystate;
+
+ if (yyssp >= yyss + yystacksize - 1)
+ {
+ /* Give user a chance to reallocate the stack */
+ /* Use copies of these so that the &'s don't force the real ones into memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short *yyss1 = yyss;
+#ifdef YYLSP_NEEDED
+ YYLTYPE *yyls1 = yyls;
+#endif
+
+ /* Get the current used size of the three stacks, in elements. */
+ int size = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ /* Each stack pointer address is followed by the size of
+ the data in use in that stack, in bytes. */
+#ifdef YYLSP_NEEDED
+ /* This used to be a conditional around just the two extra args,
+ but that might be undefined if yyoverflow is a macro. */
+ yyoverflow("parser stack overflow",
+ &yyss1, size * sizeof (*yyssp),
+ &yyvs1, size * sizeof (*yyvsp),
+ &yyls1, size * sizeof (*yylsp),
+ &yystacksize);
+#else
+ yyoverflow("parser stack overflow",
+ &yyss1, size * sizeof (*yyssp),
+ &yyvs1, size * sizeof (*yyvsp),
+ &yystacksize);
+#endif
+
+ yyss = yyss1; yyvs = yyvs1;
+#ifdef YYLSP_NEEDED
+ yyls = yyls1;
+#endif
+#else /* no yyoverflow */
+ /* Extend the stack our own way. */
+ if (yystacksize >= YYMAXDEPTH)
+ {
+ yyerror("parser stack overflow");
+ if (yyfree_stacks)
+ {
+ free (yyss);
+ free (yyvs);
+#ifdef YYLSP_NEEDED
+ free (yyls);
+#endif
+ }
+ return 2;
+ }
+ yystacksize *= 2;
+ if (yystacksize > YYMAXDEPTH)
+ yystacksize = YYMAXDEPTH;
+#ifndef YYSTACK_USE_ALLOCA
+ yyfree_stacks = 1;
+#endif
+ yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp));
+ __yy_memcpy ((char *)yyss, (char *)yyss1,
+ size * (unsigned int) sizeof (*yyssp));
+ yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp));
+ __yy_memcpy ((char *)yyvs, (char *)yyvs1,
+ size * (unsigned int) sizeof (*yyvsp));
+#ifdef YYLSP_NEEDED
+ yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp));
+ __yy_memcpy ((char *)yyls, (char *)yyls1,
+ size * (unsigned int) sizeof (*yylsp));
+#endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + size - 1;
+ yyvsp = yyvs + size - 1;
+#ifdef YYLSP_NEEDED
+ yylsp = yyls + size - 1;
+#endif
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Stack size increased to %d\n", yystacksize);
+#endif
+
+ if (yyssp >= yyss + yystacksize - 1)
+ YYABORT;
+ }
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Entering state %d\n", yystate);
+#endif
+
+ goto yybackup;
+ yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a lookahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYFLAG)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* yychar is either YYEMPTY or YYEOF
+ or a valid token in external form. */
+
+ if (yychar == YYEMPTY)
+ {
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Reading a token: ");
+#endif
+ yychar = YYLEX;
+ }
+
+ /* Convert token to internal form (in yychar1) for indexing tables with */
+
+ if (yychar <= 0) /* This means end of input. */
+ {
+ yychar1 = 0;
+ yychar = YYEOF; /* Don't call YYLEX any more */
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Now at end of input.\n");
+#endif
+ }
+ else
+ {
+ yychar1 = YYTRANSLATE(yychar);
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
+ /* Give the individual parser a way to print the precise meaning
+ of a token, for further debugging info. */
+#ifdef YYPRINT
+ YYPRINT (stderr, yychar, yylval);
+#endif
+ fprintf (stderr, ")\n");
+ }
+#endif
+ }
+
+ yyn += yychar1;
+ if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
+ goto yydefault;
+
+ yyn = yytable[yyn];
+
+ /* yyn is what to do for this token type in this state.
+ Negative => reduce, -yyn is rule number.
+ Positive => shift, yyn is new state.
+ New state is final state => don't bother to shift,
+ just return success.
+ 0, or most negative number => error. */
+
+ if (yyn < 0)
+ {
+ if (yyn == YYFLAG)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+ else if (yyn == 0)
+ goto yyerrlab;
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the lookahead token. */
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
+#endif
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+ *++yylsp = yylloc;
+#endif
+
+ /* count tokens shifted since error; after three, turn off error status. */
+ if (yyerrstatus) yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+/* Do the default action for the current state. */
+yydefault:
+
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+
+/* Do a reduction. yyn is the number of a rule to reduce with. */
+yyreduce:
+ yylen = yyr2[yyn];
+ if (yylen > 0)
+ yyval = yyvsp[1-yylen]; /* implement default value of the action */
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ int i;
+
+ fprintf (stderr, "Reducing via rule %d (line %d), ",
+ yyn, yyrline[yyn]);
+
+ /* Print the symbols being reduced, and their result. */
+ for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
+ fprintf (stderr, "%s ", yytname[yyrhs[i]]);
+ fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
+ }
+#endif
+
+
+ switch (yyn) {
+
+case 4:
+{store_res(&yyvsp[-1]); return 0;;
+ break;}
+case 5:
+{store_res(&yyvsp[-1]); return 0;;
+ break;}
+case 6:
+{store_res(&yyvsp[-1]); return 0;;
+ break;}
+case 7:
+{store_res(&yyvsp[-1]); return 0;;
+ break;}
+case 8:
+{yyerrok;;
+ break;}
+case 9:
+{yyval.type=STR;;
+ break;}
+case 10:
+{yyval.text=add_strings(yyvsp[-2].text, string_value(&yyvsp[0])); yyval.type=STR;;
+ break;}
+case 11:
+{yyval.text=add_strings(string_value(&yyvsp[-2]), yyvsp[0].text); yyval.type=STR;;
+ break;}
+case 12:
+{yyval.text=add_strings(yyvsp[-2].text, yyvsp[0].text); yyval.type=STR;;
+ break;}
+case 13:
+{yyval.val = yyvsp[0].val; yyval.type = NUM;;
+ break;}
+case 14:
+{yyval.val = 0.0;;
+ break;}
+case 15:
+{yyval.val = syntax_level ? syntax_level->clval : 0.0; ;
+ break;}
+case 16:
+{yyval.val = 3.14159265358979; yyval.type = NUM;;
+ break;}
+case 17:
+{yyval.val = 2.71828182845905; yyval.type = NUM;;
+ break;}
+case 18:
+{yyval.val = yyvsp[0].tptr->value.var; yyval.type=VAR;
+ break;}
+case 19:
+{yyval.val = yyvsp[-2].tptr->value.var = yyvsp[0].val;
+ if(yyvsp[-2].tptr->row >=0 && yyvsp[-2].tptr->col >= 0 && curr_data) curr_data->SetValue(yyvsp[-2].tptr->row, yyvsp[-2].tptr->col, yyvsp[0].val);;
+ break;}
+case 20:
+{yyval.val = (yyvsp[-3].tptr->arg_type == ARR) ? ((*yyvsp[-3].tptr->value.fnctptr)(proc_clause(&yyvsp[-1]))) :
+ (*(yyvsp[-3].tptr->value.fnctptr))(yyvsp[-1].val);;
+ break;}
+case 21:
+{yyval.val = ((yyvsp[-2].val != 0) && (yyvsp[0].val != 0))? 1 : 0;;
+ break;}
+case 22:
+{yyval.val = ((yyvsp[-2].val != 0) || (yyvsp[0].val != 0))? 1 : 0;;
+ break;}
+case 23:
+{yyval.val = (yyvsp[-2].val == yyvsp[0].val) ? 1 : 0;;
+ break;}
+case 24:
+{yyval.val = (yyvsp[-2].val != yyvsp[0].val) ? 1 : 0;;
+ break;}
+case 25:
+{yyval.val = (yyvsp[-2].val > yyvsp[0].val) ? 1 : 0;;
+ break;}
+case 26:
+{yyval.val = (yyvsp[-2].val >= yyvsp[0].val) ? 1 : 0;;
+ break;}
+case 27:
+{yyval.val = (yyvsp[-2].val < yyvsp[0].val) ? 1 : 0;;
+ break;}
+case 28:
+{yyval.val = (yyvsp[-2].val <= yyvsp[0].val) ? 1 : 0;;
+ break;}
+case 29:
+{yyval.val = yyvsp[-2].val + yyvsp[0].val;;
+ break;}
+case 30:
+{yyval.val = yyvsp[-2].val - yyvsp[0].val;;
+ break;}
+case 31:
+{yyval.val = yyvsp[-2].val * yyvsp[0].val;;
+ break;}
+case 32:
+{if(yyvsp[0].val != 0.0) yyval.val = yyvsp[-2].val / yyvsp[0].val;
+ else yyval.val = (getsym(HashValue((unsigned char*)"zdiv")))->value.var; ;
+ break;}
+case 33:
+{push(&yyval, &yyvsp[0]);;
+ break;}
+case 34:
+{get_range(&yyval, yyvsp[-2].tptr->name, yyvsp[0].tptr->name);;
+ break;}
+case 35:
+{yyval.val = -yyvsp[0].val;;
+ break;}
+case 36:
+{yyval.val = pow(yyvsp[-2].val, yyvsp[0].val);;
+ break;}
+case 37:
+{yyval.val = yyvsp[-2].val; exec_clause(&yyval);;
+ break;}
+case 38:
+{memcpy(&yyval, &yyvsp[-1], sizeof(YYSTYPE));
+ break;}
+case 39:
+{memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
+ break;}
+case 40:
+{memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
+ break;}
+case 41:
+{memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
+ break;}
+case 42:
+{memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
+ break;}
+}
+ /* the action file gets copied in in place of this dollarsign */
+
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+#ifdef YYLSP_NEEDED
+ yylsp -= yylen;
+#endif
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ short *ssp1 = yyss - 1;
+ fprintf (stderr, "state stack now");
+ while (ssp1 != yyssp)
+ fprintf (stderr, " %d", *++ssp1);
+ fprintf (stderr, "\n");
+ }
+#endif
+
+ *++yyvsp = yyval;
+
+#ifdef YYLSP_NEEDED
+ yylsp++;
+ if (yylen == 0)
+ {
+ yylsp->first_line = yylloc.first_line;
+ yylsp->first_column = yylloc.first_column;
+ yylsp->last_line = (yylsp-1)->last_line;
+ yylsp->last_column = (yylsp-1)->last_column;
+ yylsp->text = 0;
+ }
+ else
+ {
+ yylsp->last_line = (yylsp+yylen-1)->last_line;
+ yylsp->last_column = (yylsp+yylen-1)->last_column;
+ }
+#endif
+
+ /* Now "shift" the result of the reduction.
+ Determine what state that goes to,
+ based on the state we popped back to
+ and the rule number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
+ if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTBASE];
+
+ goto yynewstate;
+
+yyerrlab: /* here on detecting error */
+
+ if (! yyerrstatus)
+ /* If not already recovering from an error, report this error. */
+ {
+ ++yynerrs;
+
+#ifdef YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (yyn > YYFLAG && yyn < YYLAST)
+ {
+ int size = 0;
+ char *msg;
+ int x, count;
+
+ count = 0;
+ /* Start X at -yyn if nec to avoid negative indexes in yycheck. */
+ for (x = (yyn < 0 ? -yyn : 0);
+ x < (sizeof(yytname) / sizeof(char *)); x++)
+ if (yycheck[x + yyn] == x)
+ size += strlen(yytname[x]) + 15, count++;
+ msg = (char *) malloc(size + 15);
+ if (msg != 0)
+ {
+ strcpy(msg, "parse error");
+
+ if (count < 5)
+ {
+ count = 0;
+ for (x = (yyn < 0 ? -yyn : 0);
+ x < (sizeof(yytname) / sizeof(char *)); x++)
+ if (yycheck[x + yyn] == x)
+ {
+ strcat(msg, count == 0 ? ", expecting `" : " or `");
+ strcat(msg, yytname[x]);
+ strcat(msg, "'");
+ count++;
+ }
+ }
+ yyerror(msg);
+ free(msg);
+ }
+ else
+ yyerror ("parse error; also virtual memory exceeded");
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror("parse error");
+ }
+
+ goto yyerrlab1;
+yyerrlab1: /* here on error raised explicitly by an action */
+
+ if (yyerrstatus == 3)
+ {
+ /* if just tried and failed to reuse lookahead token after an error, discard it. */
+
+ /* return failure if at end of input */
+ if (yychar == YYEOF)
+ YYABORT;
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
+#endif
+
+ yychar = YYEMPTY;
+ }
+
+ /* Else will try to reuse lookahead token
+ after shifting the error token. */
+
+ yyerrstatus = 3; /* Each real token shifted decrements this */
+
+ goto yyerrhandle;
+
+yyerrdefault: /* current state does not do anything special for the error token. */
+
+#if 0
+ /* This is wrong; only states that explicitly want error tokens
+ should shift them. */
+ yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/
+ if (yyn) goto yydefault;
+#endif
+
+yyerrpop: /* pop the current state because it cannot handle the error token */
+
+ if (yyssp == yyss) YYABORT;
+ yyvsp--;
+ yystate = *--yyssp;
+#ifdef YYLSP_NEEDED
+ yylsp--;
+#endif
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ short *ssp1 = yyss - 1;
+ fprintf (stderr, "Error: state stack now");
+ while (ssp1 != yyssp)
+ fprintf (stderr, " %d", *++ssp1);
+ fprintf (stderr, "\n");
+ }
+#endif
+
+yyerrhandle:
+
+ yyn = yypact[yystate];
+ if (yyn == YYFLAG)
+ goto yyerrdefault;
+
+ yyn += YYTERROR;
+ if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
+ goto yyerrdefault;
+
+ yyn = yytable[yyn];
+ if (yyn < 0)
+ {
+ if (yyn == YYFLAG)
+ goto yyerrpop;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+ else if (yyn == 0)
+ goto yyerrpop;
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Shifting error token, ");
+#endif
+
+ *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+ *++yylsp = yylloc;
+#endif
+
+ yystate = yyn;
+ goto yynewstate;
+
+ yyacceptlab:
+ /* YYACCEPT comes here. */
+ if (yyfree_stacks)
+ {
+ free (yyss);
+ free (yyvs);
+#ifdef YYLSP_NEEDED
+ free (yyls);
+#endif
+ }
+ return 0;
+
+ yyabortlab:
+ /* YYABORT comes here. */
+ if (yyfree_stacks)
+ {
+ free (yyss);
+ free (yyvs);
+#ifdef YYLSP_NEEDED
+ free (yyls);
+#endif
+ }
+ return 1;
+}
+
+
+static char *last_error = 0L;
+static void yyerror(char *s)
+{
+ //Called by yyparse on error
+ if(curr_data) curr_data->Command(CMD_ERROR, last_error = s, 0L);
+ else printf("%s\n", s);
+}
+
+static void store_res(YYSTYPE *res)
+{
+ if(res->type == STR) {
+ line_result = 0.0;
+ line_res.type = ET_TEXT;
+ line_res. value = 0.0;
+ if(res->text) strcpy(res_txt, res->text);
+ }
+ else if(res->type == ARR || (res->a_data)) {
+ line_result = 0.0;
+ line_res.type = ET_TEXT;
+ line_res. value = 0.0;
+ strcpy(res_txt, "#ARRAY");
+ }
+ else if(res->tptr && res->tptr->type == TXT) {
+ line_result = 0.0;
+ line_res.type = ET_TEXT;
+ line_res.value = 0.0;
+ if(res->tptr->text) strcpy(res_txt, res->tptr->text);
+ }
+ else {
+ line_result = res->val;
+ line_res.type = ET_VALUE;
+ line_res.value = res->val;
+ }
+}
+
+static char *add_strings(char *st1, char *st2)
+{
+ char *newstr, *ret;
+
+ if(st1 && st2) {
+ if(newstr = (char*)malloc(strlen(st1) +strlen(st2) +4)) {
+ sprintf(newstr, "%s%s", st1, st2);
+ ret = PushString(newstr);
+ free(newstr);
+ return ret;
+ }
+ else return 0L;
+ }
+ if(st1) return st1;
+ if(st2) return st2;
+ return 0L;
+}
+
+static char *string_value(YYSTYPE *exp)
+{
+ char *st1, tmp[50];
+
+ if(exp->type == STR){
+ st1 = exp->text;
+ }
+ else if(exp->tptr && exp->tptr->type == TXT) {
+ st1 = exp->tptr->text;
+ }
+ else {
+ sprintf(tmp,"%g", exp->val);
+ st1 = tmp;
+ }
+ return PushString(st1);
+}
+
+// store syntactical information
+static void push_syntax()
+{
+ syntax_info *next;
+
+ if(!(next = (syntax_info*)calloc(1, sizeof(syntax_info)))) return;
+ if(syntax_level)memcpy(next, syntax_level, sizeof(syntax_info));
+ next->next=syntax_level;
+ syntax_level = next;
+}
+
+static void pop_syntax()
+{
+ syntax_info *si;
+
+ if(si = syntax_level) {
+ syntax_level = si->next;
+ free(si);
+ }
+}
+
+// more functions
+static double sign(double v)
+{
+ if(v > 0.0) return 1.0;
+ if(v < 0.0) return -1.0;
+ return 0.0;
+}
+
+static double factorial(double v)
+{
+ return factrl((int)v);
+}
+
+static void close_arr_func(YYSTYPE *sr)
+{
+ free(sr->a_data);
+ sr->a_data = 0L; sr->a_count = 0;
+ if(sr->type == ARR) sr->type = NUM;
+}
+
+#undef min
+static double min(YYSTYPE *sr)
+{
+ int i;
+
+ if(!sr) return 0.0;
+ if(sr->a_data && sr->a_data){
+ for(i = 1, sr->val = sr->a_data[0]; i < sr->a_count; i++)
+ if(sr->a_data[i] < sr->val) sr->val = sr->a_data[i];
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+#undef max
+static double max(YYSTYPE *sr)
+{
+ int i;
+
+ if(!sr) return 0.0;
+ if(sr->a_data){
+ for(i = 1, sr->val = sr->a_data[0]; i < sr->a_count; i++)
+ if(sr->a_data[i] > sr->val) sr->val = sr->a_data[i];
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double count(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ if(sr->a_data){
+ sr->val = (double)sr->a_count;
+ close_arr_func(sr);
+ }
+ else sr->val = 0.0;
+ return sr->val;
+}
+
+static double sum(YYSTYPE *sr)
+{
+ int i;
+
+ if(!sr) return 0.0;
+ if(sr->a_data){
+ for(i = 1, sr->val = sr->a_data[0]; i < sr->a_count; i++) sr->val += sr->a_data[i];
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double calc_variance(double *values, int n)
+{
+ int i;
+ double ss, d, mean = d_amean(n, values);
+
+ for(i=0, ss=0.0; i < n; i++) ss += ((d=values[i]-mean)*d);
+ return (ss/(n-1));
+}
+
+static double mean(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ if(sr->a_data && sr->a_count){
+ sr->val = d_amean(sr->a_count, sr->a_data );
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double gmean(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ if(sr->a_data && sr->a_count){
+ sr->val = d_gmean(sr->a_count, sr->a_data );
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double hmean(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ if(sr->a_data && sr->a_count){
+ sr->val = d_hmean(sr->a_count, sr->a_data );
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double quartile1(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ if(sr->a_data && sr->a_count){
+ d_quartile(sr->a_count, sr->a_data, &sr->val, 0L, 0L);
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double quartile2(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ if(sr->a_data && sr->a_count){
+ d_quartile(sr->a_count, sr->a_data, 0L, &sr->val, 0L);
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double quartile3(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ if(sr->a_data && sr->a_count){
+ d_quartile(sr->a_count, sr->a_data, 0L, 0L, &sr->val);
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double variance(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ sr->val = 0.0;
+ if(sr->a_data && sr->a_count){
+ sr->val = calc_variance(sr->a_data, sr->a_count);
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double stdev(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ sr->val = 0.0;
+ if(sr->a_data && sr->a_count){
+ sr->val = sqrt(calc_variance(sr->a_data, sr->a_count));
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double sterr(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ sr->val = 0.0;
+ if(sr->a_data && sr->a_count){
+ sr->val = sqrt(calc_variance(sr->a_data, sr->a_count))/sqrt(sr->a_count);
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double tdist(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ sr->val = 0.0;
+ if(sr->a_data && sr->a_count == 2){
+ sr->val = t_dist(sr->a_data[0], sr->a_data[1]);
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double fdist(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ sr->val = 0;
+ if(sr->a_data && sr->a_count == 3){
+ sr->val = f_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+struct init
+{
+ unsigned int h_name;
+ double (*fnct)(double);
+ int arg_type;
+};
+
+static struct init arith_fncts[] = {
+ {HashValue((unsigned char*)"variance"), (double(*)(double))&variance, ARR},
+ {HashValue((unsigned char*)"stdev"), (double(*)(double))&stdev, ARR},
+ {HashValue((unsigned char*)"sterr"), (double(*)(double))&sterr, ARR},
+ {HashValue((unsigned char*)"min"), (double(*)(double))&min, ARR},
+ {HashValue((unsigned char*)"max"), (double(*)(double))&max, ARR},
+ {HashValue((unsigned char*)"count"), (double(*)(double))&count, ARR},
+ {HashValue((unsigned char*)"sum"), (double(*)(double))&sum, ARR},
+ {HashValue((unsigned char*)"mean"), (double(*)(double))&mean, ARR},
+ {HashValue((unsigned char*)"median"), (double(*)(double))&quartile2, ARR},
+ {HashValue((unsigned char*)"quartile1"), (double(*)(double))&quartile1, ARR},
+ {HashValue((unsigned char*)"quartile2"), (double(*)(double))&quartile2, ARR},
+ {HashValue((unsigned char*)"quartile3"), (double(*)(double))&quartile3, ARR},
+ {HashValue((unsigned char*)"gmean"), (double(*)(double))&gmean, ARR},
+ {HashValue((unsigned char*)"hmean"), (double(*)(double))&hmean, ARR},
+ {HashValue((unsigned char*)"tdist"), (double(*)(double))&tdist, ARR},
+ {HashValue((unsigned char*)"fdist"), (double(*)(double))&fdist, ARR},
+ {HashValue((unsigned char*)"sign"), sign, VAR},
+ {HashValue((unsigned char*)"gammaln"), gammln, VAR},
+ {HashValue((unsigned char*)"factorial"), factorial, VAR},
+ {HashValue((unsigned char*)"abs"), fabs, VAR},
+ {HashValue((unsigned char*)"asin"), asin, VAR},
+ {HashValue((unsigned char*)"acos"), acos, VAR},
+ {HashValue((unsigned char*)"atan"), atan, VAR},
+ {HashValue((unsigned char*)"sinh"), sinh, VAR},
+ {HashValue((unsigned char*)"cosh"), cosh, VAR},
+ {HashValue((unsigned char*)"tanh"), tanh, VAR},
+ {HashValue((unsigned char*)"sin"), sin, VAR},
+ {HashValue((unsigned char*)"cos"), cos, VAR},
+ {HashValue((unsigned char*)"atan"), atan, VAR},
+ {HashValue((unsigned char*)"log10"), log10, VAR},
+ {HashValue((unsigned char*)"ln"), log, VAR},
+ {HashValue((unsigned char*)"log"), log, VAR},
+ {HashValue((unsigned char*)"exp"), exp, VAR},
+ {HashValue((unsigned char*)"sqrt"), sqrt, VAR},
+ {0, 0, 0}};
+
+// Store strings in a list
+static char **str_list = 0L;
+static int n_str = 0;
+
+static char *PushString(char *text)
+{
+ if(text && text[0]) {
+ if(str_list = (char**)realloc(str_list, sizeof(char*)*(n_str+1)))
+ str_list[n_str] = strdup(text);
+ return str_list[n_str++];
+ }
+ return 0L;
+}
+
+//The symbol table: a chain of `struct symrec'
+static symrec *sym_table = (symrec *) 0;
+
+// Put arithmetic functions and predifened variables in table
+static void init_table (void)
+{
+ int i;
+ symrec *ptr;
+
+ for (i = 0; arith_fncts[i].h_name; i++) {
+ ptr = putsym (arith_fncts[i].h_name, FNCT, arith_fncts[i].arg_type);
+ ptr->value.fnctptr = (double (*)(...))arith_fncts[i].fnct;
+ }
+ ptr = putsym(HashValue((unsigned char*)"zdiv"), VAR, 0); ptr->value.var = 1.0;
+ str_list = 0L; n_str = 0;
+ push_syntax();
+}
+
+static void clear_table()
+{
+ int i;
+ symrec *ptr, *next;
+
+ for (ptr = sym_table; ptr != (symrec *) 0;){
+ if(ptr) {
+ if(ptr->name) free(ptr->name);
+ if(ptr->text) free(ptr->text);
+ next = (symrec*)ptr->next;
+ free(ptr);
+ }
+ ptr = next;
+ }
+ sym_table = (symrec *) 0;
+ if(str_list) {
+ for(i = 0; i < n_str; i++) if(str_list[i]) free(str_list[i]);
+ free(str_list); str_list = 0L; n_str = 0;
+ }
+ pop_syntax();
+}
+
+static symrec *
+putsym (unsigned int h_name, int sym_type, int arg_type)
+{
+ symrec *ptr;
+
+ ptr = (symrec *) malloc (sizeof (symrec));
+ ptr->h_name = h_name;
+ ptr->type = sym_type;
+ ptr->name = ptr->text = 0L;
+ ptr->value.var = 0; /* set value to 0 even if fctn. */
+ ptr->arg_type = arg_type;
+ ptr->col = ptr->row = -1;
+ ptr->next = (struct symrec *)sym_table;
+ sym_table = ptr;
+ return ptr;
+}
+
+static symrec *
+getsym (unsigned int h_name, char *sym_name)
+{
+ symrec *ptr;
+ int row, col;
+ AccRange *ar;
+ anyResult ares;
+
+ if(!h_name) return 0;
+ for (ptr = sym_table; ptr != (symrec *) 0; ptr = (symrec *)ptr->next)
+ if (ptr->h_name == h_name){
+ if(sym_name && !ptr->name) ptr->name = ptr->name=strdup(sym_name);
+ return ptr;
+ }
+ if((sym_name && curr_data) && (isalpha(sym_name[0]) || sym_name[0] == '$') && isdigit(sym_name[strlen(sym_name)-1])) {
+ if((ar = new AccRange(sym_name)) && ar->GetFirst(&col, &row) &&
+ (ptr = putsym(h_name, VAR, 0))) {
+ ptr->name = strdup(sym_name);
+ if(curr_data->GetResult(&ares, row, col)){
+ if(ares.type == ET_VALUE) {
+ ptr->type = VAR; ptr->value.var = ares.value;
+ ptr->text = 0L;
+ }
+ else if(ares.type == ET_TEXT && ares.text) {
+ ptr->type = TXT; ptr->value.var = 0.0;
+ ptr->text = strdup(ares.text);
+ }
+ else {
+ ptr->type = VAR; ptr->value.var = 0.0;
+ ptr->text = 0L;
+ }
+ }
+ ptr->row = row; ptr->col = col;
+ delete(ar);
+ return ptr;
+ }
+ }
+ return 0;
+}
+
+static int
+push(YYSTYPE *res, YYSTYPE *val)
+{
+ if(val->a_data && val->a_count) {
+ if(!(res->a_data)) {
+ if(!(val->a_data=(double*)realloc(val->a_data, (val->a_count+2)*sizeof(double))))return 0;
+ val->a_data[val->a_count++] = res->val;
+ res->a_data = val->a_data; res->a_count = val->a_count;
+ val->a_data = 0L; val->a_count = 0;
+ val->val = res->val; return 1;
+ }
+ else {
+ if(!(res->a_data=(double*)realloc(res->a_data, (val->a_count+res->a_count)*sizeof(double))))return 0;
+ memcpy(&res->a_data[res->a_count], val->a_data, val->a_count*sizeof(double));
+ res->a_count += val->a_count; free(val->a_data);
+ val->a_data = 0L; val->a_count = 0;
+ return 1;
+ }
+ }
+ if(!(res->a_data )){
+ if(!(res->a_data = (double*)malloc(2*sizeof(double))))return 0;
+ res->a_data[0] = res->val; res->a_data[1] = val->val;
+ res->a_count = 2;
+ return 1;
+ }
+ else {
+ if(!(res->a_data = (double*)realloc(res->a_data, (res->a_count+2)*sizeof(double))))return 0;
+ res->a_data[res->a_count] = val->val; res->a_count++;
+ return 1;
+ }
+ return 0;
+}
+
+static int
+get_range(YYSTYPE *res, char *first, char *last)
+{
+ char r_txt[40];
+ AccRange *r;
+ int row, col;
+ double value;
+ YYSTYPE tmp;
+
+ if(!res || !first || !last || !curr_data) return 0;
+ sprintf(r_txt, "%s:%s", first, last);
+ if(!(res->a_data ) && (r = new AccRange(r_txt)) && r->GetFirst(&col, &row)) {
+ if(!(res->a_data = (double*)malloc(r->CountItems() * sizeof(double)))) return 0;
+ res->a_count = 0;
+ for( ; r->GetNext(&col, &row); ) {
+ if(curr_data->GetValue(row, col, &value)) res->a_data[res->a_count++] = value;
+ }
+ delete r; return 1;
+ }
+ if((r = new AccRange(r_txt)) && r->GetFirst(&col, &row)) {
+ //it is probably a bit slow to push every element
+ tmp.type = NUM;
+ for( ; r->GetNext(&col, &row); ) {
+ if(curr_data->GetValue(row, col, &value)) {
+ tmp.val = value;
+ push(res, &tmp);
+ }
+ }
+ delete r; return 1;
+ }
+ return 0;
+}
+
+static YYSTYPE *proc_clause(YYSTYPE *res)
+{
+ int i, n, o_pos;
+ char *o_cmd;
+ double *n_data;
+
+ if(!(syntax_level) || !syntax_level->cl1 || syntax_level->cl2 <= syntax_level->cl1) return res;
+ if(!res->text) return res;
+ if(!res->a_data && (res->a_data = (double*)malloc(sizeof(double)))) {
+ res->a_data[0] = res->type == VAR && res->tptr ? res->tptr->value.var : res->val;
+ res->a_count = 1;
+ }
+ else if(!res->a_data) return res;
+ if(!(n_data = (double*)malloc(res->a_count * sizeof(double)))) return res;
+ o_pos = buff_pos; o_cmd = buffer;
+ for(i = n = 0; i < res->a_count; i++) {
+ buffer = res->text; buff_pos = 0;
+ if(!syntax_level) break;
+ syntax_level->clval = res->a_data[i];
+ yyparse();
+ if(line_res.type == ET_VALUE && line_res.value != 0.0) n_data[n++] = res->a_data[i];
+ }
+ free(res->a_data); res->a_data = n_data; res->a_count = n;
+ free(res->text); res->text=0L;
+ syntax_level->cl1 = syntax_level->cl2 = 0;
+ buffer = o_cmd; buff_pos = o_pos;
+ return res;
+}
+
+static void exec_clause(YYSTYPE *res)
+{
+ int i, j;
+ char *cmd;
+
+ if(!(syntax_level) || !syntax_level->cl1 || syntax_level->cl2 <= syntax_level->cl1) return;
+ if(!(cmd = (char*)malloc(syntax_level->cl2 - syntax_level->cl1 +2)))return;
+ while(buffer[syntax_level->cl1] <= ' ' && syntax_level->cl1 < syntax_level->cl2) syntax_level->cl1++;
+ for(j = 0, i = syntax_level->cl1; i< syntax_level->cl2; i++) {
+ cmd[j++] = buffer[i];
+ }
+ cmd[j++] = ';'; cmd[j++] = 0;
+ res->text = cmd;
+}
+
+struct parse_info {
+ char *buffer;
+ int buff_pos;
+ double line_result;
+ DataObj *curr_data;
+ symrec *sym_table;
+ YYSTYPE yylval;
+ struct parse_info *next;
+ char **str_list;
+ int n_str;
+};
+static parse_info *parse_stack = 0L;
+
+static void push_parser()
+{
+ parse_info *ptr;
+
+ ptr = (parse_info *) malloc(sizeof(parse_info));
+ ptr->buffer = buffer; ptr->buff_pos = buff_pos;
+ ptr->line_result = line_result; ptr->curr_data = curr_data;
+ ptr->sym_table = sym_table; sym_table = 0L;
+ memcpy(&ptr->yylval, &yylval, sizeof(YYSTYPE));
+ ptr->next = parse_stack;
+ ptr->str_list = str_list; str_list = 0L;
+ ptr->n_str = n_str; n_str = 0;
+ parse_stack = ptr;
+ push_syntax();
+}
+
+static void pop_parser()
+{
+ parse_info *ptr;
+
+ if(ptr = parse_stack) {
+ parse_stack = ptr->next;
+ buffer = ptr->buffer; buff_pos = ptr->buff_pos;
+ line_result = ptr->line_result; curr_data = ptr->curr_data;
+ sym_table = ptr->sym_table;
+ memcpy(&yylval, &ptr->yylval, sizeof(YYSTYPE));
+ str_list = ptr->str_list; n_str = ptr->n_str;
+ free(ptr);
+ }
+ pop_syntax();
+}
+
+static int is_ttoken(int h_nam)
+{
+ switch(h_nam) {
+ case 69: return E;
+ case 393: return PI;
+ case 28381:
+ if(syntax_level) syntax_level->cl1 = buff_pos;
+ return CLAUSE;
+ case 20: return CLVAL;
+ }
+ return 0;
+}
+
+static symrec *curr_sym;
+static int yylex (void)
+{
+ int i, c, tok;
+ unsigned int h_nam;
+ char tmp_txt[80];
+ symrec *s;
+
+ while((c = buffer[buff_pos++]) == ' ' || c == '\t'); //get first nonwhite char
+ if(!c) return 0;
+ //test for number
+ if(c == '.' || isdigit(c)) {
+ for(buff_pos--, i = 0; i < 79 && ((c = buffer[buff_pos]) == '.' || isdigit(c)); buff_pos++) {
+ tmp_txt[i++] = (char)c;
+ if(buffer[buff_pos+1] == 'e' && (buffer[buff_pos+2] == '-' || buffer[buff_pos+2] == '+')){
+ tmp_txt[i++] = buffer[++buff_pos];
+ tmp_txt[i++] = buffer[++buff_pos];
+ }
+ }
+ tmp_txt[i] = 0;
+ sscanf(tmp_txt, "%lf", &yylval.val);
+ yylval.type = NUM;
+ return NUM;
+ }
+ //test for name or stringtoken
+ if(isalpha(c) || c=='$') {
+ for(buff_pos--, i = 0; i < 79 && ((c = buffer[buff_pos]) && (isalnum(c) || c == '$')); buff_pos++) {
+ tmp_txt[i++] = (char)c;
+ }
+ tmp_txt[i] = 0;
+ h_nam = HashValue((unsigned char*)tmp_txt);
+ if(tok = is_ttoken(h_nam))
+ return tok;
+ if(!(strcmp(tmp_txt, "pi"))) return PI;
+ if(!(strcmp(tmp_txt, "e"))) return E;
+ if(!(s = getsym(h_nam, tmp_txt))){
+ s = putsym(h_nam, VAR, 0);
+ s->name = strdup(tmp_txt);
+ }
+
+ curr_sym = yylval.tptr = s; return s->type;
+ }
+ //test for string
+ if(c == '"' || c == '\'') {
+ for(i= 0; i < 79 && ((tok = buffer[buff_pos]) && (tok != c)); buff_pos++) {
+ tmp_txt[i++] = (char)tok;
+ }
+ if(buffer[buff_pos] == c)buff_pos++;
+ tmp_txt[i] = 0;
+ yylval.text = PushString(tmp_txt);
+ return yylval.type = STR;
+ }
+ tok = 0;
+ switch(c) {
+ case '=':
+ if(buffer[buff_pos] == '=') tok = EQ;
+ break;
+ case '!':
+ if(buffer[buff_pos] == '=') tok = NE;
+ break;
+ case '>':
+ if(buffer[buff_pos] == '=') tok = GE;
+ else return GT;
+ break;
+ case '<':
+ if(buffer[buff_pos] == '=') tok = LE;
+ else if(buffer[buff_pos] == '>') tok = NE;
+ else return LT;
+ break;
+ case '&':
+ if(buffer[buff_pos] == '&') tok = AND;
+ break;
+ case '|':
+ if(buffer[buff_pos] == '|') tok = OR;
+ break;
+ case ')':
+ if(syntax_level) {
+ if(syntax_level->cl1 && syntax_level->next) {
+ syntax_level->next->cl1 = syntax_level->cl1;
+ syntax_level->next->cl2 = buff_pos-1;
+ }
+ }
+ pop_syntax();
+ break;
+ case '(':
+ push_syntax();
+ case '?':
+ if(syntax_level) syntax_level->last_tok = c;
+ break;
+ case ':':
+ if(syntax_level) {
+ if(syntax_level->last_tok == '(') return COLR;
+ else if(syntax_level->last_tok == '?') return COLC;
+ }
+ break;
+ }
+ if(tok) {
+ buff_pos++; return tok;
+ }
+ //Any other character is a token by itself
+ return c;
+}
+
+bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOINT **pts, long *npts, char *param)
+{
+ double x, y;
+ symrec *s;
+ lfPOINT *new_points;
+ long npoints = 0;
+ int length;
+ unsigned int hn_x = HashValue((unsigned char *)"x");
+ unsigned int hn_y = HashValue((unsigned char *)"y");
+
+ if(x1 < x2) step = fabs(step);
+ else step = -fabs(step);
+ if(!(new_points = (lfPOINT*)calloc((iround(fabs(x2-x1)/fabs(step))+2), sizeof(lfPOINT))))
+ return false;
+ if(d) curr_data = d;
+ init_table();
+ if(param) {
+ length = strlen(param);
+ if(!(buffer = (char*)malloc(length+2))){
+ pop_parser();
+ return false;
+ }
+ strcpy(buffer, param); buffer[length++] = ';';
+ buffer[length] = 0; buff_pos = 0;
+ do {
+ yyparse();
+ }while(buff_pos < length);
+ free(buffer); buffer = 0L;
+ }
+ length = strlen(expr);
+ buffer = expr; s = putsym(hn_x, VAR, 0);
+ for(x = x1; step > 0.0 ? x <= x2 : x >= x2; x += step) {
+ if(s = getsym(hn_x)){
+ s->value.var = x; buff_pos = 0;
+ do {
+ yyparse();
+ }while(buff_pos < length);
+ if(s = getsym(hn_y)) y = s->value.var;
+ else y = line_result;
+ new_points[npoints].fx = (getsym(hn_x))->value.var;
+ new_points[npoints++].fy = y;
+ }
+ }
+ *pts = new_points; *npts = npoints;
+ clear_table();
+ if(curr_data) {
+ curr_data->Command(CMD_CLEAR_ERROR, 0L, 0L);
+ curr_data->Command(CMD_REDRAW, 0L, 0L);
+ }
+ return true;
+}
+
+anyResult *do_formula(DataObj *d, char *expr)
+{
+ int length;
+ static anyResult ret;
+
+ if(d) curr_data = d;
+ ret.type = ET_ERROR; ret.text = 0L;
+ if(!expr || !expr[0]) return &ret;
+ push_parser(); //make code reentrant
+ init_table(); length = strlen(expr);
+ if(!(buffer = (char*)malloc(length+2))){
+ pop_parser();
+ return &ret;
+ }
+ strcpy(buffer, expr); buffer[length++] = ';';
+ buffer[length] = 0; buff_pos = 0;
+ do {
+ yyparse();
+ }while(buff_pos < length);
+ if(curr_data && last_error) {
+ curr_data->Command(CMD_ERROR, last_error = 0L, 0L);
+ return &ret;
+ }
+ free(buffer); buffer = 0L;
+ clear_table();
+ pop_parser();
+ return &line_res;
+}
+
+bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy)
+{
+ int length, tok, pos, i;
+ char *res, desc1[2], desc2[2];
+
+ if(d) curr_data = d;
+ if(!curr_data || !of || !nf) return false;
+ push_parser(); //make code reentrant
+ init_table(); length = strlen(of);
+ if(!(buffer = (char*)malloc(length+2))){
+ pop_parser();
+ return false;
+ }
+ strcpy(buffer, of); buffer[length++] = ';';
+ buffer[length] = 0; buff_pos = pos = 0;
+ res = (char *)calloc(length*2+10, sizeof(char));
+ do {
+ tok = yylex ();
+ if(tok && tok < 256) {
+ if(res[pos-1] == ' ') pos--;
+ res[pos++] = (char)tok;
+ }
+ else switch(tok) {
+ case NUM:
+ pos += sprintf(res+pos, "%g ", yylval.val);
+ break;
+ case FNCT:
+ pos += sprintf(res+pos, "%s", curr_sym->name);
+ break;
+ case COLR:
+ pos += sprintf(res+pos, ":");
+ break;
+ case COLC:
+ pos += sprintf(res+pos, ": ");
+ break;
+ case CLVAL:
+ pos += sprintf(res+pos, "$$ ");
+ break;
+ case CLAUSE:
+ pos += sprintf(res+pos, " where ");
+ break;
+ case VAR:
+ if(curr_sym->col >= 0 && curr_sym->row >= 0) {
+ desc1[0] = desc1[1] = desc2[0] = desc2[1] = 0;
+ for(i=strlen(curr_sym->name)-1; i>0 && isdigit(curr_sym->name[i]); i--);
+ if(curr_sym->name[0] == '$') desc1[0] = '$';
+ if(curr_sym->name[i] == '$') desc2[0] = '$';
+ pos += sprintf(res+pos, "%s%s%s%d", desc1,
+ Int2ColLabel(desc1[0] ? curr_sym->col : curr_sym->col+dx, false),
+ desc2, desc2[0]? curr_sym->row+1 : curr_sym->row+1+dy);
+ }
+ else pos += sprintf(res+pos, "%s ", curr_sym->name);
+ break;
+ case STR:
+ pos += sprintf(res+pos, "\"%s\"", yylval.text && yylval.text[0] ? yylval.text : "");
+ break;
+ case PI:
+ pos += sprintf(res+pos, "pi ");
+ break;
+ case E:
+ pos += sprintf(res+pos, "e ");
+ break;
+ case AND:
+ pos += sprintf(res+pos, " && ");
+ break;
+ case OR:
+ pos += sprintf(res+pos, " || ");
+ break;
+ case EQ:
+ pos += sprintf(res+pos, " == ");
+ break;
+ case NE:
+ pos += sprintf(res+pos, " != ");
+ break;
+ case GT:
+ pos += sprintf(res+pos, " > ");
+ break;
+ case GE:
+ pos += sprintf(res+pos, " >= ");
+ break;
+ case LT:
+ pos += sprintf(res+pos, " < ");
+ break;
+ case LE:
+ pos += sprintf(res+pos, " <= ");
+ break;
+ }
+ }while(buff_pos < length);
+ while((res[pos-1] == ';' || res[pos-1] == ' ') && pos > 0) { res[pos-1] = 0; pos--;}
+ strcpy(nf, res); free(res);
+ free(buffer); buffer = 0L;
+ clear_table();
+ pop_parser();
+ return true;
+}
+
+static char *txt_formula; //function to fit
+static double **parval; //pointers to parameter values
+static void fcurve(double x, double z, double **a, double *y, double dyda[], int ma)
+{
+ int i, length;
+ double tmp, y1, y2;
+ symrec *symx, *s=0L;
+ unsigned int hn_x = HashValue((unsigned char *)"x");
+ unsigned int hn_y = HashValue((unsigned char *)"y");
+
+ if(!(symx = getsym(hn_x))) symx = putsym(hn_x, VAR, 0);
+ //swap parameters to requested set
+ if(a != parval) for(i = 0; i < ma; i++) {
+ tmp = *parval[i]; *parval[i] = *a[i]; *a[i] = tmp;
+ }
+ //calc result
+ symx->value.var = x; buffer = txt_formula;
+ buff_pos = 0; length = strlen(txt_formula);
+ do { yyparse(); }while(buff_pos < length);
+ if(s = getsym(hn_y)) *y = s->value.var;
+ else *y = line_result;
+ if(*y == HUGE_VAL || *y == -HUGE_VAL) {
+ for(i = 0, *y = 0.0; i < ma; dyda[i++] = 0.0);
+ return;
+ }
+ //partial derivatives for each parameter by numerical differentiation
+ for(i = 0; i < ma; i++) {
+ if(*parval[i] != 0.0) {
+ tmp = *parval[i];
+ *parval[i] = tmp*.995;
+ buff_pos = 0;
+ do { yyparse(); }while(buff_pos < length);
+ y1 = s ? s->value.var : line_result;
+ *parval[i] = tmp*1.005;
+ buff_pos = 0;
+ do { yyparse(); }while(buff_pos < length);
+ y2 = s ? s->value.var : line_result;
+ *parval[i] = tmp;
+ dyda[i] = (y2-y1)*100.0/tmp;
+ }
+ else dyda[i] = 0.0;
+ }
+ //swap parameters back to original
+ if(a != parval) for(i = 0; i < ma; i++) {
+ tmp = *parval[i]; *parval[i] = *a[i]; *a[i] = tmp;
+ }
+}
+
+int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr, double conv, int maxiter, double *chi_2)
+{
+ int length, i, j, k, l, ndata, nparam, r1, r2, r3, c1, c2, c3, *lista, itst, itst1;
+ symrec *tab1, *tab2, *csr, **parsym;
+ AccRange *arx, *ary, *arz;
+ double *x, *y, *z, currx, curry, currz, alamda, chisq, ochisq;
+ double **covar, **alpha;
+ char tmp_txt[500];
+
+ if(d) curr_data = d;
+ if(chi_2) *chi_2 = 0.0;
+ txt_formula = expr;
+ if(!curr_data || !par || !expr || !rx || !ry) return 0;
+ //process ranges and create arrays
+ arx = ary = arz = 0L; x = y = z = 0L; parval = 0L; parsym = 0L;
+ if(!(arx = new AccRange(rx)))return 0;
+ i = arx->CountItems()+1;
+ if(!(ary = new AccRange(ry))){
+ delete arx; return 0;
+ }
+ if(rz && !(arz = new AccRange(rz))){
+ delete ary; delete arx; return 0;
+ }
+ if(!(x = (double*)malloc(i * sizeof(double)))){
+ if(arz) delete arz;
+ delete ary; delete arx; return 0;
+ }
+ if(!(y = (double*)malloc(i * sizeof(double)))){
+ if(arz) delete arz;
+ free(x); delete arx; delete ary; return 0;
+ }
+ if(rz && !(y = (double*)malloc(i * sizeof(double)))){
+ if(arz) delete arz;
+ free(y); free(x); delete arx; delete ary; return 0;
+ }
+ arx->GetFirst(&c1, &r1); ary->GetFirst(&c2, &r2);
+ if(rz) arz->GetFirst(&c3, &r3);
+ for(ndata = j = 0; j < i; j++) {
+ if(rz) {
+ if(arx->GetNext(&c1, &r1) && ary->GetNext(&c2, & r2) && arz->GetNext(&c3, &r3) &&
+ curr_data->GetValue(r1, c1, &currx) && curr_data->GetValue(r2, c2, &curry) &&
+ curr_data->GetValue(r3, c3, &currz)) {
+ x[ndata] = currx; y[ndata] = curry; z[ndata] = currz; ndata++;
+ }
+ }
+ else {
+ if(arx->GetNext(&c1, &r1) && ary->GetNext(&c2, & r2) &&
+ curr_data->GetValue(r1, c1, &currx) && curr_data->GetValue(r2, c2, &curry)) {
+ x[ndata] = currx; y[ndata] = curry; ndata++;
+ }
+ }
+ }
+ //common initialization for parser tasks
+ push_parser(); //make code reentrant
+ init_table(); length = strlen(*par);
+ //process parameters
+ if(!(buffer = (char*)malloc(length+2))){
+ clear_table(); pop_parser();
+ if(arz) delete arz;
+ free(y); free(x); delete arx; delete ary;
+ return 0;
+ }
+ strcpy(buffer, *par); buffer[length++] = ';';
+ buffer[length] = 0; buff_pos = 0;
+ tab1 = sym_table;
+ do {
+ yyparse();
+ }while(buff_pos < length);
+ tab2 = sym_table; free(buffer); buffer =0L;
+ for(nparam = 0, csr=tab2; csr != tab1; nparam++, csr = csr->next);
+ parsym = (symrec**)malloc((nparam+1)*sizeof(symrec*));
+ parval = (double**)malloc((nparam+1)*sizeof(double*));
+ for(i = 0, csr=tab2; csr != tab1 && i < nparam; i++, csr = csr->next){
+ parsym[i] = csr; parval[i] = &csr->value.var;
+ }
+ //do iteratations to optimize fit
+ lista = (int*)malloc(sizeof(int)*nparam);
+ for(i = 0; i< nparam; i++) lista[i] = i;
+ covar = dmatrix(1, nparam, 1, nparam);
+ alpha = dmatrix(1, nparam, 1, nparam);
+ alamda = -1.0; itst = 0;
+ mrqmin(x, y, z, ndata, parval, nparam, lista, nparam, covar, alpha, &chisq, fcurve, &alamda);
+ if(!Check_MRQerror()) {
+ for(itst = itst1 = 0, ochisq = chisq; itst < maxiter && chisq > conv && ochisq >= chisq && itst1 < 9; itst++) {
+ ochisq = chisq;
+ mrqmin(x, y, z, ndata, parval, nparam, lista, nparam, covar, alpha, &chisq, fcurve, &alamda);
+ if(ochisq == chisq) itst1++;
+ else itst1 = 0;
+ }
+ alamda = 0.0;
+ mrqmin(x, y, z, ndata, parval, nparam, lista, nparam, covar, alpha, &chisq, fcurve, &alamda);
+ Check_MRQerror();
+ }
+ for(i = nparam-1, j = k = l = 0; i >= 0; l = 0, i--) {
+ if(k > 20) {
+ if(tmp_txt[j-1] == ' ') j--;
+ if(tmp_txt[j-1] == ';') j--;
+ l = sprintf(tmp_txt+j, "\n");
+ j += l; k = 0;
+ }
+ l += sprintf(tmp_txt+j, "%s%s=%g;", j && k ? " " : "", parsym[i]->name, parsym[i]->value.var);
+ j += l; k += l;
+ }
+ free(*par); *par = strdup(tmp_txt);
+ if(chi_2) *chi_2 = chisq;
+ //write back spreadsheet data if necessary
+ buffer = *par; length = strlen(buffer);
+ do {
+ yyparse();
+ }while(buff_pos < length);
+ buffer = 0L;
+ free_dmatrix(alpha, 1, nparam, 1, nparam);
+ free_dmatrix(covar, 1, nparam, 1, nparam);
+ if(arz) delete arz; if(z) free(z);
+ free(y); free(x); delete arx; delete ary;
+ if(parval) free(parval); if(parsym) free(parsym);
+ clear_table();
+ pop_parser();
+ if(curr_data){
+ curr_data->Command(CMD_CLEAR_ERROR, 0L, 0L);
+ curr_data->Command(CMD_REDRAW, 0L, 0L);
+ }
+ return itst < maxiter ? itst+1 : maxiter;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mfcalc.y b/mfcalc.y
new file mode 100755
index 0000000..9aa1928
--- /dev/null
+++ b/mfcalc.y
@@ -0,0 +1,1247 @@
+%{
+/*
+ mfcalc.y, mfcalc.cpp, Copyright (c) 2004, 2005 R.Lackner
+ parse string and simple math: based on the bison 'mfcalc' example
+
+ 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 <math.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+#include "rlplot.h"
+
+struct symrec {
+ int type, row, col;
+ unsigned int h_name;
+ char *name, *text;
+ struct {
+ double var;
+ double (*fnctptr)(...);
+ } value;
+ int arg_type;
+ struct symrec *next;
+};
+
+// syntactical information
+struct syntax_info {
+ int last_tok; //resolve ambiguous ':'
+ double clval; //current value for where - clause
+ int cl1, cl2; //limits of clause formula in buffer
+ struct syntax_info *next;
+ };
+static syntax_info *syntax_level = 0L;
+
+
+typedef struct{
+ double val;
+ int type;
+ symrec *tptr;
+ double *a_data;
+ char *text;
+ int a_count;
+
+}YYSTYPE;
+
+static symrec *putsym (unsigned int h_name, int sym_type, int arg_type);
+static symrec *getsym (unsigned int h_name, char *sym_name = 0L);
+static int push(YYSTYPE *res, YYSTYPE *val);
+static void store_res(YYSTYPE *res);
+static char *PushString(char *text);
+static char *add_strings(char *st1, char *st2);
+static char *string_value(YYSTYPE *exp);
+static int get_range(YYSTYPE *res, char *first, char *last);
+static void exec_clause(YYSTYPE *res);
+static YYSTYPE *proc_clause(YYSTYPE *res);
+static void yyerror(char *s);
+static int yylex(void);
+
+static char res_txt[1000];
+static anyResult line_res = {ET_UNKNOWN, 0.0, res_txt};
+static double line_result;
+static DataObj *curr_data;
+
+//the current command buffer
+static char *buffer = 0L;
+static int buff_pos = 0;
+%}
+
+%token <val> NUM ARR STR PI E CLVAL
+%token <tptr> VAR FNCT TXT
+%type <val> exp str_exp
+
+%right '='
+%left ',' /* list separator */
+%left CLAUSE /* clause (where) operator */
+%right COLR COLC /* range sep., conditional sep. */
+%right '?' /* conditional assignment */
+%left AND OR
+%left EQ NE GT GE LT LE
+%left '-' '+'
+%left '*' '/'
+%left NEG /* negation-unary minus */
+%right '^' /* exponentiation */
+
+/* Grammar follows */
+%%
+input: /* empty string */
+ | input line
+;
+
+line: '\n' ';'
+ | exp '\n' {store_res(&yyvsp[-1]); return 0;}
+ | exp ';' {store_res(&yyvsp[-1]); return 0;}
+ | str_exp '\n' {store_res(&yyvsp[-1]); return 0;}
+ | str_exp ';' {store_res(&yyvsp[-1]); return 0;}
+ | error '\n' {yyerrok;}
+;
+
+str_exp:
+ STR {yyval.type=STR;}
+ |str_exp '+' exp {yyval.text=add_strings(yyvsp[-2].text, string_value(&yyvsp[0])); yyval.type=STR;}
+ |exp '+' str_exp {yyval.text=add_strings(string_value(&yyvsp[-2]), yyvsp[0].text); yyval.type=STR;}
+ |str_exp '+' str_exp {yyval.text=add_strings(yyvsp[-2].text, yyvsp[0].text); yyval.type=STR;}
+;
+
+exp: NUM {$$ = $1; yyval.type = NUM;}
+ |TXT {$$ = 0.0;}
+ |CLVAL {$$ = syntax_level ? syntax_level->clval : 0.0; }
+ |PI {$$ = 3.14159265358979; yyval.type = NUM;}
+ |E {$$ = 2.71828182845905; yyval.type = NUM;}
+ |VAR {$$ = $1->value.var; yyval.type=VAR}
+ |VAR '=' exp {$$ = $1->value.var = $3;
+ if($1->row >=0 && $1->col >= 0 && curr_data) curr_data->SetValue($1->row, $1->col, $3);}
+ |FNCT '(' exp ')' {$$ = ($1->arg_type == ARR) ? ((*$1->value.fnctptr)(proc_clause(&yyvsp[-1]))) :
+ (*($1->value.fnctptr))($3);}
+ |exp AND exp {$$ = (($1 != 0) && ($3 != 0))? 1 : 0;}
+ |exp OR exp {$$ = (($1 != 0) || ($3 != 0))? 1 : 0;}
+ |exp EQ exp {$$ = ($1 == $3) ? 1 : 0;}
+ |exp NE exp {$$ = ($1 != $3) ? 1 : 0;}
+ |exp GT exp {$$ = ($1 > $3) ? 1 : 0;}
+ |exp GE exp {$$ = ($1 >= $3) ? 1 : 0;}
+ |exp LT exp {$$ = ($1 < $3) ? 1 : 0;}
+ |exp LE exp {$$ = ($1 <= $3) ? 1 : 0;}
+ |exp '+' exp {$$ = $1 + $3;}
+ |exp '-' exp {$$ = $1 - $3;}
+ |exp '*' exp {$$ = $1 * $3;}
+ |exp '/' exp {if($3 != 0.0) $$ = $1 / $3;
+ else $$ = (getsym(HashValue((unsigned char*)"zdiv")))->value.var; }
+ |exp ',' exp {push(&yyval, &yyvsp[0]);}
+ |VAR COLR VAR {get_range(&yyval, $1->name, $3->name);}
+ |'-' exp %prec NEG {$$ = -$2;}
+ |exp '^' exp {$$ = pow($1, $3);}
+ |exp CLAUSE exp {$$ = $1; exec_clause(&yyval);}
+ |'(' exp ')' {memcpy(&yyval, &yyvsp[-1], sizeof(YYSTYPE))}
+ |exp '?' exp COLC exp {memcpy(&yyval, $1 != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE))}
+ |exp '?' STR COLC STR {memcpy(&yyval, $1 != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE))}
+ |exp '?' STR COLC exp {memcpy(&yyval, $1 != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE))}
+ |exp '?' exp COLC STR {memcpy(&yyval, $1 != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE))}
+;
+%%
+
+static char *last_error = 0L;
+static void yyerror(char *s)
+{
+ //Called by yyparse on error
+ if(curr_data) curr_data->Command(CMD_ERROR, last_error = s, 0L);
+ else printf("%s\n", s);
+}
+
+static void store_res(YYSTYPE *res)
+{
+ if(res->type == STR) {
+ line_result = 0.0;
+ line_res.type = ET_TEXT;
+ line_res. value = 0.0;
+ if(res->text) strcpy(res_txt, res->text);
+ }
+ else if(res->type == ARR || (res->a_data)) {
+ line_result = 0.0;
+ line_res.type = ET_TEXT;
+ line_res. value = 0.0;
+ strcpy(res_txt, "#ARRAY");
+ }
+ else if(res->tptr && res->tptr->type == TXT) {
+ line_result = 0.0;
+ line_res.type = ET_TEXT;
+ line_res.value = 0.0;
+ if(res->tptr->text) strcpy(res_txt, res->tptr->text);
+ }
+ else {
+ line_result = res->val;
+ line_res.type = ET_VALUE;
+ line_res.value = res->val;
+ }
+}
+
+static char *add_strings(char *st1, char *st2)
+{
+ char *newstr, *ret;
+
+ if(st1 && st2) {
+ if(newstr = (char*)malloc(strlen(st1) +strlen(st2) +4)) {
+ sprintf(newstr, "%s%s", st1, st2);
+ ret = PushString(newstr);
+ free(newstr);
+ return ret;
+ }
+ else return 0L;
+ }
+ if(st1) return st1;
+ if(st2) return st2;
+ return 0L;
+}
+
+static char *string_value(YYSTYPE *exp)
+{
+ char *st1, tmp[50];
+
+ if(exp->type == STR){
+ st1 = exp->text;
+ }
+ else if(exp->tptr && exp->tptr->type == TXT) {
+ st1 = exp->tptr->text;
+ }
+ else {
+ sprintf(tmp,"%g", exp->val);
+ st1 = tmp;
+ }
+ return PushString(st1);
+}
+
+// store syntactical information
+static void push_syntax()
+{
+ syntax_info *next;
+
+ if(!(next = (syntax_info*)calloc(1, sizeof(syntax_info)))) return;
+ if(syntax_level)memcpy(next, syntax_level, sizeof(syntax_info));
+ next->next=syntax_level;
+ syntax_level = next;
+}
+
+static void pop_syntax()
+{
+ syntax_info *si;
+
+ if(si = syntax_level) {
+ syntax_level = si->next;
+ free(si);
+ }
+}
+
+// more functions
+static double sign(double v)
+{
+ if(v > 0.0) return 1.0;
+ if(v < 0.0) return -1.0;
+ return 0.0;
+}
+
+static double factorial(double v)
+{
+ return factrl((int)v);
+}
+
+static void close_arr_func(YYSTYPE *sr)
+{
+ free(sr->a_data);
+ sr->a_data = 0L; sr->a_count = 0;
+ if(sr->type == ARR) sr->type = NUM;
+}
+
+#undef min
+static double min(YYSTYPE *sr)
+{
+ int i;
+
+ if(!sr) return 0.0;
+ if(sr->a_data && sr->a_data){
+ for(i = 1, sr->val = sr->a_data[0]; i < sr->a_count; i++)
+ if(sr->a_data[i] < sr->val) sr->val = sr->a_data[i];
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+#undef max
+static double max(YYSTYPE *sr)
+{
+ int i;
+
+ if(!sr) return 0.0;
+ if(sr->a_data){
+ for(i = 1, sr->val = sr->a_data[0]; i < sr->a_count; i++)
+ if(sr->a_data[i] > sr->val) sr->val = sr->a_data[i];
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double count(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ if(sr->a_data){
+ sr->val = (double)sr->a_count;
+ close_arr_func(sr);
+ }
+ else sr->val = 0.0;
+ return sr->val;
+}
+
+static double sum(YYSTYPE *sr)
+{
+ int i;
+
+ if(!sr) return 0.0;
+ if(sr->a_data){
+ for(i = 1, sr->val = sr->a_data[0]; i < sr->a_count; i++) sr->val += sr->a_data[i];
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double calc_variance(double *values, int n)
+{
+ int i;
+ double ss, d, mean = d_amean(n, values);
+
+ for(i=0, ss=0.0; i < n; i++) ss += ((d=values[i]-mean)*d);
+ return (ss/(n-1));
+}
+
+static double mean(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ if(sr->a_data && sr->a_count){
+ sr->val = d_amean(sr->a_count, sr->a_data );
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double gmean(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ if(sr->a_data && sr->a_count){
+ sr->val = d_gmean(sr->a_count, sr->a_data );
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double hmean(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ if(sr->a_data && sr->a_count){
+ sr->val = d_hmean(sr->a_count, sr->a_data );
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double quartile1(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ if(sr->a_data && sr->a_count){
+ d_quartile(sr->a_count, sr->a_data, &sr->val, 0L, 0L);
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double quartile2(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ if(sr->a_data && sr->a_count){
+ d_quartile(sr->a_count, sr->a_data, 0L, &sr->val, 0L);
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double quartile3(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ if(sr->a_data && sr->a_count){
+ d_quartile(sr->a_count, sr->a_data, 0L, 0L, &sr->val);
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double variance(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ sr->val = 0.0;
+ if(sr->a_data && sr->a_count){
+ sr->val = calc_variance(sr->a_data, sr->a_count);
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double stdev(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ sr->val = 0.0;
+ if(sr->a_data && sr->a_count){
+ sr->val = sqrt(calc_variance(sr->a_data, sr->a_count));
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double sterr(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ sr->val = 0.0;
+ if(sr->a_data && sr->a_count){
+ sr->val = sqrt(calc_variance(sr->a_data, sr->a_count))/sqrt(sr->a_count);
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double tdist(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ sr->val = 0.0;
+ if(sr->a_data && sr->a_count == 2){
+ sr->val = t_dist(sr->a_data[0], sr->a_data[1]);
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+static double fdist(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ sr->val = 0;
+ if(sr->a_data && sr->a_count == 3){
+ sr->val = f_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
+ close_arr_func(sr);
+ }
+ return sr->val;
+}
+
+struct init
+{
+ unsigned int h_name;
+ double (*fnct)(double);
+ int arg_type;
+};
+
+static struct init arith_fncts[] = {
+ {HashValue((unsigned char*)"variance"), (double(*)(double))&variance, ARR},
+ {HashValue((unsigned char*)"stdev"), (double(*)(double))&stdev, ARR},
+ {HashValue((unsigned char*)"sterr"), (double(*)(double))&sterr, ARR},
+ {HashValue((unsigned char*)"min"), (double(*)(double))&min, ARR},
+ {HashValue((unsigned char*)"max"), (double(*)(double))&max, ARR},
+ {HashValue((unsigned char*)"count"), (double(*)(double))&count, ARR},
+ {HashValue((unsigned char*)"sum"), (double(*)(double))&sum, ARR},
+ {HashValue((unsigned char*)"mean"), (double(*)(double))&mean, ARR},
+ {HashValue((unsigned char*)"median"), (double(*)(double))&quartile2, ARR},
+ {HashValue((unsigned char*)"quartile1"), (double(*)(double))&quartile1, ARR},
+ {HashValue((unsigned char*)"quartile2"), (double(*)(double))&quartile2, ARR},
+ {HashValue((unsigned char*)"quartile3"), (double(*)(double))&quartile3, ARR},
+ {HashValue((unsigned char*)"gmean"), (double(*)(double))&gmean, ARR},
+ {HashValue((unsigned char*)"hmean"), (double(*)(double))&hmean, ARR},
+ {HashValue((unsigned char*)"tdist"), (double(*)(double))&tdist, ARR},
+ {HashValue((unsigned char*)"fdist"), (double(*)(double))&fdist, ARR},
+ {HashValue((unsigned char*)"sign"), sign, VAR},
+ {HashValue((unsigned char*)"gammaln"), gammln, VAR},
+ {HashValue((unsigned char*)"factorial"), factorial, VAR},
+ {HashValue((unsigned char*)"abs"), fabs, VAR},
+ {HashValue((unsigned char*)"asin"), asin, VAR},
+ {HashValue((unsigned char*)"acos"), acos, VAR},
+ {HashValue((unsigned char*)"atan"), atan, VAR},
+ {HashValue((unsigned char*)"sinh"), sinh, VAR},
+ {HashValue((unsigned char*)"cosh"), cosh, VAR},
+ {HashValue((unsigned char*)"tanh"), tanh, VAR},
+ {HashValue((unsigned char*)"sin"), sin, VAR},
+ {HashValue((unsigned char*)"cos"), cos, VAR},
+ {HashValue((unsigned char*)"atan"), atan, VAR},
+ {HashValue((unsigned char*)"log10"), log10, VAR},
+ {HashValue((unsigned char*)"ln"), log, VAR},
+ {HashValue((unsigned char*)"log"), log, VAR},
+ {HashValue((unsigned char*)"exp"), exp, VAR},
+ {HashValue((unsigned char*)"sqrt"), sqrt, VAR},
+ {0, 0, 0}};
+
+// Store strings in a list
+static char **str_list = 0L;
+static int n_str = 0;
+
+static char *PushString(char *text)
+{
+ if(text && text[0]) {
+ if(str_list = (char**)realloc(str_list, sizeof(char*)*(n_str+1)))
+ str_list[n_str] = strdup(text);
+ return str_list[n_str++];
+ }
+ return 0L;
+}
+
+//The symbol table: a chain of `struct symrec'
+static symrec *sym_table = (symrec *) 0;
+
+// Put arithmetic functions and predifened variables in table
+static void init_table (void)
+{
+ int i;
+ symrec *ptr;
+
+ for (i = 0; arith_fncts[i].h_name; i++) {
+ ptr = putsym (arith_fncts[i].h_name, FNCT, arith_fncts[i].arg_type);
+ ptr->value.fnctptr = (double (*)(...))arith_fncts[i].fnct;
+ }
+ ptr = putsym(HashValue((unsigned char*)"zdiv"), VAR, 0); ptr->value.var = 1.0;
+ str_list = 0L; n_str = 0;
+ push_syntax();
+}
+
+static void clear_table()
+{
+ int i;
+ symrec *ptr, *next;
+
+ for (ptr = sym_table; ptr != (symrec *) 0;){
+ if(ptr) {
+ if(ptr->name) free(ptr->name);
+ if(ptr->text) free(ptr->text);
+ next = (symrec*)ptr->next;
+ free(ptr);
+ }
+ ptr = next;
+ }
+ sym_table = (symrec *) 0;
+ if(str_list) {
+ for(i = 0; i < n_str; i++) if(str_list[i]) free(str_list[i]);
+ free(str_list); str_list = 0L; n_str = 0;
+ }
+ pop_syntax();
+}
+
+static symrec *
+putsym (unsigned int h_name, int sym_type, int arg_type)
+{
+ symrec *ptr;
+
+ ptr = (symrec *) malloc (sizeof (symrec));
+ ptr->h_name = h_name;
+ ptr->type = sym_type;
+ ptr->name = ptr->text = 0L;
+ ptr->value.var = 0; /* set value to 0 even if fctn. */
+ ptr->arg_type = arg_type;
+ ptr->col = ptr->row = -1;
+ ptr->next = (struct symrec *)sym_table;
+ sym_table = ptr;
+ return ptr;
+}
+
+static symrec *
+getsym (unsigned int h_name, char *sym_name)
+{
+ symrec *ptr;
+ int row, col;
+ AccRange *ar;
+ anyResult ares;
+
+ if(!h_name) return 0;
+ for (ptr = sym_table; ptr != (symrec *) 0; ptr = (symrec *)ptr->next)
+ if (ptr->h_name == h_name){
+ if(sym_name && !ptr->name) ptr->name = ptr->name=strdup(sym_name);
+ return ptr;
+ }
+ if((sym_name && curr_data) && (isalpha(sym_name[0]) || sym_name[0] == '$') && isdigit(sym_name[strlen(sym_name)-1])) {
+ if((ar = new AccRange(sym_name)) && ar->GetFirst(&col, &row) &&
+ (ptr = putsym(h_name, VAR, 0))) {
+ ptr->name = strdup(sym_name);
+ if(curr_data->GetResult(&ares, row, col)){
+ if(ares.type == ET_VALUE) {
+ ptr->type = VAR; ptr->value.var = ares.value;
+ ptr->text = 0L;
+ }
+ else if(ares.type == ET_TEXT && ares.text) {
+ ptr->type = TXT; ptr->value.var = 0.0;
+ ptr->text = strdup(ares.text);
+ }
+ else {
+ ptr->type = VAR; ptr->value.var = 0.0;
+ ptr->text = 0L;
+ }
+ }
+ ptr->row = row; ptr->col = col;
+ delete(ar);
+ return ptr;
+ }
+ }
+ return 0;
+}
+
+static int
+push(YYSTYPE *res, YYSTYPE *val)
+{
+ if(val->a_data && val->a_count) {
+ if(!(res->a_data)) {
+ if(!(val->a_data=(double*)realloc(val->a_data, (val->a_count+2)*sizeof(double))))return 0;
+ val->a_data[val->a_count++] = res->val;
+ res->a_data = val->a_data; res->a_count = val->a_count;
+ val->a_data = 0L; val->a_count = 0;
+ val->val = res->val; return 1;
+ }
+ else {
+ if(!(res->a_data=(double*)realloc(res->a_data, (val->a_count+res->a_count)*sizeof(double))))return 0;
+ memcpy(&res->a_data[res->a_count], val->a_data, val->a_count*sizeof(double));
+ res->a_count += val->a_count; free(val->a_data);
+ val->a_data = 0L; val->a_count = 0;
+ return 1;
+ }
+ }
+ if(!(res->a_data )){
+ if(!(res->a_data = (double*)malloc(2*sizeof(double))))return 0;
+ res->a_data[0] = res->val; res->a_data[1] = val->val;
+ res->a_count = 2;
+ return 1;
+ }
+ else {
+ if(!(res->a_data = (double*)realloc(res->a_data, (res->a_count+2)*sizeof(double))))return 0;
+ res->a_data[res->a_count] = val->val; res->a_count++;
+ return 1;
+ }
+ return 0;
+}
+
+static int
+get_range(YYSTYPE *res, char *first, char *last)
+{
+ char r_txt[40];
+ AccRange *r;
+ int row, col;
+ double value;
+ YYSTYPE tmp;
+
+ if(!res || !first || !last || !curr_data) return 0;
+ sprintf(r_txt, "%s:%s", first, last);
+ if(!(res->a_data ) && (r = new AccRange(r_txt)) && r->GetFirst(&col, &row)) {
+ if(!(res->a_data = (double*)malloc(r->CountItems() * sizeof(double)))) return 0;
+ res->a_count = 0;
+ for( ; r->GetNext(&col, &row); ) {
+ if(curr_data->GetValue(row, col, &value)) res->a_data[res->a_count++] = value;
+ }
+ delete r; return 1;
+ }
+ if((r = new AccRange(r_txt)) && r->GetFirst(&col, &row)) {
+ //it is probably a bit slow to push every element
+ tmp.type = NUM;
+ for( ; r->GetNext(&col, &row); ) {
+ if(curr_data->GetValue(row, col, &value)) {
+ tmp.val = value;
+ push(res, &tmp);
+ }
+ }
+ delete r; return 1;
+ }
+ return 0;
+}
+
+static YYSTYPE *proc_clause(YYSTYPE *res)
+{
+ int i, n, o_pos;
+ char *o_cmd;
+ double *n_data;
+
+ if(!(syntax_level) || !syntax_level->cl1 || syntax_level->cl2 <= syntax_level->cl1) return res;
+ if(!res->text) return res;
+ if(!res->a_data && (res->a_data = (double*)malloc(sizeof(double)))) {
+ res->a_data[0] = res->type == VAR && res->tptr ? res->tptr->value.var : res->val;
+ res->a_count = 1;
+ }
+ else if(!res->a_data) return res;
+ if(!(n_data = (double*)malloc(res->a_count * sizeof(double)))) return res;
+ o_pos = buff_pos; o_cmd = buffer;
+ for(i = n = 0; i < res->a_count; i++) {
+ buffer = res->text; buff_pos = 0;
+ if(!syntax_level) break;
+ syntax_level->clval = res->a_data[i];
+ yyparse();
+ if(line_res.type == ET_VALUE && line_res.value != 0.0) n_data[n++] = res->a_data[i];
+ }
+ free(res->a_data); res->a_data = n_data; res->a_count = n;
+ free(res->text); res->text=0L;
+ syntax_level->cl1 = syntax_level->cl2 = 0;
+ buffer = o_cmd; buff_pos = o_pos;
+ return res;
+}
+
+static void exec_clause(YYSTYPE *res)
+{
+ int i, j;
+ char *cmd;
+
+ if(!(syntax_level) || !syntax_level->cl1 || syntax_level->cl2 <= syntax_level->cl1) return;
+ if(!(cmd = (char*)malloc(syntax_level->cl2 - syntax_level->cl1 +2)))return;
+ while(buffer[syntax_level->cl1] <= ' ' && syntax_level->cl1 < syntax_level->cl2) syntax_level->cl1++;
+ for(j = 0, i = syntax_level->cl1; i< syntax_level->cl2; i++) {
+ cmd[j++] = buffer[i];
+ }
+ cmd[j++] = ';'; cmd[j++] = 0;
+ res->text = cmd;
+}
+
+struct parse_info {
+ char *buffer;
+ int buff_pos;
+ double line_result;
+ DataObj *curr_data;
+ symrec *sym_table;
+ YYSTYPE yylval;
+ struct parse_info *next;
+ char **str_list;
+ int n_str;
+};
+static parse_info *parse_stack = 0L;
+
+static void push_parser()
+{
+ parse_info *ptr;
+
+ ptr = (parse_info *) malloc(sizeof(parse_info));
+ ptr->buffer = buffer; ptr->buff_pos = buff_pos;
+ ptr->line_result = line_result; ptr->curr_data = curr_data;
+ ptr->sym_table = sym_table; sym_table = 0L;
+ memcpy(&ptr->yylval, &yylval, sizeof(YYSTYPE));
+ ptr->next = parse_stack;
+ ptr->str_list = str_list; str_list = 0L;
+ ptr->n_str = n_str; n_str = 0;
+ parse_stack = ptr;
+ push_syntax();
+}
+
+static void pop_parser()
+{
+ parse_info *ptr;
+
+ if(ptr = parse_stack) {
+ parse_stack = ptr->next;
+ buffer = ptr->buffer; buff_pos = ptr->buff_pos;
+ line_result = ptr->line_result; curr_data = ptr->curr_data;
+ sym_table = ptr->sym_table;
+ memcpy(&yylval, &ptr->yylval, sizeof(YYSTYPE));
+ str_list = ptr->str_list; n_str = ptr->n_str;
+ free(ptr);
+ }
+ pop_syntax();
+}
+
+static int is_ttoken(int h_nam)
+{
+ switch(h_nam) {
+ case 69: return E;
+ case 393: return PI;
+ case 28381:
+ if(syntax_level) syntax_level->cl1 = buff_pos;
+ return CLAUSE;
+ case 20: return CLVAL;
+ }
+ return 0;
+}
+
+static symrec *curr_sym;
+static int yylex (void)
+{
+ int i, c, tok;
+ unsigned int h_nam;
+ char tmp_txt[80];
+ symrec *s;
+
+ while((c = buffer[buff_pos++]) == ' ' || c == '\t'); //get first nonwhite char
+ if(!c) return 0;
+ //test for number
+ if(c == '.' || isdigit(c)) {
+ for(buff_pos--, i = 0; i < 79 && ((c = buffer[buff_pos]) == '.' || isdigit(c)); buff_pos++) {
+ tmp_txt[i++] = (char)c;
+ if(buffer[buff_pos+1] == 'e' && (buffer[buff_pos+2] == '-' || buffer[buff_pos+2] == '+')){
+ tmp_txt[i++] = buffer[++buff_pos];
+ tmp_txt[i++] = buffer[++buff_pos];
+ }
+ }
+ tmp_txt[i] = 0;
+ sscanf(tmp_txt, "%lf", &yylval.val);
+ yylval.type = NUM;
+ return NUM;
+ }
+ //test for name or stringtoken
+ if(isalpha(c) || c=='$') {
+ for(buff_pos--, i = 0; i < 79 && ((c = buffer[buff_pos]) && (isalnum(c) || c == '$')); buff_pos++) {
+ tmp_txt[i++] = (char)c;
+ }
+ tmp_txt[i] = 0;
+ h_nam = HashValue((unsigned char*)tmp_txt);
+ if(tok = is_ttoken(h_nam))
+ return tok;
+ if(!(strcmp(tmp_txt, "pi"))) return PI;
+ if(!(strcmp(tmp_txt, "e"))) return E;
+ if(!(s = getsym(h_nam, tmp_txt))){
+ s = putsym(h_nam, VAR, 0);
+ s->name = strdup(tmp_txt);
+ }
+
+ curr_sym = yylval.tptr = s; return s->type;
+ }
+ //test for string
+ if(c == '"' || c == '\'') {
+ for(i= 0; i < 79 && ((tok = buffer[buff_pos]) && (tok != c)); buff_pos++) {
+ tmp_txt[i++] = (char)tok;
+ }
+ if(buffer[buff_pos] == c)buff_pos++;
+ tmp_txt[i] = 0;
+ yylval.text = PushString(tmp_txt);
+ return yylval.type = STR;
+ }
+ tok = 0;
+ switch(c) {
+ case '=':
+ if(buffer[buff_pos] == '=') tok = EQ;
+ break;
+ case '!':
+ if(buffer[buff_pos] == '=') tok = NE;
+ break;
+ case '>':
+ if(buffer[buff_pos] == '=') tok = GE;
+ else return GT;
+ break;
+ case '<':
+ if(buffer[buff_pos] == '=') tok = LE;
+ else if(buffer[buff_pos] == '>') tok = NE;
+ else return LT;
+ break;
+ case '&':
+ if(buffer[buff_pos] == '&') tok = AND;
+ break;
+ case '|':
+ if(buffer[buff_pos] == '|') tok = OR;
+ break;
+ case ')':
+ if(syntax_level) {
+ if(syntax_level->cl1 && syntax_level->next) {
+ syntax_level->next->cl1 = syntax_level->cl1;
+ syntax_level->next->cl2 = buff_pos-1;
+ }
+ }
+ pop_syntax();
+ break;
+ case '(':
+ push_syntax();
+ case '?':
+ if(syntax_level) syntax_level->last_tok = c;
+ break;
+ case ':':
+ if(syntax_level) {
+ if(syntax_level->last_tok == '(') return COLR;
+ else if(syntax_level->last_tok == '?') return COLC;
+ }
+ break;
+ }
+ if(tok) {
+ buff_pos++; return tok;
+ }
+ //Any other character is a token by itself
+ return c;
+}
+
+bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOINT **pts, long *npts, char *param)
+{
+ double x, y;
+ symrec *s;
+ lfPOINT *new_points;
+ long npoints = 0;
+ int length;
+ unsigned int hn_x = HashValue((unsigned char *)"x");
+ unsigned int hn_y = HashValue((unsigned char *)"y");
+
+ if(x1 < x2) step = fabs(step);
+ else step = -fabs(step);
+ if(!(new_points = (lfPOINT*)calloc((iround(fabs(x2-x1)/fabs(step))+2), sizeof(lfPOINT))))
+ return false;
+ if(d) curr_data = d;
+ init_table();
+ if(param) {
+ length = strlen(param);
+ if(!(buffer = (char*)malloc(length+2))){
+ pop_parser();
+ return false;
+ }
+ strcpy(buffer, param); buffer[length++] = ';';
+ buffer[length] = 0; buff_pos = 0;
+ do {
+ yyparse();
+ }while(buff_pos < length);
+ free(buffer); buffer = 0L;
+ }
+ length = strlen(expr);
+ buffer = expr; s = putsym(hn_x, VAR, 0);
+ for(x = x1; step > 0.0 ? x <= x2 : x >= x2; x += step) {
+ if(s = getsym(hn_x)){
+ s->value.var = x; buff_pos = 0;
+ do {
+ yyparse();
+ }while(buff_pos < length);
+ if(s = getsym(hn_y)) y = s->value.var;
+ else y = line_result;
+ new_points[npoints].fx = (getsym(hn_x))->value.var;
+ new_points[npoints++].fy = y;
+ }
+ }
+ *pts = new_points; *npts = npoints;
+ clear_table();
+ if(curr_data) {
+ curr_data->Command(CMD_CLEAR_ERROR, 0L, 0L);
+ curr_data->Command(CMD_REDRAW, 0L, 0L);
+ }
+ return true;
+}
+
+anyResult *do_formula(DataObj *d, char *expr)
+{
+ int length;
+ static anyResult ret;
+
+ if(d) curr_data = d;
+ ret.type = ET_ERROR; ret.text = 0L;
+ if(!expr || !expr[0]) return &ret;
+ push_parser(); //make code reentrant
+ init_table(); length = strlen(expr);
+ if(!(buffer = (char*)malloc(length+2))){
+ pop_parser();
+ return &ret;
+ }
+ strcpy(buffer, expr); buffer[length++] = ';';
+ buffer[length] = 0; buff_pos = 0;
+ do {
+ yyparse();
+ }while(buff_pos < length);
+ if(curr_data && last_error) {
+ curr_data->Command(CMD_ERROR, last_error = 0L, 0L);
+ return &ret;
+ }
+ free(buffer); buffer = 0L;
+ clear_table();
+ pop_parser();
+ return &line_res;
+}
+
+bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy)
+{
+ int length, tok, pos, i;
+ char *res, desc1[2], desc2[2];
+
+ if(d) curr_data = d;
+ if(!curr_data || !of || !nf) return false;
+ push_parser(); //make code reentrant
+ init_table(); length = strlen(of);
+ if(!(buffer = (char*)malloc(length+2))){
+ pop_parser();
+ return false;
+ }
+ strcpy(buffer, of); buffer[length++] = ';';
+ buffer[length] = 0; buff_pos = pos = 0;
+ res = (char *)calloc(length*2+10, sizeof(char));
+ do {
+ tok = yylex ();
+ if(tok && tok < 256) {
+ if(res[pos-1] == ' ') pos--;
+ res[pos++] = (char)tok;
+ }
+ else switch(tok) {
+ case NUM:
+ pos += sprintf(res+pos, "%g ", yylval.val);
+ break;
+ case FNCT:
+ pos += sprintf(res+pos, "%s", curr_sym->name);
+ break;
+ case COLR:
+ pos += sprintf(res+pos, ":");
+ break;
+ case COLC:
+ pos += sprintf(res+pos, ": ");
+ break;
+ case CLVAL:
+ pos += sprintf(res+pos, "$$ ");
+ break;
+ case CLAUSE:
+ pos += sprintf(res+pos, " where ");
+ break;
+ case VAR:
+ if(curr_sym->col >= 0 && curr_sym->row >= 0) {
+ desc1[0] = desc1[1] = desc2[0] = desc2[1] = 0;
+ for(i=strlen(curr_sym->name)-1; i>0 && isdigit(curr_sym->name[i]); i--);
+ if(curr_sym->name[0] == '$') desc1[0] = '$';
+ if(curr_sym->name[i] == '$') desc2[0] = '$';
+ pos += sprintf(res+pos, "%s%s%s%d", desc1,
+ Int2ColLabel(desc1[0] ? curr_sym->col : curr_sym->col+dx, false),
+ desc2, desc2[0]? curr_sym->row+1 : curr_sym->row+1+dy);
+ }
+ else pos += sprintf(res+pos, "%s ", curr_sym->name);
+ break;
+ case STR:
+ pos += sprintf(res+pos, "\"%s\"", yylval.text && yylval.text[0] ? yylval.text : "");
+ break;
+ case PI:
+ pos += sprintf(res+pos, "pi ");
+ break;
+ case E:
+ pos += sprintf(res+pos, "e ");
+ break;
+ case AND:
+ pos += sprintf(res+pos, " && ");
+ break;
+ case OR:
+ pos += sprintf(res+pos, " || ");
+ break;
+ case EQ:
+ pos += sprintf(res+pos, " == ");
+ break;
+ case NE:
+ pos += sprintf(res+pos, " != ");
+ break;
+ case GT:
+ pos += sprintf(res+pos, " > ");
+ break;
+ case GE:
+ pos += sprintf(res+pos, " >= ");
+ break;
+ case LT:
+ pos += sprintf(res+pos, " < ");
+ break;
+ case LE:
+ pos += sprintf(res+pos, " <= ");
+ break;
+ }
+ }while(buff_pos < length);
+ while((res[pos-1] == ';' || res[pos-1] == ' ') && pos > 0) { res[pos-1] = 0; pos--;}
+ strcpy(nf, res); free(res);
+ free(buffer); buffer = 0L;
+ clear_table();
+ pop_parser();
+ return true;
+}
+
+static char *txt_formula; //function to fit
+static double **parval; //pointers to parameter values
+static void fcurve(double x, double z, double **a, double *y, double dyda[], int ma)
+{
+ int i, length;
+ double tmp, y1, y2;
+ symrec *symx, *s=0L;
+ unsigned int hn_x = HashValue((unsigned char *)"x");
+ unsigned int hn_y = HashValue((unsigned char *)"y");
+
+ if(!(symx = getsym(hn_x))) symx = putsym(hn_x, VAR, 0);
+ //swap parameters to requested set
+ if(a != parval) for(i = 0; i < ma; i++) {
+ tmp = *parval[i]; *parval[i] = *a[i]; *a[i] = tmp;
+ }
+ //calc result
+ symx->value.var = x; buffer = txt_formula;
+ buff_pos = 0; length = strlen(txt_formula);
+ do { yyparse(); }while(buff_pos < length);
+ if(s = getsym(hn_y)) *y = s->value.var;
+ else *y = line_result;
+ if(*y == HUGE_VAL || *y == -HUGE_VAL) {
+ for(i = 0, *y = 0.0; i < ma; dyda[i++] = 0.0);
+ return;
+ }
+ //partial derivatives for each parameter by numerical differentiation
+ for(i = 0; i < ma; i++) {
+ if(*parval[i] != 0.0) {
+ tmp = *parval[i];
+ *parval[i] = tmp*.995;
+ buff_pos = 0;
+ do { yyparse(); }while(buff_pos < length);
+ y1 = s ? s->value.var : line_result;
+ *parval[i] = tmp*1.005;
+ buff_pos = 0;
+ do { yyparse(); }while(buff_pos < length);
+ y2 = s ? s->value.var : line_result;
+ *parval[i] = tmp;
+ dyda[i] = (y2-y1)*100.0/tmp;
+ }
+ else dyda[i] = 0.0;
+ }
+ //swap parameters back to original
+ if(a != parval) for(i = 0; i < ma; i++) {
+ tmp = *parval[i]; *parval[i] = *a[i]; *a[i] = tmp;
+ }
+}
+
+int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr, double conv, int maxiter, double *chi_2)
+{
+ int length, i, j, k, l, ndata, nparam, r1, r2, r3, c1, c2, c3, *lista, itst, itst1;
+ symrec *tab1, *tab2, *csr, **parsym;
+ AccRange *arx, *ary, *arz;
+ double *x, *y, *z, currx, curry, currz, alamda, chisq, ochisq;
+ double **covar, **alpha;
+ char tmp_txt[500];
+
+ if(d) curr_data = d;
+ if(chi_2) *chi_2 = 0.0;
+ txt_formula = expr;
+ if(!curr_data || !par || !expr || !rx || !ry) return 0;
+ //process ranges and create arrays
+ arx = ary = arz = 0L; x = y = z = 0L; parval = 0L; parsym = 0L;
+ if(!(arx = new AccRange(rx)))return 0;
+ i = arx->CountItems()+1;
+ if(!(ary = new AccRange(ry))){
+ delete arx; return 0;
+ }
+ if(rz && !(arz = new AccRange(rz))){
+ delete ary; delete arx; return 0;
+ }
+ if(!(x = (double*)malloc(i * sizeof(double)))){
+ if(arz) delete arz;
+ delete ary; delete arx; return 0;
+ }
+ if(!(y = (double*)malloc(i * sizeof(double)))){
+ if(arz) delete arz;
+ free(x); delete arx; delete ary; return 0;
+ }
+ if(rz && !(y = (double*)malloc(i * sizeof(double)))){
+ if(arz) delete arz;
+ free(y); free(x); delete arx; delete ary; return 0;
+ }
+ arx->GetFirst(&c1, &r1); ary->GetFirst(&c2, &r2);
+ if(rz) arz->GetFirst(&c3, &r3);
+ for(ndata = j = 0; j < i; j++) {
+ if(rz) {
+ if(arx->GetNext(&c1, &r1) && ary->GetNext(&c2, & r2) && arz->GetNext(&c3, &r3) &&
+ curr_data->GetValue(r1, c1, &currx) && curr_data->GetValue(r2, c2, &curry) &&
+ curr_data->GetValue(r3, c3, &currz)) {
+ x[ndata] = currx; y[ndata] = curry; z[ndata] = currz; ndata++;
+ }
+ }
+ else {
+ if(arx->GetNext(&c1, &r1) && ary->GetNext(&c2, & r2) &&
+ curr_data->GetValue(r1, c1, &currx) && curr_data->GetValue(r2, c2, &curry)) {
+ x[ndata] = currx; y[ndata] = curry; ndata++;
+ }
+ }
+ }
+ //common initialization for parser tasks
+ push_parser(); //make code reentrant
+ init_table(); length = strlen(*par);
+ //process parameters
+ if(!(buffer = (char*)malloc(length+2))){
+ clear_table(); pop_parser();
+ if(arz) delete arz;
+ free(y); free(x); delete arx; delete ary;
+ return 0;
+ }
+ strcpy(buffer, *par); buffer[length++] = ';';
+ buffer[length] = 0; buff_pos = 0;
+ tab1 = sym_table;
+ do {
+ yyparse();
+ }while(buff_pos < length);
+ tab2 = sym_table; free(buffer); buffer =0L;
+ for(nparam = 0, csr=tab2; csr != tab1; nparam++, csr = csr->next);
+ parsym = (symrec**)malloc((nparam+1)*sizeof(symrec*));
+ parval = (double**)malloc((nparam+1)*sizeof(double*));
+ for(i = 0, csr=tab2; csr != tab1 && i < nparam; i++, csr = csr->next){
+ parsym[i] = csr; parval[i] = &csr->value.var;
+ }
+ //do iteratations to optimize fit
+ lista = (int*)malloc(sizeof(int)*nparam);
+ for(i = 0; i< nparam; i++) lista[i] = i;
+ covar = dmatrix(1, nparam, 1, nparam);
+ alpha = dmatrix(1, nparam, 1, nparam);
+ alamda = -1.0; itst = 0;
+ mrqmin(x, y, z, ndata, parval, nparam, lista, nparam, covar, alpha, &chisq, fcurve, &alamda);
+ if(!Check_MRQerror()) {
+ for(itst = itst1 = 0, ochisq = chisq; itst < maxiter && chisq > conv && ochisq >= chisq && itst1 < 9; itst++) {
+ ochisq = chisq;
+ mrqmin(x, y, z, ndata, parval, nparam, lista, nparam, covar, alpha, &chisq, fcurve, &alamda);
+ if(ochisq == chisq) itst1++;
+ else itst1 = 0;
+ }
+ alamda = 0.0;
+ mrqmin(x, y, z, ndata, parval, nparam, lista, nparam, covar, alpha, &chisq, fcurve, &alamda);
+ Check_MRQerror();
+ }
+ for(i = nparam-1, j = k = l = 0; i >= 0; l = 0, i--) {
+ if(k > 20) {
+ if(tmp_txt[j-1] == ' ') j--;
+ if(tmp_txt[j-1] == ';') j--;
+ l = sprintf(tmp_txt+j, "\n");
+ j += l; k = 0;
+ }
+ l += sprintf(tmp_txt+j, "%s%s=%g;", j && k ? " " : "", parsym[i]->name, parsym[i]->value.var);
+ j += l; k += l;
+ }
+ free(*par); *par = strdup(tmp_txt);
+ if(chi_2) *chi_2 = chisq;
+ //write back spreadsheet data if necessary
+ buffer = *par; length = strlen(buffer);
+ do {
+ yyparse();
+ }while(buff_pos < length);
+ buffer = 0L;
+ free_dmatrix(alpha, 1, nparam, 1, nparam);
+ free_dmatrix(covar, 1, nparam, 1, nparam);
+ if(arz) delete arz; if(z) free(z);
+ free(y); free(x); delete arx; delete ary;
+ if(parval) free(parval); if(parsym) free(parsym);
+ clear_table();
+ pop_parser();
+ if(curr_data){
+ curr_data->Command(CMD_CLEAR_ERROR, 0L, 0L);
+ curr_data->Command(CMD_REDRAW, 0L, 0L);
+ }
+ return itst < maxiter ? itst+1 : maxiter;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resource.h b/resource.h
new file mode 100755
index 0000000..2e03463
--- /dev/null
+++ b/resource.h
@@ -0,0 +1,86 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by RLPLOT.RC
+//
+#define ACCELERATORS_1 1
+#define IDI_EVAL 50
+#define MENU_1 400
+#define MENU_2 401
+#define MENU_3 402
+#define CM_OPEN 500
+#define CM_SAVEDATAAS 501
+#define CM_EXIT 502
+#define CM_NEWGRAPH 503
+#define CM_NEWPAGE 504
+#define CM_DELGRAPH 505
+#define CM_ADDPLOT 506
+#define CM_ABOUT 507
+#define CM_ADDROWCOL 508
+#define CM_COPYGRAPH 509
+#define CM_SAVEGRAPHAS 510
+#define CM_REDRAW 511
+#define CM_ZOOM25 512
+#define CM_ZOOM50 513
+#define CM_ZOOM100 514
+#define CM_ZOOM200 515
+#define CM_ZOOM400 516
+#define CM_PRINT 517
+#define CM_EXPORT 518
+#define CM_DELOBJ 519
+#define CM_REBOOT 520
+#define CM_SHUTDOWN 521
+#define CM_DEFAULTS 522
+#define CM_COPY 523
+#define CM_PASTE 524
+#define CM_UPDATE 525
+#define CM_ADDAXIS 526
+#define CM_UNDO 527
+#define CM_ZOOMIN 528
+#define CM_ZOOMOUT 529
+#define CM_ZOOMFIT 530
+#define CM_FILE1 531
+#define CM_FILE2 532
+#define CM_FILE3 533
+#define CM_FILE4 534
+#define CM_FILE5 535
+#define CM_FILE6 536
+#define CM_FILLRANGE 537
+#define CM_CUT 538
+#define CM_LEGEND 539
+#define CM_LAYERS 540
+#define CM_T_STANDARD 550
+#define CM_T_DRAW 551
+#define CM_T_POLYLINE 552
+#define CM_T_POLYGON 553
+#define CM_T_RECTANGLE 554
+#define CM_T_ROUNDREC 555
+#define CM_T_ELLIPSE 556
+#define CM_T_ARROW 557
+#define CM_T_TEXT 558
+#define CM_DELKEY 600
+#define CM_LEFTARRKEY 601
+#define CM_RIGHTARRKEY 602
+#define CM_UPARRKEY 603
+#define CM_DOWNARRKEY 604
+#define CM_TAB 605
+#define CM_SHTAB 606
+#define CM_PGUP 607
+#define CM_PGDOWN 608
+#define CM_POS_FIRST 609
+#define CM_POS_LAST 610
+#define CM_SHLEFT 611
+#define CM_SHRIGHT 612
+#define CM_SHUP 613
+#define CM_SHDOWN 614
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 103
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/rlp_math.cpp b/rlp_math.cpp
new file mode 100755
index 0000000..9420d89
--- /dev/null
+++ b/rlp_math.cpp
@@ -0,0 +1,411 @@
+//rlp_math.cpp, Copyright (c) 2004, 2005 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 <math.h>
+#include <stdlib.h>
+
+#define SWAP(a,b) {double temp=(a);(a)=(b);(b)=temp;}
+static char *MRQ_error = 0L;
+
+//---------------------------------------------------------------------------
+//utilitity functions for memory allocation
+double **dmatrix(int nrl, int nrh, int ncl, int nch)
+{
+ int i;
+ double **m;
+
+ m = (double **)malloc(nrh * sizeof(double*));
+ //Allocate rows and set pointers to them
+ for(i = 0; i < nrh; i++) {
+ m[i] = (double *)malloc(nrh * sizeof(double));
+ }
+ return m;
+}
+void free_dmatrix(double **m, int nrl, int nrh, int ncl, int)
+{
+ int i;
+
+ for(i = 0; i < nrh; i++) free(m[i]);
+ free(m);
+}
+
+//---------------------------------------------------------------------------
+//The routine gaussj solves linear equations by Gauss-Jordan elimination
+bool gaussj(double **a, int n, double **b, int m)
+{
+ int *indxc, *indxr, *ipiv;
+ int i, icol, irow, j, k, l, ll;
+ double big, dum, pivinv;
+
+ indxc = (int*)malloc(n*sizeof(int*));
+ indxr = (int*)malloc(n*sizeof(int*));
+ ipiv = (int*)malloc(n*sizeof(int*));
+ for (j = 0; j < n; j++) ipiv[j] = 0;
+ for (i = 0; i < n; i++) { //This is the main loop over the
+ big = 0.0; // columns to be reduced
+ for(j = 0; j < n; j ++) //This is the outer loop of the search
+ if(ipiv[j] != 1) // for a pivot element
+ for(k = 0; k < n; k ++) {
+ if (ipiv[k] == 0) {
+ if(fabs(a[j][k]) >= big) {
+ big = fabs(a[j][k]);
+ irow = j; icol = k;
+ }
+ }
+ else if(ipiv[k] > 1) {
+ MRQ_error = "Singular Matrix (1)";
+ free(ipiv); free(indxr); free(indxc);
+ return false;
+ }
+ }
+ ++(ipiv[icol]);
+ //We now have the pivot element, so we interchange rows, if needed,
+ // to put the pivot element on the diagonal.
+ if(irow != icol) {
+ for(l = 0; l < n; l++) SWAP(a[irow][l], a[icol][l])
+ for(l = 0; l < m; l++) SWAP(b[irow][l], b[icol][l])
+ }
+ indxr[i] = irow; indxc[i] = icol;
+ if(a[icol][icol] == 0.0) {
+ MRQ_error = "Singular Matrix (2)";
+ free(ipiv); free(indxr); free(indxc);
+ return false;
+ }
+ pivinv = 1.0/a[icol][icol];
+ a[icol][icol] = 1.0;
+ for(l = 0; l < n; l++) a[icol][l] *= pivinv;
+ for(l = 0; l < m; l++) b[icol][l] *= pivinv;
+ for(ll = 0; ll < n; ll++)
+ if(ll != icol) { //Next, we reduce the rows
+ dum = a[ll][icol];
+ a[ll][icol] = 0.0;
+ for(l = 0; l < n; l++) a[ll][l] -= a[icol][l]*dum;
+ for(l = 0; l < m; l++) b[ll][l] -= b[icol][l]*dum;
+ }
+ } // This is the end of the main loop
+ for (l = n; l > 0; l--) { // over columns of the reduction.
+ if(indxr[l] != indxc[l]) // Unscramble the solution
+ for(k = 0; k < n; k++) SWAP (a[k][indxr[l]], a[k][indxc[l]]);
+ } //And we are done.
+ free(ipiv); free(indxr); free(indxc);
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//The routine mrqcof is called by mrqmin to evaluate the linearized fitting
+// matrix alpha and vector beta
+void mrqcof(double x[], double y[], double z[], int ndata, double **a, int ma,
+ int lista[], int mfit, double **alpha, double beta[], double *chisq,
+ void (*funcs)(double, double, double **, double *, double *, int))
+{
+ int k, j, i;
+ double ymod, wt, dy;
+ double *dyda;
+
+ dyda = (double*)malloc(ma*sizeof(double));
+ for(j = 0; j < mfit; j++) { //Initialize (symmetric) alpha, beta
+ for(k = 0; k <= j; k++) alpha[j][k] = 0.0;
+ beta[j] = 0.0;
+ }
+ *chisq = 0.0;
+ for (i = 0; i < ndata; i++) { //Summation loop over all data
+ (*funcs)(x[i], z ? z[i] : 0.0, a, &ymod, dyda, ma);
+ if(ymod != 0.0) dy = y[i]-ymod; //functions = 0.0 if out of range
+ else dy = 0.0;
+ for(j = 0; j < mfit; j++) {
+ wt = dyda[lista[j]];
+ for (k = 0; k <= j; k++){
+ alpha[j][k] += wt*dyda[lista[k]];
+ }
+ beta[j] += dy*wt;
+ }
+ (*chisq) += dy*dy; //And find X^2 if function o.k.
+ }
+ for(j = 0; j < mfit; j++) //Fill the symmetric side
+ for(k = 0; k <= j; k++) alpha[k][j]=alpha[j][k];
+ free(dyda);
+}
+
+//---------------------------------------------------------------------------
+//The routine mrqmin performs one iteration of Marquart's method for nonlinear
+// parameter estimation
+bool mrqmin(double *x, double *y, double *z, int ndata, double **a, int ma,
+ int *lista, int mfit, double **covar, double **alpha, double *chisq,
+ void (*funcs)(double, double, double **, double *, double *, int), double *alamda)
+{
+ int k, kk, j, ihit;
+ static double *da, *atry, *beta, ochisq;
+ static double **oneda, **atryref;
+
+ if (*alamda < 0.0) { //Initialization
+ MRQ_error = 0L;
+ oneda = dmatrix(1, mfit, 1, 1);
+ atry = (double *)malloc(ma * sizeof(double));
+ atryref = (double**)malloc(ma * sizeof(double*));
+ for(j=0; j < ma; atryref[j++] = &atry[j]);
+ da = (double*)malloc(ma *sizeof(double));
+ beta = (double*)malloc(ma *sizeof(double));
+ kk = mfit+1;
+ for(j = 0; j < ma; j++) { //Does lista contain a proper
+ ihit = 0; // permutation of the
+ for(k = 0; k < mfit; k++) // coefficients ?
+ if(lista[k] == j) ihit++;
+ if(ihit == 0)
+ lista[kk++] = j;
+ else if (ihit >1) ErrorBox("Bad LISTA permutations in MRQMIN-1");
+ }
+ if(kk != ma+1) ErrorBox("Bad LISTA permutations in MRQMIN-2");
+ *alamda = 0.001;
+ mrqcof(x, y, z, ndata, a, ma, lista, mfit, alpha, beta, chisq, funcs);
+ ochisq=(*chisq);
+ }
+ for (j = 0; j < mfit; j++) { //Alter linearized fitting matrix
+ for(k = 0; k < mfit; k++) covar[j][k] = alpha[j][k]; // by augmenting
+ covar[j][j] = alpha[j][j]*(1.0+(*alamda)); // diagaonal elements
+ oneda[j][0] = beta[j];
+ }
+ if (!gaussj(covar, mfit, oneda, 1)) return false; //Matrix solution ?
+ for(j = 0; j < mfit; j++) da[j] = oneda[j][0];
+ if(*alamda == 0.0) { //Once converged evaluate
+ // covariance matrix with
+ free(beta); // alamda = 0.
+ free(da);
+ free(atry);
+ free(atryref);
+ free_dmatrix(oneda, 1, mfit, 1, 1);
+ return true;
+ }
+ for(j = 0; j < ma; j++) atry[j] = *a[j];
+ for(j = 0; j < mfit; j++) //Did the trial succeed ?
+ atry[lista[j]] = *a[lista[j]] + da[j];
+ mrqcof(x, y, z, ndata, atryref, ma, lista, mfit, covar, da, chisq, funcs);
+ if(*chisq < ochisq) { //Success, accept the new solution
+ *alamda *= 0.1;
+ ochisq=(*chisq);
+ for(j = 0; j < mfit; j++) {
+ for(k = 0; k < mfit; k++) alpha[j][k] = covar[j][k];
+ beta[j] = da[j];
+ *a[lista[j]] = atry[lista[j]];
+ }
+ }
+ else { //Failure, increase almda and
+ *alamda *= 10.0; // return.
+ *chisq = ochisq;
+ }
+ return true;
+}
+
+bool Check_MRQerror()
+{
+ bool bRet;
+
+ if(bRet = MRQ_error != 0L) ErrorBox(MRQ_error);
+ MRQ_error = 0L;
+ return bRet;
+}
+
+//---------------------------------------------------------------------------
+//Use heap sort to sort elements of an float array
+//W.H. pres, B.P. Flannery, S.A. Teukolsky, W.T. Vetterling (1988/1989)
+//Numerical Recipes in C, Cambridge University Press, ISBN 0-521-35465-X
+// p. 245
+void SortArray(int n, double *vals)
+{
+ int l, j, ir, i;
+ double rra, *ra = vals-1;
+
+ l=(n >> 1) + 1; ir = n;
+ for( ; ; ) {
+ if(l > 1) rra = ra[--l];
+ else {
+ rra = ra[ir]; ra[ir] = ra[1];
+ if(--ir == 1) {
+ ra[1] = rra; return;
+ }
+ }
+ i = l; j = l << 1;
+ while (j <= ir) {
+ if (j < ir && ra[j] < ra[j+1]) ++j;
+ if (rra < ra[j]) {
+ ra[i] = ra[j]; j += (i=j);
+ }
+ else j = ir + 1;
+ }
+ ra[i] = rra;
+ }
+}
+//---------------------------------------------------------------------------
+// Special Functions
+// Ref.: W.H. Press, B.P. Flannery, S.A. Teukolsky, W.T. Vetterling (1989),
+// Numerical Rcipies in C. The Art of Scientific Computing,
+// Cambridge University Press, ISBN 0-521-35465, pp. 166 ff.
+
+// The Gamma Function: return the ln(G(xx)) for xx > 0
+double gammln(double xx)
+{
+ double x, tmp, ser, pi=3.14159265358979;
+ static double cof[6] = {76.18009173, -86.50532033, 24.01409822,
+ -1.231739516, 0.120858003e-2, -0.536382e-5};
+ int j;
+
+ if(xx < 0) return 0.0;
+ if(xx < 1.0) //reflect
+ return log((pi*(1.0-xx))/(exp(gammln(2.0-xx))*sin(pi*(1.0-xx))));
+ x = xx-1; tmp = x + 5.5; tmp -= (x + 0.5)*log(tmp);
+ for (j = 0, ser = 1.0; j <= 5; j++) {
+ x += 1.0; ser += cof[j]/x;
+ }
+ return -tmp + log(2.50662827465*ser);
+}
+
+//The Factorial Function: return n!
+double factrl(int n)
+{
+ static int ntop = 4;
+ static double a[33]={1.0, 1.0, 2.0, 6.0, 24.0};
+ int j;
+
+ if(n < 0) return 0.0; //error: no factorial for negative numbers
+ if(n > 32) return exp(gammln(n+1.0));
+ while(ntop < n) { //fill in table up to desired value
+ j = ntop++; a[ntop]=a[j] * ntop;
+ }
+ return a[n];
+}
+
+//continued fraction for incomplete beta function, used by betai()
+double betacf(double a, double b, double x)
+{
+ double qap, qam, qab, em, tem, d, bz, bm = 1.0, bp, bpp, az = 1.0, am = 1.0, ap, app, aold;
+ int m;
+
+ qab = a+b; qap = a+1.0; qam = a-1.0; bz = 1.0-qab*x/qap;
+ for(m = 1; m <= 100; m++) {
+ em = (double)m; tem = em+em;
+ d = em*(b-em)*x/((qam+tem)*(a+tem));
+ ap = az + d * am; bp = bz + d *bm;
+ d = -(a+em)*(qab+em)*x/((qap+tem)*(a+tem));
+ app = ap + d * az; bpp = bp + d * bz;
+ aold = az; am = ap/bpp;
+ bm = bp/bpp; az = app/bpp;
+ bz = 1.0;
+ if(fabs(az-aold) <= (1.0e-12 * fabs(az))) return az; //success: return
+ }
+ return az; //fail: iterations exceeded
+}
+
+//The incomplete beta function Ix(a,b) for 0 <= x <= 1
+double betai(double a, double b, double x)
+{
+ double bt;
+
+ if(x < 0.0 || x > 1.0) return 0.0; //range !
+ if(x == 0.0 || x == 1.0) bt = 0.0;
+ else
+ bt = exp(gammln(a+b)-gammln(a)-gammln(b)+a*log(x)+b*log(1.0-x));
+ if(x < (a+1.0)/(a+b+2.0)) return bt * betacf(a, b, x)/a;
+ else return 1.0 - bt * betacf(b, a, 1.0 - x)/b;
+}
+
+double t_dist(double t, double df)
+{
+ return betai(df/2.0, 0.5, (df/(df+t*t)));
+}
+
+double f_dist(double f, double df1, double df2)
+{
+ return betai(df2/2.0, df1/2.0, df2/(df2+df1*f));
+}
+
+//---------------------------------------------------------------------------
+//some statistical basics
+//do quartiles, median of data
+void d_quartile(int n, double *v, double *q1, double *q2, double *q3)
+{
+ int n2, n3;
+ double f1, f2;
+
+ if(!v || n<2) return;
+ SortArray(n, v); n2 = n >> 1;
+ if(q1) {
+ n3 = n2 >> 1;
+ switch(n%4) {
+ case 3: n3 ++; f1 = 2.0; f2 = 2.0; break;
+ case 2: n3 ++; f1 = 3.0; f2 = 1.0; break;
+ case 1: n3 ++; f1 = 4.0; f2 = 0.0; break;
+ default: f1 = 1.0; f2 = 3.0; break;
+ }
+ *q1 = (f1*v[n3-1] + f2*v[n3])/4.0;
+ }
+ if(q2) {
+ if(n & 1) *q2 = v[n2];
+ else *q2 = (v[n2-1] + v[n2])/2.0;
+ }
+ if(q3) {
+ n3 = n2 >> 1;
+ switch(n%4) {
+ case 3: n3++; f1 = 2.0; f2 = 2.0; break;
+ case 2: f1 = 3.0; f2 = 1.0; break;
+ case 1: f1 = 4.0; f2 = 0.0; break;
+ default: f1 = 1.0; f2 = 3.0; break;
+ }
+ n3 += n2;
+ *q3 = (f2*v[n3-1] + f1*v[n3])/4.0;
+ }
+}
+
+//do arithmethic mean
+double d_amean(int n, double *v)
+{
+ int i;
+ double sum;
+
+ for(i = 0, sum = 0.0; i < n; i++) {
+ sum += (v[i]);
+ }
+ return (sum/n);
+}
+
+
+//do geometric mean
+double d_gmean(int n, double *v)
+{
+ int i;
+ double sum;
+
+ for(i = 0, sum = 0.0; i < n; i++) {
+ if(v[i] <= 0.0) return 0.0;
+ sum += log(v[i]);
+ }
+ return exp(sum/n);
+}
+
+//do harmonic mean
+double d_hmean(int n, double *v)
+{
+ int i;
+
+ double sum;
+
+ for(i = 0, sum = 0.0; i < n; i++) {
+ if(v[i] == 0.0) return 0.0;
+ sum += 1.0/(v[i]);
+ }
+ return (n/sum);
+}
diff --git a/rlplot.1 b/rlplot.1
new file mode 100755
index 0000000..7d85027
--- /dev/null
+++ b/rlplot.1
@@ -0,0 +1,105 @@
+.\" Hey, EMACS: -*- nroff -*-
+.\" First parameter, NAME, should be all caps
+.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
+.\" other parameters are allowed: see man(7), man(1)
+.TH RLPLOT 1
+.\" Please adjust this date whenever revising the manpage.
+.\"
+.\" Some roff macros, for reference:
+.\" .nh disable hyphenation
+.\" .hy enable hyphenation
+.\" .ad l left justify
+.\" .ad b justify to both left and right margins
+.\" .nf disable filling
+.\" .fi enable filling
+.\" .br insert line break
+.\" .sp <n> insert n+1 empty lines
+.\" for manpage-specific macros, see man(7)
+.SH NAME
+rlplot \- generate publication quality graphs
+.br
+exprlp \- convert rlplot files to vector based graphic files
+.SH SYNOPSIS
+.B rlplot
+.I <file>
+.br
+.B exprlp
+.RI [options] <input> [options] [<output>]
+.SH DESCRIPTION
+This manual page documents briefly the
+.B rlplot
+and
+.B exprlp
+commands.
+.PP
+.B rlplot
+is a GUI based program for displaying scientific data in standard
+formats. Output is generated on the X display where further
+changes can be made to the graph using point and click methods.
+Images can be exported as scalable vector graphics (SVG) as well as
+EPS, WMF and TIFF formats.
+.PP
+.B exprlp
+reads RLPlot files and exports various vector based graphic file
+formats including scaleable vector graphics (SVG), Encapsulated
+PostScript (EPS), and Windows Metafile (WMF).
+.SH OPTIONS
+.B rlplot
+does not have any command line options but the following options are
+available for
+.B exprlp
+.
+.TP
+.B \-
+use stdin/stdout as input or output file; requires that file format is set by -e | -s | -w option
+.TP
+.B \-h
+help
+.TP
+.B \-d
+delete input file after read
+.TP
+.B \-e
+output Encapsulated PostScript, *.eps
+.TP
+.B \-s
+output Scalable Vector Graphics, *.svg
+.TP
+.B \-S
+like -s, start output with "Content-Type: image/svg+xml"
+.TP
+.B \-v
+print RLPlot version
+.TP
+.B \-w
+output Windows Meta File, *.wmf
+.TP
+.B \-q
+quiet mode: suppress output to the console
+.SH EXAMPLES
+.B exprlp
+foo.rlp foo.svg ;exports Scalable Vector Graphics
+.TP
+.B exprlp
+\-q foo.rlp foo.eps ;exports Encapsulated PostScript, no messages
+.TP
+.B exprlp
+foo.rlp foo.wmf ;exports Windows Meta File
+.TP
+.B exprlp
+\-sq foo.rlp \- ;exports SVG to the console, no messages
+.TP
+.B exprlp
+exprlp \-eq \- \- ;converts inputfile from stdin to EPS on stdout
+.TP
+switch character is either '\-' or '\//'
+
+.SH AUTHOR
+.B rlplot
+and
+.B exprlp
+were written by Reinhard Lackner and are released under the GNU general
+public license.
+.sp
+This manual page was written by James Stone <jmstone at dsl.pipex.com>.
+
diff --git a/rlplot.cpp b/rlplot.cpp
new file mode 100755
index 0000000..0de7a6b
--- /dev/null
+++ b/rlplot.cpp
@@ -0,0 +1,9618 @@
+//RLPlot.cpp, Copyright 2000, 2001, 2002, 2003, 2004, 2005 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 <math.h>
+#include <string.h>
+
+extern tag_Units Units[];
+extern char TmpTxt[];
+extern Default defs;
+
+GraphObj *CurrGO, *TrackGO; //Selected Graphic Objects
+Label *CurrLabel = 0L;
+Graph *CurrGraph = 0L;
+dragHandle *CurrHandle = 0L;
+Axis **CurrAxes = 0L;
+UndoObj Undo;
+int cGraphs = 0;
+int cPlots = 0;
+int cPages = 0;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// grapic objects
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+GraphObj::GraphObj(GraphObj *par, DataObj *d)
+{
+ parent = par;
+ data = d;
+ Id = GO_UNKNOWN;
+ type = moveable = 0;
+ name = 0L;
+ rDims.left = rDims.right = rDims.top = rDims.bottom = 0;
+}
+
+GraphObj::~GraphObj()
+{
+ if(name)free(name);
+ name = 0L;
+ if(CurrGO == this) CurrGO = 0L;
+ if(TrackGO == this) TrackGO = 0L;
+}
+
+double
+GraphObj::GetSize(int select)
+{
+ if(parent) return parent->GetSize(select);
+ else return defs.GetSize(select);
+}
+
+DWORD
+GraphObj::GetColor(int select){
+ return defs.Color(select);
+}
+
+void
+GraphObj::RegGO(void *n)
+{
+ ((notary*)n)->AddRegGO(this);
+}
+
+void *
+GraphObj::ObjThere(int x, int y)
+{
+ if(IsInRect(&rDims, x, y)) return this;
+ else return 0L;
+}
+
+void
+GraphObj::Track(POINT *p, anyOutput *o)
+{
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Spread sheet buttons used for rows and columns
+ssButton::ssButton(GraphObj *par, int x, int y, int w, int h):GraphObj(par, 0L)
+{
+ bLBdown = false;
+ SetMinMaxRect(&rDims, x, y, x+w, y+h);
+ Line.width = 0.0f; Line.patlength = 1.0f;
+ Line.color = 0x00000000L; Line.pattern = 0x00000000L;
+ Fill.type = FILL_NONE; Fill.color = 0x00d8d8d8L;
+ Fill.scale = 1.0; Fill.hatch = NULL;
+ TextDef.ColTxt = 0x00000000L; TextDef.ColBg = 0x00ffffffL;
+ TextDef.fSize = 4.0; TextDef.RotBL = TextDef.RotCHAR = 0.0;
+ TextDef.iSize = 0; TextDef.Align = TXA_HLEFT | TXA_VTOP;
+ TextDef.Mode = TXM_TRANSPARENT; TextDef.Style = TXS_NORMAL;
+ TextDef.Font = FONT_HELVETICA; TextDef.text = 0L;
+}
+
+ssButton::~ssButton()
+{
+ if(TextDef.text) free(TextDef.text);
+}
+
+void
+ssButton::DoPlot(anyOutput *o)
+{
+ POINT pts[3];
+
+ Line.color = 0x00000000L;
+ o->SetLine(&Line);
+ o->SetFill(&Fill);
+ if(bLBdown){
+ o->oRectangle(rDims.left, rDims.top, rDims.right, rDims.bottom);
+ }
+ else {
+ o->oRectangle(rDims.left, rDims.top, rDims.right-1, rDims.bottom-1);
+ Line.color = 0x00000000L;
+ o->SetLine(&Line);
+ pts[0].x = rDims.left; pts[0].y = pts[1].y = rDims.bottom-1;
+ pts[1].x = pts[2].x = rDims.right-1; pts[2].y = rDims.top-1;
+ o->oPolyline(pts, 3);
+ Line.color = 0x00ffffffL;
+ o->SetLine(&Line);
+ pts[0].x = pts[1].x = rDims.left; pts[0].y = rDims.bottom -3;
+ pts[1].y = pts[2].y = rDims.top; pts[2].x = rDims.right -2;
+ o->oPolyline(pts, 3);
+ }
+ if(TextDef.text) {
+ o->SetTextSpec(&TextDef);
+#ifdef _WINDOWS
+ o->oTextOut((rDims.left + rDims.right)/2-2, (rDims.top + rDims.bottom)/2-1, TextDef.text, 0);
+#else
+ o->oTextOut((rDims.left + rDims.right)/2-2, (rDims.top + rDims.bottom)/2+1, TextDef.text, 0);
+#endif
+ }
+
+}
+void
+ssButton::DoMark(anyOutput *o, bool mark)
+{
+ bLBdown = mark;
+ DoPlot(o);
+ o->UpdateRect(&rDims, false);
+}
+
+bool
+ssButton::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ char *tmptxt;
+ MouseEvent *mev;
+
+ switch (cmd) {
+ case CMD_GETTEXT:
+ if(TextDef.text && tmpl) {
+ strcpy((char*)tmpl, TextDef.text);
+ return true;
+ }
+ return false;
+ case CMD_SETTEXT:
+ if(TextDef.text) free(TextDef.text);
+ if(tmpl) TextDef.text = strdup((char*)tmpl);
+ else TextDef.text = 0L;
+ return true;
+ case CMD_GETTEXTDEF:
+ if(!tmpl) return false;
+ memcpy(tmpl, &TextDef, sizeof(TextDEF));
+ return true;
+ case CMD_SETTEXTDEF:
+ if(!tmpl)return false;
+ tmptxt = TextDef.text;
+ memcpy(&TextDef, tmpl, sizeof(TextDEF));
+ TextDef.text = tmptxt;
+ return true;
+ case CMD_MOUSE_EVENT:
+ if(!o || !(mev = (MouseEvent *) tmpl)) break;
+ if(IsInRect(&rDims, mev->x, mev->y)) {
+ if(bLBdown) {
+ if(!(mev->StateFlags & 0x01)) {
+ o->HideMark();
+ if(bLBdown) {
+ bLBdown = false; DoPlot(o);
+ }
+ }
+ }
+ else if(mev->StateFlags & 0x01) {
+ o->ShowMark(this, MRK_SSB_DRAW);
+ }
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// drag handles are graphic objects which allow the user to interactively
+// change the size of an object
+dragHandle::dragHandle(GraphObj *par, int which):GraphObj(par, 0L)
+{
+ type = which;
+ Id = GO_DRAGHANDLE;
+ LineDef.width = LineDef.patlength = 0.0;
+ LineDef.color = LineDef.pattern = 0L;
+ FillDef.type = FILL_NONE;
+ FillDef.color = 0x00ffffffL;
+ FillDef.scale = 1.0;
+ FillDef.hatch = 0L;
+ minRC = maxRC = 0L;
+}
+
+dragHandle::~dragHandle()
+{
+ if(minRC) free(minRC);
+ if(maxRC) free(maxRC);
+ if(CurrHandle == this) CurrHandle = 0L;
+}
+
+void
+dragHandle::DoPlot(anyOutput *o)
+{
+ double fx, fy, dx, dy;
+ int ix, iy;
+ fPOINT3D fp3d, ifp3d;
+ bool is3D = false;
+
+ if(!o || !parent) return;
+ dx = parent->GetSize(SIZE_GRECT_LEFT); dy = parent->GetSize(SIZE_GRECT_TOP);
+ SetMinMaxRect(&drec, o->co2ix(parent->GetSize(SIZE_XPOS)+dx),
+ o->co2iy(parent->GetSize(SIZE_YPOS)+dy), o->co2ix(parent->GetSize(SIZE_XPOS+1)+dx),
+ o->co2iy(parent->GetSize(SIZE_YPOS+1)+dy));
+ switch(type) {
+ case DH_19: case DH_12:
+ fx = parent->GetSize(SIZE_XPOS); fy = parent->GetSize(SIZE_YPOS);
+ break;
+ case DH_99: case DH_22:
+ fx = parent->GetSize(SIZE_XPOS+1); fy = parent->GetSize(SIZE_YPOS+1);
+ break;
+ case DH_29:
+ fx = (parent->GetSize(SIZE_XPOS) + parent->GetSize(SIZE_XPOS+1))/2.0;
+ fy = parent->GetSize(SIZE_YPOS);
+ break;
+ case DH_39:
+ fx = parent->GetSize(SIZE_XPOS+1); fy = parent->GetSize(SIZE_YPOS);
+ break;
+ case DH_49:
+ fx = parent->GetSize(SIZE_XPOS);
+ fy = (parent->GetSize(SIZE_YPOS) + parent->GetSize(SIZE_YPOS+1))/2.0;
+ break;
+ case DH_59:
+ fx = (parent->GetSize(SIZE_XPOS) + parent->GetSize(SIZE_XPOS+1))/2.0;
+ fy = (parent->GetSize(SIZE_YPOS) + parent->GetSize(SIZE_YPOS+1))/2.0;
+ break;
+ case DH_69:
+ fx = parent->GetSize(SIZE_XPOS+1);
+ fy = (parent->GetSize(SIZE_YPOS) + parent->GetSize(SIZE_YPOS+1))/2.0;
+ break;
+ case DH_79:
+ fx = parent->GetSize(SIZE_XPOS);
+ fy = parent->GetSize(SIZE_YPOS+1);
+ break;
+ case DH_89:
+ fx = (parent->GetSize(SIZE_XPOS) + parent->GetSize(SIZE_XPOS+1))/2.0;
+ fy = parent->GetSize(SIZE_YPOS+1);
+ break;
+ case DH_18: case DH_28: case DH_38: case DH_48:
+ case DH_58: case DH_68: case DH_78: case DH_88:
+ fp3d.fx = parent->GetSize(SIZE_XPOS + type - DH_18);
+ fp3d.fy = parent->GetSize(SIZE_YPOS + type - DH_18);
+ fp3d.fz = parent->GetSize(SIZE_ZPOS + type - DH_18);
+ is3D = true;
+ break;
+ default:
+ if(type >= DH_DATA) {
+ fx = parent->GetSize(SIZE_XPOS + type - DH_DATA);
+ fy = parent->GetSize(SIZE_YPOS + type - DH_DATA);
+ FillDef.color = (this == CurrHandle) ? 0x0L : 0x00ffffffL;
+ }
+ else return;
+ }
+ if(is3D) {
+ o->cvec2ivec(&fp3d, &ifp3d);
+ ix = iround(ifp3d.fx); iy = iround(ifp3d.fy);
+ }
+ else {
+ ix = o->co2ix(fx+dx); iy = o->co2iy(fy+dy);
+ }
+ SetMinMaxRect(&rDims, ix-4, iy-4, ix+4, iy+4);
+ memcpy(&upd, &rDims, sizeof(RECT));
+ switch(type) {
+ case DH_12: case DH_22: case DH_19: case DH_29: case DH_39:
+ case DH_49: case DH_69: case DH_79: case DH_89: case DH_99:
+ o->SetLine(&LineDef); o->SetFill(&FillDef);
+ o->oRectangle(rDims.left, rDims.top, rDims.right, rDims.bottom);
+ o->UpdateRect(&rDims, false);
+ break;
+ case DH_59:
+ o->SetLine(&LineDef); o->SetFill(&FillDef);
+ IncrementMinMaxRect(&rDims, 2);
+ o->oCircle(rDims.left, rDims.top, rDims.right, rDims.bottom);
+ IncrementMinMaxRect(&rDims, 1);
+ o->UpdateRect(&rDims, false);
+ break;
+ default:
+ if(type >= DH_DATA) {
+ o->SetLine(&LineDef); o->SetFill(&FillDef);
+ o->oRectangle(rDims.left, rDims.top, rDims.right, rDims.bottom);
+ o->UpdateRect(&rDims, false);
+ }
+ else {
+ IncrementMinMaxRect(&rDims, -1);
+ o->UpdateRect(&rDims, true);
+ }
+ break;
+ }
+}
+
+bool
+dragHandle::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ lfPOINT pos;
+ int idx;
+
+ if(!parent) return false;
+ switch (cmd) {
+ case CMD_MOUSECURSOR:
+ if(o) switch(type) {
+ case DH_19: case DH_99:
+ o->MouseCursor(MC_SE, false); break;
+ case DH_29: case DH_89:
+ o->MouseCursor(MC_NORTH, false); break;
+ case DH_39: case DH_79:
+ o->MouseCursor(MC_NE, false); break;
+ case DH_49: case DH_69:
+ o->MouseCursor(MC_EAST, false); break;
+ default:
+ if(type >= DH_DATA) o->MouseCursor(MC_SALL, false);
+ else o->MouseCursor(MC_MOVE, false); break;
+ }
+ return true;
+ case CMD_MINRC:
+ if(!(minRC)) minRC = (RECT*)calloc(1, sizeof(RECT));
+ if(tmpl && minRC) SetMinMaxRect(minRC, ((RECT*)tmpl)->left, ((RECT*)tmpl)->top,
+ ((RECT*)tmpl)->right, ((RECT*)tmpl)->bottom);
+ return true;
+ case CMD_MAXRC:
+ if(!(maxRC)) maxRC = (RECT*)calloc(1, sizeof(RECT));
+ if(tmpl && maxRC) SetMinMaxRect(maxRC, ((RECT*)tmpl)->left, ((RECT*)tmpl)->top,
+ ((RECT*)tmpl)->right, ((RECT*)tmpl)->bottom);
+ return true;
+ case CMD_MOVE:
+ idx = type >= DH_DATA ? type - DH_DATA : 0;
+ pos.fx = NiceValue(((lfPOINT*)tmpl)[0].fx);
+ pos.fy = NiceValue(((lfPOINT*)tmpl)[0].fy);
+ if(pos.fx == 0.0 && pos.fy == 0.0) return false;
+ parent->Command(CMD_SAVEPOS, &idx, o);
+ switch(type) {
+ case DH_12:
+ parent->SetSize(SIZE_XPOS, pos.fx + parent->GetSize(SIZE_XPOS));
+ parent->SetSize(SIZE_YPOS, pos.fy + parent->GetSize(SIZE_YPOS));
+ break;
+ case DH_22:
+ parent->SetSize(SIZE_XPOS+1, pos.fx + parent->GetSize(SIZE_XPOS+1));
+ parent->SetSize(SIZE_YPOS+1, pos.fy + parent->GetSize(SIZE_YPOS+1));
+ break;
+ case DH_19: parent->parent->SetSize(SIZE_XPOS,
+ pos.fx + parent->GetSize(SIZE_XPOS));
+ case DH_29: parent->parent->SetSize(SIZE_YPOS,
+ pos.fy + parent->GetSize(SIZE_YPOS));
+ break;
+ case DH_39: parent->parent->SetSize(SIZE_YPOS,
+ pos.fy + parent->GetSize(SIZE_YPOS));
+ case DH_69: parent->parent->SetSize(SIZE_XPOS+1,
+ pos.fx + parent->GetSize(SIZE_XPOS+1));
+ break;
+ case DH_99: parent->parent->SetSize(SIZE_XPOS+1,
+ pos.fx + parent->GetSize(SIZE_XPOS+1));
+ case DH_89: parent->parent->SetSize(SIZE_YPOS+1,
+ pos.fy + parent->GetSize(SIZE_YPOS+1));
+ break;
+ case DH_79: parent->parent->SetSize(SIZE_YPOS+1,
+ pos.fy + parent->GetSize(SIZE_YPOS+1));
+ case DH_49:
+ parent->parent->SetSize(SIZE_XPOS,
+ pos.fx + parent->GetSize(SIZE_XPOS));
+ break;
+ case DH_18: case DH_28: case DH_38: case DH_48:
+ case DH_58: case DH_68: case DH_78: case DH_88:
+ case DH_59:
+ return parent->parent->Command(cmd, tmpl, o);
+ default:
+ if (type >= DH_DATA) {
+ parent->SetSize(SIZE_XPOS + idx, pos.fx + parent->GetSize(SIZE_XPOS + idx));
+ parent->SetSize(SIZE_YPOS + idx, pos.fy + parent->GetSize(SIZE_YPOS + idx));
+ CurrGO = parent;
+ }
+ break;
+ }
+ return parent->Command(CMD_REDRAW, 0L, o);
+ break;
+ }
+ return false;
+}
+
+void *
+dragHandle::ObjThere(int x, int y)
+{
+ if(IsInRect(&rDims, x, y)) return (CurrHandle = this);
+ else return 0L;
+}
+
+
+void
+dragHandle::Track(POINT *p, anyOutput *o)
+{
+ POINT p1, p2, pts[5];
+ double dx, dy;
+ int npts=0, idx;
+ DWORD color;
+
+ if(!parent || !o) return;
+ Command(CMD_MOUSECURSOR, 0L, o);
+ if(upd.right < upd.left) Swap(upd.right, upd.left);
+ if(upd.bottom < upd.top) Swap(upd.bottom, upd.top);
+ dx = parent->GetSize(SIZE_GRECT_LEFT); dy = parent->GetSize(SIZE_GRECT_TOP);
+ IncrementMinMaxRect(&upd, 2);
+ o->UpdateRect(&upd, false);
+ if(type >= DH_19 && type <= DH_99) memcpy(&upd, &drec, sizeof(RECT));
+ color = parent->GetColor(COL_DATA_LINE);
+ switch(type) {
+ case DH_12:
+ case DH_22:
+ pts[0].x = o->co2ix(parent->GetSize(SIZE_XPOS)+dx);
+ pts[0].y = o->co2iy(parent->GetSize(SIZE_YPOS)+dy);
+ pts[1].x = o->co2ix(parent->GetSize(SIZE_XPOS+1)+dx);
+ pts[1].y = o->co2iy(parent->GetSize(SIZE_YPOS+1)+dy);
+ if(type == DH_12) {
+ pts[0].x += p->x; pts[0].y += p->y;
+ }
+ else if(type == DH_22) {
+ pts[1].x += p->x; pts[1].y += p->y;
+ }
+ UpdateMinMaxRect(&upd, pts[0].x, pts[0].y);
+ UpdateMinMaxRect(&upd, pts[1].x, pts[1].y);
+ npts = 2;
+ break;
+ case DH_19:
+ if(minRC && IsInRect(minRC, upd.left+p->x, (upd.top+upd.bottom)>>1))
+ upd.left = minRC->left;
+ else if(maxRC && !IsInRect(maxRC, upd.left+p->x, (upd.top+upd.bottom)>>1))
+ upd.left = upd.left+p->x >= maxRC->right ? maxRC->right : maxRC->left;
+ else upd.left += p->x;
+ case DH_29:
+ if(minRC && IsInRect(minRC, (upd.left + upd.right)>>1, upd.top+p->y))
+ upd.top = minRC->top;
+ else if(maxRC && !IsInRect(maxRC, (upd.left + upd.right)>>1, upd.top+p->y))
+ upd.top = upd.top +p->y >= maxRC->bottom? maxRC->bottom : maxRC->top;
+ else upd.top += p->y;
+ break;
+ case DH_39:
+ if(minRC && IsInRect(minRC, (upd.left + upd.right)>>1, upd.top+p->y))
+ upd.top = minRC->top;
+ else if(maxRC && !IsInRect(maxRC, (upd.left + upd.right)>>1, upd.top+p->y))
+ upd.top = upd.top+p->y >= maxRC->bottom ? maxRC->bottom : maxRC->top;
+ else upd.top += p->y;
+ case DH_69:
+ if(minRC && IsInRect(minRC, upd.right+p->x, (upd.top+upd.bottom)>>1))
+ upd.right = minRC->right;
+ else if(maxRC && !IsInRect(maxRC, upd.right+p->x, (upd.top+upd.bottom)>>1))
+ upd.right = upd.right+p->x <= maxRC->left ? maxRC->left : maxRC->right;
+ else upd.right += p->x;
+ break;
+ case DH_99:
+ if(minRC && IsInRect(minRC, upd.right+p->x, (upd.top+upd.bottom)>>1))
+ upd.right = minRC->right;
+ else if(maxRC && !IsInRect(maxRC, upd.right+p->x, (upd.top+upd.bottom)>>1))
+ upd.right = upd.right+p->x <= maxRC->left ? maxRC->left : maxRC->right;
+ else upd.right += p->x;
+ case DH_89:
+ if(minRC && IsInRect(minRC, (upd.left + upd.right)>>1, upd.bottom+p->y))
+ upd.bottom = minRC->bottom;
+ else if(maxRC && !IsInRect(maxRC, (upd.left + upd.right)>>1, upd.bottom+p->y))
+ upd.bottom = upd.bottom+p->y <= maxRC->top? maxRC->top : maxRC->bottom;
+ else upd.bottom += p->y;
+ break;
+ case DH_79:
+ if(minRC && IsInRect(minRC, (upd.left + upd.right)>>1, upd.bottom+p->y))
+ upd.bottom = minRC->bottom;
+ else if(maxRC && !IsInRect(maxRC, (upd.left + upd.right)>>1, upd.bottom+p->y))
+ upd.bottom = upd.bottom+p->y <= maxRC->top? maxRC->top : maxRC->bottom;
+ else upd.bottom += p->y;
+ case DH_49:
+ if(minRC && IsInRect(minRC, upd.left+p->x, (upd.top+upd.bottom)>>1))
+ upd.left = minRC->left;
+ else if(maxRC && !IsInRect(maxRC, upd.left+p->x, (upd.top+upd.bottom)>>1))
+ upd.left = upd.left+p->x >= maxRC->right ? maxRC->right : maxRC->left;
+ else upd.left += p->x;
+ break;
+ case DH_18: case DH_28: case DH_38: case DH_48:
+ case DH_58: case DH_68: case DH_78: case DH_88:
+ CurrGO = this;
+ case DH_59:
+ parent->parent->Track(p, o);
+ return;
+ default:
+ if(type >= DH_DATA) {
+ idx = type - DH_DATA;
+ pts[1].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx)+dx);
+ pts[1].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx)+dy);
+ pts[1].x += p->x; pts[1].y += p->y;
+ if(type > DH_DATA) {
+ pts[0].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx -1)+dx);
+ pts[0].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx -1)+dy);
+ }
+ else {
+ pts[0].x = pts[1].x; pts[0].y = pts[1].y;
+ }
+ pts[2].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx +1)+dx);
+ pts[2].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx +1)+dy);
+ UpdateMinMaxRect(&upd, pts[0].x, pts[0].y);
+ UpdateMinMaxRect(&upd, pts[1].x, pts[1].y);
+ UpdateMinMaxRect(&upd, pts[2].x, pts[2].y);
+ npts = 3;
+ if(color == 0x0L || color == 0x00ffffffL) color = 0x00c0c0c0L;
+ }
+ else return;
+ }
+ if(type >= DH_19 && type <= DH_99) {
+ pts[0].x = pts[4].x = pts[3].x = p1.x = upd.left;
+ pts[0].y = pts[1].y = pts[4].y = p1.y = upd.top;
+ pts[1].x = pts[2].x = p2.x = upd.right;
+ pts[2].y = pts[3].y = p2.y = upd.bottom;
+ npts = 5;
+ if(parent->parent->Id == GO_ELLIPSE) o->ShowEllipse(p1, p2, color);
+ }
+ o->ShowLine(pts, npts, color);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// the dragRect object uses nine dragHandles to create a user interface
+// for modification of rectangular shapes
+dragRect::dragRect(GraphObj *par, int which):GraphObj(par, 0L)
+{
+ int i;
+
+ type = which;
+ Id = GO_DRAGRECT;
+ if(handles = (dragHandle**)calloc(9, sizeof(dragHandle*)))
+ for(i = 0; i < 9; i++){
+ if(i == 4 && type == 0) handles[i] = new dragHandle(this, DH_19 + i);
+ else if(i != 4) handles[i] = new dragHandle(this, DH_19 + i);
+ }
+}
+
+dragRect::~dragRect()
+{
+ int i;
+
+ if(handles) for(i = 0; i < 9; i++) if(handles[i]) DeleteGO(handles[i]);
+}
+
+void
+dragRect::DoPlot(anyOutput *o)
+{
+ int i;
+
+ if(handles) for(i = 0; i < 9; i++) if(handles[i]) handles[i]->DoPlot(o);
+}
+
+bool
+dragRect::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i;
+
+ if(!parent) return false;
+ switch (cmd) {
+ case CMD_MINRC:
+ case CMD_MAXRC:
+ if(handles) for(i = 0; i < 9; i++) {
+ if(handles[i]) handles[i]->Command(cmd, tmpl, o);
+ }
+ break;
+ case CMD_SAVEPOS:
+ case CMD_REDRAW:
+ return parent->Command(cmd, tmpl, o);
+ }
+ return false;
+}
+
+void *
+dragRect::ObjThere(int x, int y)
+{
+ int i;
+ void *go;
+
+ if(handles) for(i = 0; i < 9; i++)
+ if(handles[i] && (go = (handles[i])->ObjThere(x, y))) return go;
+ return 0L;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// implement some kind of virtual trackball for 3D plots
+Drag3D::Drag3D(GraphObj *par):GraphObj(par, 0L)
+{
+ int i;
+
+ Id = GO_DRAG3D;
+ if(handles = (dragHandle**)calloc(8, sizeof(dragHandle*)))
+ for(i = 0; i < 8; i++){
+ handles[i] = new dragHandle(this, DH_18 + i);
+ }
+}
+
+Drag3D::~Drag3D()
+{
+ int i;
+
+ if(handles) for(i = 0; i < 8; i++) if(handles[i]) DeleteGO(handles[i]);
+}
+
+void
+Drag3D::DoPlot(anyOutput *o)
+{
+ int i;
+
+ if(handles) for(i = 0; i < 8; i++) if(handles[i]) handles[i]->DoPlot(o);
+}
+
+void *
+Drag3D::ObjThere(int x, int y)
+{
+ int i;
+ void *go;
+
+ if(handles) for(i = 0; i < 8; i++)
+ if(handles[i] && (go = (handles[i])->ObjThere(x, y))) return go;
+ return 0L;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// frame rectangle
+FrmRect::FrmRect(GraphObj *par, fRECT *lim, fRECT *c, fRECT *chld):GraphObj(par, 0L)
+{
+ parent = par;
+ limRC = lim; cRC = c; chldRC = chld;
+ drag = 0L; mo = 0L;
+ Id = GO_FRAMERECT;
+ moveable = true;
+ Fill.type = FILL_NONE;
+ Line.color = FillLine.color = Fill.color = 0x00ffffffL;
+ Line.width = FillLine.width = 0.0;
+ Line.patlength = FillLine.patlength = Fill.scale = 1.0;
+ Line.pattern = FillLine.pattern = 0x0L;
+ Fill.hatch = &FillLine;
+ minRC = maxRC = 0L;
+}
+
+FrmRect::~FrmRect()
+{
+ if(drag) DeleteGO(drag); drag = 0L;
+ if(minRC) free(minRC); minRC = 0L;
+ if(maxRC) free(maxRC); maxRC = 0L;
+ if(mo) DelBitmapClass(mo); mo = 0L;
+}
+
+double
+FrmRect::GetSize(int select)
+{
+ switch(select) {
+ case SIZE_XPOS: return CurrRect.Xmin;
+ case SIZE_XPOS+1: return CurrRect.Xmax;
+ case SIZE_YPOS: return CurrRect.Ymin;
+ case SIZE_YPOS+1: return CurrRect.Ymax;
+ }
+ return 0.0;
+}
+
+bool
+FrmRect::SetSize(int select, double value)
+{
+ double tmp, o_left, o_top;
+
+ o_left = cRC->Xmin; o_top = cRC->Ymin;
+ switch (select & 0xfff) {
+ case SIZE_XPOS:
+ if(limRC) value -= limRC->Xmin;
+ if(swapX) cRC->Xmax = value;
+ else cRC->Xmin = value;
+ break;
+ case SIZE_XPOS+1:
+ if(limRC) value -= limRC->Xmin;
+ if(swapX) cRC->Xmin = value;
+ else cRC->Xmax = value;
+ break;
+ case SIZE_YPOS:
+ if(limRC) value -= limRC->Ymin;
+ if(swapY) cRC->Ymin = value;
+ else cRC->Ymax = value;
+ break;
+ case SIZE_YPOS+1:
+ if(limRC) value -= limRC->Ymin;
+ if(swapY) cRC->Ymax = value;
+ else cRC->Ymin = value;
+ break;
+ default: return false;
+ }
+ if((swapX && cRC->Xmin < cRC->Xmax) || (!swapX && cRC->Xmin > cRC->Xmax)) {
+ tmp = cRC->Xmin; cRC->Xmin = cRC->Xmax; cRC->Xmax = tmp;
+ }
+ if((swapY && cRC->Ymin > cRC->Ymax) || (!swapY && cRC->Ymin < cRC->Ymax)) {
+ tmp = cRC->Ymin; cRC->Ymin = cRC->Ymax; cRC->Ymax = tmp;
+ }
+ if(chldRC) { //check if new rectangle is not inside child rectangle
+ if(cRC->Xmin > o_left+ chldRC->Xmin) cRC->Xmin = o_left + chldRC->Xmin;
+ if(cRC->Xmax < o_left+ chldRC->Xmax) cRC->Xmax = o_left + chldRC->Xmax;
+ if(cRC->Ymin > o_top+ chldRC->Ymin) cRC->Ymin = o_top + chldRC->Ymin;
+ if(cRC->Ymax < o_top+ chldRC->Ymax) cRC->Ymax = o_top + chldRC->Ymax;
+ }
+ if(chldRC && (o_left != cRC->Xmin || o_top != cRC->Ymin)) {
+ chldRC->Xmin -= (tmp = cRC->Xmin - o_left); chldRC->Xmax -= tmp;
+ chldRC->Ymin -= (tmp = cRC->Ymin - o_top); chldRC->Ymax -= tmp;
+ }
+ return true;
+}
+
+bool
+FrmRect::SetColor(int select, DWORD col)
+{
+ switch(select & 0xfff){
+ case COL_DRECT:
+ Line.color = col;
+ case COL_BG:
+ Fill.color = col; return true;
+ case COL_GRECT:
+ Fill.color = col; return true;
+ case COL_GRECTLINE:
+ Line.color = col; return true;
+ }
+ return false;
+}
+
+void
+FrmRect::DoMark(anyOutput *o, bool mark)
+{
+ if(!parent || !o) return;
+ if(!drag && (drag = new dragRect(this, (!limRC && parent->moveable) ? 0 : 1))){
+ if(minRC) drag->Command(CMD_MINRC, minRC, o);
+ if(maxRC) drag->Command(CMD_MAXRC, maxRC, o);
+ }
+ if(mark && drag){
+ memcpy(&mrc, &rDims, sizeof(RECT));
+ IncrementMinMaxRect(&mrc, 6);
+ mo = GetRectBitmap(&mrc, o);
+ drag->DoPlot(o);
+ o->UpdateRect(&mrc, false);
+ }
+ else RestoreRectBitmap(&mo, &mrc, o);
+}
+
+void
+FrmRect::DoPlot(anyOutput *o)
+{
+ int x1, y1, x2, y2;
+ double tmp;
+
+ if(!(cRC) || !o) return;
+ o->dFillCol = Fill.color ^ 0x00ffffff; //force new brush
+ o->dLineCol = Line.color ^ 0x00ffffff; //force new pen
+ o->SetLine(&Line); o->SetFill(&Fill);
+ CurrRect.Xmin = cRC->Xmin; CurrRect.Xmax = cRC->Xmax;
+ CurrRect.Ymin = cRC->Ymax; CurrRect.Ymax = cRC->Ymin;
+ if(limRC) {
+ CurrRect.Xmin += limRC->Xmin; CurrRect.Xmax += limRC->Xmin;
+ CurrRect.Ymin += limRC->Ymin; CurrRect.Ymax += limRC->Ymin;
+ }
+ if(swapX = (CurrRect.Xmin > CurrRect.Xmax)) {
+ tmp = CurrRect.Xmin; CurrRect.Xmin = CurrRect.Xmax; CurrRect.Xmax = tmp;
+ }
+ if(swapY = (CurrRect.Ymin > CurrRect.Ymax)) {
+ tmp = CurrRect.Ymin; CurrRect.Ymin = CurrRect.Ymax; CurrRect.Ymax = tmp;
+ }
+ o->oRectangle(x1 = o->co2ix(CurrRect.Xmin), y1 = o->co2iy(CurrRect.Ymin),
+ x2 = o->co2ix(CurrRect.Xmax), y2 = o->co2iy(CurrRect.Ymax));
+ SetMinMaxRect(&rDims, x1, y1, x2, y2);
+}
+
+bool
+FrmRect::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+
+ if(!parent) return false;
+ switch (cmd) {
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(IsInRect(&rDims, mev->x, mev->y) && !(CurrGO) && (o)){
+ o->ShowMark(this, MRK_GODRAW);
+ if(parent && parent->Id == GO_GRAPH) CurrGraph = (Graph*)parent;
+ return true;
+ }
+ }
+ return false;
+ case CMD_MINRC:
+ if(!(minRC)) minRC = (RECT*)calloc(1, sizeof(RECT));
+ if(minRC && tmpl) SetMinMaxRect(minRC, ((RECT*)tmpl)->left, ((RECT*)tmpl)->top,
+ ((RECT*)tmpl)->right, ((RECT*)tmpl)->bottom);
+ if(drag) drag->Command(cmd, tmpl, o);
+ return true;
+ case CMD_MAXRC:
+ if(!(maxRC)) maxRC = (RECT*)calloc(1, sizeof(RECT));
+ if(maxRC && tmpl) SetMinMaxRect(maxRC, ((RECT*)tmpl)->left, ((RECT*)tmpl)->top,
+ ((RECT*)tmpl)->right, ((RECT*)tmpl)->bottom);
+ if(drag) drag->Command(cmd, tmpl, o);
+ return true;
+ case CMD_MOVE:
+ cRC->Xmin += NiceValue(((lfPOINT*)tmpl)[0].fx);
+ cRC->Ymin += NiceValue(((lfPOINT*)tmpl)[0].fy);
+ cRC->Xmax += NiceValue(((lfPOINT*)tmpl)[0].fx);
+ cRC->Ymax += NiceValue(((lfPOINT*)tmpl)[0].fy);
+ case CMD_REDRAW:
+ return parent->Command(CMD_REDRAW, 0L, o);
+ case CMD_SAVEPOS:
+ return parent->Command(cmd, tmpl, o);
+ case CMD_SETCHILD:
+ chldRC = (fRECT*)tmpl;
+ return true;
+ }
+ return false;
+}
+
+void *
+FrmRect::ObjThere(int x, int y)
+{
+ if(drag) return drag->ObjThere(x, y);
+ return 0L;
+}
+
+void
+FrmRect::Track(POINT *p, anyOutput *o)
+{
+ POINT tpts[5];
+ RECT old_rc;
+
+ if(o){
+ memcpy(&old_rc, &rDims, sizeof(rDims));
+ o->UpdateRect(&rDims, false);
+ tpts[0].x = tpts[1].x = tpts[4].x = o->co2ix(cRC->Xmin)+p->x;
+ tpts[0].y = tpts[3].y = tpts[4].y = o->co2iy(cRC->Ymin)+p->y;
+ tpts[1].y = tpts[2].y = o->co2iy(cRC->Ymax)+p->y;
+ tpts[2].x = tpts[3].x = o->co2ix(cRC->Xmax)+p->x;
+ UpdateMinMaxRect(&rDims, tpts[0].x, tpts[0].y);
+ UpdateMinMaxRect(&rDims, tpts[2].x, tpts[2].y);
+ if(old_rc.left != rDims.left || old_rc.right != rDims.right || old_rc.top !=
+ rDims.top || old_rc.bottom != rDims.bottom)IncrementMinMaxRect(&rDims, 3);
+ o->ShowLine(tpts, 5, Fill.color ^ 0x00ffffffL);
+ }
+
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// This is a special object to read certain svg-settings from a *.rlp file
+svgOptions::svgOptions(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(defs.svgScript) free(defs.svgScript);
+ if(defs.svgAttr) free(defs.svgAttr);
+ defs.svgScript = defs.svgAttr = 0L;
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ if(script) defs.svgScript = script;
+ if(svgattr) defs.svgAttr = svgattr;
+ script = svgattr = 0L;
+ }
+ Id=GO_SVGOPTIONS;
+}
+
+svgOptions::~svgOptions()
+{
+ if(script)free(script);
+ script = 0L;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Symbols are graphic objects
+Symbol::Symbol(GraphObj *par, DataObj *d, double x, double y, int which,
+ int xc, int xr, int yc, int yr):GraphObj(par, d)
+{
+ //Symbols with no parent are part of a dialog
+ FileIO(INIT_VARS);
+ fPos.fx = x;
+ fPos.fy = y;
+ type = which;
+ Id = GO_SYMBOL;
+ if(xc >= 0 && xr >= 0 && yc >= 0 && yr >= 0) {
+ if(ssRef = (POINT*)malloc(sizeof(POINT)*2)) {
+ ssRef[0].x = xc; ssRef[0].y = xr;
+ ssRef[1].x = yc; ssRef[1].y = yr;
+ cssRef = 2;
+ }
+ }
+}
+
+Symbol::Symbol(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ SymFill.hatch = (LineDEF *) NULL;
+ }
+}
+
+Symbol::~Symbol()
+{
+ Command(CMD_FLUSH, 0L, 0L);
+}
+
+double
+Symbol::GetSize(int select)
+{
+ switch(select) {
+ case SIZE_MINE:
+ case SIZE_SYMBOL:
+ return size;
+ case SIZE_SYM_LINE:
+ return SymLine.width;
+ case SIZE_XPOS:
+ return fPos.fx;
+ case SIZE_YPOS:
+ return fPos.fy;
+ default:
+ return parent ? parent->GetSize(select) : defs.GetSize(select);
+ }
+}
+
+bool
+Symbol::SetSize(int select, double value)
+{
+ switch(select & 0xfff){
+ case SIZE_MINE:
+ case SIZE_SYMBOL:
+ size = value;
+ return true;
+ case SIZE_SYM_LINE:
+ SymLine.width = value;
+ return true;
+ case SIZE_XPOS:
+ fPos.fx = value;
+ return true;
+ case SIZE_YPOS:
+ fPos.fy = value;
+ return true;
+ }
+ return false;
+}
+
+DWORD
+Symbol::GetColor(int select)
+{
+ switch(select) {
+ case COL_SYM_LINE:
+ return SymLine.color;
+ case COL_SYM_FILL:
+ return SymFill.color;
+ default:
+ return parent ? parent->GetColor(select) : defs.Color(select);
+ }
+}
+
+bool
+Symbol::SetColor(int select, DWORD col)
+{
+ switch(select & 0xfff) {
+ case COL_SYM_LINE:
+ SymLine.color = col;
+ if(SymTxt) SymTxt->ColTxt = col;
+ return true;
+ case COL_SYM_FILL:
+ SymFill.color = col;
+ return true;
+ default:
+ return false;
+ }
+}
+
+void
+Symbol::DoPlot(anyOutput *target)
+{
+ int ix, iy, rx, ry, atype;
+ lfPOINT fip;
+ POINT pts[5];
+ FillDEF cf;
+
+ if(size <= 0.001) return;
+ atype = (type & 0xfff);
+ memcpy(&cf, &SymFill, sizeof(FillDEF));
+ if(atype == SYM_CIRCLEF || atype == SYM_RECTF || atype == SYM_TRIAUF ||
+ atype == SYM_TRIADF || atype == SYM_DIAMONDF) cf.color = SymLine.color;
+ if(type & SYM_POS_PARENT) {
+ if(!parent) return;
+ fip.fx = parent->GetSize(SIZE_XCENTER);
+ fip.fy = parent->GetSize(SIZE_YCENTER);
+ }
+ else if(!target->fp2fip(&fPos, &fip)) return;
+ ix = iround(fip.fx); iy = iround(fip.fy);
+ target->SetLine(&SymLine);
+ switch(atype){
+ default:
+ case SYM_CIRCLE: //circle
+ case SYM_CIRCLEF: //filled circle
+ rx = target->un2ix(size/2.0); ry = target->un2iy(size/2.0);
+ target->SetFill(&cf);
+ target->oCircle(ix-rx, iy-ry, ix+rx+1, iy+ry+1, name);
+ rx--;ry--; //smaller marking rectangle
+ break;
+ case SYM_RECT: //rectange (square)
+ case SYM_RECTF: //filled rectangle
+ rx = target->un2ix(size/2.25676);
+ ry = target->un2iy(size/2.25676);
+ target->SetFill(&cf);
+ target->oRectangle(ix-rx, iy-ry, ix+rx+1, iy+ry+1, name);
+ break;
+ case SYM_TRIAU: //triangles up and down, open or closed
+ case SYM_TRIAUF:
+ case SYM_TRIAD:
+ case SYM_TRIADF:
+ rx = target->un2ix(size/1.48503);
+ ry = target->un2iy(size/1.48503);
+ target->SetFill(&cf);
+ pts[0].x = pts[3].x = ix - rx; pts[1].x = ix; pts[2].x = ix+rx;
+ if(type == SYM_TRIAU || type == SYM_TRIAUF) {
+ pts[0].y = pts[2].y = pts[3].y = iy+target->un2iy(size*0.38878f);
+ pts[1].y = iy-target->un2iy(size*0.77756f);
+ }
+ else {
+ pts[0].y = pts[2].y = pts[3].y = iy-target->un2iy(size*0.38878f);
+ pts[1].y = iy+target->un2iy(size*0.77756f);
+ }
+ target->oPolygon(pts, 4);
+ rx--; ry--;
+ break;
+ case SYM_DIAMOND:
+ case SYM_DIAMONDF:
+ rx = target->un2ix(size/1.59588f);
+ ry = target->un2iy(size/1.59588f);
+ target->SetFill(&cf);
+ pts[0].x = pts[2].x = pts[4].x = ix;
+ pts[0].y = pts[4].y = iy -ry;
+ pts[1].x = ix +rx; pts[1].y = pts[3].y = iy;
+ pts[2].y = iy +ry; pts[3].x = ix-rx;
+ target->oPolygon(pts, 5);
+ rx--; ry--;
+ break;
+ case SYM_STAR: //star is a combination of + and x symbols
+ case SYM_PLUS: //draw a + sign
+ case SYM_HLINE:
+ case SYM_VLINE:
+ rx = target->un2ix(size/2.0f);
+ ry = target->un2iy(size/2.0f);
+ pts[0].x = pts[1].x = ix;
+ pts[0].y = iy - ry; pts[1].y = iy + ry +1;
+ if(type != SYM_HLINE) target->oPolyline(pts, 2);
+ pts[0].x = ix -rx; pts[1].x = ix + rx +1;
+ pts[0].y = pts[1].y = iy;
+ if(type != SYM_VLINE) target->oPolyline(pts, 2);
+ if(type == SYM_VLINE){ rx = 2; break;}
+ if(type == SYM_HLINE){ ry = 2; break;}
+ if(type == SYM_PLUS) break; //continue with x symbol for star
+ case SYM_CROSS: //draw a x symbol
+ rx = target->un2ix(size/2.5);
+ ry = target->un2iy(size/2.5);
+ pts[0].x = ix - rx; pts[1].x = ix + rx;
+ pts[0].y = iy - ry; pts[1].y = iy + ry;
+ target->oPolyline(pts, 2);
+ Swap(pts[0].y, pts[1].y);
+ target->oPolyline(pts, 2);
+ break;
+ case SYM_TEXT:
+ if(!SymTxt) Command(CMD_SETTEXT, (void *)"text", target);
+ if(!SymTxt || !SymTxt->text || !SymTxt->text[0])return;
+ SymTxt->iSize = target->un2iy(SymTxt->fSize = size *1.5);
+ target->SetTextSpec(SymTxt);
+ fmtText(target, ix, iy, SymTxt->text);
+ if (target->oGetTextExtent(SymTxt->text, 0, &rx, &ry)){
+ rx >>= 1; ry >>= 1;
+ }
+ else rx = ry = 10;
+ }
+ rDims.left = ix-rx-1; rDims.right = ix+rx+1;
+ rDims.top = iy-ry-1; rDims.bottom = iy+ry+1;
+}
+
+bool
+Symbol::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ char *tmptxt;
+ AccRange *ac;
+ int i, r, c;
+
+ switch (cmd) {
+ case CMD_FLUSH:
+ if(SymTxt) {
+ if(SymTxt->text) free(SymTxt->text);
+ free(SymTxt);
+ }
+ if(ssRef) free(ssRef); ssRef = 0L;
+ if(name)free(name); name = 0L;
+ return true;
+ case CMD_REDRAW:
+ //if we come here its most likely the result of Undo
+ if(parent && parent->Id==GO_REGRESSION)
+ return parent->Command(CMD_MRK_DIRTY, 0L, o);
+ return false;
+ case CMD_GETTEXT:
+ if(SymTxt && SymTxt->text && tmpl) {
+ strcpy((char*)tmpl, SymTxt->text);
+ return true;
+ }
+ return false;
+ case CMD_SYMTEXT_UNDO:
+ if(SymTxt && SymTxt->text){
+ Undo.String(this, &SymTxt->text, UNDO_CONTINUE);
+ if(tmpl) {
+ if(SymTxt->text = (char*)realloc(SymTxt->text, strlen((char*)tmpl))+2)
+ strcpy(SymTxt->text, (char*)tmpl);
+ }
+ else if(SymTxt->text) SymTxt->text[0] = 0;
+ return true;
+ }
+ //fall through if its new
+ case CMD_SYMTEXT: case CMD_SETTEXT:
+ if(!SymTxt && (SymTxt = (TextDEF *) calloc(1, sizeof(TextDEF)))) {
+ SymTxt->ColTxt = SymLine.color;
+ SymTxt->fSize = size*1.5;
+ SymTxt->ColBg = parent ? parent->GetColor(COL_BG) : 0x00ffffffL;
+ SymTxt->Align = TXA_VCENTER | TXA_HCENTER;
+ SymTxt->Style = TXS_NORMAL;
+ SymTxt->Mode = TXM_TRANSPARENT;
+ SymTxt->Font = FONT_HELVETICA;
+ SymTxt->text = 0L;
+ }
+ if(!SymTxt) return false;
+ if(tmpl) {
+ if(SymTxt->text = (char*)realloc(SymTxt->text, strlen((char*)tmpl)+1))
+ strcpy(SymTxt->text, (char*)tmpl);
+ }
+ else if(SymTxt->text) SymTxt->text[0] = 0;
+ return true;
+ case CMD_SYM_TYPE:
+ if(tmpl)type = *((int*)tmpl);
+ return true;
+ case CMD_GETTEXTDEF:
+ if(!SymTxt || !tmpl) return false;
+ memcpy(tmpl, SymTxt, sizeof(TextDEF));
+ return true;
+ case CMD_SYMTEXTDEF:
+ case CMD_SETTEXTDEF:
+ if(!tmpl)return false;
+ if(SymTxt) tmptxt = SymTxt->text;
+ else tmptxt = 0L;
+ if(!SymTxt && !(SymTxt = (TextDEF *) calloc(1, sizeof(TextDEF)))) return false;
+ memcpy(SymTxt, tmpl, sizeof(TextDEF));
+ SymTxt->text = tmptxt;
+ return true;
+ case CMD_SYM_RANGETEXT:
+ case CMD_RANGETEXT:
+ if(!data || !tmpl) return false;
+ if(!(tmptxt = (char*)malloc(500)))return false;
+ if((ac = new AccRange((char*)tmpl)) && ac->GetFirst(&c, &r)) {
+ for(i = 0; i <= idx; i++) ac->GetNext(&c, &r);
+ data->GetText(r, c, tmptxt, 500);
+ delete(ac);
+ }
+ Command(CMD_SETTEXT, tmptxt, 0L);
+ free(tmptxt);
+ return true;
+ case CMD_SET_DATAOBJ:
+ Id = GO_SYMBOL;
+ data = (DataObj *)tmpl;
+ return true;
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
+ o->ShowMark(&rDims, MRK_INVERT);
+ CurrGO = this;
+ return true;
+ }
+ break;
+ }
+ break;
+ case CMD_UPDATE:
+ if(ssRef && cssRef >1 && data) {
+ data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
+ data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
+ return true;
+ }
+ return false;
+ case CMD_AUTOSCALE:
+ if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+ ((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Bubbles are graphic objects
+Bubble::Bubble(GraphObj *par, DataObj *d, double x, double y, double s, int which,
+ FillDEF *fill, LineDEF *outline, int xc, int xr, int yc, int yr, int sc,
+ int sr):GraphObj(par, d)
+{
+ FileIO(INIT_VARS);
+ fPos.fx = x; fPos.fy = y; fs = s;
+ type = which;
+ if(fill) {
+ memcpy(&BubbleFill,fill, sizeof(FillDEF));
+ if(BubbleFill.hatch) memcpy(&BubbleFillLine, BubbleFill.hatch, sizeof(LineDEF));
+ }
+ BubbleFill.hatch = &BubbleFillLine;
+ if(outline)memcpy(&BubbleLine, outline, sizeof(LineDEF));
+ Id = GO_BUBBLE;
+ if(xc >= 0 || xr >= 0 || yc >= 0 || yr >= 0 || sc >= 0 || sr >= 0) {
+ if(ssRef = (POINT*)malloc(sizeof(POINT)*3)) {
+ ssRef[0].x = xc; ssRef[0].y = xr;
+ ssRef[1].x = yc; ssRef[1].y = yr;
+ ssRef[2].x = sc; ssRef[2].y = sr;
+ cssRef = 3;
+ }
+ }
+}
+
+Bubble::Bubble(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+Bubble::~Bubble()
+{
+ Command(CMD_FLUSH, 0L, 0L);
+}
+
+void
+Bubble::DoPlot(anyOutput *o)
+{
+ int x1, y1, x2, y2, ix, iy, tmp;
+ double fix, fiy;
+
+ o->SetLine(&BubbleLine);
+ o->SetFill(&BubbleFill);
+ switch(type & 0x0f0) {
+ case BUBBLE_UNITS:
+ fix = o->un2fix(fs); fiy = o->un2fiy(fs);
+ break;
+ case BUBBLE_XAXIS:
+ fix = (o->fx2fix(fPos.fx+fs) - o->fx2fix(fPos.fx-fs))/2.0;
+ fiy = fix * (o->un2fiy(10.0f)/o->un2fix(10.0f)); //x and y resolution different ?
+ break;
+ case BUBBLE_YAXIS:
+ fix = (o->fy2fiy(fPos.fy-fs) - o->fy2fiy(fPos.fy+fs))/2.0;
+ fiy = fix * (o->un2fiy(10.0f)/o->un2fix(10.0f)); //x and y resolution different ?
+ break;
+ }
+ fix = fix < 0.0 ? -fix : fix; //sign must be positive
+ fiy = fiy < 0.0 ? -fiy : fiy;
+ rDims.left = rDims.right = iround(o->fx2fix(fPos.fx));
+ rDims.top = rDims.bottom = iround(o->fy2fiy(fPos.fy));
+ switch(type & 0x00f) {
+ case BUBBLE_CIRCLE:
+ ix = (int)(fix/2.0); iy = (int)(fiy/2.0);
+ tmp = iround(o->fx2fix(fPos.fx)); x1 = tmp - ix; x2 = tmp + ix;
+ tmp = iround(o->fy2fiy(fPos.fy)); y1 = tmp - iy; y2 = tmp + iy;
+ o->oCircle(x1, y1, x2, y2, name);
+ UpdateMinMaxRect(&rDims, x1, y1); UpdateMinMaxRect(&rDims, x2, y2);
+ break;
+ case BUBBLE_SQUARE:
+ if((type & 0xf00) == BUBBLE_CIRCUM) {
+ ix = iround(fix*.392699081); iy = iround(fiy*.392699081);
+ }
+ else if((type & 0xf00) == BUBBLE_AREA) {
+ ix = iround(fix*.443113462); iy = iround(fiy*.443113462);
+ }
+ else {
+ ix = iround(fix*.353553391); iy = iround(fiy*.353553391);
+ }
+ tmp = iround(o->fx2fix(fPos.fx)); x1 = tmp - ix; x2 = tmp + ix;
+ tmp = iround(o->fy2fiy(fPos.fy)); y1 = tmp - iy; y2 = tmp + iy;
+ o->oRectangle(x1, y1, x2, y2, name);
+ UpdateMinMaxRect(&rDims, x1, y1); UpdateMinMaxRect(&rDims, x2, y2);
+ break;
+ case BUBBLE_UPTRIA:
+ case BUBBLE_DOWNTRIA:
+ if((type & 0xf00) == BUBBLE_CIRCUM) {
+ fix *= .523598775; fiy *= .523598775;
+ }
+ else if((type & 0xf00) == BUBBLE_AREA) {
+ fix *= .673386843; fiy *= .673386843;
+ }
+ else {
+ fix *=.433012702; fiy *= .433012702;
+ }
+ ix = iround(fix); iy = iround(fiy*.57735);
+ tmp = iround(o->fx2fix(fPos.fx));
+ pts[0].x = pts[3].x = tmp - ix; pts[1].x = tmp + ix; pts[2].x = tmp;
+ tmp = iround(o->fy2fiy(fPos.fy));
+ if((type & 0x00f) == BUBBLE_UPTRIA) {
+ pts[0].y = pts[1].y = pts[3].y = tmp + iy;
+ pts[2].y = tmp - iround(fiy*1.1547);
+ }
+ else {
+ pts[0].y = pts[1].y = pts[3].y = tmp - iy;
+ pts[2].y = tmp + iround(fiy*1.1547);
+ }
+ o->oPolygon(pts, 4);
+ UpdateMinMaxRect(&rDims, pts[0].x, pts[0].y);
+ UpdateMinMaxRect(&rDims, pts[1].x, pts[2].y);
+ break;
+ }
+}
+
+void
+Bubble::DoMark(anyOutput *o, bool mark)
+{
+ if(mark) {
+ BubbleFillLine.color ^= 0x00ffffffL;
+ BubbleFill.color ^= 0x00ffffffL;
+ DoPlot(o);
+ BubbleFill.color ^= 0x00ffffffL;
+ BubbleFillLine.color ^= 0x00ffffffL;
+ }
+ else {
+ if(parent) parent->DoPlot(o);
+ else DoPlot(o);
+ }
+ o->UpdateRect(&rDims, false);
+}
+
+bool
+Bubble::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ bool bSelected = false;
+ unsigned long n, s;
+ POINT p;
+
+ switch (cmd) {
+ case CMD_FLUSH:
+ if(ssRef) free(ssRef); ssRef = 0L;
+ if(name)free(name); name = 0L;
+ return true;
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(IsInRect(&rDims, p.x = mev->x, p.y = mev->y) && !CurrGO) {
+ switch(type & 0x00f) {
+ case BUBBLE_CIRCLE:
+ n = s = p.x - ((rDims.right+rDims.left)>>1);
+ s *= n;
+ n = p.y - ((rDims.bottom+rDims.top)>>1);
+ n = isqr(s += n*n) -2;
+ bSelected = ((unsigned)((rDims.right-rDims.left)>>1) > n);
+ break;
+ case BUBBLE_SQUARE:
+ bSelected = true;
+ break;
+ case BUBBLE_UPTRIA:
+ case BUBBLE_DOWNTRIA:
+ if(!(bSelected = IsInPolygon(&p, pts, 4)))
+ bSelected = IsCloseToPL(p, pts, 4);
+ break;
+ }
+ if(bSelected) o->ShowMark(this, MRK_GODRAW);
+ return bSelected;
+ }
+ break;
+ }
+ break;
+ case CMD_SET_DATAOBJ:
+ Id = GO_BUBBLE;
+ data = (DataObj*)tmpl;
+ return true;
+ case CMD_UPDATE:
+ if(ssRef && cssRef >2 && data) {
+ data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
+ data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
+ data->GetValue(ssRef[2].y, ssRef[2].x, &fs);
+ return true;
+ }
+ return false;
+ case CMD_BUBBLE_ATTRIB:
+ if(tmpl) {
+ type &= ~0xff0;
+ type |= (*((int*)tmpl) & 0xff0);
+ return true;
+ }
+ return false;
+ case CMD_BUBBLE_TYPE:
+ if(tmpl) {
+ type &= ~0x00f;
+ type |= (*((int*)tmpl) & 0x00f);
+ return true;
+ }
+ return false;
+ case CMD_BUBBLE_FILL:
+ if(tmpl) {
+ BubbleFill.type = ((FillDEF*)tmpl)->type;
+ BubbleFill.color = ((FillDEF*)tmpl)->color;
+ BubbleFill.scale = ((FillDEF*)tmpl)->scale;
+ if(((FillDEF*)tmpl)->hatch)
+ memcpy(&BubbleFillLine, ((FillDEF*)tmpl)->hatch, sizeof(LineDEF));
+ }
+ return true;
+ case CMD_BUBBLE_LINE:
+ if(tmpl) memcpy(&BubbleLine, tmpl, sizeof(LineDEF));
+ return true;
+ case CMD_AUTOSCALE:
+ if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+ ((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Bars are graphic objects
+Bar::Bar(GraphObj *par, DataObj *d, double x, double y, int which,int xc, int xr,
+ int yc, int yr):GraphObj(par, d)
+{
+ FileIO(INIT_VARS);
+ parent = par;
+ fPos.fx = x;
+ fPos.fy = y;
+ type = which;
+ if(type & BAR_RELWIDTH) size = 60.0;
+ data = d;
+ Id = GO_BAR;
+ if(xc >= 0 || xr >= 0 || yc >= 0 || yr >= 0) {
+ if(ssRef = (POINT*)malloc(sizeof(POINT)*2)) {
+ ssRef[0].x = xc; ssRef[0].y = xr;
+ ssRef[1].x = yc; ssRef[1].y = yr;
+ cssRef = 2;
+ }
+ }
+}
+
+Bar::Bar(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+Bar::~Bar()
+{
+ Command(CMD_FLUSH, 0L, 0L);
+}
+
+double
+Bar::GetSize(int select)
+{
+ switch(select){
+ case SIZE_XPOS: return fPos.fx;
+ case SIZE_YPOS: return fPos.fy;
+ }
+ return 0.0;
+}
+
+bool
+Bar::SetSize(int select, double value)
+{
+ switch(select & 0xfff) {
+ case SIZE_BAR:
+ size = value;
+ return true;
+ case SIZE_BAR_LINE:
+ BarLine.width = value;
+ return true;
+ case SIZE_XBASE:
+ BarBase.fx = value;
+ return true;
+ case SIZE_YBASE:
+ BarBase.fy = value;
+ return true;
+ }
+ return false;
+}
+
+bool
+Bar::SetColor(int select, DWORD col)
+{
+ switch(select & 0xfff) {
+ case COL_BAR_LINE:
+ BarLine.color = col;
+ return true;
+ case COL_BAR_FILL:
+ BarFill.color = col;
+ return true;
+ }
+ return false;
+}
+
+void
+Bar::DoPlot(anyOutput *target)
+{
+ int w;
+ double fBase, rsize;
+ POINT pts[2];
+
+ if(!parent || size <= 0.001) return;
+ target->SetLine(&BarLine);
+ target->SetFill(&BarFill);
+ switch(type & 0xff) {
+ case BAR_VERTU: case BAR_VERTT: case BAR_VERTB:
+ switch(type & 0xff) {
+ case BAR_VERTB:
+ fBase = parent->GetSize(SIZE_BOUNDS_BOTTOM);
+ break;
+ case BAR_VERTT:
+ fBase = parent->GetSize(SIZE_BOUNDS_TOP);
+ break;
+ case BAR_VERTU:
+ fBase = BarBase.fy;
+ break;
+ }
+ if(type & BAR_RELWIDTH) {
+ rsize = size * parent->GetSize(SIZE_BARMINX)/100.0;
+ pts[0].x = iround(target->fx2fix(fPos.fx - rsize/2.0));
+ pts[1].x = iround(target->fx2fix(fPos.fx + rsize/2.0));
+ }
+ else {
+ w = target->un2ix(size);
+ pts[0].x = iround(target->fx2fix(fPos.fx)) - (w>>1);
+ pts[1].x = pts[0].x + w;
+ }
+ if(type & BAR_CENTERED) {
+ pts[0].y = iround(target->fy2fiy(fBase - (fPos.fy - fBase)));
+ pts[1].y = iround(target->fy2fiy(fBase + (fPos.fy - fBase)));
+ }
+ else {
+ pts[0].y = iround(target->fy2fiy(fBase));
+ pts[1].y = iround(target->fy2fiy(fPos.fy));
+ }
+ break;
+ case BAR_HORU: case BAR_HORR: case BAR_HORL:
+ switch(type & 0xff) {
+ case BAR_HORL:
+ fBase = parent->GetSize(SIZE_BOUNDS_LEFT);
+ break;
+ case BAR_HORR:
+ fBase = parent->GetSize(SIZE_BOUNDS_RIGHT);
+ break;
+ case BAR_HORU:
+ fBase = BarBase.fx;
+ break;
+ }
+ if(type & BAR_RELWIDTH) {
+ rsize = size * parent->GetSize(SIZE_BARMINY)/100.0;
+ pts[0].y = iround(target->fy2fiy(fPos.fy - rsize/2.0));
+ pts[1].y = iround(target->fy2fiy(fPos.fy + rsize/2.0));
+ }
+ else {
+ w = target->un2iy(size);
+ pts[0].y = target->fy2iy(fPos.fy) - w/2;
+ pts[1].y = pts[0].y+w;
+ }
+ if(type & BAR_CENTERED) {
+ pts[0].x = target->fx2ix(fBase - (fPos.fx - fBase));
+ pts[1].x = target->fx2ix(fBase + (fPos.fx - fBase));
+ }
+ else {
+ pts[0].x = target->fx2ix(fBase);
+ pts[1].x = target->fx2ix(fPos.fx);
+ }
+ break;
+ default:
+ return;
+ }
+ if(pts[0].x == pts[1].x || pts[0].y == pts[1].y) {
+ target->oSolidLine(pts);
+ }
+ else target->oRectangle(pts[0].x, pts[0].y, pts[1].x, pts[1].y, name);
+ SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+}
+
+bool
+Bar::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ FillDEF *TmpFill;
+ lfPOINT bl;
+
+ switch (cmd) {
+ case CMD_FLUSH:
+ if(ssRef) free(ssRef); ssRef = 0L;
+ if(name)free(name); name = 0L;
+ return true;
+ case CMD_LEGEND:
+ if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+ ((Legend*)tmpl)->HasFill(&BarLine, &BarFill);
+ break;
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
+ o->ShowMark(&rDims, MRK_INVERT);
+ CurrGO = this;
+ return true;
+ }
+ break;
+ }
+ return false;
+ case CMD_BAR_FILL:
+ TmpFill = (FillDEF *)tmpl;
+ if(TmpFill) {
+ BarFill.type = TmpFill->type;
+ BarFill.color = TmpFill->color;
+ BarFill.scale = TmpFill->scale;
+ if(TmpFill->hatch) memcpy(&HatchLine, TmpFill->hatch, sizeof(LineDEF));
+ }
+ return true;
+ case CMD_BAR_TYPE:
+ if(tmpl) type = *((int*)tmpl);
+ return true;
+ case CMD_SET_DATAOBJ:
+ Id = GO_BAR;
+ data = (DataObj *)tmpl;
+ return true;
+ case CMD_UPDATE:
+ if(ssRef && cssRef >1 && data) {
+ data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
+ data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
+ return true;
+ }
+ return false;
+ case CMD_AUTOSCALE:
+ if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+ ((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);
+ switch(type & 0xff) {
+ case BAR_VERTU:
+ case BAR_VERTT:
+ case BAR_VERTB:
+ bl.fx = fPos.fx;
+ switch (type & 0xff) {
+ case BAR_VERTU:
+ bl.fy = BarBase.fy;
+ break;
+ case BAR_VERTT:
+ case BAR_VERTB:
+ bl.fy = 0.0f; //cannot resolve
+ break;
+ }
+ if(type & BAR_CENTERED) bl.fy -= fPos.fy;
+ break;
+ case BAR_HORU:
+ case BAR_HORR:
+ case BAR_HORL:
+ bl.fy = fPos.fy;
+ switch(type & 0xff) {
+ case BAR_HORU:
+ bl.fx = BarBase.fx;
+ case BAR_HORR:
+ case BAR_HORL:
+ bl.fx = 0.0f; //cannot resolve
+ }
+ if(type & BAR_CENTERED) bl.fx -= fPos.fx;
+ break;
+ }
+ ((Plot*)parent)->CheckBounds(bl.fx, bl.fy);
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Data line is a graphic object
+DataLine::DataLine(GraphObj *par, DataObj *d, char *xrange, char *yrange):GraphObj(par, d)
+{
+ FileIO(INIT_VARS);
+ Id = GO_DATALINE;
+ if(xrange)ssXref = strdup(xrange); if(yrange)ssYref = strdup(yrange);
+ SetValues();
+}
+
+DataLine::DataLine(GraphObj *par, DataObj *d, lfPOINT *val, long nval):GraphObj(par, d)
+{
+ FileIO(INIT_VARS);
+ Values = val; nPnt = nval; nPntSet = nPnt-1;
+ Id = GO_DATALINE;
+}
+
+DataLine::DataLine(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+DataLine::~DataLine()
+{
+ if(Values)free(Values); Values = 0L;
+ if(pts) free(pts); pts = 0L;
+ if(ssXref) free(ssXref); ssXref = 0L;
+ if(ssYref) free(ssYref); ssYref = 0L;
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ if(parent)parent->Command(CMD_MRK_DIRTY, 0L, 0L);
+}
+
+bool
+DataLine::SetColor(int select, DWORD col)
+{
+ switch(select & 0xfff) {
+ case COL_DATA_LINE:
+ LineDef.color = col;
+ return true;
+ }
+ return false;
+}
+
+void
+DataLine::DoPlot(anyOutput *target)
+{
+ int i;
+ lfPOINT fip;
+ POINT pn, *tmppts;
+
+ if(!Values || nPntSet < 1) return;
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ if(pts) free(pts);
+ if(type & 0xff) pts = (POINT *)malloc(sizeof(POINT)*(nPntSet+2)*2);
+ else pts = (POINT *)malloc(sizeof(POINT)*(nPntSet+2));
+ if(!pts)return;
+ if(max.fx > min.fx && max.fy > min.fy) dirty = false;
+ else if(dirty)Command(CMD_AUTOSCALE, 0L, target);
+ cp = 0;
+ switch(type & 0xf) {
+ case 0:
+ for (i = 0; i <= nPntSet; i++){
+ target->fp2fip(Values+i, &fip);
+ pn.x = iround(fip.fx); pn.y = iround(fip.fy);
+ AddToPolygon(&cp, pts, &pn);
+ }
+ break;
+ case 5:
+ target->fp2fip(Values, &fip);
+ pn.x = iround(fip.fx); pn.y = iround(fip.fy);
+ target->fp2fip(Values+1, &fip);
+ pn.y += (pn.y -iround(fip.fy))>>1;
+ AddToPolygon(&cp, pts, &pn);
+ case 1:
+ target->fp2fip(Values, &fip);
+ pn.x = iround(fip.fx); pn.y = iround(+fip.fy);
+ for (i = 0; i <= nPntSet; i++){
+ target->fp2fip(Values+i, &fip);
+ pn.x = iround(fip.fx); AddToPolygon(&cp, pts, &pn);
+ pn.y = iround(fip.fy); AddToPolygon(&cp, pts, &pn);
+ }
+ if((type &0xf) == 5) {
+ target->fp2fip(Values+i-2, &fip);
+ pn.x += (pn.x - iround(fip.fx))>>1;
+ AddToPolygon(&cp, pts, &pn);
+ }
+ break;
+ case 6:
+ target->fp2fip(Values, &fip);
+ pn.x = iround(fip.fx); pn.y = iround(fip.fy);
+ target->fp2fip(Values+1, &fip);
+ pn.x += (pn.x - iround(fip.fx))>>1;
+ AddToPolygon(&cp, pts, &pn);
+ case 2:
+ target->fp2fip(Values, &fip);
+ pn.x = iround(fip.fx); pn.y = iround(fip.fy);
+ for (i = 0; i <= nPntSet; i++){
+ target->fp2fip(Values+i, &fip);
+ pn.y = iround(fip.fy); AddToPolygon(&cp, pts, &pn);
+ pn.x = iround(fip.fx); AddToPolygon(&cp, pts, &pn);
+ }
+ if((type &0xf) == 6) {
+ target->fp2fip(Values+i-2, &fip);
+ pn.y += (pn.y - iround(fip.fy))>>1;
+ AddToPolygon(&cp, pts, &pn);
+ }
+ break;
+ case 7:
+ target->fp2fip(Values, &fip);
+ pn.x = iround(fip.fx); pn.y = iround(fip.fy);
+ target->fp2fip(Values+1, &fip);
+ pn.x += (pn.x - iround(fip.fx))>>1;
+ AddToPolygon(&cp, pts, &pn);
+ case 3:
+ target->fp2fip(Values, &fip);
+ pn.x = iround(fip.fx); pn.y = iround(fip.fy);
+ for (i = 0; i <= nPntSet; i++){
+ target->fp2fip(Values+i, &fip);
+ pn.x = (pn.x + iround(fip.fx))>>1; AddToPolygon(&cp, pts, &pn);
+ pn.y = iround(fip.fy); AddToPolygon(&cp, pts, &pn);
+ pn.x = iround(fip.fx);
+ }
+ AddToPolygon(&cp, pts, &pn);
+ if((type &0xf) == 7) {
+ target->fp2fip(Values+i-2, &fip);
+ pn.x += (pn.x - iround(fip.fx))>>1;
+ AddToPolygon(&cp, pts, &pn);
+ }
+ break;
+ case 8:
+ target->fp2fip(Values, &fip);
+ pn.x = iround(fip.fx); pn.y = iround(fip.fy);
+ target->fp2fip(Values+1, &fip);
+ pn.y += (pn.y - iround(fip.fy))>>1;
+ AddToPolygon(&cp, pts, &pn);
+ case 4:
+ target->fp2fip(Values, &fip);
+ pn.x = iround(fip.fx); pn.y = iround(fip.fy);
+ for (i = 0; i <= nPntSet; i++){
+ target->fp2fip(Values+i, &fip);
+ pn.y = (pn.y + iround(fip.fy))>>1; AddToPolygon(&cp, pts, &pn);
+ pn.x = iround(fip.fx); AddToPolygon(&cp, pts, &pn);
+ pn.y = iround(fip.fy);
+ }
+ AddToPolygon(&cp, pts, &pn);
+ if((type &0xf) == 8) {
+ target->fp2fip(Values+i-2, &fip);
+ pn.y += (pn.y - iround(fip.fy))>>1;
+ AddToPolygon(&cp, pts, &pn);
+ }
+ break;
+ }
+ if(cp < 2) return;
+ if(isPolygon) { //for mark polygon only !!
+ AddToPolygon(&cp, pts, pts);
+ }
+ else{
+ target->SetLine(&LineDef);
+ target->oPolyline(pts, cp);
+ }
+ if(tmppts = (POINT*)realloc(pts, cp *sizeof(POINT))) pts = tmppts;
+ SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+ for(i = 2; i < cp; i++) UpdateMinMaxRect(&rDims, pts[i].x, pts[i].y);
+ i = 2*target->un2ix(LineDef.width); //increase size of rectangle for marks
+ IncrementMinMaxRect(&rDims, i);
+}
+
+void
+DataLine::DoMark(anyOutput *o, bool mark)
+{
+ if(pts && cp && o){
+ if(mark){
+ memcpy(&mrc, &rDims, sizeof(RECT));
+ IncrementMinMaxRect(&mrc, 6 + o->un2ix(LineDef.width));
+ mo = GetRectBitmap(&mrc, o);
+ InvertLine(pts, cp, &LineDef, &mrc, o, mark);
+ }
+ else if(mo) RestoreRectBitmap(&mo, &mrc, o);
+ }
+}
+
+bool
+DataLine::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ bool bFound = false;
+ POINT p1;
+ int i;
+
+ switch (cmd) {
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(!IsInRect(&rDims, p1.x= mev->x, p1.y= mev->y) || CurrGO || !o || nPntSet <2)
+ return false;
+ if(isPolygon && IsInPolygon(&p1, pts, cp)) bFound = true;
+ if(bFound || IsCloseToPL(p1,pts,cp))
+ return o->ShowMark(this, MRK_GODRAW);
+ }
+ break;
+ case CMD_SET_DATAOBJ:
+ Id = isPolygon ? GO_DATAPOLYGON : GO_DATALINE;
+ data = (DataObj*)tmpl;
+ return true;
+ case CMD_LEGEND:
+ if(tmpl && ((GraphObj*)tmpl)->Id == GO_LEGEND) {
+ if(Id == GO_DATALINE) ((Legend*)tmpl)->HasFill(&LineDef, 0L);
+ }
+ break;
+ case CMD_SET_LINE:
+ if(tmpl) memcpy(&LineDef, tmpl, sizeof(LineDEF));
+ return true;
+ case CMD_UPDATE:
+ SetValues();
+ return true;
+ case CMD_AUTOSCALE:
+ if(nPntSet < 2 || !Values) return false;
+ if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+ if(dirty) {
+ min.fx = max.fx = Values[0].fx; min.fy = max.fy = Values[0].fy;
+ for (i = 1; i <= nPntSet; i++){
+ min.fx = Values[i].fx < min.fx ? Values[i].fx : min.fx;
+ max.fx = Values[i].fx > max.fx ? Values[i].fx : max.fx;
+ min.fy = Values[i].fy < min.fy ? Values[i].fy : min.fy;
+ max.fy = Values[i].fy > max.fy ? Values[i].fy : max.fy;
+ }
+ }
+ ((Plot*)parent)->CheckBounds(min.fx, min.fy);
+ ((Plot*)parent)->CheckBounds(max.fx, max.fy);
+ dirty = false;
+ return true;
+ }
+ return false;
+ }
+ return false;
+}
+
+void
+DataLine::SetValues()
+{
+ AccRange *rX, *rY1=0L, *rY2=0L;
+ int i, j, k, l, m, n;
+ double x, y;
+ char *yref1 = 0L, *yref2 = 0L;
+ lfPOINT *tmpValues = 0L;
+
+ if(!ssXref || !ssYref) return;
+ if(!(yref1 = strdup(ssYref)))return;
+ for(i = 0; yref1[i]; i++) {
+ if(yref1[i] == ';') {
+ yref1[i++] = 0;
+ while(yref1[i] && yref1[i] < 33) i++;
+ yref2 = strdup(yref1+i);
+ }
+ }
+ nPnt = nPntSet = 0;
+ if(Values) free(Values); Values = 0L;
+ min.fx = min.fy = HUGE_VAL; max.fx = max.fy = -HUGE_VAL;
+ rX = new AccRange(ssXref); rY1 = new AccRange(yref1);
+ if(!rX || !rY1){
+ if(yref1) free(yref1); if(yref2) free(yref2);
+ if(rX) delete(rX); if(rY1) delete(rY1);
+ return;
+ }
+ if(yref2 &&((nPnt = rX->CountItems()) == (rY1->CountItems()))) {
+ if(!(Values = (lfPOINT *)calloc(nPnt*2+2, sizeof(lfPOINT)))) return;
+ if(!(rY2 = new AccRange(yref2))) {
+ if(yref1) free(yref1); if(yref2) free(yref2);
+ if(rX) delete(rX); if(rY1) delete(rY1);
+ return;
+ }
+ if(rX->GetFirst(&i, &j) && rY1->GetFirst(&k, &l) &&
+ rX->GetNext(&i, &j) && rY1->GetNext(&k, &l) &&
+ rY2->GetFirst(&m, &n) && rY2->GetNext(&m, &n)) do {
+ if(data->GetValue(j, i, &x)){
+ if(data->GetValue(l, k, &y)){
+ Values[nPntSet].fx = x; Values[nPntSet++].fy = y;
+ }
+ if(data->GetValue(n, m, &y)){
+ Values[nPntSet].fx = x; Values[nPntSet++].fy = y;
+ }
+ }
+ }while(rX->GetNext(&i, &j) && rY1->GetNext(&k, &l) && rY2->GetNext(&m, &n));
+ }
+ else {
+ if((nPnt = rX->CountItems()) != (rY1->CountItems())) return;
+ if(!(Values = (lfPOINT *)calloc(nPnt+2, sizeof(lfPOINT)))) return;
+ if(rX->GetFirst(&i, &j) && rY1->GetFirst(&k, &l) &&
+ rX->GetNext(&i, &j) && rY1->GetNext(&k, &l)) do {
+ if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y)){
+ Values[nPntSet].fx = x; Values[nPntSet++].fy = y;
+ }
+ }while(rX->GetNext(&i, &j) && rY1->GetNext(&k, &l));
+ }
+ nPnt = nPntSet; nPntSet--; dirty = true;
+ Command(CMD_AUTOSCALE, 0L, 0L);
+ if(tmpValues = (lfPOINT *)realloc(Values, (nPnt+2)*sizeof(lfPOINT)))
+ Values = tmpValues;
+ if(rX) delete(rX); if(rY1) delete(rY1); if(rY2) delete(rY2);
+ if(yref1) free(yref1); if(yref2) free(yref2);
+}
+
+void
+DataLine::LineData(lfPOINT *val, long nval)
+{
+ if(Values)free(Values); Values = 0L;
+ if(pts) free(pts); pts = 0L;
+ Values = val; dirty = true;
+ nPnt = nval; nPntSet = nPnt-1;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// DataPolygon is a graphic object based on DataLine
+DataPolygon::DataPolygon(GraphObj *par, DataObj *d, char *xrange, char *yrange):
+ DataLine(par, d, xrange, yrange)
+{
+ lfPOINT *fp = Values;
+ char *rx = ssXref;
+ char *ry = ssYref;
+
+ FileIO(INIT_VARS);
+ Values = fp; //FileIO will just set Values to 0L !
+ ssXref = rx; ssYref = ry;
+ Id = GO_DATAPOLYGON;
+}
+
+DataPolygon::DataPolygon(int src):DataLine(0L, 0)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+DataPolygon::~DataPolygon()
+{
+ if(Values)free(Values); Values =0L;
+ if(pts) free (pts); pts = 0L;
+ if(ssXref) free(ssXref); ssXref = 0L;
+ if(ssYref) free(ssYref); ssYref = 0L;
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ if(parent)parent->Command(CMD_MRK_DIRTY, 0L, 0L);
+}
+
+void
+DataPolygon::DoPlot(anyOutput *target)
+{
+ if(!Values || nPntSet < 2) return;
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ DataLine::DoPlot(target); //no drawing but fill pts only
+ target->SetLine(&LineDef); target->SetFill(&pgFill);
+ target->oPolygon(pts, cp);
+}
+
+void
+DataPolygon::DoMark(anyOutput *o, bool mark)
+{
+ if(pts && cp && o){
+ if(mark){
+ memcpy(&mrc, &rDims, sizeof(RECT));
+ IncrementMinMaxRect(&mrc, 6 + o->un2ix(LineDef.width));
+ mo = GetRectBitmap(&mrc, o);
+ InvertPolygon(pts, cp, &LineDef, &pgFill, &mrc, o, mark);
+ }
+ else RestoreRectBitmap(&mo, &mrc, o);
+ }
+}
+
+bool
+DataPolygon::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ switch (cmd) {
+ case CMD_PG_FILL:
+ if(tmpl) {
+ memcpy((void*)&pgFill, tmpl, sizeof(FillDEF));
+ if(pgFill.hatch) memcpy((void*)&pgFillLine, (void*)pgFill.hatch, sizeof(LineDEF));
+ pgFill.hatch = (LineDEF*)&pgFillLine;
+ }
+ return true;
+ case CMD_LEGEND:
+ if(tmpl && ((GraphObj*)tmpl)->Id == GO_LEGEND) {
+ if(Id == GO_DATAPOLYGON) ((Legend*)tmpl)->HasFill(&LineDef, &pgFill);
+ }
+ break;
+ default:
+ return DataLine::Command(cmd, tmpl, o);
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Calculate and display a regression line
+// Ref.: "Biometry" third edition 1995 (ed. R.R. Sokal and F.J. Rohlf),
+// W.H. Freeman and Company, New York; ISBN 0-7167-2411-1; pp. 451ff
+RegLine::RegLine(GraphObj *par, DataObj *d, lfPOINT *values, long n, int sel):
+ GraphObj(par, d)
+{
+ FileIO(INIT_VARS);
+ type = sel;
+ Id = GO_REGLINE;
+ uclip.Xmin = uclip.Ymin = lim.Xmin = lim.Ymin = -1.0;
+ uclip.Xmax = uclip.Ymax = lim.Xmax = lim.Ymax = 1.0;
+ Recalc(values, n);
+}
+
+RegLine::RegLine(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) FileIO(FILE_READ);
+}
+
+RegLine::~RegLine()
+{
+ if(pts) free(pts);
+ pts = 0L;
+ if(parent)parent->Command(CMD_MRK_DIRTY, 0L, 0L);
+}
+
+double
+RegLine::GetSize(int select)
+{
+ double a, b;
+
+ switch(select) {
+ case SIZE_MX: return mx;
+ case SIZE_MY: return my;
+ case SIZE_A:
+ case SIZE_B:
+ switch(type & 0x07) {
+ case 1: a = l2.fx; b = l2.fy; break;
+ case 2: a = l3.fx; b = l3.fy; break;
+ case 3: a = l4.fx; b = l4.fy; break;
+ case 4: a = l5.fx; b = l5.fy; break;
+ default: a = l1.fx; b = l1.fy; break;
+ }
+ if(select == SIZE_A) return a;
+ else return b;
+ }
+ return 0.0;
+}
+
+void
+RegLine::DoPlot(anyOutput *o)
+{
+ int i;
+ POINT pn, *tmppts;
+ double x, x1, y, d, a, b;
+ fRECT cliprc;
+ bool dValid;
+
+ switch (type & 0x70) {
+ case 0x20: memcpy(&cliprc, &uclip, sizeof(fRECT)); break;
+ case 0x10:
+ if(parent) {
+ cliprc.Xmin = parent->GetSize(SIZE_BOUNDS_LEFT);
+ cliprc.Xmax = parent->GetSize(SIZE_BOUNDS_RIGHT);
+ cliprc.Ymin = parent->GetSize(SIZE_BOUNDS_BOTTOM);
+ cliprc.Ymax = parent->GetSize(SIZE_BOUNDS_TOP);
+ break;
+ }
+ //no parent: use default
+ default: memcpy(&cliprc, &lim, sizeof(fRECT)); break;
+ }
+ if(cliprc.Xmax < cliprc.Xmin) {
+ x = cliprc.Xmax; cliprc.Xmax = cliprc.Xmin; cliprc.Xmin = x;
+ }
+ if(cliprc.Ymax < cliprc.Ymin) {
+ y = cliprc.Ymax; cliprc.Ymax = cliprc.Ymin; cliprc.Ymin = y;
+ }
+ if(cliprc.Xmin == cliprc.Xmax || cliprc.Ymin == cliprc.Ymax) return;
+ if(pts) free(pts);
+ if(!(pts = (POINT *)malloc(sizeof(POINT)*200)))return;
+ switch(type & 0x07) {
+ case 1: a = l2.fx; b = l2.fy; break;
+ case 2: a = l3.fx; b = l3.fy; break;
+ case 3: a = l4.fx; b = l4.fy; break;
+ case 4: a = l5.fx; b = l5.fy; break;
+ default: a = l1.fx; b = l1.fy; break;
+ }
+ x = cliprc.Xmin; d = (cliprc.Xmax - cliprc.Xmin)/200.0;
+ for (cp = i = 0; i <= 200; i++){
+ dValid = true;
+ switch(type & 0x700) {
+ case 0x100: //logarithmic x
+ if(dValid = x > defs.min4log) x1 = log10(x);
+ break;
+ case 0x200: //reciprocal x
+ if(dValid = fabs(x) > defs.min4log) x1 = 1.0/x;
+ break;
+ case 0x300: //square root x
+ if(dValid = fabs(x) > defs.min4log) x1 = sqrt(x);
+ break;
+ default: x1 = x; break; //linear x
+ }
+ y = a + b*x1;
+ if(dValid) switch(type & 0x7000) {
+ case 0x1000: //logarithmic y
+ y = pow(10.0, y);
+ break;
+ case 0x2000: //reciprocal y
+ if(dValid = fabs(y) >0.0001) y = 1.0/y;
+ break;
+ case 0x3000: //square root y
+ if(dValid = fabs(y) >0.0001) y = y*y;
+ break;
+ }
+ if(dValid && y >= cliprc.Ymin && y <= cliprc.Ymax) {
+ pn.x = o->fx2ix(x); pn.y = o->fy2iy(y);
+ AddToPolygon(&cp, pts, &pn);
+ }
+ x += d;
+ }
+ if(cp < 2) return;
+ o->SetLine(&LineDef);
+ o->oPolyline(pts, cp);
+ if(tmppts = (POINT*)realloc(pts, cp *sizeof(POINT))) pts = tmppts;
+ SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+ for(i = 2; i < cp; i++) UpdateMinMaxRect(&rDims, pts[i].x, pts[i].y);
+ i = 2*o->un2ix(LineDef.width); //increase size of rectangle for marks
+ IncrementMinMaxRect(&rDims, i);
+}
+
+void
+RegLine::DoMark(anyOutput *o, bool mark)
+{
+ if(pts && cp && o){
+ if(mark)InvertLine(pts, cp, &LineDef, &rDims, o, mark);
+ else if(parent) parent->Command(CMD_REDRAW, 0L, o);
+ }
+}
+
+bool
+RegLine::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ POINT p1;
+
+ switch (cmd) {
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(!IsInRect(&rDims, p1.x= mev->x, p1.y= mev->y) || CurrGO || !o || nPoints <2)
+ return false;
+ if(IsCloseToPL(p1,pts,cp)) return o->ShowMark(CurrGO= this, MRK_GODRAW);
+ }
+ break;
+ case CMD_SET_DATAOBJ:
+ Id = GO_REGLINE;
+ return true;
+ case CMD_BOUNDS:
+ if(tmpl) {
+ memcpy(&lim, tmpl, sizeof(fRECT));
+ memcpy(&uclip, tmpl, sizeof(fRECT));
+ }
+ return true;
+ case CMD_AUTOSCALE:
+ if(nPoints < 2) return false;
+ if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+ ((Plot*)parent)->CheckBounds(lim.Xmin, lim.Ymin);
+ ((Plot*)parent)->CheckBounds(lim.Xmax, lim.Ymax);
+ return true;
+ }
+ return false;
+ }
+ return false;
+}
+
+void
+RegLine::Recalc(lfPOINT *values, long n)
+{
+ double sx, sy, dx, dy, sxy, sxx, syy;
+ double a, b, k;
+ long ic;
+
+ sx = sy = 0.0;
+ if((nPoints = n)<2) return;
+ for(ic = 0; ic < n; ic++) {
+ sx += values[ic].fx; sy += values[ic].fy;
+ }
+ mx = sx /((double)nPoints); my = sy/((double)nPoints);
+ sxy = sxx = syy = 0.0;
+ for(ic = 0; ic < n; ic++) {
+ dx = mx - values[ic].fx; dy = my - values[ic].fy;
+ sxx += (dx*dx); syy += (dy*dy); sxy += (dx*dy);
+ }
+ l1.fy = sxy / sxx; l1.fx = my - (sxy / sxx) * mx;
+ b = sxy / syy; a = mx - (sxy / syy) * my;
+ l2.fy = 1.0/b; l2.fx = -a / b;
+ l3.fy = (l1.fy+l2.fy)/2.0; l3.fx = (l1.fx+l2.fx)/2.0;
+ l4.fy = sy/sx; l4.fx = 0.0;
+ if(l5.fx == 0.0 && l5.fx == 0.0){
+ l5.fy = l1.fy; l5.fx = l1.fx;
+ }
+ //calculate distance point from line algorithm
+ //Ref: K. Thompson, 1990: Vertical Distance from a Point to a Line. In:
+ // Graphic Gems (Andrew S. Glassner, ed.), Academic Press,
+ // pp. 47-48; ISBN 0-12-286165-5
+ k = (sqrt(1.0/(1.0+l1.fy*l1.fy))+sqrt(1.0/(1.0+l2.fy*l2.fy)))/2.0;
+ b = sqrt(1.0/(k*k) -1.0);
+ l3.fy = l3.fy > 0.0 ? b : -b;
+ l3.fx = my - mx * l3.fy;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Calculate and display a statnard deviation (SD-) ellipse
+SDellipse::SDellipse(GraphObj *par, DataObj *d, lfPOINT *values, long n, int sel):
+ GraphObj(par, d)
+{
+ FileIO(INIT_VARS);
+ type = sel;
+ Id = GO_SDELLIPSE;
+ if(val = (lfPOINT*)malloc(n * sizeof(lfPOINT))){
+ memcpy(val, values, (nPoints = n)*sizeof(lfPOINT));
+ rl = new RegLine(this, data, values, n, type);
+ }
+}
+
+SDellipse::SDellipse(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) FileIO(FILE_READ);
+}
+
+SDellipse::~SDellipse()
+{
+ if(val) free(val);
+ if(pts) free(pts);
+ if(!(type & 0x10000) && parent && rl &&
+ parent->Command(CMD_DROP_OBJECT, rl, 0L)) return;
+ if(rl) DeleteGO(rl);
+}
+
+void
+SDellipse::DoPlot(anyOutput *o)
+{
+ int i;
+ double a1, b1, a2, b2, fv, k1, k2, ss1, ss2, np, x, dx, si, csi;
+ lfPOINT fp, fip;
+ POINT p1, *tmppts;
+
+ if(!rl) return;
+ if(pts) free(pts);
+ if(!(pts = (POINT *)malloc(sizeof(POINT)*420)))return;
+ //get line data from regression line object
+ mx = rl->GetSize(SIZE_MX); my = rl->GetSize(SIZE_MY);
+ a1 = rl->GetSize(SIZE_A); b1 = rl->GetSize(SIZE_B);
+ b2 = -1.0/b1; a2 = my - b2 * mx;
+ //calculate sine and cosine for back rotation
+ fv = sqrt(1.0+b1*b1); si = b1/fv; csi = 1.0/fv;
+ //calculate distance from line for each point and squared sum of distances
+ //Ref: K. Thompson, 1990: Vertical Distance from a Point to a Line. In:
+ // Graphic Gems (Andrew S. Glassner, ed.), Academic Press,
+ // pp. 47-48; ISBN 0-12-286165-5
+ k1 = sqrt(1.0/(1.0+b1*b1)); k2 = sqrt(1.0/(1.0+b2*b2));
+ // y = a + b*x;
+ ss1 = ss2 = 0.0;
+ for(i = 0; i < nPoints; i++) {
+ fv = (a1 + b1 * val[i].fx - val[i].fy) * k1; ss1 += (fv*fv);
+ fv = (a2 + b2 * val[i].fx - val[i].fy) * k2; ss2 += (fv*fv);
+ }
+ np = ((double)(nPoints-1));
+ //SD perpendicular and in direction of regression line
+ sd1 = sqrt(ss1 /= np); sd2 = sqrt(ss2 /= np);
+ dx = sd2/100.0;
+ for(i = 0, cp = 0, x = -sd2; i < 2; i++) {
+ do {
+ fv = (x*x)/ss2;
+ fv = fv < 0.99999 ? sqrt((1.0-fv)*ss1) : 0.0;
+ fv = i ? fv : -fv;
+ fp.fx = mx + x * csi - fv * si;
+ fp.fy = my + x * si + fv * csi;
+ switch(type & 0x700) {
+ case 0x100: //logarithmic x
+ fp.fx = pow(10.0, fp.fx);
+ break;
+ case 0x200: //reciprocal x
+ if(fabs(fp.fx) > defs.min4log) fp.fx = 1.0/fp.fx;
+ else fp.fx = 0.0;
+ break;
+ case 0x300: //square root x
+ if(fabs(fp.fx) > defs.min4log) fp.fx = fp.fx*fp.fx;
+ else fp.fx = 0.0;
+ break;
+ }
+ switch(type & 0x7000) {
+ case 0x1000: //logarithmic y
+ fp.fy = pow(10.0, fp.fy);
+ break;
+ case 0x2000: //reciprocal y
+ if(fabs(fp.fy) > defs.min4log) fp.fy = 1.0/fp.fy;
+ else fp.fy = 0.0;
+ break;
+ case 0x3000: //square root y
+ if(fabs(fp.fy) > defs.min4log) fp.fy = fp.fy*fp.fy;
+ else fp.fy = 0.0;
+ break;
+ }
+ o->fp2fip(&fp, &fip); p1.x = iround(fip.fx); p1.y = iround(fip.fy);
+ AddToPolygon(&cp, pts, &p1);
+ }while((x += dx) < sd2 && x > -sd2);
+ x = sd2;
+ dx *= -1.0;
+ }
+ o->SetLine(&LineDef);
+ if(cp > 2) {
+ AddToPolygon(&cp, pts, pts); //close polygon
+ if(tmppts = (POINT*)realloc(pts, cp *sizeof(POINT))) pts = tmppts;
+ SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+ for(i = 2; i < cp; i++)
+ UpdateMinMaxRect(&rDims, pts[i].x, pts[i].y);
+ i = 3*o->un2ix(LineDef.width); //increase size of rectangle for marks
+ IncrementMinMaxRect(&rDims, i);
+ o->oPolyline(pts, cp);
+ }
+ else {
+ free(pts);
+ cp = 0;
+ }
+ if(!(type & 0x10000))rl->DoPlot(o);
+}
+
+void
+SDellipse::DoMark(anyOutput *o, bool mark)
+{
+ if(pts && cp && o){
+ if(mark)InvertLine(pts, cp, &LineDef, &rDims, o, mark);
+ else if(parent) parent->Command(CMD_REDRAW, 0L, o);
+ }
+}
+
+bool
+SDellipse::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ POINT p1;
+
+ switch (cmd) {
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(!(type & 0x10000) && rl && rl->Command(cmd, tmpl, o)) return true;
+ if(!IsInRect(&rDims, p1.x= mev->x, p1.y= mev->y) || CurrGO || !o || nPoints <2)
+ return false;
+ if(IsCloseToPL(p1,pts,cp)) return o->ShowMark(CurrGO= this, MRK_GODRAW);
+ }
+ break;
+ case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ case CMD_RMU:
+ if(!(type & 0x10000) && parent && rl && parent->Command(CMD_DROP_OBJECT, rl, o)){
+ rl = 0L;
+ return true;
+ }
+ return false;
+ case CMD_INIT:
+ if(rl) return rl->PropertyDlg();
+ break;
+ case CMD_DROP_OBJECT:
+ if(tmpl && ((GraphObj*)tmpl)->Id == GO_REGLINE && !rl) {
+ rl = (RegLine *)tmpl;
+ rl->parent = this;
+ return true;
+ }
+ return false;
+ case CMD_SET_DATAOBJ:
+ Id = GO_SDELLIPSE;
+ if(rl) rl->Command(cmd, tmpl, o);
+ return true;
+ case CMD_BOUNDS:
+ if(tmpl) {
+ if(rl) rl->Command(cmd, tmpl, o);
+ memcpy(&lim, tmpl, sizeof(fRECT));
+ }
+ return true;
+ case CMD_DELOBJ:
+ if(tmpl && tmpl == (void*)rl) {
+ Undo.ValInt(parent, &type, 0L);
+ type |= 0x10000;
+ if(parent) parent->Command(CMD_REDRAW, 0L, o);
+ return true;
+ }
+ break;
+ case CMD_AUTOSCALE:
+ if(nPoints < 2) return false;
+ if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+ ((Plot*)parent)->CheckBounds(lim.Xmin, lim.Ymin);
+ ((Plot*)parent)->CheckBounds(lim.Xmax, lim.Ymax);
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
+void
+SDellipse::Recalc(lfPOINT *values, long n)
+{
+ if(val) free(val);
+ if(val = (lfPOINT*)malloc(n * sizeof(lfPOINT)))
+ memcpy(val, values, (nPoints = n)*sizeof(lfPOINT));
+ if(rl) rl->Recalc(values, n);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Error bars are simple graphic objects
+ErrorBar::ErrorBar(GraphObj *par, DataObj *d, double x, double y, double err, int which,
+ int xc, int xr, int yc, int yr, int ec, int er):GraphObj(par, d)
+{
+ FileIO(INIT_VARS);
+ fPos.fx = x; fPos.fy = y;
+ ferr = err;
+ type = which;
+ Id = GO_ERRBAR;
+ data = d;
+ if(xc >= 0 || xr >= 0 || yc >= 0 || yr >= 0 || ec >= 0 || er >= 0) {
+ if(ssRef = (POINT*)malloc(sizeof(POINT)*3)) {
+ ssRef[0].x = xc; ssRef[0].y = xr;
+ ssRef[1].x = yc; ssRef[1].y = yr;
+ ssRef[2].x = ec; ssRef[2].y = er;
+ cssRef = 3;
+ }
+ }
+ Command(CMD_AUTOSCALE, 0L, 0L);
+}
+
+ErrorBar::ErrorBar(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ type = ERRBAR_VSYM;
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+ErrorBar::~ErrorBar()
+{
+ if(ssRef) free(ssRef);
+ ssRef = 0L;
+}
+
+bool
+ErrorBar::SetSize(int select, double value)
+{
+ switch(select & 0xfff) {
+ case SIZE_ERRBAR:
+ SizeBar = value;
+ return true;
+ case SIZE_ERRBAR_LINE:
+ ErrLine.width = value;
+ return true;
+ }
+ return false;
+}
+
+bool
+ErrorBar::SetColor(int select, DWORD col)
+{
+ switch(select & 0xfff) {
+ case COL_ERROR_LINE:
+ ErrLine.color = col;
+ return true;
+ }
+ return false;
+}
+
+void
+ErrorBar::DoPlot(anyOutput *target)
+{
+ int ie;
+
+ switch (type & 0x0ff) {
+ case ERRBAR_VSYM:
+ case ERRBAR_VUP:
+ case ERRBAR_VDOWN:
+ ie = target->un2ix(SizeBar/2.0f);
+ break;
+ default:
+ ie = target->un2iy(SizeBar/2.0f);
+ break;
+ }
+ target->SetLine(&ErrLine);
+ switch(type) {
+ case ERRBAR_VSYM:
+ ebpts[0].x = ebpts[1].x = target->fx2ix(fPos.fx);
+ ebpts[0].y = target->fy2iy(fPos.fy-ferr);
+ ebpts[4].y = ebpts[5].y = ebpts[1].y = target->fy2iy(fPos.fy+ferr);
+ if(ebpts[1].y != ebpts[0].y) target->oSolidLine(ebpts);
+ ebpts[4].x = ebpts[2].x = ebpts[0].x - ie;
+ ebpts[5].x = ebpts[3].x = ebpts[1].x + ie+1;
+ ebpts[2].y = ebpts[3].y = ebpts[0].y;
+ if(ebpts[3].x > ebpts[2].x) {
+ target->oSolidLine(ebpts+2);
+ target->oSolidLine(ebpts+4);
+ }
+ rDims.left = ebpts[2].x; rDims.right = ebpts[3].x;
+ rDims.top = ebpts[0].y; rDims.bottom = ebpts[1].y;
+ break;
+ case ERRBAR_VUP:
+ case ERRBAR_VDOWN:
+ ebpts[0].x = ebpts[1].x = target->fx2ix(fPos.fx);
+ ebpts[0].y = target->fy2iy(fPos.fy);
+ ebpts[2].y = ebpts[3].y = ebpts[1].y =
+ target->fy2iy(type == ERRBAR_VUP ? fPos.fy+ferr : fPos.fy-ferr);
+ if(ebpts[1].y != ebpts[0].y) target->oSolidLine(ebpts);
+ ebpts[2].x = ebpts[0].x - ie;
+ ebpts[3].x = ebpts[1].x + ie+1;
+ if(ebpts[3].x > ebpts[2].x) target->oSolidLine(ebpts+2);
+ rDims.left = ebpts[2].x; rDims.right = ebpts[3].x;
+ rDims.top = ebpts[0].y; rDims.bottom = ebpts[1].y;
+ break;
+ case ERRBAR_HSYM:
+ ebpts[2].x = ebpts[3].x = ebpts[0].x = target->fx2ix(fPos.fx-ferr);
+ ebpts[4].x = ebpts[5].x = ebpts[1].x = target->fx2ix(fPos.fx+ferr);
+ ebpts[0].y = ebpts[1].y = target->fy2iy(fPos.fy);
+ if(ebpts[1].x != ebpts[0].x) target->oSolidLine(ebpts);
+ ebpts[2].y = ebpts[4].y = ebpts[0].y - ie;
+ ebpts[3].y = ebpts[5].y = ebpts[1].y + ie+1;
+ if(ebpts[3].y >ebpts[2].y) {
+ target->oSolidLine(ebpts+2);
+ target->oSolidLine(ebpts+4);
+ }
+ rDims.left = ebpts[0].x; rDims.right = ebpts[1].x;
+ rDims.top = ebpts[2].y; rDims.bottom = ebpts[3].y;
+ break;
+ case ERRBAR_HLEFT:
+ case ERRBAR_HRIGHT:
+ ebpts[0].x = target->fx2ix(fPos.fx);
+ ebpts[0].y = ebpts[1].y = target->fy2iy(fPos.fy);
+ ebpts[2].x = ebpts[3].x = ebpts[1].x =
+ target->fx2ix(type == ERRBAR_HRIGHT ? fPos.fx+ferr : fPos.fx-ferr);
+ if(ebpts[1].x != ebpts[0].x) target->oSolidLine(ebpts);
+ ebpts[2].y = ebpts[0].y - ie;
+ ebpts[3].y = ebpts[1].y + ie+1;
+ if(ebpts[3].y > ebpts[2].y) target->oSolidLine(ebpts+2);
+ rDims.left = ebpts[0].x; rDims.right = ebpts[1].x;
+ rDims.top = ebpts[2].y; rDims.bottom = ebpts[3].y;
+ break;
+ }
+ if(rDims.left > rDims.right) Swap(rDims.left, rDims.right);
+ if(rDims.top > rDims.bottom) Swap(rDims.top, rDims.bottom);
+ IncrementMinMaxRect(&rDims, 3);
+}
+
+void
+ErrorBar::DoMark(anyOutput *o, bool mark)
+{
+ LineDEF OldLine;
+
+ memcpy(&OldLine, &ErrLine, sizeof(LineDEF));
+ if(mark) {
+ ErrLine.color = 0x00000000L;
+ ErrLine.width = 1.2f;
+ DoPlot(o);
+ ErrLine.width = 0.4f;
+ ErrLine.color = OldLine.color ^ 0x00ffffffL;
+ DoPlot(o);
+ }
+ else {
+ ErrLine.color = 0x00ffffffL; //DEBUG: assume white background
+ ErrLine.width = 1.2f;
+ DoPlot(o);
+ ErrLine.width = OldLine.width;
+ ErrLine.color = OldLine.color;
+ DoPlot(o);
+ }
+ memcpy(&ErrLine, &OldLine, sizeof(LineDEF));
+ o->UpdateRect(&rDims, false);
+}
+
+bool
+ErrorBar::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ bool bFound;
+
+ switch (cmd) {
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ bFound = false;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(!IsInRect(&rDims, mev->x, mev->y) || CurrGO) return false;
+ switch (type) {
+ case ERRBAR_HSYM:
+ case ERRBAR_HLEFT:
+ case ERRBAR_HRIGHT:
+ if(mev->y >= (ebpts[0].y-2) && mev->y <= (ebpts[1].y+2)) bFound = true;
+ else if(mev->x >= (ebpts[2].x-2) && mev->x <= (ebpts[2].x+2)) bFound = true;
+ else if(type == ERRBAR_HSYM && mev->x >= (ebpts[4].x-2) &&
+ mev->x <= (ebpts[4].x + 2)) bFound = true;
+ break;
+ case ERRBAR_VSYM:
+ case ERRBAR_VUP:
+ case ERRBAR_VDOWN:
+ if(mev->x >= (ebpts[0].x-2) && mev->x <= (ebpts[1].x+2)) bFound = true;
+ else if(mev->y >= (ebpts[2].y-2) && mev->y <= (ebpts[2].y+2)) bFound = true;
+ else if(type == ERRBAR_VSYM && mev->y >= (ebpts[4].y-2) &&
+ mev->y <= (ebpts[4].y + 2)) bFound = true;
+ break;
+ }
+ if(bFound) o->ShowMark(this, MRK_GODRAW);
+ }
+ case CMD_SET_DATAOBJ:
+ Id = GO_ERRBAR;
+ data = (DataObj *) tmpl;
+ return true;
+ case CMD_UPDATE:
+ if(ssRef && cssRef >2 && data) {
+ data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
+ data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
+ data->GetValue(ssRef[2].y, ssRef[2].x, &ferr);
+ return true;
+ }
+ return false;
+ case CMD_AUTOSCALE:
+ if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+ switch(type) {
+ case ERRBAR_VSYM:
+ ((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy+ferr);
+ ((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy-ferr); break;
+ case ERRBAR_VUP:
+ ((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);
+ ((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy+ferr); break;
+ case ERRBAR_VDOWN:
+ ((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);
+ ((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy-ferr); break;
+ case ERRBAR_HSYM:
+ ((Plot*)parent)->CheckBounds(fPos.fx+ferr, fPos.fy);
+ ((Plot*)parent)->CheckBounds(fPos.fx-ferr, fPos.fy); break;
+ case ERRBAR_HLEFT:
+ ((Plot*)parent)->CheckBounds(fPos.fx-ferr, fPos.fy);
+ ((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy); break;
+ case ERRBAR_HRIGHT:
+ ((Plot*)parent)->CheckBounds(fPos.fx+ferr, fPos.fy);
+ ((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy); break;
+ }
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// arrows to data points or with absolute coordinates
+Arrow::Arrow(GraphObj * par, DataObj *d, lfPOINT fp1, lfPOINT fp2, int which,
+ int xc1, int xr1, int yc1, int yr1, int xc2, int xr2, int yc2, int yr2):
+ GraphObj(par, d)
+{
+ double dx, dy;
+
+ FileIO(INIT_VARS);
+ memcpy(&pos1, &fp1, sizeof(lfPOINT));
+ memcpy(&pos2, &fp2, sizeof(lfPOINT));
+ type = which;
+ if(type & ARROW_UNITS) {
+ dx = parent->GetSize(SIZE_GRECT_LEFT); dy = parent->GetSize(SIZE_GRECT_TOP);
+ pos1.fx -= dx; pos1.fy -= dy; pos2.fx -= dx; pos2.fy -= dy;
+ }
+ if(xc1 >= 0 || xr1 >= 0 || yc1 >= 0 || yr1 >= 0 || xc2 >= 0 || xr2 >= 0 ||
+ yc2 >= 0 || yr2 >= 0) {
+ if(ssRef = (POINT*)malloc(sizeof(POINT)*4)) {
+ ssRef[0].x = xc1; ssRef[0].y = xr1;
+ ssRef[1].x = yc1; ssRef[1].y = yr1;
+ ssRef[2].x = xc2; ssRef[2].y = xr2;
+ ssRef[3].x = yc2; ssRef[3].y = yr2;
+ cssRef = 4;
+ }
+ }
+ bModified = false;
+}
+
+Arrow::Arrow(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+ bModified = false;
+}
+
+Arrow::~Arrow()
+{
+ Command(CMD_FLUSH, 0L, 0L);
+ if(bModified) Undo.InvalidGO(this);
+}
+
+double
+Arrow::GetSize(int select)
+{
+ switch(select) {
+ case SIZE_XPOS: return pos1.fx;
+ case SIZE_XPOS+1: return pos2.fx;
+ case SIZE_YPOS: return pos1.fy;
+ case SIZE_YPOS+1: return pos2.fy;
+ case SIZE_GRECT_LEFT: case SIZE_GRECT_TOP:
+ case SIZE_GRECT_RIGHT: case SIZE_GRECT_BOTTOM:
+ if(parent) return parent->GetSize(select);
+ break;
+ }
+ return 0.0;
+}
+
+bool
+Arrow::SetSize(int select, double value)
+{
+ switch(select & 0xfff) {
+ case SIZE_ARROW_LINE: LineDef.width = value; return true;
+ case SIZE_ARROW_CAPWIDTH: cw = value; return true;
+ case SIZE_ARROW_CAPLENGTH: cl = value; return true;
+ case SIZE_XPOS: pos1.fx = value; return true;
+ case SIZE_XPOS+1: pos2.fx = value; return true;
+ case SIZE_YPOS: pos1.fy = value; return true;
+ case SIZE_YPOS+1: pos2.fy = value; return true;
+ }
+ return false;
+}
+
+bool
+Arrow::SetColor(int select, DWORD col)
+{
+ switch(select & 0xfff) {
+ case COL_ARROW:
+ LineDef.color = col;
+ return true;
+ }
+ return false;
+}
+
+void
+Arrow::DoPlot(anyOutput *o)
+{
+ double si, csi, tmp, fix1, fiy1, fix2, fiy2, dx, dy;
+
+ if(!o || !parent) return;
+ if(type & ARROW_UNITS) {
+ dx = parent->GetSize(SIZE_GRECT_LEFT); dy = parent->GetSize(SIZE_GRECT_TOP);
+ fix1 = o->co2fix(pos1.fx+dx); fix2 = o->co2fix(pos2.fx+dx);
+ fiy1 = o->co2fiy(pos1.fy+dy); fiy2 = o->co2fiy(pos2.fy+dy);
+ }
+ else {
+ fix1 = o->fx2fix(pos1.fx); fix2 = o->fx2fix(pos2.fx);
+ fiy1 = o->fy2fiy(pos1.fy); fiy2 = o->fy2fiy(pos2.fy);
+ }
+ if(fix1 == fix2 && fiy1 == fiy2) return; //zero length
+ //draw arrow line
+ pts[0].x = iround(fix1); pts[1].x = iround(fix2);
+ pts[0].y = iround(fiy1); pts[1].y = iround(fiy2);
+ SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+ //calculate sine and cosine for cap
+ si = fiy1-fiy2;
+ tmp = fix2 - fix1;
+ si = si/sqrt(si*si + tmp*tmp);
+ csi = fix2-fix1;
+ tmp = fiy2 - fiy1;
+ csi = csi/sqrt(csi*csi + tmp*tmp);
+ //draw cap
+ pts[2].x = pts[1].x - o->un2ix(csi*cl + si*cw/2.0);
+ pts[2].y = pts[1].y + o->un2iy(si*cl - csi*cw/2.0);
+ pts[3].x = pts[1].x; pts[3].y = pts[1].y;
+ pts[4].x = pts[1].x - o->un2ix(csi*cl - si*cw/2.0);
+ pts[4].y = pts[1].y + o->un2iy(si*cl + csi*cw/2.0);
+ switch(type & 0xff) {
+ case ARROW_NOCAP:
+ pts[2].x = pts[3].x = pts[4].x = pts[1].x;
+ pts[2].y = pts[3].y = pts[4].y = pts[1].y;
+ break;
+ }
+ UpdateMinMaxRect(&rDims, pts[2].x, pts[2].y);
+ UpdateMinMaxRect(&rDims, pts[4].x, pts[4].y);
+ IncrementMinMaxRect(&rDims, 3);
+ if(this == CurrGO) o->ShowMark(this, MRK_GODRAW);
+ else Redraw(o);
+}
+
+void
+Arrow::DoMark(anyOutput *o, bool mark)
+{
+ LineDEF OldLine;
+
+ if(type & ARROW_UNITS) {
+ if(!dh1) dh1 = new dragHandle(this, DH_12);
+ if(!dh2) dh2 = new dragHandle(this, DH_22);
+ }
+ else {
+ if (dh1) DeleteGO(dh1); if (dh2) DeleteGO(dh2);
+ dh1 = dh2 = 0L;
+ }
+ memcpy(&OldLine, &LineDef, sizeof(LineDEF));
+ if(mark) {
+ LineDef.color = 0x00000000L;
+ LineDef.width = OldLine.width *3.0;
+ Redraw(o);
+ LineDef.width = OldLine.width;
+ LineDef.color = OldLine.color ^ 0x00ffffffL;
+ Redraw(o);
+ if(dh1) dh1->DoPlot(o); if(dh2) dh2->DoPlot(o);
+ }
+ else if(parent){
+ LineDef.color = 0x00ffffffL;
+ LineDef.width = OldLine.width *3.0;
+ Redraw(o);
+ LineDef.width = OldLine.width;
+ LineDef.color = OldLine.color;
+ parent->DoPlot(o);
+ }
+ memcpy(&LineDef, &OldLine, sizeof(LineDEF));
+ o->UpdateRect(&rDims, false);
+}
+
+bool
+Arrow::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+
+ switch (cmd) {
+ case CMD_SAVEPOS:
+ bModified = true;
+ Undo.SaveLFP(this, &pos1, 0L);
+ Undo.SaveLFP(this, &pos2, UNDO_CONTINUE);
+ return true;
+ case CMD_FLUSH:
+ if (dh1) DeleteGO(dh1); dh1 = 0L;
+ if (dh2) DeleteGO(dh2); dh2 = 0L;
+ if(ssRef) free(ssRef); ssRef = 0L;
+ if(name) free(name); name = 0L;
+ return true;
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(!CurrGO && ObjThere(mev->x, mev->y)){
+ o->ShowMark(this, MRK_GODRAW);
+ return true;
+ }
+ }
+ break;
+ case CMD_ARROW_ORG:
+ memcpy(&pos1, tmpl, sizeof(lfPOINT));
+ if(ssRef && cssRef >3)
+ ssRef[0].x = ssRef[0].y = ssRef[1].x = ssRef[1].y = -1;
+ return true;
+ case CMD_ARROW_TYPE:
+ if(tmpl) {
+ type &= ~0xff; type |= (*((int*)tmpl));
+ return true;
+ }
+ return false;
+ case CMD_SET_DATAOBJ:
+ Id = GO_ARROW;
+ data = (DataObj *)tmpl;
+ return true;
+ case CMD_UPDATE:
+ if(ssRef && cssRef >3 && data) {
+ data->GetValue(ssRef[0].y, ssRef[0].x, &pos1.fx);
+ data->GetValue(ssRef[1].y, ssRef[1].x, &pos1.fy);
+ data->GetValue(ssRef[2].y, ssRef[2].x, &pos2.fx);
+ data->GetValue(ssRef[3].y, ssRef[3].x, &pos2.fy);
+ return true;
+ }
+ return false;
+ case CMD_AUTOSCALE:
+ if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+ ((Plot*)parent)->CheckBounds(pos1.fx, pos1.fy);
+ ((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy);
+ return true;
+ }
+ break;
+ case CMD_MRK_DIRTY: //from Undo ?
+ case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ case CMD_MOVE:
+ bModified = true;
+ case CMD_UNDO_MOVE:
+ if(type & ARROW_UNITS) {
+ if(cmd == CMD_MOVE) Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
+ pos1.fx += ((lfPOINT*)tmpl)[0].fx; pos1.fy += ((lfPOINT*)tmpl)[0].fy;
+ pos2.fx += ((lfPOINT*)tmpl)[0].fx; pos2.fy += ((lfPOINT*)tmpl)[0].fy;
+ if(o){
+ o->StartPage(); parent->DoPlot(o); o->EndPage();
+ }
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
+void *
+Arrow::ObjThere(int x, int y)
+{
+ if(!IsInRect(&rDims, x, y)) return 0L;
+ if(IsCloseToLine(&pts[0], &pts[1], x, y) ||
+ IsCloseToLine(&pts[2], &pts[3], x, y) ||
+ IsCloseToLine(&pts[3], &pts[4], x, y)){
+ if(dh1 && dh1->ObjThere(x, y)) return dh1;
+ if(dh2 && dh2->ObjThere(x, y)) return dh2;
+ return this;
+ }
+ return 0L;
+}
+
+void
+Arrow::Track(POINT *p, anyOutput *o)
+{
+ POINT *tpts;
+ RECT old_rc;
+ int i;
+
+ if(o && (tpts = (POINT*)malloc(6*sizeof(POINT)))){
+ memcpy(&old_rc, &rDims, sizeof(rDims));
+ o->UpdateRect(&rDims, false);
+ for(i = 0; i < 5; i++) {
+ tpts[i].x = pts[i].x+p->x;
+ tpts[i].y = pts[i].y+p->y;
+ UpdateMinMaxRect(&rDims, tpts[i].x, tpts[i].y);
+ }
+ switch(type & 0xff) {
+ case ARROW_LINE:
+ o->ShowLine(tpts+2, 3, LineDef.color);
+ case ARROW_NOCAP:
+ o->ShowLine(tpts, 2, LineDef.color);
+ break;
+ case ARROW_TRIANGLE:
+ tpts[5].x = tpts[2].x; tpts[5].y = tpts[2].y;
+ o->ShowLine(tpts+2, 4, LineDef.color);
+ tpts[1].x = (tpts[2].x + tpts[4].x)>>1;
+ tpts[1].y = (tpts[2].y + tpts[4].y)>>1;
+ o->ShowLine(tpts, 2, LineDef.color);
+ break;
+ }
+ if(old_rc.left != rDims.left || old_rc.right != rDims.right || old_rc.top !=
+ rDims.top || old_rc.bottom != rDims.bottom)IncrementMinMaxRect(&rDims, 3);
+ free(tpts);
+ }
+}
+
+void
+Arrow::Redraw(anyOutput *o)
+{
+ FillDEF FillCap;
+
+ o->SetLine(&LineDef);
+ o->oSolidLine(pts);
+ switch(type & 0xff) {
+ case ARROW_NOCAP:
+ break;
+ case ARROW_LINE:
+ o->oSolidLine(pts+2);
+ o->oSolidLine(pts+3);
+ break;
+ case ARROW_TRIANGLE:
+ FillCap.type = FILL_NONE;
+ FillCap.color = LineDef.color;
+ FillCap.scale = 1.0f;
+ FillCap.hatch = 0L;
+ o->SetFill(&FillCap);
+ o->oPolygon(pts+2, 3);
+ break;
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// universal boxes
+Box::Box(GraphObj * par, DataObj *d, lfPOINT fp1, lfPOINT fp2, int which,
+ int xc1, int xr1, int yc1, int yr1, int xc2, int xr2,
+ int yc2, int yr2):GraphObj(par, d)
+{
+ FileIO(INIT_VARS);
+ memcpy(&pos1, &fp1, sizeof(lfPOINT));
+ memcpy(&pos2, &fp2, sizeof(lfPOINT));
+ type = which;
+ Id = GO_BOX;
+ if(xc1 >= 0 || xr1 >= 0 || yc1 >= 0 || yr1 >= 0 || xc2 >= 0 || xr2 >= 0 ||
+ yc2 >= 0 || yr2 >= 0) {
+ if(ssRef = (POINT*)malloc(sizeof(POINT)*4)) {
+ ssRef[0].x = xc1; ssRef[0].y = xr1;
+ ssRef[1].x = yc1; ssRef[1].y = yr1;
+ ssRef[2].x = xc2; ssRef[2].y = xr2;
+ ssRef[3].x = yc2; ssRef[3].y = yr2;
+ cssRef = 4;
+ }
+ }
+}
+
+Box::Box(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+Box::~Box()
+{
+ Command(CMD_FLUSH, 0L, 0L);
+}
+
+double
+Box::GetSize(int select)
+{
+ switch(select) {
+ case SIZE_XPOS:
+ return (pos1.fx + pos2.fx)/2.0;
+ case SIZE_YPOS:
+ return (pos1.fy + pos2.fy)/2.0;
+ }
+ return 1.0;
+}
+
+bool
+Box::SetSize(int select, double value)
+{
+ switch(select & 0xfff) {
+ case SIZE_BOX_LINE:
+ Outline.width = value;
+ return true;
+ case SIZE_BOX:
+ size = value;
+ return true;
+ }
+ return false;
+}
+
+bool
+Box::SetColor(int select, DWORD col)
+{
+ switch(select & 0xfff) {
+ case COL_BOX_LINE:
+ Outline.color = col;
+ return true;
+ }
+ return false;
+}
+
+void
+Box::DoPlot(anyOutput *o)
+{
+ double si, csi, tmp, fix1, fiy1, fix2, fiy2, fsize, dx, dy;
+
+ if(!parent || !o || size <= 0.001) return;
+ o->SetLine(&Outline);
+ o->SetFill(&Fill);
+ //calculate coordinates
+ fix1 = o->fx2fix(pos1.fx); fix2 = o->fx2fix(pos2.fx);
+ fiy1 = o->fy2fiy(pos1.fy); fiy2 = o->fy2fiy(pos2.fy);
+ //calculate sine and cosine
+ si = fiy1-fiy2;
+ tmp = fix2 - fix1;
+ si = si/sqrt(si*si + tmp*tmp);
+ csi = fix2-fix1;
+ tmp = fiy2 - fiy1;
+ csi = csi/sqrt(csi*csi + tmp*tmp);
+ if(type & BAR_WIDTHDATA) { //use e.g. for density distribution
+ dx = si * size; dy = csi * size;
+ pts[0].x = o->fx2ix(pos1.fx + dx); pts[1].x = o->fx2ix(pos2.fx + dx);
+ pts[2].x = o->fx2ix(pos2.fx - dx); pts[3].x = o->fx2ix(pos1.fx - dx);
+ pts[0].y = o->fy2iy(pos1.fy + dy); pts[1].y = o->fy2iy(pos2.fy + dy);
+ pts[2].y = o->fy2iy(pos2.fy - dy); pts[3].y = o->fy2iy(pos1.fy - dy);
+ }
+ else if(type & BAR_RELWIDTH) {
+ if(!parent) return;
+ fsize = parent->GetSize(pos1.fy == pos2.fy ? SIZE_BOXMINY : SIZE_BOXMINX);
+ fsize = fsize * size /200.0;
+ dx = si * fsize; dy = csi * fsize;
+ pts[0].x = o->fx2ix(pos1.fx + dx); pts[1].x = o->fx2ix(pos2.fx + dx);
+ pts[2].x = o->fx2ix(pos2.fx - dx); pts[3].x = o->fx2ix(pos1.fx - dx);
+ pts[0].y = o->fy2iy(pos1.fy + dy); pts[1].y = o->fy2iy(pos2.fy + dy);
+ pts[2].y = o->fy2iy(pos2.fy - dy); pts[3].y = o->fy2iy(pos1.fy - dy);
+ }
+ else {
+ dx = o->un2fix(si*size/2.0); dy = o->un2fiy(csi*size/2.0);
+ pts[0].x = iround(fix1 + dx); pts[1].x = iround(fix2 + dx);
+ pts[2].x = iround(fix2 - dx); pts[3].x = iround(fix1 - dx);
+ pts[0].y = iround(fiy1 + dy); pts[1].y = iround(fiy2 + dy);
+ pts[2].y = iround(fiy2 - dy); pts[3].y = iround(fiy1 - dy);
+ }
+ pts[4].x = pts[0].x; pts[4].y = pts[0].y; //close polygon
+ if(pts[0].x == pts[1].x){
+ o->oRectangle(pts[3].x, pts[3].y, pts[1].x, pts[1].y, name);
+ }
+ else {
+ o->oPolygon(pts, 5);
+ }
+ SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[2].x, pts[2].y);
+ UpdateMinMaxRect(&rDims, pts[1].x, pts[1].y);
+ UpdateMinMaxRect(&rDims, pts[3].x, pts[3].y);
+}
+
+void
+Box::DoMark(anyOutput *o, bool mark)
+{
+ InvertPolygon(pts, 5, &Outline, &Fill, &rDims, o, mark);
+}
+
+bool
+Box::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ POINT p;
+
+ switch (cmd) {
+ case CMD_FLUSH:
+ if(ssRef) free(ssRef); ssRef = 0L;
+ if(name)free(name); name = 0L;
+ return true;
+ case CMD_LEGEND:
+ if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+ ((Legend*)tmpl)->HasFill(&Outline, &Fill);
+ break;
+ case CMD_MRK_DIRTY: case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
+ if(pts[0].x == pts[1].x || pts[0].y == pts[1].y) {
+ o->ShowMark(&rDims, MRK_INVERT);
+ CurrGO = this;
+ return true;
+ }
+ else {
+ p.x = mev->x; p.y = mev->y;
+ if(IsInPolygon(&p, pts, 5)) {
+ o->ShowMark(this, MRK_GODRAW);
+ return true;
+ }
+ }
+ }
+ break;
+ }
+ return false;
+ case CMD_SET_DATAOBJ:
+ Id = GO_BOX;
+ data = (DataObj *)tmpl;
+ return true;
+ case CMD_UPDATE:
+ if(ssRef && cssRef >3 && data) {
+ data->GetValue(ssRef[0].y, ssRef[0].x, &pos1.fx);
+ data->GetValue(ssRef[1].y, ssRef[1].x, &pos1.fy);
+ data->GetValue(ssRef[2].y, ssRef[2].x, &pos2.fx);
+ data->GetValue(ssRef[3].y, ssRef[3].x, &pos2.fy);
+ return true;
+ }
+ return false;
+ case CMD_BOX_TYPE:
+ if(tmpl)type = *((int*)tmpl);
+ return true;
+ case CMD_BOX_FILL:
+ if(tmpl) {
+ memcpy(&Fill, tmpl, sizeof(FillDEF));
+ if(Fill.hatch) memcpy(&Hatchline, Fill.hatch, sizeof(LineDEF));
+ Fill.hatch = &Hatchline;
+ return true;
+ }
+ break;
+ case CMD_AUTOSCALE:
+ if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+ ((Plot*)parent)->CheckBounds(pos1.fx, pos1.fy);
+ ((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy);
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// whisker
+Whisker::Whisker(GraphObj *par, DataObj *d, lfPOINT fp1, lfPOINT fp2, int which,
+ int xc1, int xr1, int yc1, int yr1, int xc2, int xr2,
+ int yc2, int yr2):GraphObj(par, d)
+{
+ FileIO(INIT_VARS);
+ memcpy(&pos1, &fp1, sizeof(lfPOINT));
+ memcpy(&pos2, &fp2, sizeof(lfPOINT));
+ type = which;
+ Id = GO_WHISKER;
+ if(xc1 >= 0 || xr1 >= 0 || yc1 >= 0 || yr1 >= 0 || xc2 >= 0 || xr2 >= 0 ||
+ yc2 >= 0 || yr2 >= 0) {
+ if(ssRef = (POINT*)malloc(sizeof(POINT)*4)) {
+ ssRef[0].x = xc1; ssRef[0].y = xr1;
+ ssRef[1].x = yc1; ssRef[1].y = yr1;
+ ssRef[2].x = xc2; ssRef[2].y = xr2;
+ ssRef[3].x = yc2; ssRef[3].y = yr2;
+ cssRef = 4;
+ }
+ }
+}
+
+Whisker::Whisker(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+bool
+Whisker::SetSize(int select, double value)
+{
+ switch(select & 0xfff) {
+ case SIZE_WHISKER:
+ size = value;
+ return true;
+ case SIZE_WHISKER_LINE:
+ LineDef.width = value;
+ return true;
+ }
+ return false;
+}
+
+bool
+Whisker::SetColor(int select, DWORD col)
+{
+ switch(select & 0xfff) {
+ case COL_WHISKER:
+ LineDef.color = col;
+ return true;
+ }
+ return false;
+}
+
+void
+Whisker::DoPlot(anyOutput *o)
+{
+ double si, csi, tmp, fix1, fiy1, fix2, fiy2, dx, dy;
+ int i;
+
+ fix1 = o->fx2fix(pos1.fx); fix2 = o->fx2fix(pos2.fx);
+ fiy1 = o->fy2fiy(pos1.fy); fiy2 = o->fy2fiy(pos2.fy);
+ if(fix1 == fix2 && fiy1 == fiy2) return; //zero length
+ pts[2].x = iround(fix1); pts[3].x = iround(fix2);
+ pts[2].y = iround(fiy1); pts[3].y = iround(fiy2);
+ //calculate sine and cosine
+ si = fiy1-fiy2;
+ tmp = fix2 - fix1;
+ si = si/sqrt(si*si + tmp*tmp);
+ csi = fix2-fix1;
+ tmp = fiy2 - fiy1;
+ csi = csi/sqrt(csi*csi + tmp*tmp);
+ dx = o->un2fix(si*size/2.0);
+ dy = o->un2fiy(csi*size/2.0);
+ //calc cap
+ pts[0].x = iround(fix1 - dx); pts[4].x = iround(fix2 - dx);
+ pts[0].y = iround(fiy1 - dy); pts[4].y = iround(fiy2 - dy);
+ pts[1].x = iround(fix1 + dx); pts[5].x = iround(fix2 + dx);
+ pts[1].y = iround(fiy1 + dy); pts[5].y = iround(fiy2 + dy);
+ //draw whisker
+ SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+ UpdateMinMaxRect(&rDims, pts[4].x, pts[4].y);
+ UpdateMinMaxRect(&rDims, pts[5].x, pts[5].y);
+ IncrementMinMaxRect(&rDims, 3+(o->un2ix(LineDef.width)<<1));
+ o->SetLine(&LineDef);
+ switch(type & 0x0f) {
+ case 2:
+ pts[4].x = pts[3].x; pts[4].y = pts[3].y;
+ pts[1].x = pts[2].x; pts[1].y = pts[2].y;
+ case 3:
+ if((type & 0x0f) == 3){
+ pts[5].x = pts[3].x; pts[5].y = pts[3].y;
+ pts[0].x = pts[2].x; pts[0].y = pts[2].y;
+ }
+ case 0:
+ for(i = 0; i < 5; i+=2) o->oSolidLine(pts+i);
+ break;
+ case 1:
+ pts[4].x = pts[5].x = pts[3].x; pts[4].y = pts[5].y = pts[3].y;
+ pts[1].x = pts[0].x = pts[2].x; pts[1].y = pts[0].y = pts[2].y;
+ o->oSolidLine(pts+2);
+ break;
+ }
+}
+
+void
+Whisker::DoMark(anyOutput *o, bool mark)
+{
+ LineDEF OldLine;
+ int i;
+
+ memcpy(&OldLine, &LineDef, sizeof(LineDEF));
+ if(mark) {
+ LineDef.color = 0x00000000L;
+ LineDef.width = 1.2f;
+ o->SetLine(&LineDef);
+ for(i = 0; i < 5; i+=2) o->oSolidLine(pts+i);
+ LineDef.width = 0.4f;
+ LineDef.color = OldLine.color ^ 0x00ffffffL;
+ o->SetLine(&LineDef);
+ for(i = 0; i < 5; i+=2) o->oSolidLine(pts+i);
+ }
+ else {
+ LineDef.color = 0x00ffffffL; //DEBUG: assume white background
+ LineDef.width = 1.2f;
+ o->SetLine(&LineDef);
+ for(i = 0; i < 5; i+=2) o->oSolidLine(pts+i);
+ LineDef.width = OldLine.width;
+ LineDef.color = OldLine.color;
+ o->SetLine(&LineDef);
+ for(i = 0; i < 5; i+=2) o->oSolidLine(pts+i);
+ }
+ memcpy(&LineDef, &OldLine, sizeof(LineDEF));
+ o->UpdateRect(&rDims, false);
+}
+
+bool
+Whisker::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+
+ switch (cmd) {
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
+ if(IsCloseToLine(&pts[2], &pts[3], mev->x, mev->y) ||
+ IsCloseToLine(&pts[0], &pts[1], mev->x, mev->y) ||
+ IsCloseToLine(&pts[4], &pts[5], mev->x, mev->y)) {
+ o->ShowMark(this, MRK_GODRAW);
+ return true;
+ }
+ }
+ break;
+ }
+ return false;
+ case CMD_SET_DATAOBJ:
+ Id = GO_WHISKER;
+ data = (DataObj *)tmpl;
+ return true;
+ case CMD_UPDATE:
+ if(ssRef && cssRef >3 && data) {
+ data->GetValue(ssRef[0].y, ssRef[0].x, &pos1.fx);
+ data->GetValue(ssRef[1].y, ssRef[1].x, &pos1.fy);
+ data->GetValue(ssRef[2].y, ssRef[2].x, &pos2.fx);
+ data->GetValue(ssRef[3].y, ssRef[3].x, &pos2.fy);
+ return true;
+ }
+ return false;
+ case CMD_AUTOSCALE:
+ if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+ ((Plot*)parent)->CheckBounds(pos1.fx, pos1.fy);
+ ((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy);
+ return true;
+ }
+ break;
+ case CMD_WHISKER_STYLE:
+ if(tmpl) type = *((int*)tmpl);
+ return true;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// drop line
+DropLine::DropLine(GraphObj *par, DataObj *d, double x, double y, int which, int xc,
+ int xr, int yc, int yr):GraphObj(par, d)
+{
+ FileIO(INIT_VARS);
+ fPos.fx = x;
+ fPos.fy = y;
+ type = which;
+ Id = GO_DROPLINE;
+ if(xc >= 0 && xr >= 0 && yc >= 0 && yr >= 0) {
+ if(ssRef = (POINT*)malloc(sizeof(POINT)*2)) {
+ ssRef[0].x = xc; ssRef[0].y = xr;
+ ssRef[1].x = yc; ssRef[1].y = yr;
+ cssRef = 2;
+ }
+ }
+ bModified = false;
+}
+
+DropLine::DropLine(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+ bModified = false;
+}
+
+DropLine::~DropLine()
+{
+ if(bModified) Undo.InvalidGO(this);
+ if(ssRef) free(ssRef);
+ ssRef = 0L;
+}
+
+void
+DropLine::DoPlot(anyOutput *o)
+{
+ int tmp;
+
+ o->RLP.fp = 0.0f; //reset line pattern start
+ if(parent) {
+ pts[0].x = pts[1].x = pts[2].x = pts[3].x = o->fx2ix(fPos.fx);
+ pts[0].y = pts[1].y = pts[2].y = pts[3].y = o->fy2iy(fPos.fy);
+ if(type & DL_LEFT) {
+ tmp = o->fx2ix(parent->GetSize(SIZE_BOUNDS_LEFT));
+ if(tmp < pts[0].x) pts[0].x = tmp;
+ if(tmp > pts[1].x) pts[1].x = tmp;
+ }
+ if(type & DL_RIGHT) {
+ tmp = o->fx2ix(parent->GetSize(SIZE_BOUNDS_RIGHT));
+ if(tmp < pts[0].x) pts[0].x = tmp;
+ if(tmp > pts[1].x) pts[1].x = tmp;
+ }
+ if(type & DL_YAXIS) {
+ tmp = iround(parent->GetSize(SIZE_YAXISX));
+ if(tmp < pts[0].x) pts[0].x = tmp;
+ if(tmp > pts[1].x) pts[1].x = tmp;
+ }
+ if(type & DL_TOP) {
+ tmp = o->fy2iy(parent->GetSize(SIZE_BOUNDS_TOP));
+ if(tmp < pts[2].y) pts[2].y = tmp;
+ if(tmp > pts[3].y) pts[3].y = tmp;
+ }
+ if(type & DL_BOTTOM) {
+ tmp = o->fy2iy(parent->GetSize(SIZE_BOUNDS_BOTTOM));
+ if(tmp < pts[2].y) pts[2].y = tmp;
+ if(tmp > pts[3].y) pts[3].y = tmp;
+ }
+ if(type & DL_XAXIS) {
+ tmp = iround(parent->GetSize(SIZE_XAXISY));
+ if(tmp < pts[2].y) pts[2].y = tmp;
+ if(tmp > pts[3].y) pts[3].y = tmp;
+ }
+ SetMinMaxRect(&rDims, pts[0].x, pts[2].y, pts[1].x, pts[3].y);
+ IncrementMinMaxRect(&rDims, 3);
+ o->SetLine(&LineDef);
+ o->oPolyline(pts, 2);
+ o->oPolyline(pts+2, 2);
+ }
+}
+
+void
+DropLine::DoMark(anyOutput *o, bool mark)
+{
+
+ InvertLine(pts, 2, &LineDef, 0L, o, mark);
+ InvertLine(pts+2, 2, &LineDef, &rDims, o, mark);
+}
+
+bool
+DropLine::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+
+ switch (cmd) {
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
+ if(IsCloseToLine(&pts[0], &pts[1], mev->x, mev->y) ||
+ IsCloseToLine(&pts[2], &pts[3], mev->x, mev->y)) {
+ o->ShowMark(this, MRK_GODRAW);
+ return true;
+ }
+ }
+ break;
+ }
+ return false;
+ case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ case CMD_DL_LINE:
+ if(tmpl) memcpy(&LineDef, tmpl, sizeof(LineDEF));
+ return true;
+ case CMD_DL_TYPE:
+ if(tmpl)type = *((int*)tmpl);
+ return true;
+ case CMD_SET_DATAOBJ:
+ Id = GO_DROPLINE;
+ data = (DataObj *)tmpl;
+ return true;
+ case CMD_UPDATE:
+ if(ssRef && cssRef >1 && data) {
+ data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
+ data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
+ return true;
+ }
+ return false;
+ case CMD_AUTOSCALE:
+ if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+ ((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// define a spherical scanline used for clipping spheres
+sph_scanline::sph_scanline(POINT3D *center, int radius, bool bVert):GraphObj(0, 0)
+{
+ Id = GO_SPHSCANL;
+ rad = radius >= 0 ? radius : -radius;
+ memcpy(&p1, center, sizeof(POINT3D)); memcpy(&p2, center, sizeof(POINT3D));
+ memcpy(¢, center, sizeof(POINT3D));
+ if(vert = bVert) {
+ p1.y -= rad; p2.y += rad;
+ }
+ else {
+ p1.x -= rad; p2.x += rad;
+ }
+ if(p1.x < 1) p1.x = 1; if(p1.y < 1) p1.y = 1;
+ if(p2.x < p1.x) p2.x = p1.x; if(p2.y < p1.y) p2.y = p1.y;
+ bValid1 = bValid2 = true;
+}
+
+bool
+sph_scanline::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ switch(cmd) {
+ case CMD_ADDTOLINE:
+ if(bValid1 && tmpl){
+ memcpy(&p2, tmpl, sizeof(POINT3D));
+ bValid2 = true;
+ return true;
+ }
+ break;
+ case CMD_STARTLINE:
+ if(!bValid1 && tmpl){
+ memcpy(&p1, tmpl, sizeof(POINT3D));
+ bValid1 = true;
+ }
+ break;
+ return true;
+ }
+ return false;
+}
+
+void
+sph_scanline::DoClip(GraphObj *co)
+{
+ POINT3D *pla;
+ int np, i;
+
+ if(!bValid1 || !bValid2) return;
+ switch(co->Id){
+ case GO_SPHERE:
+ bValid1 = bValid2 = false;
+ clip_sphline_sphere(this, &p1, &p2, ¢, rad, iround(co->GetSize(SIZE_RADIUS1)),
+ iround(co->GetSize(SIZE_XPOS)), iround(co->GetSize(SIZE_YPOS)),
+ iround(co->GetSize(SIZE_ZPOS)));
+ break;
+ case GO_PLANE:
+ for(i=0; ((plane*)co)->GetPolygon(&pla, &np, i); i++) {
+ bValid1 = bValid2 = false;
+ clip_sphline_plane(this, &p1, &p2, ¢, rad, pla, np, ((plane*)co)->GetVec());
+ }
+ break;
+ }
+}
+
+bool
+sph_scanline::GetPoint(POINT *p, int sel)
+{
+ if(!bValid1 || !bValid2) {
+ p->x = p->y = 0;
+ return false;
+ }
+ switch(sel) {
+ case 1:
+ p->x = p1.x; p->y = p1.y;
+ return true;
+ case 2:
+ p->x = p2.x; p->y = p2.y;
+ return true;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Sphere: a symbol in three dimensional space
+Sphere::Sphere(GraphObj *par, DataObj *d, int sel, double x, double y, double z,
+ double r, int xc, int xr, int yc, int yr, int zc, int zr, int rc, int rr)
+ :GraphObj(par, d)
+{
+ FileIO(INIT_VARS);
+ Id = GO_SPHERE;
+ fPos.fx = x; fPos.fy = y; fPos.fz = z; size = r;
+ if(xc >=0 || xr >=0 || yc >=0 || yr >=0 || zc >=0 || zr >=0 || rc >=0 || rr >=0) {
+ if(ssRef = (POINT*)malloc(sizeof(POINT)*4)) {
+ ssRef[0].x = xc; ssRef[0].y = xr;
+ ssRef[1].x = yc; ssRef[1].y = yr;
+ ssRef[2].x = zc; ssRef[2].y = zr;
+ ssRef[3].x = rc; ssRef[3].y = rr;
+ cssRef = 4;
+ }
+ }
+ type = sel;
+ bModified = false;
+}
+
+Sphere::Sphere(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+ bModified = false;
+}
+
+Sphere::~Sphere()
+{
+ if(bModified) Undo.InvalidGO(this);
+ Command(CMD_FLUSH, 0L, 0L);
+}
+
+double
+Sphere::GetSize(int select)
+{
+ switch(select) {
+ case SIZE_MIN_X: return fip.fx - (double)rx;
+ case SIZE_MAX_X: return fip.fx + (double)rx;
+ case SIZE_MIN_Y: return fip.fy - (double)ry;
+ case SIZE_MAX_Y: return fip.fy + (double)ry;
+ case SIZE_MIN_Z: return fip.fz - (double)rx;
+ case SIZE_MAX_Z: return fip.fz + (double)rx;
+ case SIZE_XPOS: return fip.fx;
+ case SIZE_YPOS: return fip.fy;
+ case SIZE_ZPOS: return fip.fz;
+ case SIZE_RADIUS1: case SIZE_RADIUS2: return (double)rx;
+ case SIZE_XCENT: return fPos.fx;
+ case SIZE_YCENT: return fPos.fy;
+ case SIZE_ZCENT: return fPos.fz;
+ case SIZE_DRADIUS: return size;
+ case SIZE_SYMBOL:
+ if(!type) return size;
+ else return defs.GetSize(SIZE_SYMBOL);
+ case SIZE_SYM_LINE: return Line.width;
+ }
+ return 0.0;
+}
+
+bool
+Sphere::SetSize(int select, double value)
+{
+ switch(select & 0xfff) {
+ case SIZE_SYMBOL: size = value; break;
+ case SIZE_SYM_LINE: Line.width = value; break;
+ }
+ return true;
+}
+
+DWORD
+Sphere::GetColor(int select)
+{
+ switch(select) {
+ case COL_SYM_LINE: return Line.color;
+ case COL_SYM_FILL: return Fill.color;
+ default: return defs.Color(select);
+ }
+}
+
+bool
+Sphere::SetColor(int select, DWORD col)
+{
+ switch(select & 0xfff) {
+ case COL_SYM_LINE: Line.color = col; break;
+ case COL_SYM_FILL: Fill.color = col; break;
+ }
+ return true;
+}
+
+void
+Sphere::DoPlot(anyOutput *o)
+{
+ int i;
+
+ if(size <= 0.001 || !o) return;
+ if(!o->fvec2ivec(&fPos, &fip)) return;
+ bDrawDone = false;
+ if(scl){
+ for(i = 0; i < nscl; i++) if(scl[i]) delete(scl[i]);
+ free(scl);
+ scl = 0L; nscl = 0;
+ }
+ ix = iround(fip.fx); iy = iround(fip.fy);
+ switch (type) {
+ case 1:
+ rx = ry = iround(size * 0.5 * o->ddx); break;
+ case 2:
+ rx = ry = iround(size * 0.5 * o->ddy); break;
+ case 3:
+ rx = ry = iround(size * 0.5 * o->ddz); break;
+ default:
+ rx = o->un2ix(size/2.0); ry = o->un2iy(size/2.0);
+ type = 0;
+ break;
+ }
+ rDims.left = ix - rx; rDims.right = ix + rx;
+ rDims.top = iy - ry; rDims.bottom = iy + ry;
+ if(o->VPscale > 1.5 && (
+ (rDims.right < defs.clipRC.left) || (rDims.left > defs.clipRC.right) ||
+ (rDims.bottom < defs.clipRC.top) || (rDims.top > defs.clipRC.bottom))){
+ bDrawDone = true; return;
+ }
+ if(parent && parent->Command(CMD_SET_GO3D, this, o)) return;
+ Command(CMD_REDRAW, 0L, o);
+}
+
+bool
+Sphere::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ int i;
+
+ switch (cmd) {
+ case CMD_FLUSH:
+ if(ssRef) free(ssRef); ssRef = 0L;
+ if(name) free(name); name = 0L;
+ if(scl){
+ for(i = 0; i < nscl; i++) if(scl[i]) delete(scl[i]);
+ free(scl);
+ scl = 0L; nscl = 0;
+ }
+ return true;
+ case CMD_SYM_FILL:
+ if(tmpl) memcpy(&Fill, tmpl, sizeof(FillDEF));
+ return true;
+ case CMD_MRK_DIRTY:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ case CMD_SET_DATAOBJ:
+ Id = GO_SPHERE;
+ data = (DataObj *)tmpl;
+ return true;
+ case CMD_REDRAW:
+ //Note: this command is issued either by Undo (no output given) or
+ // by Plot3D::DoPlot after sorting all objects (output specified)
+ if(!parent) return false;
+ if(!o) return parent->Command(cmd, tmpl, o);
+ if(bDrawDone) return false;
+ bDrawDone = true;
+ if(scl) DrawPG(o, 0);
+ else {
+ o->SetLine(&Line); o->SetFill(&Fill);
+ if(Fill.type & FILL_LIGHT3D) o->oSphere(ix, iy, rx, 0L, 0, 0L);
+ else o->oCircle(ix-rx, iy-ry, ix+rx+1, iy+ry+1, name);
+ }
+ rx--;ry--; //smaller marking rectangle
+ rDims.left = ix-rx-1; rDims.right = ix+rx+1;
+ rDims.top = iy-ry-1; rDims.bottom = iy+ry+1;
+ return true;
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
+ o->ShowMark(&rDims, MRK_INVERT);
+ CurrGO = this;
+ return true;
+ }
+ break;
+ }
+ break;
+ case CMD_UPDATE:
+ if(ssRef && cssRef >1 && data) {
+ data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
+ data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
+ data->GetValue(ssRef[2].y, ssRef[2].x, &fPos.fz);
+ if(cssRef >3) data->GetValue(ssRef[3].y, ssRef[3].x, &size);
+ return true;
+ }
+ return false;
+ case CMD_CLIP:
+ if(co = (GraphObj*)tmpl){
+ switch(co->Id) {
+ case GO_PLANE:
+ case GO_SPHERE:
+ DoClip(co);
+ break;
+ }
+ }
+ return false;
+ case CMD_AUTOSCALE:
+ if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+ ((Plot*)parent)->CheckBounds3D(fPos.fx, fPos.fy, fPos.fz);
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
+void
+Sphere::DoClip(GraphObj *co)
+{
+ RECT cliprc;
+ double d, d1;
+ POINT3D cscl;
+ int x, y, q, di, de, lim, cx, cy;
+ int i;
+
+ if(co && co->Id == GO_SPHERE) {
+ if(co->GetSize(SIZE_ZPOS) > fip.fz) return;
+ d1 = (d = co->GetSize(SIZE_XPOS) - fip.fx) * d;
+ d1 += (d = co->GetSize(SIZE_YPOS) - fip.fy) * d;
+ d1 = sqrt(d1 + (d = co->GetSize(SIZE_ZPOS) - fip.fz) * d);
+ if(d1 >= (co->GetSize(SIZE_RADIUS1) + rx))return;
+ }
+ else {
+ cliprc.left = iround(co->GetSize(SIZE_MIN_X));
+ cliprc.right = iround(co->GetSize(SIZE_MAX_X));
+ cliprc.top = iround(co->GetSize(SIZE_MIN_Y));
+ cliprc.bottom = iround(co->GetSize(SIZE_MAX_Y));
+ if(!OverlapRect(&rDims, &cliprc))return;
+ }
+ //use a list of horizontal scanlines created by a circular Bresenham's algorithm
+ //Ref: C. Montani, R. Scopigno (1990) "Speres-To-Voxel Conversion", in:
+ // Graphic Gems (A.S. Glassner ed.) Academic Press, Inc.;
+ // ISBN 0-12-288165-5
+ if(!scl && (scl = (sph_scanline**)calloc(rx*7+2, sizeof(sph_scanline*)))) {
+ cscl.z = iround(fip.fz); nscl = 0;
+ for(q = 0; q < 2; q++) {
+ x = lim = 0; y = rx; di = 2*(1-rx);
+ while( y >= lim) {
+ if(di < 0) {
+ de = 2*di + 2*y -1;
+ if(de > 0) {
+ x++; y--; di += (2*x -2*y +2);
+ }
+ else {
+ x++; di += (2*x +1);
+ }
+ }
+ else {
+ de = 2*di -2*x -1;
+ if(de > 0) {
+ y--; di += (-2*y +1);
+ }
+ else {
+ x++; y--; di += (2*x -2*y +2);
+ }
+ }
+ switch(q) {
+ case 0:
+ cy = rx - y; cx = x;
+ break;
+ case 1:
+ cy = rx + x; cx = y;
+ break;
+ }
+ cscl.y = iround(fip.fy); cscl.x = iround(fip.fx);
+ cscl.y = cscl.y - rx + cy;
+ if(cx > 1) scl[nscl++] = new sph_scanline(&cscl, cx, false);
+ }
+ }
+ }
+ if(!scl) return;
+ //do clip for every scanline
+ for(i = 0; i < nscl; i++) if(scl[i]) scl[i]->DoClip(co);
+}
+
+void
+Sphere::DrawPG(anyOutput *o, int start)
+{
+ POINT *pts, np;
+ long cp = 0;
+ int i = start, step = 1;
+
+ if(!o || !scl ||!nscl) return;
+ if((pts = (POINT*)calloc(nscl*2, sizeof(POINT)))) {
+ do {
+ if(scl[i]) {
+ if(step > 0) scl[i]->GetPoint(&np, 1);
+ else scl[i]->GetPoint(&np, 2);
+ if(np.x && np.y){
+ AddToPolygon(&cp, pts, &np);
+ }
+ else if(cp){
+ if(step > 0) DrawPG(o, i); //split sphere
+ step = -1;
+ }
+ }
+ if(i == nscl && step > 0) step = -1;
+ else i += step;
+ }while(i > start);
+ }
+ o->SetLine(&Line); o->SetFill(&Fill);
+ if(cp) o->oSphere(ix, iy, rx, pts, cp, name);
+ free(pts);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// plane: utility object to draw a flat plane in 3D space
+plane::plane(GraphObj *par, DataObj *d, fPOINT3D *pts, int nPts, LineDEF *line,
+ FillDEF *fill):GraphObj(par, d)
+{
+ int i;
+ long area;
+ double vlength, v1[3], v2[3], vp[3], area1;
+ bool v_valid = false;
+
+ nli = n_ipts = n_lines = 0;
+ nldata = 0L; ldata = 0L; co = 0L; lines = 0L; PlaneVec = 0L;
+ Id = GO_PLANE; totalArea = 0;
+ memcpy(&Line, line, sizeof(LineDEF));
+ memcpy(&Fill, fill, sizeof(FillDEF));
+ rDims.left = rDims.right = rDims.top = rDims.bottom = 0;
+ if(nPts > 2 && (ldata =(POINT3D**)calloc(1, sizeof(POINT3D*))) &&
+ (ldata[0] = (POINT3D *)calloc(nPts+1, sizeof(POINT3D))) &&
+ (nldata = (int*)calloc(1, sizeof(int))) &&
+ (ipts = (POINT*)calloc(nPts, sizeof(POINT)))){
+ for(i = 0; i < nPts; i++) {
+ ipts[i].x = ldata[0][i].x = iround(pts[i].fx);
+ ipts[i].y = ldata[0][i].y = iround(pts[i].fy);
+ ldata[0][i].z = iround(pts[i].fz);
+ }
+ nldata[0] = nPts; nli = 1; n_ipts = nPts;
+ xBounds.fx = xBounds.fy = pts[0].fx; yBounds.fx = yBounds.fy = pts[0].fy;
+ zBounds.fx = zBounds.fy = pts[0].fz;
+ rDims.left = rDims.right = ipts[0].x; rDims.top = rDims.bottom = ipts[0].y;
+ for(i = 1; i < nPts; i++){
+ UpdateMinMaxRect(&rDims, ipts[i].x, ipts[i].y);
+ if(pts[i].fx < xBounds.fx) xBounds.fx = pts[i].fx;
+ if(pts[i].fx > xBounds.fy) xBounds.fy = pts[i].fx;
+ if(pts[i].fy < yBounds.fx) yBounds.fx = pts[i].fy;
+ if(pts[i].fy > yBounds.fy) yBounds.fy = pts[i].fy;
+ if(pts[i].fz < zBounds.fx) zBounds.fx = pts[i].fz;
+ if(pts[i].fz > zBounds.fy) zBounds.fy = pts[i].fz;
+ }
+ //test if plane vertical
+ area1 = (xBounds.fx - xBounds.fy) * (yBounds.fx - yBounds.fy);
+ for(area = 0, i = 1; i < nPts; i++) {
+ area += (ipts[i].x - ipts[i-1].x) * ((ipts[i].y + ipts[i-1].y)>>1);
+ }
+ totalArea= area = abs(area);
+ area1 = area ? fabs(area1/area) : 101.0;
+ if(area < 100 && area1 > 100.0) { //its small or vertical !
+ if(lines=(line_segment**)calloc(nPts, sizeof(line_segment*))){
+ for(i = 1; i < nPts; i++) {
+ lines[i-1] = new line_segment(par, d, line, &ldata[0][i-1], &ldata[0][i]);
+ }
+ n_lines = nPts-1;
+ }
+ }
+ else { //for a visible plane get vector perpendicular to plane
+ for (i = 1; i < (nPts-1); i++) {
+ v1[0] = pts[i].fx - pts[i-1].fx; v1[1] = pts[i].fy - pts[i-1].fy;
+ v1[2] = pts[i].fz - pts[i-1].fz; v2[0] = pts[i+1].fx - pts[i].fx;
+ v2[1] = pts[i+1].fy - pts[i].fy; v2[2] = pts[i+1].fz - pts[i].fz;
+ vp[0] = v1[1]*v2[2] - v1[2]*v2[1]; vp[1] = v1[2]*v2[0] - v1[0]*v2[2];
+ vp[2] = v1[0]*v2[1] - v1[1]*v2[0];
+ vlength = sqrt(vp[0]*vp[0]+vp[1]*vp[1]+vp[2]*vp[2]);
+ if(v_valid = (vlength > 100.0)) break;
+ }
+ if(v_valid && (PlaneVec = (double*)malloc(4 * sizeof(double)))) {
+ PlaneVec[0] = vp[0]/vlength; PlaneVec[1] = vp[1]/vlength;
+ PlaneVec[2] = -vp[2]/vlength;
+ PlaneVec[3] = PlaneVec[0] * pts[i].fx + PlaneVec[1] * pts[i].fy - PlaneVec[2] * pts[i].fz;
+ }
+ }
+ }
+}
+
+plane::~plane()
+{
+ int i;
+
+ if(ldata) {
+ for(i = 0; i < nli; i++) if(ldata[i]) free(ldata[i]);
+ free(ldata); ldata = 0L; nli = 0;
+ }
+ if(lines) {
+ for(i = 0; i < n_lines; i++) if(lines[i]) delete(lines[i]);
+ free(lines); lines = 0L; n_lines = 0;
+ }
+ if(nldata) free(nldata); nldata = 0L;
+ if(ipts) free(ipts); ipts = 0L;
+ if(PlaneVec) free(PlaneVec); PlaneVec = 0L;
+}
+
+double
+plane::GetSize(int select)
+{
+ switch(select) {
+ case SIZE_MIN_X: return xBounds.fx;
+ case SIZE_MAX_X: return xBounds.fy;
+ case SIZE_MIN_Y: return yBounds.fx;
+ case SIZE_MAX_Y: return yBounds.fy;
+ case SIZE_MIN_Z: return zBounds.fx;
+ case SIZE_MAX_Z: return zBounds.fy;
+ }
+ return 0.0;
+}
+
+void
+plane::DoPlot(anyOutput *o)
+{
+ int i;
+
+ bDrawDone = bReqPoint = false;
+ if(Fill.type & FILL_LIGHT3D){
+ Fill.color = o->VecColor(PlaneVec, Fill.color2, Fill.color);
+ Fill.type &= ~FILL_LIGHT3D;
+ }
+ if(o->VPscale > 1.5 && (
+ //ignore objects outside the display ara
+ (rDims.right < defs.clipRC.left) || (rDims.left > defs.clipRC.right) ||
+ (rDims.bottom < defs.clipRC.top) || (rDims.top > defs.clipRC.bottom))){
+ bDrawDone = true; return;
+ }
+ if(lines) {
+ //draw line segments for vertical plane
+ for(i = 0; i < n_lines; i++) if(lines[i]) lines[i]->DoPlot(o);
+ bDrawDone = true; return;
+ }
+ if(parent && parent->Command(CMD_SET_GO3D, this, o)) return;
+ Command(CMD_REDRAW, 0L, o);
+}
+
+void
+plane::DoMark(anyOutput *o, bool mark)
+{
+ FillDEF tmpfill;
+ LineDEF tmpline;
+
+ memcpy(&tmpfill, &Fill, sizeof(FillDEF));
+ memcpy(&tmpline, &Line, sizeof(LineDEF));
+ if(mark){
+ tmpfill.color ^= 0x00ffffffL; tmpline.color ^= 0x00ffffffL;
+ }
+ o->SetLine(&tmpline); o->SetFill(&tmpfill);
+ o->oPolygon(ipts, n_ipts);
+}
+
+bool
+plane::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ POINT *pt;
+ POINT3D *ap;
+ int i, j;
+
+ switch (cmd) {
+ case CMD_MOUSE_EVENT:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ case CMD_REDRAW:
+ if(bDrawDone) return false;
+ bDrawDone = true;
+ if(o && data && nldata){
+ o->SetLine(&Line); o->SetFill(&Fill);
+ for(i = 0; i < nli; i++){
+ if(nldata[i] > 2 && (pt = (POINT*)malloc(nldata[i]*sizeof(POINT)))){
+ for(j = 0; j < nldata[i]; j++) {
+ pt[j].x = ldata[i][j].x; pt[j].y = ldata[i][j].y;
+ }
+ o->oPolygon(pt, nldata[i]);
+ free(pt);
+ }
+ }
+ }
+ return true;
+ case CMD_STARTLINE:
+ if(ap = (POINT3D*)tmpl) {
+ if(ldata && nldata && nli) {
+ if(bReqPoint) {
+ Command(CMD_ADDTOLINE, &ReqPoint, o);
+ bReqPoint = false;
+ }
+ i = nli-1; j = nldata[i]-1;
+ if(ldata[i][j].x == ap->x && ldata[i][j].y == ap->y && ldata[i][j].z == ap->z){
+ return true;
+ }
+ if(IsValidPG(ldata[i], nldata[i])) {
+ //close previous polygon first
+ if(ldata[i][0].x != ldata[i][j].x || ldata[i][0].y != ldata[i][j].y ||
+ ldata[i][0].z != ldata[i][j].z){
+ j++;
+ ldata[i][j].x = ldata[i][0].x; ldata[i][j].y = ldata[i][0].y;
+ ldata[i][j].z = ldata[i][0].z; nldata[i]++;
+ }
+ ldata = (POINT3D**)realloc(ldata, sizeof(POINT3D*) * (nli+1));
+ ldata[nli] = (POINT3D*)malloc(sizeof(POINT3D)*2);
+ nldata = (int*)realloc(nldata, sizeof(int) * (nli+1));
+ }
+ else { //drop incomplete or invalid polygon
+ nli--;
+ }
+ }
+ else {
+ ldata = (POINT3D**)calloc(1, sizeof(POINT3D*));
+ ldata[nli = 0] = (POINT3D*)malloc(sizeof(POINT3D));
+ nldata = (int*)calloc(1, sizeof(int));
+ bReqPoint = false;
+ }
+ if(ldata && nldata) {
+ ldata[nli][0].x = ap->x; ldata[nli][0].y = ap->y;
+ ldata[nli][0].z = ap->z; nldata[nli++] = 1;
+ return true;
+ }
+ }
+ break;
+ case CMD_REQ_POINT:
+ if(ap = (POINT3D*)tmpl) {
+ ReqPoint.x = ap->x; ReqPoint.y = ap->y; ReqPoint.z = ap->z;
+ bReqPoint = true;
+ }
+ return true;
+ case CMD_ADDTOLINE:
+ if((ap = (POINT3D*)tmpl) && ldata && nldata && nli) {
+ i= nli-1; j=nldata[i]-1;
+ if((ldata[i][j].x == ap->x && ldata[i][j].y == ap->y) ||
+ (ldata[i][j].y == ap->y && ldata[i][j].z == ap->z)){
+ //probably nothing to add
+ ldata[i][j].x = ap->x; ldata[i][j].y = ap->y;
+ return j>0 ? true : false;
+ }
+ ldata[i] = (POINT3D*)realloc(ldata[i], ((j=nldata[i])+2) * sizeof(POINT3D));
+ ldata[i][j].x = ap->x; ldata[i][j].y = ap->y;
+ ldata[i][j].z = ap->z; nldata[i]++;
+ return true;
+ }
+ case CMD_CLIP:
+ if(co = (GraphObj*)tmpl){
+ switch(co->Id) {
+ case GO_PLANE:
+ //Clip only planes which are drawn later
+ if(GetSize(SIZE_MIN_Z) < co->GetSize(SIZE_MIN_Z)) return false;
+ if(nli){
+ DoClip(co);
+ if(nli && ldata) {
+ i = nli-1; j = nldata[i]-1;
+ //is last part valid ?
+ if(j < 2) {
+ free(ldata[i]); ldata[i] = 0L;
+ nldata[i] = 0;
+ nli--;
+ }
+ //close last polygon
+ else if(ldata[i][0].x != ldata[i][j].x ||
+ ldata[i][0].y != ldata[i][j].y ||
+ ldata[i][0].z != ldata[i][j].z){
+ j++;
+ ldata[i][j].x = ldata[i][0].x;
+ ldata[i][j].y = ldata[i][0].y;
+ ldata[i][j].z = ldata[i][0].z;
+ nldata[i]++;
+ }
+ }
+ }
+ else xBounds.fx=xBounds.fy=yBounds.fx=yBounds.fy=zBounds.fx=zBounds.fy=0.0;
+ break;
+ }
+ }
+ break;
+ }
+ return false;
+}
+
+void *
+plane::ObjThere(int x, int y)
+{
+ POINT p1;
+
+ if(bDrawDone && IsInRect(&rDims, p1.x = x, p1.y = y) &&
+ (IsInPolygon(&p1, ipts, n_ipts) || IsCloseToPL(p1, ipts, n_ipts))) return this;
+ return 0L;
+}
+
+bool
+plane::GetPolygon(POINT3D **pla, int *npt, int n)
+{
+ if(n < nli && ldata && ldata[n]) {
+ *pla = ldata[n]; *npt = nldata[n];
+ return true;
+ }
+ return false;
+}
+
+void
+plane::DoClip(GraphObj *co)
+{
+ RECT cliprc;
+ int o_nli, *o_nldata = 0L;
+ POINT3D **o_ldata = 0L;
+ POINT3D *tpg;
+ int i, j, tnpt;
+ bool is_valid = false;
+
+ if(co->parent == parent && co->Id == GO_PLANE) {
+ //if both planes have the same parent it means they are part of one object
+ // do not clip!
+ return;
+ }
+ cliprc.left = iround(co->GetSize(SIZE_MIN_X));
+ cliprc.right = iround(co->GetSize(SIZE_MAX_X));
+ cliprc.top = iround(co->GetSize(SIZE_MIN_Y));
+ cliprc.bottom = iround(co->GetSize(SIZE_MAX_Y));
+ if(OverlapRect(&rDims, &cliprc) && co != this) {
+ o_nli = nli; nli = 0;
+ o_nldata = nldata; nldata = 0L;
+ o_ldata = ldata; ldata = 0L;
+ switch(co->Id) {
+ case GO_PLANE:
+ //clip all parts of this plane with all from another plane
+ for(i = 0; ((plane*)co)->GetPolygon(&tpg, &tnpt, i); i++){
+ for(j = 0; j < o_nli; j++) {
+ if(o_nldata[j] >2) clip_plane_plane(this, o_ldata[j], o_nldata[j], PlaneVec,
+ tpg, tnpt, ((plane*)co)->GetVec(), ipts, n_ipts );
+ }
+ if(bReqPoint){
+ Command(CMD_ADDTOLINE, &ReqPoint, 0L);
+ bReqPoint = false;
+ }
+ if(nli) is_valid = true;
+ if(o_ldata) {
+ for(j = 0; j < o_nli; j++) if(o_ldata[j]) free(o_ldata[j]);
+ free(o_ldata);
+ }
+ if(o_nldata) free(o_nldata);
+ o_nli = nli; nli = 0;
+ o_nldata = nldata; nldata = 0L;
+ o_ldata = ldata; ldata = 0L;
+ if(!o_nli) { //plane is completly hidden
+ return;
+ }
+ }
+ if(is_valid || i==0){
+ nli = o_nli; o_nli = 0;
+ nldata = o_nldata; o_nldata = 0L;
+ ldata = o_ldata; o_ldata = 0L;
+ }
+ if(nli > 1) for(i = 1; i < nli; i++) {
+ if(nldata[i] > 3 && ldata[i][nldata[i]-1].x == ldata[i-1][0].x
+ && ldata[i][nldata[i]-1].y == ldata[i-1][0].y) {
+ nldata[i]--; //bad vis: ignore last point
+ }
+ }
+ break;
+ default:
+ nli = o_nli; o_nli = 0;
+ nldata = o_nldata; o_nldata = 0L;
+ ldata = o_ldata; o_ldata = 0L;
+ break;
+ }
+ //check shape and recalc some values
+ if(is_valid && nli) {
+ xBounds.fx = xBounds.fy = ldata[0][0].x; yBounds.fx = yBounds.fy = ldata[0][0].y;
+ zBounds.fx = zBounds.fy = ldata[0][0].z;
+ rDims.left = rDims.right = ldata[0][0].x; rDims.top = rDims.bottom = ldata[0][0].y;
+ for(i = 0; i < nli; i++) if(nldata[i] > 2){
+ if(ldata[i][0].x != ldata[i][nldata[i]-1].x || ldata[i][0].y != ldata[i][nldata[i]-1].y
+ || ldata[i][0].z != ldata[i][nldata[i]-1].z) {
+ ldata[i][nldata[i]].x = ldata[i][0].x; ldata[i][nldata[i]].y = ldata[i][0].y;
+ ldata[i][nldata[i]].z = ldata[i][0].z; nldata[i]++;
+ }
+ for(j = 0; j < (nldata[i]-1); j++) {
+ UpdateMinMaxRect(&rDims, ldata[i][j].x, ldata[i][j].y);
+ if(ldata[i][j].x < xBounds.fx) xBounds.fx = ldata[i][j].x;
+ if(ldata[i][j].x > xBounds.fy) xBounds.fy = ldata[i][j].x;
+ if(ldata[i][j].y < yBounds.fx) yBounds.fx = ldata[i][j].y;
+ if(ldata[i][j].y > yBounds.fy) yBounds.fy = ldata[i][j].y;
+ if(ldata[i][j].z < zBounds.fx) zBounds.fx = ldata[i][j].z;
+ if(ldata[i][j].z > zBounds.fy) zBounds.fy = ldata[i][j].z;
+ }
+ }
+ }
+ }
+ if(o_ldata) {
+ for(i = 0; i < o_nli; i++) if(o_ldata[i]) free(o_ldata[i]);
+ free(o_ldata);
+ }
+ if(o_nldata) free(o_nldata);
+}
+
+bool
+plane::IsValidPG(POINT3D *pg, int npg)
+{
+ int i;
+ long area;
+
+ //a polygon must have more than 3 Points
+ if(npg < 3) return false;
+ //check for a reasonable size
+ for(area = 0, i = 1; i < npg; i++) {
+ area += (pg[i].x - pg[i-1].x) * ((pg[i].y + pg[i-1].y)>>1);
+ }
+ area += (pg[0].x - pg[i-1].x) * ((pg[0].y + pg[i-1].y)>>1);
+ area = abs(area);
+ if(area < 20) return false;
+ if(totalArea/area > 100) return false;
+ return true;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// a simple plane in three dimensional space
+Plane3D::Plane3D(GraphObj *par, DataObj *da, fPOINT3D *pt, long npt)
+ :GraphObj(par, da)
+{
+ FileIO(INIT_VARS);
+ Id = GO_PLANE3D;
+ dt = (fPOINT3D*) memdup(pt, sizeof(fPOINT3D)*npt, 0L);
+ ndt = npt;
+}
+
+Plane3D::Plane3D(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+Plane3D::~Plane3D()
+{
+ if(dt) free(dt); if(pts) free(pts);
+ dt = 0L; ndt = 0L;
+ if(ipl) delete (ipl); ipl = 0L;
+}
+
+bool
+Plane3D::SetSize(int select, double value)
+{
+ int i;
+
+ if((select & 0xfff) >= SIZE_XPOS && (select & 0xfff) <= SIZE_XPOS_LAST){
+ if((i = select-SIZE_XPOS) >=0 && i <= 200 && i < (int)ndt){
+ dt[i].fx = value; return true;
+ }
+ }
+ else if((select & 0xfff) >= SIZE_YPOS && (select & 0xfff) <= SIZE_YPOS_LAST){
+ if((i = select-SIZE_YPOS) >=0 && i <= 200 && i < (int)ndt){
+ dt[i].fy = value; return true;
+ }
+ }
+ else if((select & 0xfff) >= SIZE_ZPOS && (select & 0xfff) <= SIZE_ZPOS_LAST){
+ if((i = select-SIZE_ZPOS) >=0 && i <= 200 && i < (int)ndt){
+ dt[i].fz = value; return true;
+ }
+ }
+ else switch(select) {
+ case SIZE_SYM_LINE:
+ Line.width = value;
+ }
+ return false;
+}
+
+bool
+Plane3D::SetColor(int select, DWORD col)
+{
+ switch(select) {
+ case COL_POLYLINE: Line.color = col; return true;
+ case COL_POLYGON: Fill.color = col; return true;
+ }
+ return false;
+}
+
+void
+Plane3D::DoPlot(anyOutput *o)
+{
+ int i;
+
+ if(ipl) delete ipl; ipl = 0L;
+ if(pts) free(pts); pts = 0L;
+ o->ActualSize(&rDims);
+ rDims.left = rDims.right; rDims.top = rDims.bottom;
+ rDims.right = rDims.bottom = 0;
+ if((pts = (fPOINT3D*)malloc(sizeof(fPOINT3D)*ndt))){
+ for(i = 0; i < ndt; i++) {
+ if(!o->fvec2ivec(&dt[i], &pts[i])){
+ free(pts); pts = 0L; return;
+ }
+ UpdateMinMaxRect(&rDims, iround(pts[i].fx), iround(pts[i].fy));
+ }
+ if(ipl = new plane(this, data, pts, i, &Line, &Fill))ipl->DoPlot(o);
+ }
+ IncrementMinMaxRect(&rDims, o->un2ix(Line.width)+1);
+}
+
+void
+Plane3D::DoMark(anyOutput *o, bool mark)
+{
+ if(mark){
+ if(pts && ipl)ipl->DoMark(o, mark);
+ o->UpdateRect(&rDims, false);
+ }
+ else if(parent) parent->Command(CMD_REDRAW, 0L, o);
+}
+
+bool
+Plane3D::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i;
+ MouseEvent *mev;
+
+ switch (cmd) {
+ case CMD_SET_DATAOBJ:
+ Id = GO_PLANE3D;
+ data = (DataObj *)tmpl;
+ return true;
+ case CMD_LEGEND:
+ if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+ ((Legend*)tmpl)->HasFill(&Line, &Fill);
+ break;
+ case CMD_MRK_DIRTY:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ case CMD_SYM_FILL:
+ if(tmpl) memcpy(&Fill, tmpl, sizeof(FillDEF));
+ return true;
+ case CMD_REDRAW:
+ //Note: this command is issued either by Undo (no output given) or
+ // by Plot3D::DoPlot after sorting all objects (output specified)
+ if(!parent) return false;
+ if(!o) return parent->Command(cmd, tmpl, o);
+ return true;
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
+ if(ipl && ipl->ObjThere(mev->x, mev->y)){
+ o->ShowMark(CurrGO=this, MRK_GODRAW);
+ return true;
+ }
+ }
+ break;
+ }
+ break;
+ case CMD_PG_FILL:
+ if(tmpl) {
+ memcpy((void*)&Fill, tmpl, sizeof(FillDEF));
+ Fill.hatch = 0L;
+ }
+ break;
+ case CMD_AUTOSCALE:
+ if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH && dt) {
+ for(i = 0; i < ndt; i++)
+ ((Plot*)parent)->CheckBounds3D(dt[i].fx, dt[i].fy, dt[i].fz);
+ return true;
+ }
+ break;
+ case CMD_SET_GO3D:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Brick: a bar in three dimensional space
+Brick::Brick(GraphObj *par, DataObj *da, double x, double y, double z,
+ double d, double w, double h, DWORD flg, int xc, int xr, int yc,
+ int yr, int zc, int zr, int dc, int dr, int wc, int wr, int hc,
+ int hr):GraphObj(par, da)
+{
+ FileIO(INIT_VARS);
+ Id = GO_BRICK;
+ fPos.fx = x; fPos.fy = y; fPos.fz = z;
+ depth = d; width = w; height = h;
+ flags = flg;
+ if(xc >= 0 || xr >= 0 || yc >= 0 || yr >= 0 || zc >= 0 || zr >= 0 ||
+ dc >= 0 || dr >= 0 || wc >= 0 || wr >= 0 || hc >= 0 || hr >= 0) {
+ if(ssRef = (POINT*)malloc(sizeof(POINT)*6)) {
+ ssRef[0].x = xc; ssRef[0].y = xr;
+ ssRef[1].x = yc; ssRef[1].y = yr;
+ ssRef[2].x = zc; ssRef[2].y = zr;
+ ssRef[3].x = dc; ssRef[3].y = dr;
+ ssRef[4].x = wc; ssRef[4].y = wr;
+ ssRef[5].x = hc; ssRef[5].y = hr;
+ cssRef = 6;
+ }
+ }
+ bModified = false;
+}
+
+Brick::Brick(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+ bModified = false;
+}
+
+Brick::~Brick()
+{
+ int i;
+
+ if(faces) {
+ for(i = 0; i < 6; i++) if(faces[i]) delete(faces[i]);
+ free(faces);
+ }
+ faces = 0L;
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ Command(CMD_FLUSH, 0L, 0L);
+ if(bModified) Undo.InvalidGO(this);
+}
+
+bool
+Brick::SetSize(int select, double value)
+{
+ switch(select & 0xfff) {
+ case SIZE_BAR_LINE: Line.width = value; return true;
+ case SIZE_BAR_BASE: fPos.fy = value; return true;
+ case SIZE_BAR: width = value; return true;
+ case SIZE_BAR_DEPTH: depth = value; return true;
+ }
+ return false;
+}
+
+bool
+Brick::SetColor(int select, DWORD col)
+{
+ switch(select & 0xfff) {
+ case COL_BAR_LINE: Line.color = col; return true;
+ case COL_BAR_FILL: Fill.color = col; return true;
+ }
+ return false;
+}
+
+void
+Brick::DoPlot(anyOutput *o)
+{
+ fPOINT3D cpt[8], fip1, fip2, tmp, itmp, *pg;
+ plane *npl;
+ double dtmp;
+ int i;
+
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ if(!faces || !o || !o->fvec2ivec(&fPos, &fip1)) return;
+ if(!(pg = (fPOINT3D *)malloc(5*sizeof(fPOINT3D)))) return;
+ for(i = 0; i < 6; i++) {
+ if(faces[i]) delete(faces[i]);
+ faces[i] = 0L;
+ }
+ if(flags & 0x800L) { //height is data
+ tmp.fx = fPos.fx; tmp.fy = height;
+ tmp.fz = fPos.fz; o->fvec2ivec(&tmp, &fip2);
+ }
+ else { //height is units
+ tmp.fx = tmp.fz = 0.0; tmp.fy = height;
+ o->uvec2ivec(&tmp, &fip2);
+ fip2.fx += fip1.fx; fip2.fy += fip1.fy;
+ fip2.fz += fip1.fz;
+ }
+ //calc output-device coordinates of cubic brick: 8 corners
+ tmp.fx = -(width/2.0); tmp.fz = (depth/2.0); tmp.fy = 0.0;
+ o->uvec2ivec(&tmp, &itmp);
+ cpt[0].fx= fip1.fx+itmp.fx; cpt[0].fy= fip1.fy+itmp.fy; cpt[0].fz= fip1.fz+itmp.fz;
+ cpt[2].fx= fip1.fx-itmp.fx; cpt[2].fy= fip1.fy-itmp.fy; cpt[2].fz= fip1.fz-itmp.fz;
+ cpt[4].fx= fip2.fx+itmp.fx; cpt[4].fy= fip2.fy+itmp.fy; cpt[4].fz= fip2.fz+itmp.fz;
+ cpt[6].fx= fip2.fx-itmp.fx; cpt[6].fy= fip2.fy-itmp.fy; cpt[6].fz= fip2.fz-itmp.fz;
+ tmp.fx = (width/2.0); tmp.fz = (depth/2.0); tmp.fy = 0.0;
+ o->uvec2ivec(&tmp, &itmp);
+ cpt[1].fx= fip1.fx+itmp.fx; cpt[1].fy= fip1.fy+itmp.fy; cpt[1].fz= fip1.fz+itmp.fz;
+ cpt[3].fx= fip1.fx-itmp.fx; cpt[3].fy= fip1.fy-itmp.fy; cpt[3].fz= fip1.fz-itmp.fz;
+ cpt[5].fx= fip2.fx+itmp.fx; cpt[5].fy= fip2.fy+itmp.fy; cpt[5].fz= fip2.fz+itmp.fz;
+ cpt[7].fx= fip2.fx-itmp.fx; cpt[7].fy= fip2.fy-itmp.fy; cpt[7].fz= fip2.fz-itmp.fz;
+ //set up 6 faces
+ pg[0].fx = pg[4].fx = cpt[0].fx; pg[1].fx = cpt[1].fx;
+ pg[2].fx = cpt[2].fx; pg[3].fx = cpt[3].fx;
+ pg[0].fy = pg[4].fy = cpt[0].fy; pg[1].fy = cpt[1].fy;
+ pg[2].fy = cpt[2].fy; pg[3].fy = cpt[3].fy;
+ pg[0].fz = pg[4].fz = cpt[0].fz; pg[1].fz = cpt[1].fz;
+ pg[2].fz = cpt[2].fz; pg[3].fz = cpt[3].fz;
+ faces[0] = new plane(this, data, pg, 5, &Line, &Fill);
+ pg[2].fx = cpt[5].fx; pg[3].fx = cpt[4].fx;
+ pg[2].fy = cpt[5].fy; pg[3].fy = cpt[4].fy;
+ pg[2].fz = cpt[5].fz; pg[3].fz = cpt[4].fz;
+ npl = new plane(this, data, pg, 5, &Line, &Fill);
+ if(npl->GetSize(SIZE_MAX_Z) > faces[0]->GetSize(SIZE_MAX_Z)) faces[1] = npl;
+ else {
+ faces[1] = faces[0]; faces[0] = npl;
+ }
+ pg[0].fx = pg[4].fx = cpt[2].fx; pg[1].fx = cpt[6].fx;
+ pg[2].fx = cpt[5].fx; pg[3].fx = cpt[1].fx;
+ pg[0].fy = pg[4].fy = cpt[2].fy; pg[1].fy = cpt[6].fy;
+ pg[2].fy = cpt[5].fy; pg[3].fy = cpt[1].fy;
+ pg[0].fz = pg[4].fz = cpt[2].fz; pg[1].fz = cpt[6].fz;
+ pg[2].fz = cpt[5].fz; pg[3].fz = cpt[1].fz;
+ npl = new plane(this, data, pg, 5, &Line, &Fill);
+ if((dtmp = npl->GetSize(SIZE_MAX_Z)) > faces[1]->GetSize(SIZE_MAX_Z)) faces[2] = npl;
+ else {
+ faces[2] = faces[1];
+ if(dtmp > faces[0]->GetSize(SIZE_MAX_Z)) faces[1] = npl;
+ else {
+ faces[1] = faces[0]; faces[0] = npl;
+ }
+ }
+ pg[2].fx = cpt[7].fx; pg[3].fx = cpt[3].fx;
+ pg[2].fy = cpt[7].fy; pg[3].fy = cpt[3].fy;
+ pg[2].fz = cpt[7].fz; pg[3].fz = cpt[3].fz;
+ npl = new plane(this, data, pg, 5, &Line, &Fill);
+ dtmp = npl->GetSize(SIZE_MAX_Z);
+ for (i = 3; i; i--) {
+ if(dtmp >faces[i-1]->GetSize(SIZE_MAX_Z)) {
+ faces[i] = npl; break;
+ }
+ else faces[i] = faces[i-1];
+ }
+ if(!i) faces[0] = npl;
+ pg[0].fx = pg[4].fx = cpt[4].fx; pg[1].fx = cpt[7].fx;
+ pg[2].fx = cpt[3].fx; pg[3].fx = cpt[0].fx;
+ pg[0].fy = pg[4].fy = cpt[4].fy; pg[1].fy = cpt[7].fy;
+ pg[2].fy = cpt[3].fy; pg[3].fy = cpt[0].fy;
+ pg[0].fz = pg[4].fz = cpt[4].fz; pg[1].fz = cpt[7].fz;
+ pg[2].fz = cpt[3].fz; pg[3].fz = cpt[0].fz;
+ npl = new plane(this, data, pg, 5, &Line, &Fill);
+ dtmp = npl->GetSize(SIZE_MAX_Z);
+ for (i = 4; i; i--) {
+ if(dtmp >faces[i-1]->GetSize(SIZE_MAX_Z)) {
+ faces[i] = npl; break;
+ }
+ else faces[i] = faces[i-1];
+ }
+ if(!i) faces[0] = npl;
+ pg[2].fx = cpt[6].fx; pg[3].fx = cpt[5].fx;
+ pg[2].fy = cpt[6].fy; pg[3].fy = cpt[5].fy;
+ pg[2].fz = cpt[6].fz; pg[3].fz = cpt[5].fz;
+ npl = new plane(this, data, pg, 5, &Line, &Fill);
+ dtmp = npl->GetSize(SIZE_MAX_Z);
+ for (i = 5; i; i--) {
+ if(dtmp >faces[i-1]->GetSize(SIZE_MAX_Z)) {
+ faces[i] = npl; break;
+ }
+ else faces[i] = faces[i-1];
+ }
+ if(!i) faces[0] = npl;
+ rDims.left = rDims.right = (int)pg[0].fx;
+ rDims.top = rDims.bottom = (int)pg[0].fy;
+ for (i= 3; i < 6; i++) if(faces[i]) {
+ faces[i]->DoPlot(o);
+ UpdateMinMaxRect(&rDims, faces[i]->rDims.left, faces[i]->rDims.top);
+ UpdateMinMaxRect(&rDims, faces[i]->rDims.right, faces[i]->rDims.bottom);
+ }
+ free(pg);
+}
+
+void
+Brick::DoMark(anyOutput *o, bool mark)
+{
+ int i;
+
+ if(mark){
+ memcpy(&mrc, &rDims, sizeof(RECT));
+ IncrementMinMaxRect(&mrc, 6 + o->un2ix(Line.width));
+ mo = GetRectBitmap(&mrc, o);
+ if(faces) for(i = 3; i < 6; i++)
+ if(faces[i]) faces[i]->DoMark(o, mark);
+ o->UpdateRect(&rDims, false);
+ }
+ else if(mo) RestoreRectBitmap(&mo, &mrc, o);
+}
+
+bool
+Brick::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+
+ switch (cmd) {
+ case CMD_FLUSH:
+ if(ssRef) free(ssRef); ssRef = 0L;
+ if(name) free(name); name = 0L;
+ return true;
+ case CMD_LEGEND:
+ if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+ ((Legend*)tmpl)->HasFill(&Line, &Fill);
+ break;
+ case CMD_BAR_FILL:
+ if(tmpl) {
+ memcpy(&Fill, tmpl, sizeof(FillDEF));
+ Fill.hatch = 0L;
+ return true;
+ }
+ break;
+ case CMD_MRK_DIRTY:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ case CMD_SET_DATAOBJ:
+ Id = GO_BRICK;
+ data = (DataObj *)tmpl;
+ return true;
+ case CMD_REDRAW:
+ //Note: this command is issued either by Undo (no output given) or
+ // by Plot3D::DoPlot after sorting all objects (output specified)
+ if(!parent) return false;
+ if(!o) return parent->Command(cmd, tmpl, o);
+ //Should we ever come here ?
+ return true;
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
+ if(faces && faces[3] && faces[4] && faces[5] &&
+ (faces[3]->ObjThere(mev->x, mev->y) ||
+ faces[4]->ObjThere(mev->x, mev->y) ||
+ faces[5]->ObjThere(mev->x, mev->y))){
+ o->ShowMark(CurrGO=this, MRK_GODRAW);
+ return true;
+ }
+ }
+ break;
+ }
+ break;
+ case CMD_UPDATE:
+ if(ssRef && cssRef > 5 && data) {
+ data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
+ data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
+ data->GetValue(ssRef[2].y, ssRef[2].x, &fPos.fz);
+ data->GetValue(ssRef[3].y, ssRef[3].x, &depth);
+ data->GetValue(ssRef[4].y, ssRef[4].x, &width);
+ data->GetValue(ssRef[5].y, ssRef[5].x, &height);
+ return true;
+ }
+ return false;
+ case CMD_AUTOSCALE:
+ if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+ ((Plot*)parent)->CheckBounds3D(fPos.fx, fPos.fy, fPos.fz);
+ if(flags & 0x800L) { //height is data
+ ((Plot*)parent)->CheckBounds3D(fPos.fx, height, fPos.fz);
+ }
+ return true;
+ }
+ break;
+ case CMD_SET_GO3D:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// line_segment: utility object to draw a piece of a polyline in 3D space
+line_segment::line_segment(GraphObj *par, DataObj *d, LineDEF *ld, POINT3D *p1, POINT3D *p2)
+ :GraphObj(par, d)
+{
+ double tmp, tmp1, tmp2;
+
+ nli = 0; nldata = 0L; ldata = 0L; prop = 1.0; df_go = 0L;
+ fmin.fx = fmax.fx = fmin.fy = fmax.fy = fmin.fz = fmax.fz = 0.0;
+ ndf_go = 0;
+ if(ld) memcpy(&Line, ld, sizeof(LineDEF));
+ if(p1 && p2 &&(ldata =(POINT3D**)calloc(1, sizeof(POINT3D*))) &&
+ (ldata[0] = (POINT3D*)malloc(2 * sizeof(POINT3D))) &&
+ (nldata = (int*)calloc(1, sizeof(int)))){
+ if(Line.pattern) {
+ tmp1 = (tmp = (p2->x - p1->x)) * tmp;
+ tmp2 = (tmp1 += (tmp = (p2->y - p1->y)) * tmp);
+ tmp1 += (tmp = (p2->z - p1->z)) * tmp;
+ if(tmp1 > 1.0) prop = sqrt(tmp2)/sqrt(tmp1);
+ }
+ memcpy(&ldata[0][0], p1, sizeof(POINT3D));
+ memcpy(&ldata[0][1], p2, sizeof(POINT3D));
+ nldata[0] = 2; nli = 1;
+ rDims.left = rDims.right = p1->x; rDims.top = rDims.bottom = p1->y;
+ UpdateMinMaxRect(&rDims, p2->x, p2->y);
+ fmin.fx = (double)rDims.left; fmin.fy = (double)rDims.top;
+ fmax.fx = (double)rDims.right; fmax.fy = (double)rDims.bottom;
+ if(p2->z > p1->z) {
+ fmin.fz = (double)p1->z; fmax.fz = (double)p2->z;
+ }
+ else {
+ fmin.fz = (double)p2->z; fmax.fz = (double)p1->z;
+ }
+ }
+ Id = GO_LINESEG;
+}
+
+line_segment::~line_segment()
+{
+ int i;
+
+ if(ldata) {
+ for(i = 0; i < nli; i++) if(ldata[i]) free(ldata[i]);
+ free(ldata);
+ }
+ if(nldata) free(nldata); nldata = 0L;
+}
+
+double
+line_segment::GetSize(int select)
+{
+ switch(select) {
+ case SIZE_MIN_Z:
+ return fmin.fz;
+ case SIZE_MAX_Z:
+ return fmax.fz;
+ }
+ return 0.0;
+}
+
+void
+line_segment::DoPlot(anyOutput *o)
+{
+ bDrawDone = false; co = 0L;
+ if(df_go) free(df_go);
+ df_go = 0L; ndf_go = 0;
+ if(o->VPscale > 1.5 && (
+ (rDims.right < defs.clipRC.left) || (rDims.left > defs.clipRC.right) ||
+ (rDims.bottom < defs.clipRC.top) || (rDims.top > defs.clipRC.bottom))){
+ bDrawDone = true; return;
+ }
+ if(parent && parent->Command(CMD_SET_GO3D, this, o)) return;
+ Command(CMD_REDRAW, 0L, o);
+}
+
+bool
+line_segment::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i, j;
+ POINT pts[2];
+ LineDEF cLine;
+ POINT3D *ap;
+
+ switch (cmd) {
+ case CMD_MOUSE_EVENT:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ case CMD_DRAW_LATER:
+ if(!co) return false;
+ if(df_go){
+ for(i = 0; i < ndf_go; i++) if(df_go[i] == co) return true;
+ if(df_go = (GraphObj**)realloc(df_go, (ndf_go +1) * sizeof(GraphObj*))) {
+ df_go[ndf_go++] = co;
+ }
+ }
+ else {
+ if(df_go = (GraphObj**)malloc(sizeof(GraphObj*))){
+ df_go[0] = co; ndf_go = 1;
+ }
+ }
+ return true;
+ case CMD_REDRAW:
+ if(bDrawDone) return false;
+ bDrawDone = true;
+ if(!nli) return false;
+ if(df_go) {
+ for(i = 0; i < ndf_go; i++) if(df_go[i]) df_go[i]->Command(cmd, tmpl, o);
+ free(df_go); df_go = 0L; ndf_go = 0L;
+ }
+ if(o && ldata && nldata){
+ memcpy(&cLine, &Line, sizeof(LineDEF));
+ cLine.patlength *= prop;
+ o->SetLine(&cLine);
+ for(i = 0; i < nli; i++) for(j = 0; j < (nldata[i]-1); j++) {
+ pts[0].x = ldata[i][j].x; pts[0].y = ldata[i][j].y;
+ pts[1].x = ldata[i][j+1].x; pts[1].y = ldata[i][j+1].y;
+ if(pts[0].x != pts[1].x || pts[0].y != pts[1].y) o->oPolyline(pts, 2);
+ }
+ }
+ return true;
+ case CMD_CLIP:
+ if(co = (GraphObj*)tmpl){
+ switch(co->Id) {
+ case GO_PLANE:
+ case GO_SPHERE:
+ DoClip(co);
+ break;
+ }
+ }
+ return false;
+ case CMD_STARTLINE:
+ if(tmpl) {
+ if(ldata && nldata) {
+ ldata = (POINT3D**)realloc(ldata, sizeof(POINT3D*) * (nli+1));
+ ldata[nli] = (POINT3D*)malloc(2 * sizeof(POINT3D));
+ nldata = (int*)realloc(nldata, sizeof(int)*(nli+1));
+ }
+ else {
+ ldata = (POINT3D**)calloc(1, sizeof(POINT3D*));
+ ldata[nli = 0] = (POINT3D*)malloc(2 * sizeof(POINT3D));
+ nldata = (int*)calloc(1, sizeof(int));
+ }
+ if(ldata && nldata) {
+ memcpy(&ldata[nli][0], tmpl, sizeof(POINT3D));
+ memcpy(&ldata[nli][1], tmpl, sizeof(POINT3D));
+ nldata[nli++] = 1;
+ return true;
+ }
+ }
+ break;
+ case CMD_ADDTOLINE:
+ if((ap = (POINT3D*)tmpl) && ldata && nldata && nli && nldata[i =(nli-1)]) {
+ j = nldata[i];
+ ldata[i] = (POINT3D*)realloc(ldata[i], (nldata[i]+2) * sizeof(POINT3D));
+ if(j && ldata[i][j-1].x == ap->x && ldata[i][j-1].y == ap->y &&
+ ldata[i][j-1].z == ap->z) return true;
+ else {
+ j = (nldata[i]++);
+ }
+ memcpy(&ldata[i][j-1], tmpl, sizeof(POINT3D));
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
+void *
+line_segment::ObjThere(int x, int y)
+{
+ int i, j;
+ POINT pts[2];
+
+ if(ldata && nldata){
+ for(i = 0; i < nli; i++) for(j = 0; j < nldata[i]; j +=2) {
+ pts[0].x = ldata[i][j].x; pts[0].y = ldata[i][j].y;
+ pts[1].x = ldata[i][j+1].x; pts[1].y = ldata[i][j+1].y;
+ if(IsCloseToLine(&pts[0], &pts[1], x, y))return this;
+ }
+ }
+ return 0L;
+}
+
+void
+line_segment::DoClip(GraphObj *co)
+{
+ RECT cliprc;
+ int o_nli, *o_nldata = 0L;
+ POINT3D **o_ldata = 0L, *pts = 0L, *pla;
+ int i, j, k, np, r, cx, cy, cz;
+ bool is_valid = false;
+
+ cliprc.left = iround(co->GetSize(SIZE_MIN_X));
+ cliprc.right = iround(co->GetSize(SIZE_MAX_X));
+ cliprc.top = iround(co->GetSize(SIZE_MIN_Y));
+ cliprc.bottom = iround(co->GetSize(SIZE_MAX_Y));
+ if(OverlapRect(&rDims, &cliprc)) {
+ if(!(pts = (POINT3D*)calloc(2, sizeof(POINT3D))))return;
+ o_nli = nli; nli = 0;
+ o_nldata = nldata; nldata = 0L;
+ o_ldata = ldata; ldata = 0L;
+ switch(co->Id) {
+ case GO_SPHERE:
+ cx = iround(co->GetSize(SIZE_XPOS));
+ cy = iround(co->GetSize(SIZE_YPOS));
+ cz = iround(co->GetSize(SIZE_ZPOS));
+ r = iround(co->GetSize(SIZE_RADIUS1));
+ for(i = 0; i < o_nli; i++) for(j = 0; j < (o_nldata[i]-1); j ++) {
+ pts[0].x = o_ldata[i][j].x; pts[0].y = o_ldata[i][j].y;
+ pts[0].z = o_ldata[i][j].z; pts[1].x = o_ldata[i][j+1].x;
+ pts[1].y = o_ldata[i][j+1].y; pts[1].z = o_ldata[i][j+1].z;
+ clip_line_sphere(this, &pts, r, cx, cy, cz);
+ }
+ break;
+ case GO_PLANE:
+ for(i = 0; ((plane*)co)->GetPolygon(&pla, &np, i); i++){
+ for(j = 0; j < o_nli; j++) {
+ if(o_nldata[j] >1) for(k = 0; k < (o_nldata[j]-1); k++){
+ pts[0].x = o_ldata[j][k].x; pts[0].y = o_ldata[j][k].y;
+ pts[0].z = o_ldata[j][k].z; pts[1].x = o_ldata[j][k+1].x;
+ pts[1].y = o_ldata[j][k+1].y; pts[1].z = o_ldata[j][k+1].z;
+ if(pts[0].x != pts[1].x || pts[0].y != pts[1].y || pts[0].z != pts[1].z)
+ clip_line_plane(this, &pts, pla, np, ((plane*)co)->GetVec());
+ }
+ }
+ if(nli) is_valid = true;
+ if(o_ldata) {
+ for(j = 0; j < o_nli; j++) if(o_ldata[j]) free(o_ldata[j]);
+ free(o_ldata);
+ }
+ if(o_nldata) free(o_nldata);
+ o_nli = nli; nli = 0;
+ o_nldata = nldata; nldata = 0L;
+ o_ldata = ldata; ldata = 0L;
+ if(!o_nli) return; //line is completly hidden
+ }
+ if(is_valid || i==0){
+ nli = o_nli; o_nli = 0;
+ nldata = o_nldata; o_nldata = 0L;
+ ldata = o_ldata; o_ldata = 0L;
+ }
+ break;
+ default:
+ nli = o_nli; o_nli = 0;
+ nldata = o_nldata; o_nldata = 0L;
+ ldata = o_ldata; o_ldata = 0L;
+ break;
+ }
+ if(pts) free(pts);
+ }
+ if(o_ldata) {
+ for(i = 0; i < o_nli; i++) if(o_ldata[i]) free(o_ldata[i]);
+ free(o_ldata);
+ }
+ if(o_nldata) free(o_nldata);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// define a drop line in 3D space
+DropLine3D::DropLine3D(GraphObj *par, DataObj *d, fPOINT3D *p1, int xc,
+ int xr, int yc, int yr, int zc, int zr):GraphObj(par, d)
+{
+ FileIO(INIT_VARS);
+ Id = GO_DROPL3D;
+ memcpy(&fPos, p1, sizeof(fPOINT3D));
+ if(xc >= 0 || xr >= 0 || yc >= 0 || yr >= 0 || zc >= 0 || zr >= 0) {
+ if(ssRef = (POINT*)malloc(sizeof(POINT)*3)) {
+ ssRef[0].x = xc; ssRef[0].y = xr;
+ ssRef[1].x = yc; ssRef[1].y = yr;
+ ssRef[2].x = zc; ssRef[2].y = zr;
+ cssRef = 3;
+ }
+ }
+ bModified = false;
+ type = 0x01;
+}
+
+DropLine3D::DropLine3D(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+ bModified = false;
+}
+
+DropLine3D::~DropLine3D()
+{
+ if(bModified) Undo.InvalidGO(this);
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ Command(CMD_FLUSH, 0L, 0L);
+}
+
+void
+DropLine3D::DoPlot(anyOutput *o)
+{
+ fPOINT3D fip, fp, fp1;
+ POINT3D p1, p2;
+ int i;
+
+ if(!parent || !o || !o->fvec2ivec(&fPos, &fip)) return;
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ for(i = 0; i < 6; i++){
+ if(ls[i]) delete(ls[i]);
+ ls[i] = 0L;
+ }
+ p1.x = iround(fip.fx); p1.y = iround(fip.fy); p1.z = iround(fip.fz);
+ rDims.left = rDims.right = p1.x; rDims.top = rDims.bottom = p1.y;
+ for(i = 0; i < 6; i++) {
+ fp.fx = fPos.fx; fp.fy = fPos.fy; fp.fz = fPos.fz;
+ if(type & (1 << i)){
+ switch (i) {
+ case 0: fp.fy = parent->GetSize(SIZE_BOUNDS_YMIN); break;
+ case 1: fp.fy = parent->GetSize(SIZE_BOUNDS_YMAX); break;
+ case 2: fp.fz = parent->GetSize(SIZE_BOUNDS_ZMIN); break;
+ case 3: fp.fz = parent->GetSize(SIZE_BOUNDS_ZMAX); break;
+ case 4: fp.fx = parent->GetSize(SIZE_BOUNDS_XMIN); break;
+ case 5: fp.fx = parent->GetSize(SIZE_BOUNDS_XMAX); break;
+ }
+ o->fvec2ivec(&fp, &fp1); p2.x = iround(fp1.fx);
+ p2.y = iround(fp1.fy); p2.z = iround(fp1.fz);
+ UpdateMinMaxRect(&rDims, p2.x, p2.y);
+ if(ls[i] = new line_segment(this, data, &Line, &p1, &p2)) ls[i]->DoPlot(o);
+ mpts[i][0].x = p1.x; mpts[i][0].y = p1.y;
+ mpts[i][1].x = p2.x; mpts[i][1].y = p2.y;
+ }
+ }
+ IncrementMinMaxRect(&rDims, 5);
+}
+
+void
+DropLine3D::DoMark(anyOutput *o, bool mark)
+{
+ int i;
+
+ if(mark) {
+ memcpy(&mrc, &rDims, sizeof(RECT));
+ IncrementMinMaxRect(&mrc, 6 + o->un2ix(Line.width));
+ mo = GetRectBitmap(&mrc, o);
+ for(i = 0; i < 6; i++) {
+ if(type & (1 << i)){
+ InvertLine(mpts[i], 2, &Line, 0L, o, mark);
+ }
+ }
+ o->UpdateRect(&mrc, false);
+ }
+ else RestoreRectBitmap(&mo, &mrc, o);
+}
+
+bool
+DropLine3D::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ int i;
+
+ switch (cmd) {
+ case CMD_FLUSH:
+ for(i = 0; i < 6; i++){
+ if(ls[i]) delete(ls[i]);
+ ls[i] = 0L;
+ }
+ if(ssRef) free(ssRef); ssRef = 0L;
+ if(name) free(name); name = 0L;
+ return true;
+ case CMD_DL_TYPE:
+ if(tmpl && *((int*)tmpl)) type = *((int*)tmpl);
+ return true;
+ case CMD_DL_LINE:
+ if(tmpl) memcpy(&Line, tmpl, sizeof(LineDEF));
+ return true;
+ case CMD_SET_DATAOBJ:
+ Id = GO_DROPL3D;
+ data = (DataObj *)tmpl;
+ return true;
+ case CMD_REDRAW:
+ //Note: this command is issued either by Undo (no output given) or
+ // by Plot3D::DoPlot after sorting all objects (output specified)
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
+ for(i = 0; i < 6; i++) {
+ if(ls[i] && ls[i]->ObjThere(mev->x, mev->y)){
+ o->ShowMark(this, MRK_GODRAW);
+ return true;
+ }
+ }
+ }
+ break;
+ }
+ break;
+ case CMD_UPDATE:
+ if(ssRef && cssRef >2 && data) {
+ data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
+ data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
+ data->GetValue(ssRef[2].y, ssRef[2].x, &fPos.fz);
+ return true;
+ }
+ return false;
+ case CMD_AUTOSCALE:
+ if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+ ((Plot*)parent)->CheckBounds3D(fPos.fx, fPos.fy, fPos.fz);
+ return true;
+ }
+ break;
+ case CMD_SET_GO3D:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// define an arrow in 3D space
+Arrow3D::Arrow3D(GraphObj *par, DataObj *d, fPOINT3D *p1, fPOINT3D *p2, int xc1,
+ int xr1, int yc1, int yr1, int zc1, int zr1, int xc2, int xr2, int yc2,
+ int yr2, int zc2, int zr2):GraphObj(par, d)
+{
+ FileIO(INIT_VARS);
+ Id = GO_ARROW3D;
+ memcpy(&fPos1, p1, sizeof(fPOINT3D)); memcpy(&fPos2, p2, sizeof(fPOINT3D));
+ if(xc1 >= 0 || xr1 >= 0 || yc1 >= 0 || yr1 >= 0 || zc1 >= 0 || zr1 >= 0 ||
+ xc2 >= 0 || xr2 >= 0 || yc2 >= 0 || yr2 >= 0 || zc2 >= 0 || zr2 >= 0) {
+ if(ssRef = (POINT*)malloc(sizeof(POINT)*6)) {
+ ssRef[0].x = xc1; ssRef[0].y = xr1;
+ ssRef[1].x = yc1; ssRef[1].y = yr1;
+ ssRef[2].x = zc1; ssRef[2].y = zr1;
+ ssRef[3].x = xc2; ssRef[3].y = xr2;
+ ssRef[4].x = yc2; ssRef[4].y = yr2;
+ ssRef[5].x = zc2; ssRef[5].y = zr2;
+ cssRef = 6;
+ }
+ }
+ bModified = false;
+}
+
+Arrow3D::Arrow3D(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+ bModified = false;
+}
+
+Arrow3D::~Arrow3D()
+{
+ if(bModified) Undo.InvalidGO(this);
+ Command(CMD_FLUSH, 0L, 0L);
+}
+
+bool
+Arrow3D::SetSize(int select, double value)
+{
+ switch(select & 0xfff) {
+ case SIZE_ARROW_LINE:
+ Line.width = value;
+ return true;
+ case SIZE_ARROW_CAPWIDTH:
+ cw = value;
+ return true;
+ case SIZE_ARROW_CAPLENGTH:
+ cl = value;
+ return true;
+ }
+ return false;
+}
+
+bool
+Arrow3D::SetColor(int select, DWORD col)
+{
+ switch(select & 0xfff) {
+ case COL_ARROW:
+ Line.color = col;
+ return true;
+ }
+ return false;
+}
+
+void
+Arrow3D::DoPlot(anyOutput *o)
+{
+ double si, csi, tmp, cwr, clr, d, d1, d2;
+ fPOINT3D fip1, fip2, tria[3];
+ POINT3D p1, p2, cp1, cp2;
+ FillDEF fill;
+ int i;
+
+ if(!parent || !o || !o->fvec2ivec(&fPos1, &fip1) ||!o->fvec2ivec(&fPos2, &fip2)) return;
+ for(i = 0; i < 3; i++){
+ if(ls[i]) delete(ls[i]);
+ ls[i] = 0L;
+ }
+ p1.x = iround(fip1.fx); p1.y = iround(fip1.fy); p1.z = iround(fip1.fz);
+ p2.x = iround(fip2.fx); p2.y = iround(fip2.fy); p2.z = iround(fip2.fz);
+ if(p1.x == p2.x && p1.y == p2.y && p1.z == p2.z) return; //zero length arrow
+ rDims.left = rDims.right = p1.x; rDims.top = rDims.bottom = p1.y;
+ UpdateMinMaxRect(&rDims, p2.x, p2.y);
+ IncrementMinMaxRect(&rDims, 5);
+ if(ls[0] = new line_segment(this, data, &Line, &p1, &p2)) ls[0]->DoPlot(o);
+ mpts[0][0].x = p1.x; mpts[0][0].y = p1.y; mpts[0][1].x = p2.x; mpts[0][1].y = p2.y;
+ if(p1.x == p2.x && p1.y == p2.y) return; //zero length in 2D
+ if((type & 0xff) == ARROW_NOCAP) return; //no cap;
+ //calculate sine and cosine for cap
+ si = fip1.fy-fip2.fy;
+ tmp = fip2.fx - fip1.fx;
+ si = si/sqrt(si*si + tmp*tmp);
+ csi = fip2.fx-fip1.fx;
+ tmp = fip2.fy - fip1.fy;
+ csi = csi/sqrt(csi*csi + tmp*tmp);
+ //cap corners
+ d1 = (d = fip2.fx - fip1.fx) * d;
+ d1 += ((d = fip2.fy - fip1.fy) * d);
+ d2 = d1 + ((d = fip2.fz - fip1.fz) * d);
+ d1 = sqrt(d1); d2 = sqrt(d2); d = d1/d2;
+ cwr = cw; clr = cl*d;
+ cp1.x = p2.x - o->un2ix(csi*clr + si*cwr/2.0);
+ cp1.y = p2.y + o->un2iy(si*clr - csi*cwr/2.0);
+ cp2.x = p2.x - o->un2ix(csi*clr - si*cwr/2.0);
+ cp2.y = p2.y + o->un2iy(si*clr + csi*cwr/2.0);
+ cp1.z = cp2.z = p2.z;
+ mpts[1][0].x = p2.x; mpts[1][0].y = p2.y; mpts[1][1].x = cp1.x; mpts[1][1].y = cp1.y;
+ mpts[2][0].x = p2.x; mpts[2][0].y = p2.y; mpts[2][1].x = cp2.x; mpts[2][1].y = cp2.y;
+ if((type & 0xff) == ARROW_LINE) {
+ if(ls[1] = new line_segment(this, data, &Line, &p2, &cp1)) ls[1]->DoPlot(o);
+ if(ls[2] = new line_segment(this, data, &Line, &p2, &cp2)) ls[2]->DoPlot(o);
+ }
+ else if((type & 0xff) == ARROW_TRIANGLE) {
+ fill.type = FILL_NONE; fill.color = Line.color;
+ fill.scale = 1.0; fill.hatch = 0L;
+ tria[0].fz = tria[1].fz = tria[2].fz = fip2.fz;
+ tria[0].fx = cp1.x; tria[0].fy = cp1.y;
+ tria[1].fx = fip2.fx; tria[1].fy = fip2.fy;
+ tria[2].fx = cp2.x; tria[2].fy = cp2.y;
+ if(cap = new plane(this, data, tria, 3, &Line, &fill))cap->DoPlot(o);
+ }
+}
+
+void
+Arrow3D::DoMark(anyOutput *o, bool mark)
+{
+ int i;
+
+ if(mark) {
+ for(i = 0; i < 3; i++) {
+ if(ls[i]){
+ InvertLine(mpts[i], 2, &Line, 0L, o, mark);
+ }
+ }
+ }
+ else if(parent) parent->Command(CMD_REDRAW, 0L, o);
+}
+
+bool
+Arrow3D::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ int i;
+
+ switch (cmd) {
+ case CMD_FLUSH:
+ for(i = 0; i < 3; i++){
+ if(ls[i]) delete(ls[i]);
+ ls[i] = 0L;
+ }
+ if(cap) delete(cap); cap = 0L;
+ if(ssRef) free(ssRef); ssRef = 0L;
+ if(name) free(name); name = 0L;
+ return true;
+ case CMD_SET_DATAOBJ:
+ Id = GO_ARROW3D;
+ data = (DataObj *)tmpl;
+ return true;
+ case CMD_MRK_DIRTY: //from Undo ?
+ case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
+ for(i = 0; i < 3; i++) {
+ if(ls[i] && ls[i]->ObjThere(mev->x, mev->y)){
+ o->ShowMark(this, MRK_GODRAW);
+ return true;
+ }
+ }
+ }
+ break;
+ }
+ break;
+ case CMD_ARROW_ORG3D:
+ if(tmpl) memcpy(&fPos1, tmpl, sizeof(fPOINT3D));
+ return true;
+ case CMD_ARROW_TYPE:
+ if(tmpl) type = *((int*)tmpl);
+ return true;
+ case CMD_UPDATE:
+ if(ssRef && cssRef >5 && data) {
+ data->GetValue(ssRef[0].y, ssRef[0].x, &fPos2.fx);
+ data->GetValue(ssRef[1].y, ssRef[1].x, &fPos2.fy);
+ data->GetValue(ssRef[2].y, ssRef[2].x, &fPos2.fz);
+ data->GetValue(ssRef[3].y, ssRef[3].x, &fPos1.fx);
+ data->GetValue(ssRef[4].y, ssRef[4].x, &fPos1.fy);
+ data->GetValue(ssRef[5].y, ssRef[5].x, &fPos1.fz);
+ return true;
+ }
+ return false;
+ case CMD_AUTOSCALE:
+ if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+ ((Plot*)parent)->CheckBounds3D(fPos1.fx, fPos1.fy, fPos1.fz);
+ ((Plot*)parent)->CheckBounds3D(fPos2.fx, fPos2.fy, fPos2.fz);
+ return true;
+ }
+ break;
+ case CMD_SET_GO3D:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// a data line in 3D space
+Line3D::Line3D(GraphObj *par, DataObj *d, char *rx, char *ry, char *rz)
+ :GraphObj(par, d)
+{
+ FileIO(INIT_VARS);
+ if(rx && rx[0]) x_range = strdup(rx); if(ry && ry[0]) y_range = strdup(ry);
+ if(rz && rz[0]) z_range = strdup(rz);
+ DoUpdate();
+ Id = GO_LINE3D;
+ bModified = false;
+}
+
+Line3D::Line3D(GraphObj *par, DataObj *d, fPOINT3D *pt, int n_pt)
+ :GraphObj(par, d)
+{
+ FileIO(INIT_VARS);
+ if(pt && n_pt) {
+ values = (fPOINT3D*)memdup(pt, n_pt * sizeof(fPOINT3D), 0L);
+ nPts = n_pt;
+ ls = (line_segment **)calloc(nPts-1, sizeof(line_segment*));
+ }
+ Id = GO_LINE3D;
+ bModified = false;
+}
+
+Line3D::Line3D(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+ bModified = false;
+}
+
+Line3D::~Line3D()
+{
+ int i;
+
+ if(bModified) Undo.InvalidGO(this);
+ if(ls){
+ for(i = 0; i < (nPts-1); i++) if(ls[i]) delete(ls[i]);
+ free(ls);
+ }
+ if(pts && npts) free(pts); pts = 0L; npts = 0;
+ if(x_range) free(x_range); x_range = 0L;
+ if(y_range) free(y_range); y_range = 0L;
+ if(z_range) free(z_range); z_range = 0L;
+ if(values) free(values); values = 0L;
+ if(mo) DelBitmapClass(mo); mo = 0L;
+}
+
+void
+Line3D::DoPlot(anyOutput *o)
+{
+ int i, j;
+ fPOINT3D fip;
+ POINT3D p1, p2;
+ POINT np;
+
+
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ if(ls) {
+ if(pts && npts) free(pts);
+ npts = 0; if(!(pts = (POINT*)calloc(nPts, sizeof(POINT))))return;
+ for(i = 0; i< nPts; i++) {
+ if(!o->fvec2ivec(&values[i], &fip)) return;
+ p2.x = iround(fip.fx); p2.y = iround(fip.fy); p2.z = iround(fip.fz);
+ np.x = p2.x; np.y = p2.y;
+ AddToPolygon(&npts, pts, &np);
+ if(i) {
+ UpdateMinMaxRect(&rDims, np.x, np.y);
+ j = i-1;
+ if(ls[j]) delete(ls[j]);
+ if(ls[j] = new line_segment(this, data, &Line, &p1, &p2)) {
+ ls[j]->DoPlot(o);
+ }
+ }
+ else {
+ rDims.left = rDims.right = p2.x;
+ rDims.top = rDims.bottom = p2.y;
+ }
+ p1.x = p2.x; p1.y = p2.y; p1.z = p2.z;
+ }
+ IncrementMinMaxRect(&rDims, 6);
+ }
+}
+
+void
+Line3D::DoMark(anyOutput *o, bool mark)
+{
+ if(mark) {
+ memcpy(&mrc, &rDims, sizeof(RECT));
+ IncrementMinMaxRect(&mrc, 6 + o->un2ix(Line.width));
+ mo = GetRectBitmap(&mrc, o);
+ InvertLine(pts, npts, &Line, &rDims, o, true);
+ }
+ else RestoreRectBitmap(&mo, &mrc, o);
+}
+
+bool
+Line3D::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ POINT p1;
+ int i;
+
+ switch (cmd) {
+ case CMD_FLUSH:
+ if(name) free(name); name = 0L;
+ return true;
+ case CMD_SET_LINE:
+ if(tmpl) {
+ memcpy(&Line, tmpl, sizeof(LineDEF));
+ return true;
+ }
+ return false;
+ case CMD_SET_DATAOBJ:
+ Id = GO_LINE3D;
+ data = (DataObj *)tmpl;
+ return true;
+ case CMD_REDRAW:
+ //Note: this command is issued by Undo (no output given)
+ if(!parent) return false;
+ if(!o) return parent->Command(cmd, tmpl, o);
+ //Should we ever come here ?
+ return true;
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(!IsInRect(&rDims, p1.x= mev->x, p1.y=mev->y)|| CurrGO || !o || nPts <2 ||
+ !IsCloseToPL(p1, pts, npts))return false;
+ o->ShowMark(CurrGO=this, MRK_GODRAW);
+ return true;
+ }
+ return false;
+ case CMD_UPDATE:
+ DoUpdate();
+ case CMD_AUTOSCALE:
+ if(parent && parent->Id > GO_PLOT && parent->Id < GO_GRAPH){
+ if(min.fx == max.fx || min.fy == max.fy){ //z's may be equal !
+ min.fx = min.fy = min.fz = HUGE_VAL;
+ max.fx = max.fy = max.fz = -HUGE_VAL;
+ for(i = 0; i < nPts; i++) {
+ if(values[i].fx < min.fx) min.fx = values[i].fx;
+ if(values[i].fy < min.fy) min.fy = values[i].fy;
+ if(values[i].fz < min.fz) min.fz = values[i].fz;
+ if(values[i].fx > max.fx) max.fx = values[i].fx;
+ if(values[i].fy > max.fy) max.fy = values[i].fy;
+ if(values[i].fz > max.fz) max.fz = values[i].fz;
+ }
+ }
+ ((Plot*)parent)->CheckBounds3D(min.fx, min.fy, min.fz);
+ ((Plot*)parent)->CheckBounds3D(max.fx, max.fy, max.fz);
+ return true;
+ }
+ return false;
+ case CMD_SET_GO3D:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ }
+ return false;
+}
+
+void
+Line3D::DoUpdate()
+{
+ int n1 = 0, ic = 0, i, j, k, l, m, n;
+ double x, y, z;
+ AccRange *rX=0L, *rY=0L, *rZ=0L;
+
+ if(!x_range || !y_range || !z_range) return;
+ if(values) free(values); values = 0L;
+ if(ls) free(ls); ls = 0L;
+ rX = new AccRange(x_range);
+ rY = new AccRange(y_range);
+ rZ = new AccRange(z_range);
+ min.fx = min.fy = min.fz = HUGE_VAL; max.fx = max.fy = max.fz = -HUGE_VAL;
+ if(rX) n1 = rX->CountItems();
+ if(n1 && rY && rZ && (values = (fPOINT3D*)malloc(n1 * sizeof(fPOINT3D)))){
+ rX->GetFirst(&i, &j); rX->GetNext(&i, &j);
+ rY->GetFirst(&k, &l); rY->GetNext(&k, &l);
+ rZ->GetFirst(&m, &n); rZ->GetNext(&m, &n);
+ do {
+ if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y) &&
+ data->GetValue(n, m, &z)){
+ values[ic].fx = x; values[ic].fy = y; values[ic].fz = z;
+ if(x < min.fx) min.fx = x; if(x > max.fx) max.fx = x;
+ if(y < min.fy) min.fy = y; if(y > max.fy) max.fy = y;
+ if(z < min.fz) min.fz = z; if(z > max.fz) max.fz = z;
+ ic++;
+ }
+ }while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l) && rZ->GetNext(&m, &n));
+ nPts = ic;
+ if(ic > 1) ls = (line_segment **)calloc(ic-1, sizeof(line_segment*));
+ }
+ if(rX) delete(rX); if(rY) delete(rY); if(rZ) delete(rZ);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// the text label class
+Label::Label(GraphObj *par, DataObj *d, double x, double y, TextDEF *td, DWORD flg,
+ int xc, int xr, int yc, int yr, int tc, int tr):GraphObj(par, d)
+{
+ FileIO(INIT_VARS);
+ fPos.fx = x; fPos.fy = y; flags = flg;
+ if(parent){
+ fDist.fx = parent->GetSize(SIZE_LB_XDIST);
+ fDist.fy = parent->GetSize(SIZE_LB_YDIST);
+ }
+ Id = GO_LABEL;
+ if(td){
+ memcpy(&TextDef, td, sizeof(TextDEF));
+ if(td->text) TextDef.text = strdup(td->text);
+ }
+ if(xc >= 0 || xr >= 0 || yc >= 0 || yr >= 0 || tc >= 0 || tr >= 0) {
+ if(ssRef = (POINT*)malloc(sizeof(POINT)*3)) {
+ ssRef[0].x = xc; ssRef[0].y = xr;
+ ssRef[1].x = yc; ssRef[1].y = yr;
+ ssRef[2].x = tc; ssRef[2].y = tr;
+ cssRef = 3;
+ }
+ }
+}
+
+Label::Label(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+Label::~Label()
+{
+ Command(CMD_FLUSH, 0L, 0L);
+ if(fmt_txt) delete(fmt_txt); fmt_txt = 0L;
+ if(bModified)Undo.InvalidGO(this);
+}
+
+double
+Label::GetSize(int select)
+{
+ switch(select){
+ case SIZE_CURSORPOS:
+ return (double)CursorPos;
+ case SIZE_CURSOR_XMIN:
+ return (double) (Cursor.right > Cursor.left ? Cursor.left : Cursor.right);
+ case SIZE_CURSOR_XMAX:
+ return (double) (Cursor.right > Cursor.left ? Cursor.right : Cursor.left);
+ case SIZE_CURSOR_YMIN:
+ return (double) (Cursor.bottom > Cursor.top ? Cursor.top : Cursor.bottom);
+ case SIZE_CURSOR_YMAX:
+ return (double) (Cursor.bottom > Cursor.top ? Cursor.bottom : Cursor.top);
+ case SIZE_MIN_Z: case SIZE_MAX_Z: case SIZE_ZPOS:
+ return curr_z;
+ }
+ return 0.0;
+}
+
+bool
+Label::SetSize(int select, double value)
+{
+ switch(select & 0xfff) {
+ case SIZE_LB_XDIST: fDist.fx = value; return true;
+ case SIZE_LB_YDIST: fDist.fy = value; return true;
+ case SIZE_XPOS: fPos.fx = value; return true;
+ case SIZE_YPOS: fPos.fy = value; return true;
+ case SIZE_ZPOS: curr_z = value; return is3D = true;
+ }
+ return false;
+}
+
+bool
+Label::SetColor(int select, DWORD col)
+{
+ switch(select & 0xfff) {
+ case COL_TEXT:
+ if(select & UNDO_STORESET) {
+ Undo.ValDword(this, &TextDef.ColTxt, UNDO_CONTINUE);
+ bModified = true;
+ }
+ TextDef.ColTxt = col; bBGvalid = false;
+ return true;
+ case COL_BG:
+ bgcolor = col; bBGvalid = true;
+ return true;
+ }
+ return false;
+}
+
+void
+Label::DoPlot(anyOutput *o)
+{
+ if(is3D && parent && parent->Command(CMD_SET_GO3D, this, o)) return;
+ DoPlotText(o);
+}
+
+void
+Label::DoMark(anyOutput *o, bool mark)
+{
+ DWORD bgpix[16];
+ int i, d, d1, ix, iy, dx, dy, n;
+ RECT mrc;
+ anyOutput *mo;
+
+ if(mark) {
+ //find color with maximum contrast to text
+ if(!bBGvalid) {
+ mrc.left = rDims.left; mrc.right = rDims.right;
+ mrc.top = rDims.top; mrc.bottom = rDims.bottom;
+ dx = mrc.right - mrc.left; dy = mrc.bottom - mrc.top;
+ if(dx <= 0 || dy <= 0) return;
+ if(mo = GetRectBitmap(&mrc, o)) {
+ for(i = 0, ix = 1; ix < dx; ix += dx<<2) {
+ for(iy = 1; iy < dy; dy += dy<<2) {
+ if(!(mo->oGetPix(pts[ix].x, pts[iy].y, &bgpix[i]))) bgpix[i] = 0x00ffffff;
+ i++;
+ }
+ }
+ DelBitmapClass(mo); n = i;
+ }
+ bgcolor = bgpix[0];
+ d = ColDiff(bgcolor, TextDef.ColTxt);
+ for(i = 1; i < n; i++) {
+ if(d < (d1 = ColDiff(bgpix[i], TextDef.ColTxt))) {
+ d = d1; bgcolor = bgpix[i];
+ }
+ }
+ if(!d) bgcolor = TextDef.ColTxt ^ 0x00ffffffL;
+ bBGvalid = true;
+ }
+ //in dialogs parent has no parent
+ if(parent && parent->parent) o->ShowLine(pts, 5, TextDef.ColTxt);
+ ShowCursor(o); CurrGO = this; CurrLabel = this;
+ }
+ else {
+ HideTextCursor();
+ bgLine.color = bgcolor; o->SetLine(&bgLine);
+ //in dialogs parent has no parent
+ if(parent && parent->parent) o->oPolyline(pts, 5);
+ IncrementMinMaxRect(&rDims, 3);
+ o->UpdateRect(&rDims, false); IncrementMinMaxRect(&rDims, -3);
+ if(CurrLabel == this) CurrLabel = 0L;
+ if(parent && parent->Id != GO_MLABEL && (!TextDef.text || !TextDef.text[0]))
+ parent->Command(CMD_DELOBJ, (void*)this, o);
+ }
+}
+
+bool
+Label::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ char *tmptxt;
+
+ if(cmd != CMD_SET_DATAOBJ && !parent) return false;
+ switch (cmd) {
+ case CMD_FLUSH:
+ if(CurrLabel == this) CurrLabel = 0L;
+ if(TextDef.text) free(TextDef.text); TextDef.text = 0L;
+ if(ssRef) free(ssRef); ssRef = 0L;
+ return true;
+ case CMD_POS_FIRST: case CMD_POS_LAST:
+ Undo.ValInt(this, &CursorPos, 0L);
+ bModified = true;
+ if(o && TextDef.text) {
+ CursorPos = (cmd == CMD_POS_LAST) ? strlen(TextDef.text) : 0;
+ ShowCursor(o);
+ return true;
+ }
+ return false;
+ case CMD_CURRLEFT:
+ if(o && CursorPos >0 && TextDef.text && fmt_txt) {
+ Undo.ValInt(this, &CursorPos, 0L);
+ bModified = true; fmt_txt->cur_left(&CursorPos); ShowCursor(o);
+ return true;
+ }
+ return false;
+ case CMD_CURRIGHT:
+ if(o && TextDef.text && CursorPos < (int)strlen(TextDef.text) && fmt_txt) {
+ Undo.ValInt(this, &CursorPos, 0L);
+ bModified = true; fmt_txt->cur_right(&CursorPos); ShowCursor(o);
+ return true;
+ }
+ return false;
+ case CMD_ADDCHAR:
+ SetModified();
+ if(tmpl && 8 != *((int*)tmpl)) return AddChar(*((int*)tmpl), o);
+ //value 8 == backspace
+ case CMD_BACKSP:
+ SetModified();
+ if(CursorPos <=0 && o) {
+ if(parent->Id == GO_MLABEL) {
+ parent->Command(CMD_SETFOCUS, this, o);
+ return parent->Command(CMD_BACKSP, tmpl, o);
+ }
+ RedrawEdit(o);
+ return true;
+ }
+ Undo.ValInt(this, &CursorPos, 0L);
+ CursorPos--; //continue as if delete
+ case CMD_DELETE:
+ SetModified();
+ if(cmd == CMD_DELETE) Undo.ValInt(this, &CursorPos, 0L);
+ if(TextDef.text && TextDef.text[CursorPos]) {
+ Undo.String(this, &TextDef.text, UNDO_CONTINUE);
+ strcpy(TextDef.text + CursorPos, TextDef.text + CursorPos + 1);
+ if(o)RedrawEdit(o);
+ }
+ else if(TextDef.text && parent->Id == GO_MLABEL) {
+ parent->Command(CMD_SETFOCUS, this, o);
+ return parent->Command(CMD_DELETE, tmpl, o);
+ }
+ else o->HideMark();
+ break;
+ case CMD_GETTEXT:
+ if(TextDef.text && tmpl) {
+ strcpy((char*)tmpl, TextDef.text);
+ return true;
+ }
+ return false;
+ case CMD_SETTEXT:
+ if(TextDef.text) free(TextDef.text);
+ if(tmpl) TextDef.text = strdup((char*)tmpl);
+ else TextDef.text = 0L;
+ return true;
+ case CMD_GETTEXTDEF:
+ if(!tmpl) return false;
+ memcpy(tmpl, &TextDef, sizeof(TextDEF));
+ return true;
+ case CMD_SETTEXTDEF:
+ if(!tmpl)return false;
+ tmptxt = TextDef.text;
+ memcpy(&TextDef, tmpl, sizeof(TextDEF));
+ if(!TextDef.text){
+ TextDef.text = tmptxt;
+ tmptxt = 0L;
+ }
+ else if(((TextDEF*)tmpl)->text) TextDef.text = strdup(((TextDEF*)tmpl)->text);
+ if(tmptxt) free(tmptxt);
+ return true;
+ case CMD_SET_DATAOBJ:
+ Id = GO_LABEL;
+ data = (DataObj*)tmpl;
+ return true;
+ case CMD_UPDATE:
+ if(ssRef && cssRef >2 && data) {
+ data->GetValue(ssRef[0].y, ssRef[0].x, &fPos.fx);
+ data->GetValue(ssRef[1].y, ssRef[1].x, &fPos.fy);
+ if(data->GetText(ssRef[2].y, ssRef[2].x, TmpTxt, TMP_TXT_SIZE)) {
+ if(TextDef.text) free(TextDef.text);
+ TextDef.text = strdup(TmpTxt);
+ }
+ return true;
+ }
+ return false;
+ case CMD_SELECT:
+ if(!o || !tmpl) return false;
+ CalcCursorPos(((POINT*)tmpl)->x, ((POINT*)tmpl)->y, o);
+ o->ShowMark(this, MRK_GODRAW);
+ return true;
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(ObjThere(mev->x, mev->y)) {
+ if(parent && parent->Id == GO_MLABEL) parent->Command(CMD_SETFOCUS, this, o);
+ CalcCursorPos(mev->x, mev->y, o);
+ o->ShowMark(this, MRK_GODRAW);
+ return true;
+ }
+ break;
+ }
+ break;
+ case CMD_AUTOSCALE:
+ if(parent->Id >= GO_PLOT && parent->Id < GO_GRAPH
+ && (flags & LB_X_DATA) && (flags & LB_Y_DATA)) {
+ ((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);
+ return true;
+ }
+ break;
+ case CMD_REDRAW:
+ if(is3D && o) {
+ DoPlotText(o);
+ is3D = false; //enable edit
+ }
+ else if(CurrGO == this) {
+ if(parent && parent->parent) RedrawEdit(defDisp); //not a dialog
+ else ShowCursor(defDisp); //dialog !
+ }
+ else return parent->Command(cmd, tmpl, o);
+ return true;
+ case CMD_MOVE:
+ if(parent && (parent->Id == GO_MLABEL || parent->Id == GO_LEGITEM))
+ return parent->Command(cmd, tmpl, o);
+ Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
+ case CMD_UNDO_MOVE:
+ if(fmt_txt) delete(fmt_txt); fmt_txt = 0L;
+ if(!(flags & 0x03)) fPos.fx += ((lfPOINT*)tmpl)[0].fx;
+ if(!(flags & 0x30)) fPos.fy += ((lfPOINT*)tmpl)[0].fy;
+ if(o){
+ o->StartPage(); parent->DoPlot(o); o->EndPage();
+ }
+ return bModified = true;
+ }
+ return false;
+}
+
+void *
+Label::ObjThere(int x, int y)
+{
+ POINT p1;
+
+ if(IsInRect(&rDims, p1.x = x, p1.y = y) && IsInPolygon(&p1, pts, 5))
+ return this;
+ return 0L;
+}
+
+void
+Label::Track(POINT *p, anyOutput *o)
+{
+ POINT *tpts;
+ RECT old_rc;
+ int i;
+
+ if(!parent) return;
+ if(parent->Id == GO_MLABEL || parent->Id == GO_LEGITEM){
+ parent->Track(p, o);
+ return;
+ }
+ if(o && (tpts = (POINT*)malloc(5*sizeof(POINT)))){
+ memcpy(&old_rc, &rDims, sizeof(rDims));
+ //note: mLabel set Id to zero upon trackking
+ // thus rectangle is not updated if parent is a mLabel
+ if(parent->Id) o->UpdateRect(&rDims, false);
+ for(i = 0; i < 5; i++) {
+ tpts[i].x = pts[i].x+p->x; tpts[i].y = pts[i].y+p->y;
+ UpdateMinMaxRect(&rDims, tpts[i].x, tpts[i].y);
+ }
+ o->ShowLine(tpts, 5, TextDef.ColTxt);
+ if(old_rc.left != rDims.left || old_rc.right != rDims.right || old_rc.top !=
+ rDims.top || old_rc.bottom != rDims.bottom)IncrementMinMaxRect(&rDims, 3);
+ free(tpts);
+ }
+}
+
+bool
+Label::CalcRect(anyOutput *o)
+{
+ int rx1, rx, ry;
+ fRECT rc, rcc;
+
+ if(parent && parent->Id != GO_MLABEL) o->SetTextSpec(&TextDef);
+ if(fmt_txt && TextDef.text && TextDef.text[0]) {
+ fmt_txt->SetText(0L, TextDef.text, &ix, &iy);
+ if(!(fmt_txt->oGetTextExtent(o, &rx, &ry, 0))) return false;
+ rx++;
+ }
+ else {
+ if(!(o->oGetTextExtent("A", 1, &rx, &ry))) return false;
+ rx = 1;
+ }
+ rx += 4; rc.Xmin = -2.0f; rc.Ymin = 0.0f; rc.Xmax = rx; rc.Ymax = ry;
+ si = sin(TextDef.RotBL *0.01745329252); csi = cos(TextDef.RotBL *0.01745329252);
+ if(TextDef.Align & TXA_HCENTER) {
+ rc.Xmin -= rx/2.0-1.0; rc.Xmax -= rx/2.0-1.0;
+ }
+ else if(TextDef.Align & TXA_HRIGHT) {
+ rc.Xmin -= rx-2.0; rc.Xmax -= rx-2.0;
+ }
+ if(TextDef.Align & TXA_VCENTER) {
+ rc.Ymin -= ry/2.0; rc.Ymax -= ry/2.0;
+ }
+ else if(TextDef.Align & TXA_VBOTTOM) {
+ rc.Ymin -= ry; rc.Ymax -= ry;
+ }
+ if(fmt_txt && fmt_txt->oGetTextExtent(o, &rx1, &ry, CursorPos)){
+ rx = CursorPos ? (int)rx1 : 0;
+ }
+ else rx = 0;
+ rcc.Xmax = rc.Xmin + (double)rx+2.0; rcc.Ymin = rc.Ymin+2.0;
+ rcc.Xmin = rc.Xmin; rcc.Ymax = rc.Ymax-2.0;
+ pts[0].x = iround(rc.Xmin*csi + rc.Ymin*si)+ix;
+ pts[0].y = iround(rc.Ymin*csi - rc.Xmin*si)+iy;
+ pts[1].x = iround(rc.Xmax*csi + rc.Ymin*si)+ix;
+ pts[1].y = iround(rc.Ymin*csi - rc.Xmax*si)+iy;
+ pts[2].x = iround(rc.Xmax*csi + rc.Ymax*si)+ix;
+ pts[2].y = iround(rc.Ymax*csi - rc.Xmax*si)+iy;
+ pts[3].x = iround(rc.Xmin*csi + rc.Ymax*si)+ix;
+ pts[3].y = iround(rc.Ymax*csi - rc.Xmin*si)+iy;
+ pts[4].x = pts[0].x; pts[4].y = pts[0].y;
+ Cursor.left = iround(rcc.Xmax*csi + rcc.Ymin*si)+ix;
+ Cursor.top = iround(rcc.Ymin*csi - rcc.Xmax*si)+iy;
+ Cursor.right = iround(rcc.Xmax*csi + rcc.Ymax*si)+ix;
+ Cursor.bottom = iround(rcc.Ymax*csi - rcc.Xmax*si)+iy;
+ return true;
+}
+
+void
+Label::RedrawEdit(anyOutput *o)
+{
+ FillDEF bgFill = {FILL_NONE, bgcolor, 1.0, 0L, bgcolor};
+
+ if(!o || !parent) return;
+ bgLine.color = bgcolor; o->SetLine(&bgLine); o->SetFill(&bgFill);
+ o->oPolygon(pts, 5); IncrementMinMaxRect(&rDims, 3);
+ o->UpdateRect(&rDims, false);
+ CalcRect(o); bgLine.color ^= 0x00ffffffL;
+ o->SetLine(&bgLine); o->oPolygon(pts, 5);
+ if(parent->Id == GO_MLABEL) {
+ if(parent->parent && parent->parent->Id == GO_LEGITEM && parent->parent->parent)
+ parent->parent->parent->DoPlot(o);
+ else parent->DoPlot(o);
+ }
+ else if(parent->Id == GO_LEGITEM && parent->parent) parent->parent->DoPlot(o);
+ else DoPlot(o);
+ o->UpdateRect(&rDims, false);
+ DoMark(o, true); ShowCursor(o);
+}
+
+void
+Label::ShowCursor(anyOutput *o)
+{
+ CalcRect(o);
+ ShowTextCursor(o, &Cursor, TextDef.ColTxt);
+}
+
+bool
+Label::AddChar(int ci, anyOutput *o)
+{
+ char c, *txt1 = 0L;
+ int i, j, k;
+ GraphObj *golist[2];
+
+ if(!o) return false;
+ if(ci == 13 && parent){ //CR
+ if(parent->Id == GO_MLABEL){
+ parent->Command(CMD_SETFOCUS, this, o);
+ return parent->Command(CMD_ADDCHAR, &ci, o);
+ }
+ if(golist[1] = new mLabel(parent, data, fPos.fx, fPos.fy, &TextDef,
+ TextDef.text, CursorPos, flags)){
+ golist[1]->moveable = moveable;
+ golist[1]->SetSize(SIZE_LB_XDIST, fDist.fx);
+ golist[1]->SetSize(SIZE_LB_YDIST, fDist.fy);
+ }
+ golist[0] = this;
+ if(!parent->Command(CMD_MUTATE, golist, o)) DeleteGO(golist[1]);
+ return false;
+ }
+ if(ci < 254 && ci > 31) c = (char)ci;
+ else return false;
+ if(!TextDef.text || CursorPos < 10 || c == ' ') {
+ Undo.String(this, &TextDef.text, 0L);
+ Undo.ValInt(this, &CursorPos, UNDO_CONTINUE);
+ }
+ if(TextDef.text) txt1 = (char*)calloc((i = strlen(TextDef.text))+2, sizeof(char));
+ else txt1 = (char*)calloc((i = 0)+2, sizeof(char));
+ if(txt1) {
+ for(j = k = 0; j< i && j < CursorPos; txt1[k++] = TextDef.text[j++]);
+ txt1[k++] = c;
+ for(; j< i; txt1[k++] = TextDef.text[j++]);
+ if(TextDef.text) free(TextDef.text);
+ TextDef.text = txt1;
+ CursorPos++; RedrawEdit(o);
+ }
+ return true;
+}
+
+void
+Label::CalcCursorPos(int x, int y, anyOutput *o)
+{
+ int i, j, ix, x1, y1, x2, h;
+
+ if(!o || !TextDef.text) return;
+ TextDef.iSize = o->un2iy(TextDef.fSize);
+ if(parent && parent->Id != GO_MLABEL) o->SetTextSpec(&TextDef);
+ x1 = ((pts[3].x + pts[4].x)>>1); y1 = ((pts[3].y + pts[4].y)>>1);
+ ix = ((j=(x1-x))*j); ix += ((j=(y1-y))*j); ix = isqr(ix);
+ for(i = 1, x1 = 0; TextDef.text[i-1]; i++) {
+ o->oGetTextExtent(TextDef.text, i, &x2, &h);
+ if(x1 <= ix && x2 >= ix) {
+ if((ix-x1) < (x2-ix)) CursorPos = i-1;
+ else CursorPos = i;
+ return;
+ }
+ else if(ix < x2){
+ CursorPos = i-1;
+ return;
+ }
+ x1 = x2;
+ }
+ if(pts[3].x < pts[2].x && x < pts[3].x) CursorPos = 0;
+ else CursorPos = strlen(TextDef.text);
+}
+
+void
+Label::SetModified()
+{
+ AxisDEF *adef;
+
+ bModified = true;
+ if(parent && parent->Id==GO_TICK && parent->parent && parent->parent->Id==GO_AXIS){
+ adef = ((Axis*)(parent->parent))->GetAxis();
+ adef->flags &= ~AXIS_AUTOSCALE;
+ }
+}
+
+void
+Label::DoPlotText(anyOutput *o)
+{
+ if(!parent || !o) return;
+ defDisp = o;
+ if(parent && parent->Id == GO_MLABEL) parent->Command(CMD_SETFOCUS, this, o);
+ switch(flags & 0x03) {
+ case LB_X_DATA: ix = o->fx2ix(fPos.fx); break;
+ case LB_X_PARENT:
+ ix = iround(parent->GetSize(SIZE_LB_XPOS));
+ break;
+ default:
+ ix = o->co2ix(fPos.fx + parent->GetSize(SIZE_GRECT_LEFT));
+ break;
+ }
+ switch(flags & 0x30) {
+ case LB_Y_DATA: iy = o->fy2iy(fPos.fy); break;
+ case LB_Y_PARENT:
+ iy = iround(parent->GetSize(SIZE_LB_YPOS));
+ break;
+ default:
+ iy = o->co2iy(fPos.fy +parent->GetSize(SIZE_GRECT_TOP));
+ break;
+ }
+ ix += o->un2ix(fDist.fx); iy += o->un2iy(fDist.fy);
+ TextDef.iSize = o->un2iy(TextDef.fSize);
+ o->SetTextSpec(&TextDef);
+ if(TextDef.text && TextDef.text[0]){
+ if(fmt_txt) fmt_txt->SetText(o, TextDef.text, &ix, &iy);
+ else fmt_txt = new fmtText(o, ix, iy, TextDef.text);
+ }
+ if(!(CalcRect(o))) return;
+ SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+ UpdateMinMaxRect(&rDims, pts[2].x, pts[2].y);
+ UpdateMinMaxRect(&rDims, pts[3].x, pts[3].y);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// a multiline label consists of several Label objects
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+mLabel::mLabel(GraphObj *par, DataObj *d, double x, double y, TextDEF *td, char *txt,
+ int cp, DWORD flg):GraphObj(par, d)
+{
+ int i;
+
+ memcpy(&TextDef, td, sizeof(TextDEF));
+ TextDef.text = 0L; fPos.fx = x; fPos.fy = y;
+ Lines = 0L; flags = flg;
+ fDist.fx = 0.0; fDist.fy = 0.0;
+ CurrGO = CurrLabel = 0L;
+ if(txt && (Lines = (Label**)calloc(2, sizeof(Label*)))) {
+ for(i = 0; i < cp && txt[i]; i ++) TmpTxt[i] = txt[i];
+ TmpTxt[i] = 0;
+ if(Lines[0] = new Label(this, d, x, y, &TextDef, LB_X_PARENT | LB_Y_PARENT))
+ Lines[0]->Command(CMD_SETTEXT, TmpTxt, 0L);
+ if(Lines[1] = new Label(this, d, x, y, &TextDef, LB_X_PARENT | LB_Y_PARENT)){
+ Lines[1]->Command(CMD_SETTEXT, txt+cp, 0L);
+ CurrGO = CurrLabel = Lines[1];
+ }
+ nLines = 2; cli = 1;
+ }
+ Id = GO_MLABEL;
+}
+
+mLabel::mLabel(GraphObj *par, DataObj *d, double x, double y, TextDEF *td, char *txt)
+ :GraphObj(par, d)
+{
+ int i, nll;
+ char **llist;
+
+ memcpy(&TextDef, td, sizeof(TextDEF));
+ TextDef.text = 0L; fPos.fx = x; fPos.fy = y;
+ Lines = 0L; flags = 0L; Id = GO_MLABEL;
+ fDist.fx = 0.0; fDist.fy = 0.0;
+ CurrGO = CurrLabel = 0L;
+ if(txt){
+ if((llist=split(txt,'\n',&nll)) && nll && (Lines=(Label**)calloc(nll, sizeof(Label*)))){
+ for(i = 0; i < nll; i++) {
+ if(llist[i]){
+ Lines[i] = new Label(this, d, x, y, &TextDef, LB_X_PARENT | LB_Y_PARENT);
+ Lines[i]->Command(CMD_SETTEXT, llist[i], 0L);
+ free(llist[i]);
+ }
+ }
+ free(llist); nLines = nll; cli = 0;
+ }
+ }
+}
+
+mLabel::mLabel(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+mLabel::~mLabel()
+{
+ int i;
+
+ Undo.InvalidGO(this);
+ if(Lines){
+ for(i = 0; i < nLines; i++) if(Lines[i]) DeleteGO(Lines[i]);
+ free(Lines);
+ }
+}
+
+double
+mLabel::GetSize(int select)
+{
+ switch(select){
+ case SIZE_LB_XPOS: return cPos1.fx;
+ case SIZE_LB_YPOS: return cPos1.fy;
+ case SIZE_GRECT_TOP:
+ if (parent) return parent->GetSize(select);
+ break;
+ case SIZE_MIN_Z: case SIZE_MAX_Z: case SIZE_ZPOS:
+ return curr_z;
+ }
+ return 0.0;
+}
+
+bool
+mLabel::SetSize(int select, double value)
+{
+ int i;
+
+ switch(select & 0xfff) {
+ case SIZE_LB_XDIST:
+ undo_flags = CheckNewFloat(&fDist.fx, fDist.fx, value, this, undo_flags);
+ return true;
+ case SIZE_LB_YDIST:
+ undo_flags = CheckNewFloat(&fDist.fy, fDist.fy, value, this, undo_flags);
+ return true;
+ case SIZE_XPOS:
+ undo_flags = CheckNewFloat(&fPos.fx, fPos.fx, value, this, undo_flags);
+ return true;
+ case SIZE_YPOS:
+ undo_flags = CheckNewFloat(&fPos.fy, fPos.fy, value, this, undo_flags);
+ return true;
+ case SIZE_ZPOS:
+ curr_z = value;
+ if(Lines) for(i = 0; i < nLines; i++) if(Lines[i]){
+ Lines[i]->SetSize(select, value);
+ }
+ return is3D = true;
+ }
+ return false;
+}
+
+void
+mLabel::DoPlot(anyOutput *o)
+{
+ int i;
+ double dh, dx, dy;
+
+ if(!o || !Lines) return;
+ undo_flags = 0L;
+ if(parent){ //if this object is part of a dialog we dont have a parent
+ dx = parent->GetSize(SIZE_GRECT_LEFT);
+ dy = parent->GetSize(SIZE_GRECT_TOP);
+ }
+ else dx = dy = 0.0;
+ cPos.fx = cPos.fy = 0.0;
+ TextDef.iSize = o->un2iy(TextDef.fSize);
+ switch(flags & 0x03) {
+ case LB_X_DATA: cPos.fx = o->fx2fix(fPos.fx); break;
+ case LB_X_PARENT: if(parent) cPos.fx = parent->GetSize(SIZE_LB_XPOS); break;
+ default:
+ //if no parent its a dialog
+ cPos.fx = parent ? o->co2fix(fPos.fx + dx) : fPos.fx;
+ break;
+ }
+ switch(flags & 0x30) {
+ case LB_Y_DATA: cPos.fy = o->fy2fiy(fPos.fy); break;
+ case LB_Y_PARENT: if(parent) cPos.fy = parent->GetSize(SIZE_LB_YPOS); break;
+ default:
+ //if no parent its a dialog
+ cPos.fy = parent ? o->co2fiy(fPos.fy + dy) : fPos.fy;
+ break;
+ }
+ si = sin(TextDef.RotBL *0.01745329252f); csi = cos(TextDef.RotBL *0.01745329252f);
+ if(TextDef.Align & TXA_VBOTTOM) dh = (double)(nLines-1);
+ else if(TextDef.Align & TXA_VCENTER) dh = ((double)(nLines-1))/2.0;
+ else dh = 0.0; dh *= TextDef.fSize;
+ cPos.fx -= o->un2fix(dh*si); cPos.fy -= o->un2fiy(dh*csi);
+ memcpy(&cPos1, &cPos, sizeof(lfPOINT));
+ dist.fx = floor(o->un2fix(TextDef.fSize * si * 1.1));
+ dist.fy = floor(o->un2fiy(TextDef.fSize * csi * 1.1));
+ o->SetTextSpec(&TextDef);
+ rDims.left = rDims.top = rDims.right = rDims.bottom = 0;
+ for(i = 0; i < nLines; i++) if(Lines[i]){
+ Lines[i]->Command(CMD_SETTEXTDEF, &TextDef, o);
+ Lines[i]->SetSize(SIZE_LB_XDIST, fDist.fx); Lines[i]->SetSize(SIZE_LB_YDIST, fDist.fy);
+ Lines[i]->SetSize(SIZE_XPOS, fPos.fx); Lines[i]->SetSize(SIZE_YPOS, fPos.fy);
+ Lines[i]->moveable = moveable; Lines[i]->DoPlot(o);
+ UpdateMinMaxRect(&rDims, Lines[i]->rDims.left, Lines[i]->rDims.top);
+ UpdateMinMaxRect(&rDims, Lines[i]->rDims.right, Lines[i]->rDims.bottom);
+ }
+ if(CurrLabel && o && Command(CMD_SETFOCUS, CurrLabel, o))
+ Lines[cli]->ShowCursor(o);
+}
+
+bool
+mLabel::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i, j, k;
+ fRECT t_cur;
+ MouseEvent mev;
+
+ switch (cmd) {
+ case CMD_MOUSE_EVENT:
+ if(Lines && tmpl && IsInRect(&rDims, ((MouseEvent*)tmpl)->x, ((MouseEvent*)tmpl)->y))
+ for(i = 0; i<nLines; i++) if(Lines[i] && Lines[i]->Command(cmd, tmpl, o)) return true;
+ break;
+ case CMD_HIDE_MARK:
+ if(Lines && o && tmpl) for(i = 0; i< nLines; i++)
+ if(Lines[i] && tmpl == (void*)Lines[i]){
+ Lines[i]->DoMark(o, false);
+ return true;
+ }
+ return false;
+ case CMD_ADDCHAR:
+ if(!tmpl || 13 != *((int*)tmpl)) return false;
+ if(!Lines[cli] || !Lines[cli]->Command(CMD_GETTEXT, &TmpTxt, o)) return false;
+ k = iround(Lines[cli]->GetSize(SIZE_CURSORPOS));
+ if(parent)Undo.ObjConf(this, 0L);
+ if(tmpl && Lines && (Lines = (Label**)realloc(Lines, (nLines+1) * sizeof(Label*)))) {
+ for(i = nLines-1, j = nLines; i >= cli; i--, j-- ) {
+ Lines[j] = Lines[i];
+ }
+ i++, j++;
+ if(Lines[j]) DeleteGO(Lines[j]); Lines[i] = Lines[j] = 0L; nLines++;
+ if(Lines[j] = new Label(this, data, fPos.fx, fPos.fy, &TextDef, LB_X_PARENT | LB_Y_PARENT)){
+ Lines[j]->Command(CMD_SETTEXT, TmpTxt+k, o);
+ Lines[j]->Command(CMD_POS_FIRST, 0L, o);
+ CurrGO = CurrLabel = Lines[j];
+ TmpTxt[k] = 0;
+ }
+ if(Lines[i] = new Label(this, data, fPos.fx, fPos.fy, &TextDef, LB_X_PARENT | LB_Y_PARENT))
+ Lines[i]->Command(CMD_SETTEXT, TmpTxt, 0L);
+ Command(CMD_SETFOCUS, CurrGO, o);
+ if(parent) return parent->Command(CMD_REDRAW, 0L, o);
+ else if(o) DoPlot(o);
+ }
+ break;
+ case CMD_SETFOCUS:
+ for(i = 0; i< nLines; i++) if(Lines[i] == (Label*)tmpl) {
+ cli = i;
+ cPos1.fx = cPos.fx + dist.fx*i;
+ cPos1.fy = cPos.fy + dist.fy*i;
+ return true;
+ }
+ break;
+ case CMD_GETTEXT:
+ if(tmpl && Lines && nLines && Lines[0]) return Lines[0]->Command(CMD_GETTEXT, tmpl, o);
+ break;
+ case CMD_ALLTEXT:
+ if(tmpl && Lines && nLines){
+ for(i = 0, j = 500; i < nLines; i++) {
+ if(Lines[i] && Lines[i]->Command(CMD_GETTEXT, TmpTxt, o) && TmpTxt[0]){
+ j += sprintf(TmpTxt+j, "%s\n", TmpTxt);
+ }
+ }
+ strcpy((char*)tmpl, TmpTxt+500);
+ return true;
+ }
+ break;
+ case CMD_DELETE:
+ cli++;
+ //fall through
+ case CMD_BACKSP:
+ if(cli > 0 && cli < nLines && Lines && Lines[cli] && Lines[cli-1]) {
+ Lines[cli-1]->Command(CMD_POS_LAST, 0L, o);
+ TmpTxt[0] = 0;
+ Lines[cli-1]->Command(CMD_GETTEXT, TmpTxt, o);
+ Lines[cli]->Command(CMD_GETTEXT, TmpTxt+strlen(TmpTxt), o);
+ Lines[cli-1]->Command(CMD_SETTEXT, TmpTxt, o);
+ DeleteGO(Lines[cli]); Lines[cli] = 0L;
+ for(i = cli+1; i < nLines; i++){
+ Lines[i-1] = Lines[i], Lines[i]= 0L;
+ }
+ nLines--;
+ CurrGO = CurrLabel = Lines[cli-1];
+ if(parent) parent->Command(CMD_REDRAW, 0L, o);
+ if(CurrLabel) CurrLabel->RedrawEdit(o);
+ return true;
+ }
+ return false;
+ case CMD_GETTEXTDEF:
+ if(!tmpl) return false;
+ memcpy(tmpl, &TextDef, sizeof(TextDEF));
+ return true;
+ case CMD_SETTEXTDEF:
+ if(!tmpl)return false;
+ Undo.TextDef(this, &TextDef, undo_flags);
+ undo_flags |= UNDO_CONTINUE;
+ memcpy(&TextDef, tmpl, sizeof(TextDEF));
+ TextDef.text = 0L;
+ return true;
+ case CMD_SET_DATAOBJ:
+ if(Lines) for(i = 0; i< nLines; i++)
+ if(Lines[i]) Lines[i]->Command(cmd, tmpl, o);
+ Id = GO_MLABEL;
+ data = (DataObj*)tmpl;
+ if(Lines) for(i = 0; i< nLines; i++)
+ if(Lines[i])Lines[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_AUTOSCALE:
+ if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH
+ && (flags & LB_X_DATA) && (flags & LB_Y_DATA)) {
+ ((Plot*)parent)->CheckBounds(fPos.fx, fPos.fy);
+ return true;
+ }
+ break;
+ case CMD_CURRUP: case CMD_CURRDOWN:
+ if(!o) return false;
+ o->SetTextSpec(&TextDef);
+ Command(CMD_SETFOCUS, CurrGO, o);
+ if(cli >= 0 && cli < nLines && Lines && Lines[cli]) {
+ t_cur.Xmin = Lines[cli]->GetSize(SIZE_CURSOR_XMIN);
+ t_cur.Xmax = Lines[cli]->GetSize(SIZE_CURSOR_XMAX);
+ t_cur.Ymin = Lines[cli]->GetSize(SIZE_CURSOR_YMIN);
+ t_cur.Ymax = Lines[cli]->GetSize(SIZE_CURSOR_YMAX);
+ mev.StateFlags = 0; mev.Action = MOUSE_LBUP;
+ mev.x = iround((t_cur.Xmax+t_cur.Xmin)/2.0);
+ mev.y = iround((t_cur.Ymax+t_cur.Ymin)/2.0);
+ i = o->un2ix(TextDef.fSize*si); j = o->un2iy(TextDef.fSize*csi);
+ if(cmd == CMD_CURRUP && cli > 0 && Lines[cli-1]) {
+ Lines[cli-1]->CalcCursorPos(mev.x -= i, mev.y -= j, o);
+ o->ShowMark(CurrGO = CurrLabel = Lines[cli-=1], MRK_GODRAW);
+ return Command(CMD_SETFOCUS, Lines[cli], o);
+ }
+ if(cmd == CMD_CURRDOWN && cli < (nLines-1) && Lines[cli+1]) {
+ Lines[cli+1]->CalcCursorPos(mev.x += i, mev.y += j, o);
+ o->ShowMark(CurrGO = CurrLabel = Lines[cli+=1], MRK_GODRAW);
+ return Command(CMD_SETFOCUS, Lines[cli], o);
+ }
+ }
+ else return false;
+ break;
+ case CMD_SELECT:
+ if(o && tmpl) for(i = 0; i < nLines; i++){
+ o->SetTextSpec(&TextDef);
+ if(Lines[i] && ((POINT*)tmpl)->y > Lines[i]->rDims.top && ((POINT*)tmpl)->y <
+ Lines[i]->rDims.bottom) return Lines[i]->Command(cmd, tmpl, o);
+ }
+ break;
+ case CMD_DELOBJ:
+ if(parent && Lines) for(i = 0; i< nLines; i++)
+ if(Lines[i] && Lines[i] == (Label*)tmpl) return parent->Command(cmd, this, o);
+ break;
+ case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ else if(o) DoPlot(o);
+ break;
+ case CMD_MOVE:
+ if(parent && parent->Id == GO_LEGITEM) return parent->Command(cmd, tmpl, o);
+ Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
+ case CMD_UNDO_MOVE:
+ if(!(flags & 0x03)) fPos.fx += ((lfPOINT*)tmpl)[0].fx;
+ if(!(flags & 0x30)) fPos.fy += ((lfPOINT*)tmpl)[0].fy;
+ if(o && parent){
+ o->StartPage(); parent->DoPlot(o); o->EndPage();
+ }
+ return true;
+ }
+ return false;
+}
+
+void
+mLabel::Track(POINT *p, anyOutput *o)
+{
+ int i;
+
+ if(!parent) return;
+ if(parent->Id == GO_LEGITEM){
+ parent->Track(p, o);
+ return;
+ }
+ for(i = 0; i < nLines; i++) if(Lines[i]){
+ if(!i) memcpy(&rDims, &Lines[i]->rDims, sizeof(RECT));
+ else {
+ UpdateMinMaxRect(&rDims, Lines[i]->rDims.left, Lines[i]->rDims.top);
+ UpdateMinMaxRect(&rDims, Lines[i]->rDims.right, Lines[i]->rDims.bottom);
+ }
+ }
+ o->UpdateRect(&rDims, false);
+ Id = 0L; //disable reentrance from Label objects
+ for(i = 0; i < nLines; i++) if(Lines[i]) Lines[i]->Track(p, o);
+ Id = GO_MLABEL; //enable entrance from Label objects
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// The following GOs use absolute coordinates
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// The segment object is either a pie slice or a ring segment
+//
+segment::segment(GraphObj *par, DataObj *d, lfPOINT *c, double r1, double r2,
+ double a1, double a2):GraphObj(par, d)
+{
+ FileIO(INIT_VARS);
+ segFill.hatch = &segFillLine;
+ segFill.color = 0x00c0c0c0L;
+ fCent.fx = c->fx; fCent.fy = c->fy;
+ radius1 = r1; radius2 = r2;
+ angle1 = a1; angle2 = a2;
+ Id = GO_SEGMENT;
+ bModified = false;
+}
+
+segment::segment(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+ bModified = false;
+}
+
+segment::~segment()
+{
+ if(pts && nPts) free(pts);
+ if(bModified) Undo.InvalidGO(this);
+}
+
+bool
+segment::SetSize(int select, double value)
+{
+ switch(select & 0xfff) {
+ case SIZE_XPOS: fCent.fx = value; break;
+ case SIZE_YPOS: fCent.fy = value; break;
+ case SIZE_RADIUS1: radius1 = value; break;
+ case SIZE_RADIUS2: radius2 = value; break;
+ case SIZE_ANGLE1: angle1 = value; break;
+ case SIZE_ANGLE2: angle2 = value; break;
+ default: return false;
+ }
+ return true;
+}
+
+void
+segment::DoPlot(anyOutput *o)
+{
+ double dsize, dpt, frx1, frx2, dtmp, da, dda, sia, csia;
+ int i, n, npt = 12;
+ POINT np, of, cp, *tmppts;
+
+ if(!o || angle1 == angle2) return;
+ dsize = angle1 > angle2 ? angle1 -angle2 : (angle1+360.0)-angle2;
+ dpt = dsize*0.01745329252; //degrees to rad
+ frx1 = (double)o->un2fix(radius1);
+ frx2 = (double)o->un2fix(radius2);
+ dtmp = frx1*dpt;
+ npt += (int)(dtmp < dsize ? dtmp : dsize);
+ dtmp = frx2*dpt;
+ npt += (int)(dtmp < dsize ? dtmp : dsize);
+ if(!(pts = (POINT*)malloc(npt*sizeof(POINT))))return;
+ nPts = 0;
+ n = (dtmp < dsize) ? (int)dtmp : (int)dsize;
+ while (n<2) n++;
+ da = angle1*0.01745329252;
+ dda = (dsize*0.01745329252)/(double)n;
+ sia = sin(0.5*((angle2 < angle1 ? angle1 : angle1 +360) + angle2) * 0.01745329252);
+ csia = cos(0.5*((angle2 < angle1 ? angle1 : angle1 +360) + angle2) * 0.01745329252);
+ of.x = o->un2ix(shift * csia);
+ of.y = - (o->un2iy(shift * sia));
+ cp.x = o->co2ix(fCent.fx + (parent ? parent->GetSize(SIZE_GRECT_LEFT): 0.0));
+ cp.y = o->co2iy(fCent.fy + (parent ? parent->GetSize(SIZE_GRECT_TOP): 0.0));
+ for(i = 0; i < n; i++) {
+ sia = sin(da); csia = cos(da);
+ np.x = of.x + cp.x; np.y = of.y + cp.y;
+ np.x += o->un2ix(csia*radius2); np.y -= o->un2iy(sia*radius2);
+ AddToPolygon(&nPts, pts, &np);
+ da -= dda;
+ }
+ sia = sin(angle2 *0.01745329252);
+ csia = cos(angle2 *0.01745329252);
+ np.x = of.x + cp.x; np.y = of.y + cp.y;
+ np.x += o->un2ix(csia*radius2); np.y -= o->un2iy(sia*radius2);
+ AddToPolygon(&nPts, pts, &np);
+ dtmp = frx1*dpt;
+ n = dtmp < dsize ? (int)dtmp : (int)dsize;
+ da = angle2*0.01745329252;
+ if(n>1)dda = (dsize*0.01745329252)/(double)n;
+ else dda = 0.0;
+ for(i = 0; i < n; i++) {
+ sia = sin(da); csia = cos(da);
+ np.x = of.x + cp.x; np.y = of.y + cp.y;
+ np.x += o->un2ix(csia*radius1); np.y -= o->un2iy(sia*radius1);
+ AddToPolygon(&nPts, pts, &np);
+ da += dda;
+ }
+ sia = sin(angle1 *0.01745329252); csia = cos(angle1 *0.01745329252);
+ np.x = of.x + cp.x; np.y = of.y + cp.y;
+ np.x += o->un2ix(csia*radius1); np.y -= o->un2iy(sia*radius1);
+ AddToPolygon(&nPts, pts, &np);
+ if(nPts <3) return;
+ AddToPolygon(&nPts, pts, &pts[0]); //close polygon
+ o->SetLine(&segLine); o->SetFill(&segFill);
+ o->oPolygon(pts, nPts);
+ if(tmppts = (POINT*)realloc(pts, nPts *sizeof(POINT))) pts = tmppts;
+ SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+ for(i = 2; i < nPts; i++) UpdateMinMaxRect(&rDims, pts[i].x, pts[i].y);
+ i = 3*o->un2ix(segLine.width); //increase size of rectangle for marks
+ IncrementMinMaxRect(&rDims, i+6);
+}
+
+void
+segment::DoMark(anyOutput *o, bool mark)
+{
+ if(mark)InvertPolygon(pts, nPts, &segLine, &segFill, &rDims, o, mark);
+ else if(parent) {
+ parent->DoPlot(o);
+ o->UpdateRect(&rDims, false);
+ }
+}
+
+bool
+segment::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ FillDEF *TmpFill;
+ LegItem *leg;
+
+ switch (cmd) {
+ case CMD_LEGEND:
+ if(tmpl) {
+ leg = new LegItem(this, data, 0L, &segLine, &segFill);
+ if(!((Legend*)tmpl)->Command(CMD_DROP_OBJECT, leg, o)) DeleteGO(leg);
+ }
+ return true;
+ case CMD_MOUSE_EVENT:
+ switch (((MouseEvent*)tmpl)->Action) {
+ case MOUSE_LBUP:
+ if(ObjThere(((MouseEvent*)tmpl)->x, ((MouseEvent*)tmpl)->y))
+ return o->ShowMark(CurrGO=this, MRK_GODRAW);
+ }
+ return false;
+ case CMD_SET_DATAOBJ:
+ Id = GO_SEGMENT;
+ return true;
+ case CMD_REDRAW:
+ return parent ? parent->Command(cmd, tmpl, o) : false;
+ case CMD_SEG_FILL:
+ TmpFill = (FillDEF *)tmpl;
+ if(TmpFill) {
+ segFill.type = TmpFill->type; segFill.color = TmpFill->color;
+ segFill.scale = TmpFill->scale;
+ if(TmpFill->hatch) memcpy(&segFillLine, TmpFill->hatch, sizeof(LineDEF));
+ }
+ return true;
+ case CMD_SEG_LINE:
+ if(tmpl) memcpy(&segLine, tmpl, sizeof(LineDEF));
+ return true;
+ case CMD_SEG_MOVEABLE:
+ if(tmpl) moveable = *((int*)tmpl);
+ return true;
+ case CMD_SHIFT_OUT:
+ if(tmpl) shift = *((double*)tmpl);
+ return true;
+ case CMD_MOVE:
+ bModified = true;
+ Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
+ case CMD_UNDO_MOVE:
+ fCent.fx += ((lfPOINT*)tmpl)[0].fx; fCent.fy += ((lfPOINT*)tmpl)[0].fy;
+ if(parent)parent->Command(CMD_REDRAW, 0L, o);
+ return true;
+ }
+ return false;
+}
+
+void *
+segment::ObjThere(int x, int y)
+{
+ bool bFound = false;
+ POINT p1;
+
+ if(IsInRect(&rDims, p1.x = x, p1.y = y)) {
+ bFound = IsInPolygon(&p1, pts, nPts);
+ if(bFound || IsCloseToPL(p1, pts, nPts)) return this;
+ }
+ return 0L;
+}
+
+void
+segment::Track(POINT *p, anyOutput *o)
+{
+ POINT *tpts;
+ RECT old_rc;
+ int i;
+
+ if(o && (tpts = (POINT*)malloc(nPts*sizeof(POINT)))){
+ memcpy(&old_rc, &rDims, sizeof(rDims));
+ o->UpdateRect(&rDims, false);
+ for(i = 0; i < nPts; i++) {
+ tpts[i].x = pts[i].x+p->x; tpts[i].y = pts[i].y+p->y;
+ UpdateMinMaxRect(&rDims, tpts[i].x, tpts[i].y);
+ }
+ o->ShowLine(tpts, nPts, segLine.color);
+ if(old_rc.left != rDims.left || old_rc.right != rDims.right || old_rc.top !=
+ rDims.top || old_rc.bottom != rDims.bottom)IncrementMinMaxRect(&rDims, 3);
+ free(tpts);
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// the polyline object
+//
+polyline::polyline(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts):
+ GraphObj(par, d)
+{
+ double dx = 0.0, dy = 0.0;
+ int i;
+
+ FileIO(INIT_VARS);
+ if(parent){
+ dx = parent->GetSize(SIZE_GRECT_LEFT); dy = parent->GetSize(SIZE_GRECT_TOP);
+ }
+ if(Values = (lfPOINT*)malloc((nPoints = cpts)* sizeof(lfPOINT))){
+ memcpy(Values, fpts, cpts*sizeof(lfPOINT));
+ for(i = 0; i < cpts; i++) {
+ Values[i].fx -= dx; Values[i].fy -= dy;
+ }
+ }
+ Id = GO_POLYLINE;
+ bModified = false;
+}
+
+polyline::polyline(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+ bModified = false;
+}
+
+polyline::~polyline()
+{
+ Command(CMD_FLUSH, 0L, 0L);
+ if(this == CurrGO) CurrGO = 0L;
+ if(bModified) Undo.InvalidGO(this);
+}
+
+double
+polyline::GetSize(int select)
+{
+ int i;
+
+ if(select >= SIZE_XPOS && select <= SIZE_XPOS_LAST){
+ if((i = select-SIZE_XPOS) >=0 && i <= 200)
+ return i < nPoints ? Values[i].fx : Values[nPoints-2].fx;
+ }
+ if(select >= SIZE_YPOS && select <= SIZE_YPOS_LAST){
+ if((i = select-SIZE_YPOS) >=0 && i <= 200)
+ return i < nPoints ? Values[i].fy : Values[nPoints-2].fy;
+ }
+ return parent ? parent->GetSize(select) : 0.0;
+}
+
+DWORD
+polyline::GetColor(int select)
+{
+ return pgLine.color;
+}
+
+bool
+polyline::SetSize(int select, double value)
+{
+ int i;
+
+ if((select & 0xfff) >= SIZE_XPOS && (select & 0xfff) <= SIZE_XPOS_LAST){
+ if((i = select-SIZE_XPOS) >=0 && i <= 200 && i < (int)nPoints){
+ Values[i].fx = value;
+ return true;
+ }
+ }
+ if((select & 0xfff) >= SIZE_YPOS && (select & 0xfff) <= SIZE_YPOS_LAST){
+ if((i = select-SIZE_YPOS) >=0 && i <= 200 && i < (int)nPoints){
+ Values[i].fy = value;
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+polyline::DoPlot(anyOutput *o)
+{
+ POINT np, *tmppts;
+ double dx, dy;
+ int i;
+
+ if(!Values || !nPoints || !o || !parent) return;
+ if(pts) free(pts);
+ dx = parent->GetSize(SIZE_GRECT_LEFT); dy = parent->GetSize(SIZE_GRECT_TOP);
+ if(!(pts = (POINT*)malloc((nPoints+2)*sizeof(POINT))))return;
+ for(i = nPts = 0; i < nPoints; i++){
+ np.x = o->co2ix(Values[i].fx + dx); np.y = o->co2iy(Values[i].fy + dy);
+ AddToPolygon(&nPts, pts, &np);
+ }
+ if(type == 1) AddToPolygon(&nPts, pts, &pts[0]); //close polygon
+ if(tmppts = (POINT*)realloc(pts, nPts *sizeof(POINT))) pts = tmppts;
+ SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+ for(i = 2; i < nPts; i++) UpdateMinMaxRect(&rDims, pts[i].x, pts[i].y);
+ i = 3*o->un2ix(pgLine.width)+3; //increase size of rectangle for marks
+ IncrementMinMaxRect(&rDims, i);
+ o->SetLine(&pgLine);
+ if(this == CurrGO) o->ShowMark(this, MRK_GODRAW);
+ else switch(type) {
+ case 0: //line
+ o->oPolyline(pts, nPts);
+ break;
+ case 1: //polygon
+ o->SetFill(&pgFill);
+ o->oPolygon(pts, nPts);
+ break;
+ }
+}
+
+void
+polyline::DoMark(anyOutput *o, bool mark)
+{
+ RECT upd;
+
+ memcpy(&upd, &rDims, sizeof(RECT));
+ IncrementMinMaxRect(&upd, 6 + o->un2ix(pgLine.width)*4);
+ if(mark) {
+ o->SetLine(&pgLine);
+ if(nPoints < 200){
+ switch(type) {
+ case 0: //line
+ o->oPolyline(pts, nPts);
+ break;
+ case 1: //polygon
+ o->SetFill(&pgFill);
+ o->oPolygon(pts, nPts);
+ break;
+ }
+ ShowPoints(o);
+ }
+ else InvertLine(pts, nPts, &pgLine, &upd, o, true);;
+ }
+ else if(parent) parent->DoPlot(o);
+ o->UpdateRect(&upd, false);
+}
+
+bool
+polyline::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ POINT p1;
+ bool bFound = false;
+ int i;
+
+ switch (cmd) {
+ case CMD_MRK_DIRTY: //issued by Undo
+ CurrGO = this;
+ bModified = true;
+ case CMD_FLUSH:
+ if(pHandles) {
+ for(i = 0; i < nPoints; i++) if(pHandles[i]) delete(pHandles[i]);
+ free(pHandles); pHandles = 0L;
+ }
+ if(cmd == CMD_FLUSH && Values && nPoints){
+ free(Values);
+ Values = 0L; nPoints = 0;
+ }
+ if(pts && nPts) free(pts); pts = 0L; nPts = 0;
+ return true;
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(!ObjThere(p1.x= mev->x, p1.y=mev->y)|| CurrGO || !o || nPoints <2)return false;
+ o->ShowMark(CurrGO=this, MRK_GODRAW);
+ break;
+ }
+ return false;
+ case CMD_DELOBJ:
+ if(pHandles && tmpl && tmpl == (void*)CurrHandle) {
+ for(i = 0; i < nPoints; i++) if(pHandles[i] == CurrHandle) {
+ Undo.DataMem(this, (void**)&Values, nPoints * sizeof(lfPOINT), &nPoints, 0L);
+ for( ; i < nPoints-1; i++) {
+ Values[i].fx = Values[i+1].fx; Values[i].fy = Values[i+1].fy;
+ }
+ nPoints--;
+ if(pHandles[nPoints])delete(pHandles[nPoints]);
+ pHandles[nPoints] = 0L; CurrHandle = 0L;
+ CurrGO = this; bModified = true;
+ return true;
+ }
+ }
+ return false;
+ case CMD_SAVEPOS:
+ if(tmpl && Values) {
+ bModified = true;
+ i = *(int*)tmpl;
+ if(i >= 0 && i < nPoints) Undo.SaveLFP(this, Values + i, 0L);
+ }
+ return true;
+ case CMD_SET_DATAOBJ:
+ Id = type == 1 ? GO_POLYGON : GO_POLYLINE;
+ return true;
+ case CMD_SETSCROLL:
+ case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ return false;
+ case CMD_MOVE:
+ bModified = true;
+ Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
+ case CMD_UNDO_MOVE:
+ for(i = 0; i < nPoints; i++) {
+ Values[i].fx += ((lfPOINT*)tmpl)[0].fx;
+ Values[i].fy += ((lfPOINT*)tmpl)[0].fy;
+ }
+ if(o) {
+ o->StartPage(); parent->DoPlot(o); o->EndPage();
+ }
+ return true;
+ }
+ return false;
+}
+
+void *
+polyline::ObjThere(int x, int y)
+{
+ bool bFound = false;
+ POINT p1;
+ int i;
+ void *ret;
+
+ if(IsInRect(&rDims, p1.x = x, p1.y = y)) {
+ if(CurrGO == this && pHandles)
+ for(i = nPoints-1; i >= 0; i--)
+ if((pHandles[i]) && (ret = pHandles[i]->ObjThere(x, y))) return ret;
+ if(type == 1) bFound = IsInPolygon(&p1, pts, nPts);
+ if(bFound || IsCloseToPL(p1,pts,nPts)) return this;
+ }
+ return 0L;
+}
+
+void
+polyline::Track(POINT *p, anyOutput *o)
+{
+ POINT *tpts;
+ RECT old_rc;
+ int i;
+
+ if(o && (tpts = (POINT*)malloc(nPts*sizeof(POINT)))){
+ memcpy(&old_rc, &rDims, sizeof(rDims));
+ o->UpdateRect(&rDims, false);
+ for(i = 0; i < nPts; i++) {
+ tpts[i].x = pts[i].x+p->x;
+ tpts[i].y = pts[i].y+p->y;
+ UpdateMinMaxRect(&rDims, tpts[i].x, tpts[i].y);
+ }
+ o->ShowLine(tpts, nPts, pgLine.color);
+ if(old_rc.left != rDims.left || old_rc.right != rDims.right || old_rc.top !=
+ rDims.top || old_rc.bottom != rDims.bottom)IncrementMinMaxRect(&rDims, 3);
+ free(tpts);
+ }
+}
+
+void
+polyline::ShowPoints(anyOutput *o)
+{
+ int i;
+
+ if(nPoints >= 200) return;
+ if(!pHandles) if(pHandles = (dragHandle**)calloc(nPoints+1, sizeof(dragHandle*))){
+ for(i = 0; i < nPoints; i++) pHandles[i] = new dragHandle(this, DH_DATA+i);
+ }
+ else return;
+ for(i = 0; i < nPoints; i++) if(pHandles[i]) pHandles[i]->DoPlot(o);
+}
+
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// polygons are based on the polyline object
+polygon::polygon(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts):
+ polyline(par, d, fpts, cpts)
+{
+ Id = GO_POLYGON;
+ memcpy(&pgLine, defs.pgLineDEF(0L), sizeof(LineDEF));
+ type = 1;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// rectangle with absolute coordinates
+rectangle::rectangle(GraphObj *par, DataObj *d, lfPOINT *p1, lfPOINT *p2):
+ GraphObj(par, d)
+{
+ double dx = 0.0, dy = 0.0;
+
+ FileIO(INIT_VARS);
+ if(parent){
+ dx = parent->GetSize(SIZE_GRECT_LEFT); dy = parent->GetSize(SIZE_GRECT_TOP);
+ }
+ memcpy(&fp1, p1, sizeof(lfPOINT)); memcpy(&fp2, p2, sizeof(lfPOINT));
+ fp1.fx -= dx; fp1.fy -= dy; fp2.fx -= dx; fp2.fy -= dy;
+ type = 0;
+ Id = GO_RECTANGLE;
+ bModified = false;
+}
+
+rectangle::rectangle(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+ type = 0;
+ bModified = false;
+}
+
+rectangle::~rectangle()
+{
+ Command(CMD_FLUSH, 0L, 0L);
+ if(bModified) Undo.InvalidGO(this);
+}
+
+double
+rectangle::GetSize(int select)
+{
+ if(parent && parent->Id== GO_GROUP){
+ switch(select) {
+ case SIZE_XPOS: return fp1.fx + parent->GetSize(SIZE_XPOS);
+ case SIZE_XPOS+1: return fp2.fx + parent->GetSize(SIZE_XPOS);
+ case SIZE_YPOS: return fp1.fy + parent->GetSize(SIZE_YPOS);
+ case SIZE_YPOS+1: return fp2.fy + parent->GetSize(SIZE_YPOS);
+ case SIZE_GRECT_LEFT: case SIZE_GRECT_TOP:
+ case SIZE_GRECT_RIGHT: case SIZE_GRECT_BOTTOM:
+ return parent->GetSize(select);
+ }
+ return 0.0;
+ }
+ switch(select) {
+ case SIZE_XPOS: return fp1.fx;
+ case SIZE_XPOS+1: return fp2.fx;
+ case SIZE_YPOS: return fp1.fy;
+ case SIZE_YPOS+1: return fp2.fy;
+ case SIZE_GRECT_LEFT: case SIZE_GRECT_TOP:
+ case SIZE_GRECT_RIGHT: case SIZE_GRECT_BOTTOM:
+ if(parent) return parent->GetSize(select);
+ break;
+ }
+ return 0.0;
+}
+
+bool
+rectangle::SetSize(int select, double value)
+{
+ switch(select & 0xfff) {
+ case SIZE_XPOS: fp1.fx = value; return true;
+ case SIZE_XPOS+1: fp2.fx = value; return true;
+ case SIZE_YPOS: fp1.fy = value; return true;
+ case SIZE_YPOS+1: fp2.fy = value; return true;
+ }
+ return false;
+}
+
+void
+rectangle::DoMark(anyOutput *o, bool mark)
+{
+ RECT upd;
+
+ if(!drc) drc = new dragRect(this, 0);
+ memcpy(&upd, &rDims, sizeof(RECT));
+ if(mark){
+ if(drc) drc->DoPlot(o);
+ }
+ else if(parent) parent->DoPlot(o);
+ IncrementMinMaxRect(&upd, 6);
+ o->UpdateRect(&upd, false);
+}
+
+void
+rectangle::DoPlot(anyOutput *o)
+{
+ int x1, y1, x2, y2;
+ double tmp, dx, dy;
+
+ if(!parent || !o) return;
+ dx = parent->GetSize(SIZE_GRECT_LEFT); dy = parent->GetSize(SIZE_GRECT_TOP);
+ if(fp1.fx > fp2.fx) {
+ tmp = fp2.fx; fp2.fx = fp1.fx; fp1.fx = tmp;
+ }
+ if(fp1.fy > fp2.fy) {
+ tmp = fp2.fy; fp2.fy = fp1.fy; fp1.fy = tmp;
+ }
+ if(type == 2) PlotRoundRect(o);
+ else {
+ x1 = o->co2ix(fp1.fx+dx); y1 = o->co2iy(fp1.fy+dy);
+ x2 = o->co2ix(fp2.fx+dx); y2 = o->co2iy(fp2.fy+dy);
+ o->SetLine(&Line); o->SetFill(&Fill);
+ if(type == 1) o->oCircle(x1, y1, x2, y2, name);
+ else o->oRectangle(x1, y1, x2, y2, name);
+ SetMinMaxRect(&rDims, x1, y1, x2, y2);
+ }
+ o->MrkMode = MRK_NONE;
+ if(CurrGO == this) o->ShowMark(this, MRK_GODRAW);
+}
+
+bool
+rectangle::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+
+ switch (cmd) {
+ case CMD_FLUSH:
+ if(pts) free(pts); pts = 0L;
+ if(name) free(name); name = 0L;
+ return true;
+ case CMD_SAVEPOS:
+ bModified = true;
+ Undo.SaveLFP(this, &fp1, 0L);
+ Undo.SaveLFP(this, &fp2, UNDO_CONTINUE);
+ return true;
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(IsInRect(&rDims, mev->x, mev->y) && !(CurrGO) && (o)){
+ o->ShowMark(this, MRK_GODRAW);
+ return true;
+ }
+ }
+ return false;
+ case CMD_SET_DATAOBJ:
+ switch (type) {
+ case 1: Id = GO_ELLIPSE; break;
+ case 2: Id = GO_ROUNDREC; break;
+ default: Id = GO_RECTANGLE; break;
+ }
+ return true;
+ case CMD_MOVE:
+ bModified = true;
+ Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
+ case CMD_UNDO_MOVE:
+ fp1.fx += ((lfPOINT*)tmpl)[0].fx; fp1.fy += ((lfPOINT*)tmpl)[0].fy;
+ fp2.fx += ((lfPOINT*)tmpl)[0].fx; fp2.fy += ((lfPOINT*)tmpl)[0].fy;
+ CurrGO = this;
+ case CMD_REDRAW:
+ if(parent && cmd != CMD_UNDO_MOVE){
+ parent->Command(CMD_REDRAW, tmpl, o);
+ }
+ return true;
+ case CMD_SETSCROLL:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ }
+ return false;
+}
+
+void
+rectangle::Track(POINT *p, anyOutput *o)
+{
+ POINT tpts[5];
+ RECT old_rc;
+ double dx, dy;
+
+ if(o && parent){
+ dx = parent->GetSize(SIZE_GRECT_LEFT); dy = parent->GetSize(SIZE_GRECT_TOP);
+ memcpy(&old_rc, &rDims, sizeof(rDims));
+ o->UpdateRect(&rDims, false);
+ tpts[0].x = tpts[1].x = tpts[4].x = o->co2ix(fp1.fx+dx)+p->x;
+ tpts[0].y = tpts[3].y = tpts[4].y = o->co2iy(fp1.fy+dy)+p->y;
+ tpts[1].y = tpts[2].y = o->co2iy(fp2.fy+dy)+p->y;
+ tpts[2].x = tpts[3].x = o->co2ix(fp2.fx+dx)+p->x;
+ UpdateMinMaxRect(&rDims, tpts[0].x, tpts[0].y);
+ UpdateMinMaxRect(&rDims, tpts[2].x, tpts[2].y);
+ if(old_rc.left != rDims.left || old_rc.right != rDims.right || old_rc.top !=
+ rDims.top || old_rc.bottom != rDims.bottom)IncrementMinMaxRect(&rDims, 3);
+ o->ShowLine(tpts, 5, Line.color);
+ if(type == 1) o->ShowEllipse(tpts[0], tpts[2], Line.color);
+ }
+}
+
+void *
+rectangle::ObjThere(int x, int y)
+{
+ if(drc) return drc->ObjThere(x, y);
+ return 0L;
+}
+
+//use circular Bresenham's algorithm to draw rounded rectangles
+//Ref: C. Montani, R. Scopigno (1990) "Speres-To-Voxel Conversion", in:
+// Graphic Gems (A.S. Glassner ed.) Academic Press, Inc.;
+// ISBN 0-12-288165-5
+void
+rectangle::PlotRoundRect(anyOutput *o)
+{
+ int i, m, x, y, di, de, lim, ir, x1, x2, y1, y2;
+ double dx, dy;
+ POINT np;
+
+ dx = parent->GetSize(SIZE_GRECT_LEFT); dy = parent->GetSize(SIZE_GRECT_TOP);
+ ir = o->un2ix(rad);
+ x1 = o->co2ix(fp1.fx+dx); y1 = o->co2iy(fp1.fy+dy);
+ x2 = o->co2ix(fp2.fx+dx); y2 = o->co2iy(fp2.fy+dy);
+ if (x1 > x2) Swap(x1, x2); if(y1 > y2) Swap(y1, y2);
+ if(pts) free(pts); nPts = 0;
+ m = ir*4+10;
+ if(!(pts = (POINT*)malloc(m*sizeof(POINT))))return;
+ for(i = 0; i < 4; i++) {
+ x = lim = 0; y = ir; di = 2*(1-ir);
+ while (y >= lim){
+ if(di < 0) {
+ de = 2*di + 2*y -1;
+ if(de > 0) {
+ x++; y--; di += (2*x -2*y +2);
+ }
+ else {
+ x++; di += (2*x +1);
+ }
+ }
+ else {
+ de = 2*di -2*x -1;
+ if(de > 0) {
+ y--; di += (-2*y +1);
+ }
+ else {
+ x++; y--; di += (2*x -2*y +2);
+ }
+ }
+ switch(i) {
+ case 0:
+ np.x = x2-ir+x; np.y = y2-ir+y;
+ break;
+ case 1:
+ np.x = x2-ir+y; np.y = y1+ir-x;
+ break;
+ case 2:
+ np.x = x1+ir-x; np.y = y1+ir-y;
+ break;
+ case 3:
+ np.x = x1+ir-y; np.y = y2-ir+x;
+ break;
+ }
+ AddToPolygon(&nPts, pts, &np);
+ }
+ }
+ AddToPolygon(&nPts, pts, pts); //close polygon
+ o->SetLine(&Line); o->SetFill(&Fill);
+ o->oPolygon(pts, nPts, name);
+ SetMinMaxRect(&rDims, x1, y1, x2, y2);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// ellipse with absolute coordinates
+ellipse::ellipse(GraphObj *par, DataObj *d, lfPOINT *p1, lfPOINT *p2)
+ :rectangle(par, d, p1, p2)
+{
+ type = 1;
+ Id = GO_ELLIPSE;
+}
+
+ellipse::ellipse(int src)
+ :rectangle(src)
+{
+ type = 1;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// rounded rectangle
+roundrec::roundrec(GraphObj *par, DataObj *d, lfPOINT *p1, lfPOINT *p2)
+ :rectangle(par, d, p1, p2)
+{
+ type = 2;
+ Id = GO_ROUNDREC;
+}
+
+roundrec::roundrec(int src)
+ :rectangle(src)
+{
+ type = 2;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Add a legend to the graph
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LegItem::LegItem(GraphObj *par, DataObj *d, LineDEF *ld, LineDEF *lf, FillDEF *fd)
+ :GraphObj(par, d)
+{
+ FileIO(INIT_VARS);
+ if(!ld && !fd && lf) ld = lf;
+ if(ld) {
+ memcpy(&DataLine, ld, sizeof(LineDEF));
+ flags |= 0x01;
+ }
+ if(lf) memcpy(&OutLine, lf, sizeof(LineDEF));
+ if(fd) {
+ if(fd->hatch) memcpy(&HatchLine, fd->hatch, sizeof(LineDEF));
+ memcpy(&Fill, fd, sizeof(FillDEF));
+ Fill.hatch = &HatchLine;
+ flags |= 0x02;
+ }
+ DefDesc(0L); Id = GO_LEGITEM; moveable = true;
+}
+
+LegItem::LegItem(GraphObj *par, DataObj *d, LineDEF *ld, Symbol *sy)
+ :GraphObj(par, d)
+{
+ FileIO(INIT_VARS);
+ if(ld) {
+ memcpy(&DataLine, ld, sizeof(LineDEF)); flags |= 0x01;
+ }
+ if(sy) {
+ Sym = sy; Sym->parent = this; flags |= 0x04;
+ }
+ DefDesc(0L); Id = GO_LEGITEM; moveable = true;
+}
+
+LegItem::LegItem(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+ moveable = true;
+}
+
+LegItem::~LegItem()
+{
+ if(Sym) DeleteGO(Sym); Sym = 0L;
+ if(Desc) DeleteGO(Desc); Desc = 0L;
+}
+
+double
+LegItem::GetSize(int select)
+{
+ switch(select) {
+ case SIZE_XCENTER:
+ return (parent->GetSize((flags & 0x01) ? SIZE_XPOS+2 : SIZE_XPOS) +
+ parent->GetSize((flags & 0x01) ? SIZE_XPOS+3 : SIZE_XPOS+1))/2.0;
+ case SIZE_YCENTER:
+ return (parent->GetSize(SIZE_YPOS) + parent->GetSize(SIZE_YPOS+1))/2.0;
+ case SIZE_LB_XPOS: case SIZE_LB_YPOS:
+ case SIZE_GRECT_TOP: case SIZE_GRECT_LEFT:
+ default:
+ if(parent) return parent->GetSize(select);
+ break;
+ }
+ return 0.0;
+}
+
+void
+LegItem::DoPlot(anyOutput *o)
+{
+ POINT pts[2];
+
+ if(!parent || !o) return;
+ hcr.left = iround(parent->GetSize((flags & 0x01) ? SIZE_XPOS+2 : SIZE_XPOS));
+ hcr.right = iround(parent->GetSize((flags & 0x01) ? SIZE_XPOS+3 :SIZE_XPOS+1));
+ hcr.top = iround(parent->GetSize(SIZE_YPOS));
+ hcr.bottom = iround(parent->GetSize(SIZE_YPOS+1));
+ SetMinMaxRect(&rDims, hcr.left, hcr.top, hcr.right, hcr.bottom);
+ if(flags & 0x02){
+ o->SetLine(&OutLine); o->SetFill(&Fill);
+ o->oRectangle(hcr.left, hcr.top, hcr.right, hcr.bottom, name);
+ }
+ if(flags & 0x01){
+ pts[0].x = hcr.left; pts[1].x = hcr.right;
+ pts[0].y = pts[1].y = iround(GetSize(SIZE_YCENTER))+1;
+ o->SetLine(&DataLine); o->oPolyline(pts, 2, 0L);
+ }
+ if(flags & 0x04){
+ if(Sym) Sym->DoPlot(o);
+ }
+ if(Desc) {
+ Desc->moveable = false; Desc->DoPlot(o);
+ if(Desc->rDims.bottom > rDims.bottom){
+ parent->SetSize(SIZE_YPOS+1, (double)Desc->rDims.bottom);
+ }
+ UpdateMinMaxRect(&rDims, Desc->rDims.left, Desc->rDims.top);
+ UpdateMinMaxRect(&rDims, Desc->rDims.right, Desc->rDims.bottom);
+ }
+}
+
+void
+LegItem::DoMark(anyOutput *o, bool mark)
+{
+ RECT cr;
+ LineDEF ld = {0.0, 1.0, 0x00000000L, 0x00000000L};
+ POINT pts[5];
+
+ if(!parent || !o) return;
+ cr.left = hcr.left-5; cr.right = hcr.right+3;
+ cr.top = hcr.top-3; cr.bottom = hcr.bottom+1;
+ ld.color = mark ? 0x00000000L : 0x00ffffffL; o->SetLine(&ld);
+ pts[0].x = pts[3].x = pts[4].x = cr.left; pts[0].y = pts[1].y = pts[4].y = cr.top;
+ pts[1].x = pts[2].x = cr.right; pts[2].y = pts[3].y = cr.bottom;
+ o->oPolyline(pts, 5, name); IncrementMinMaxRect(&cr, 3);
+ o->UpdateRect(&cr, false);
+}
+
+bool
+LegItem::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ GraphObj **tmpPlots;
+
+ switch(cmd){
+ case CMD_MOUSE_EVENT:
+ if(tmpl && IsInRect(&rDims, ((MouseEvent*)tmpl)->x, ((MouseEvent*)tmpl)->y) && o) {
+ if(Desc && Desc->Command(cmd, tmpl, o)) return true;
+ if(!CurrGO) o->ShowMark(CurrGO=this, MRK_GODRAW);
+ }
+ break;
+ case CMD_HIDE_MARK:
+ if(!tmpl || !o) return false;
+ if(Desc && Desc == (void*)tmpl) {
+ Desc->DoMark(o, false);
+ return true;
+ }
+ return false;
+ case CMD_REDRAW: case CMD_MOVE:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ case CMD_MUTATE:
+ if(!parent || !(tmpPlots = (GraphObj **)tmpl) || !tmpPlots[0] || !tmpPlots[1]) return false;
+ if(Desc == tmpPlots[0]) {
+ Undo.MutateGO((GraphObj**)&Desc, tmpPlots[1], 0L, o);
+ return true;
+ }
+ break;
+ case CMD_SET_DATAOBJ:
+ Id = GO_LEGITEM;
+ data = (DataObj *)tmpl;
+ return true;
+ }
+ return false;
+}
+
+void
+LegItem::Track(POINT *p, anyOutput *o)
+{
+ if(parent) parent->Track(p, o);
+}
+
+bool
+LegItem::HasFill(LineDEF *ld, FillDEF *fd)
+{
+ if(ld && cmpLineDEF(ld, &OutLine)) return false;
+ if(fd && cmpFillDEF(fd, &Fill)) return false;
+ if(fd && fd->hatch && cmpLineDEF(fd->hatch, &HatchLine)) return false;
+ return true;
+}
+
+bool
+LegItem::HasSym(LineDEF *ld, GraphObj *sy)
+{
+ if(sy && !Sym) return false;
+ if(sy->Id == GO_SYMBOL && (Sym->type & 0xfff) != (Sym->type & 0xfff)) return false;
+ if(sy && Sym) {
+ if(Sym->GetSize(SIZE_SYMBOL) != sy->GetSize(SIZE_SYMBOL)) return false;
+ if(Sym->GetSize(SIZE_SYM_LINE) != sy->GetSize(SIZE_SYM_LINE)) return false;
+ if(Sym->GetColor(COL_SYM_LINE) != sy->GetColor(COL_SYM_LINE)) return false;
+ if(Sym->GetColor(COL_SYM_FILL) != sy->GetColor(COL_SYM_FILL)) return false;
+ }
+ if(ld && cmpLineDEF(ld, &DataLine)) return false;
+ return true;
+}
+
+void
+LegItem::DefDesc(char *txt)
+{
+ TextDEF td;
+
+ td.ColTxt = 0x00000000L; td.ColBg = 0x00ffffffL;
+ td.fSize = defs.GetSize(SIZE_TICK_LABELS);
+ td.RotBL = td.RotCHAR = 0.0;
+ td.iSize = 0; td.Align = TXA_VTOP | TXA_HLEFT;
+ td.Mode = TXM_TRANSPARENT; td.Style = TXS_NORMAL;
+ td.Font = FONT_HELVETICA; td.text = txt ? strdup(txt) : strdup("text");
+ Desc = new Label(this, data, 0, 0, &td, LB_X_PARENT | LB_Y_PARENT);
+}
+
+Legend::Legend(GraphObj *par, DataObj *d):GraphObj(par, d)
+{
+ FileIO(INIT_VARS); Id = GO_LEGEND; moveable = true;
+}
+
+Legend::Legend(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+ moveable = true;
+}
+
+Legend::~Legend()
+{
+ int i;
+
+ if(Items) {
+ for(i = 0; i< nItems; i++) if(Items[i]) DeleteGO(Items[i]);
+ free(Items); Items = 0L;
+ }
+ if(to) DelBitmapClass(to); to = 0L;
+}
+double
+Legend::GetSize(int select)
+{
+ switch(select) {
+ case SIZE_XPOS: return C_Rect.Xmin;
+ case SIZE_XPOS+1: return C_Rect.Xmax;
+ case SIZE_XPOS+2: return E_Rect.Xmin;
+ case SIZE_XPOS+3: return E_Rect.Xmax;
+ case SIZE_YPOS: return C_Rect.Ymin;
+ case SIZE_YPOS+1: return C_Rect.Ymax;
+ case SIZE_LB_XPOS: return lb_pos.fx;
+ case SIZE_LB_YPOS: return lb_pos.fy;
+ case SIZE_GRECT_TOP: case SIZE_GRECT_LEFT:
+ if(parent) return parent->GetSize(select);
+ break;
+ }
+ return 0.0;
+}
+
+bool
+Legend::SetSize(int select, double value)
+{
+ double tmp;
+
+ switch (select & 0xfff){
+ case SIZE_XPOS: pos.fx = value; return true;
+ case SIZE_YPOS: pos.fy = value; return true;
+ case SIZE_YPOS+1:
+ tmp = value - C_Rect.Ymax;
+ C_Rect.Ymin += tmp; C_Rect.Ymax += tmp; lb_pos.fy +=tmp;
+ }
+ return false;
+}
+
+void
+Legend::DoPlot(anyOutput *o)
+{
+ int i;
+ double y_inc, dx, dy;
+
+ if(!o || !Items) return;
+ if(to) DelBitmapClass(to); to = 0L;
+ dx = parent->GetSize(SIZE_GRECT_LEFT); dy = parent->GetSize(SIZE_GRECT_TOP);
+ C_Rect.Xmin = o->co2fix(pos.fx + B_Rect.Xmin + D_Rect.Xmin + dx);
+ C_Rect.Ymin = o->co2fiy(pos.fy + B_Rect.Ymin + D_Rect.Ymin + dy);
+ C_Rect.Xmax = C_Rect.Xmin + o->un2fix(D_Rect.Xmax - D_Rect.Xmin);
+ C_Rect.Ymax = C_Rect.Ymin + o->un2fix(D_Rect.Ymax - D_Rect.Ymin);
+ E_Rect.Ymin = C_Rect.Ymin; E_Rect.Ymax = C_Rect.Ymax;
+ E_Rect.Xmin = o->co2fix(pos.fx + B_Rect.Xmin + F_Rect.Xmin + dx);
+ E_Rect.Xmax = E_Rect.Xmin + o->un2fix(F_Rect.Xmax - F_Rect.Xmin);
+ y_inc = floor(0.5+o->un2fiy(B_Rect.Ymax - B_Rect.Ymin));
+ rDims.left = rDims.right = rDims.top = rDims.bottom = 0;
+ lb_pos.fx = o->co2fix(pos.fx + B_Rect.Xmax + dx); lb_pos.fy = C_Rect.Ymin;
+ //draw all items
+ for(i = 0; i < nItems; i++) {
+ if(Items[i]){
+ Items[i]->DoPlot(o);
+ if(rDims.left == rDims.right || rDims.top == rDims.bottom){
+ rDims.left = Items[i]->rDims.left; rDims.right = Items[i]->rDims.right;
+ rDims.top = Items[i]->rDims.top; rDims.bottom = Items[i]->rDims.bottom;
+ }
+ else {
+ UpdateMinMaxRect(&rDims, Items[i]->rDims.left, Items[i]->rDims.top);
+ UpdateMinMaxRect(&rDims, Items[i]->rDims.right, Items[i]->rDims.bottom);
+ }
+ C_Rect.Ymin += y_inc; C_Rect.Ymax += y_inc;
+ lb_pos.fy += y_inc;
+ }
+ }
+ IncrementMinMaxRect(&rDims, 6);
+}
+
+void
+Legend::DoMark(anyOutput *o, bool mark)
+{
+ RECT cr;
+ LineDEF ld = {0.0, 1.0, 0x00c0c0c0L, 0x00000000L};
+ POINT pts[5];
+
+ if(!parent || !o) return;
+ cr.left = rDims.left; cr.right = rDims.right;
+ cr.top = rDims.top; cr.bottom = rDims.bottom;
+ ld.color = mark ? 0x00c0c0c0L : 0x00ffffffL; o->SetLine(&ld);
+ pts[0].x = pts[3].x = pts[4].x = cr.left; pts[0].y = pts[1].y = pts[4].y = cr.top;
+ pts[1].x = pts[2].x = cr.right; pts[2].y = pts[3].y = cr.bottom;
+ o->oPolyline(pts, 5, name); IncrementMinMaxRect(&cr, 3);
+ o->UpdateRect(&cr, false);
+}
+
+bool
+Legend::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i;
+
+ switch(cmd){
+ case CMD_MOUSE_EVENT:
+ if(o && tmpl && IsInRect(&rDims, ((MouseEvent*)tmpl)->x, ((MouseEvent*)tmpl)->y)) {
+ if(Items) for(i = 0; i< nItems; i++)
+ if(Items[i] && Items[i]->Command(cmd, tmpl, o)) return true;
+ if(!CurrGO) o->ShowMark(CurrGO = this, MRK_GODRAW);
+ }
+ break;
+ case CMD_SET_DATAOBJ:
+ if(Items) for(i = 0; i < nItems; i++) if(Items[i]) Items[i]->Command(cmd, tmpl, o);
+ Id = GO_LEGEND;
+ data = (DataObj *)tmpl;
+ return true;
+ case CMD_HIDE_MARK:
+ if(!tmpl || !o) return false;
+ if(Items && nItems) for(i = 0; i < nItems; i++) {
+ if(Items[i]) {
+ if(tmpl == (void*)Items[i]) {
+ Items[i]->DoMark(o, false);
+ return true;
+ }
+ else if(Items[i]->Command(cmd, tmpl, o)) return true;
+ }
+ }
+ return false;
+ case CMD_DELOBJ:
+ o->HideMark();
+ if(Items && parent) for(i = 0; i < nItems; i++) {
+ if(Items[i] && tmpl == (void *)Items[i]) {
+ Undo.DeleteGO((GraphObj**)(&Items[i]), 0L, o);
+ parent->Command(CMD_REDRAW, NULL, o);
+ return true;
+ }
+ }
+ break;
+ case CMD_MOVE:
+ Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
+ case CMD_UNDO_MOVE:
+ pos.fx += ((lfPOINT*)tmpl)[0].fx; pos.fy += ((lfPOINT*)tmpl)[0].fy;
+ CurrGO = this;
+ case CMD_REDRAW:
+ if(parent && cmd != CMD_UNDO_MOVE){
+ parent->Command(CMD_REDRAW, tmpl, o);
+ }
+ return true;
+ case CMD_DROP_OBJECT:
+ if(!tmpl) return false;
+ if(!(Items = (LegItem**)realloc(Items, (2+nItems)*sizeof(LegItem*))))return false;
+ Items[nItems++] = (LegItem*)tmpl;
+ Items[nItems-1]->parent = this;
+ return true;
+ }
+ return false;
+}
+
+void
+Legend::Track(POINT *p, anyOutput *o)
+{
+ POINT pts[5];
+ LineDEF tld = {0.0, 1.0, 0x00c0c0c0, 0x0L};
+
+ if(!p || !o) return;
+ if(to) {
+ o->CopyBitmap(trc.left, trc.top, to, 0, 0, trc.right - trc.left,
+ trc.bottom - trc.top, false);
+ DelBitmapClass(to); to = 0L;
+ o->UpdateRect(&trc, false);
+ }
+ trc.left = pts[0].x = pts[1].x = pts[4].x = rDims.left + p->x;
+ trc.top = pts[0].y = pts[3].y = pts[4].y = rDims.top + p->y;
+ trc.bottom = pts[1].y = pts[2].y = rDims.bottom + p->y;
+ trc.right = pts[2].x = pts[3].x = rDims.right + p->x;
+ IncrementMinMaxRect(&trc, 3); to = GetRectBitmap(&trc, o);
+ o->SetLine(&tld); o->oPolyline(pts, 5, 0L);
+ o->UpdateRect(&trc, false);
+}
+
+bool
+Legend::HasFill(LineDEF *ld, FillDEF *fd)
+{
+ int i;
+ LegItem *li;
+
+ if(Items) for(i = 0; i < nItems; i++) {
+ if(Items[i] && Items[i]->HasFill(ld, fd)) return true;
+ }
+ if(li = new LegItem(this, data, 0L, ld, fd)){
+ if(!(Command(CMD_DROP_OBJECT, li, 0L))) DeleteGO(li);
+ }
+ return false;
+}
+
+bool
+Legend::HasSym(LineDEF *ld, GraphObj *sy)
+{
+ int i, sym;
+ Symbol *ns;
+ LegItem *li;
+
+ if(!parent || !sy) return true;
+ if(Items) for(i = 0; i < nItems; i++) {
+ if(Items[i] && Items[i]->HasSym(ld, sy)) return true;
+ }
+ sym = sy->Id == GO_SYMBOL ? (sy->type & 0xff) : 0;
+ if(!(ns = new Symbol(this, data, 0.0, 0.0, sym | SYM_POS_PARENT))) return true;
+ ns->SetSize(SIZE_SYMBOL, sy->GetSize(SIZE_SYMBOL));
+ ns->SetSize(SIZE_SYM_LINE, sy->GetSize(SIZE_SYM_LINE));
+ ns->SetColor(COL_SYM_LINE, sy->GetColor(COL_SYM_LINE));
+ ns->SetColor(COL_SYM_FILL, sy->GetColor(COL_SYM_FILL));
+ if(li = new LegItem(this, data, ld, ns)){
+ if(!(Command(CMD_DROP_OBJECT, li, 0L))) DeleteGO(li);
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Graphs are graphic objects containing plots, axes, and drawn objects
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Graph::Graph(GraphObj *par, DataObj *d, anyOutput *o):GraphObj(par, d)
+{
+ Graph::FileIO(INIT_VARS);
+ Disp = o; Id = GO_GRAPH; cGraphs++; bModified = true;
+ if (!d && parent) parent->Command(CMD_DELOBJ, this, NULL);
+}
+
+Graph::Graph(int src):GraphObj(0L, 0L)
+{
+ int i;
+
+ Graph::FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ x_axis.owner = y_axis.owner = (void *)this;
+ //do all axes
+ for(i = 0; Axes && i< NumAxes; i++) if(Axes[i]) Axes[i]->parent = this;
+ //do all plots
+ for(i = 0; Plots && i< NumPlots; i++) if(Plots[i]) Plots[i]->parent = this;
+ if(x_axis.max > x_axis.min && y_axis.max > y_axis.min &&
+ Bounds.Xmax > Bounds.Xmin && Bounds.Ymax > Bounds.Ymin) dirty = false;
+ }
+ cGraphs++; bModified = false;
+}
+
+Graph::~Graph()
+{
+ int i;
+
+ if(!parent) return; parent = 0L;
+ Undo.InvalidGO(this);
+ DoZoom("reset");
+ if(CurrGraph == this) CurrGraph = 0L;
+ if(Plots) {
+ for(i = 0; i< NumPlots; i++) if(Plots[i]) DeleteGO(Plots[i]);
+ free(Plots);
+ }
+ if(Axes) {
+ for(i = 0; i< NumAxes; i++) if(Axes[i]) delete Axes[i];
+ free(Axes);
+ }
+ if(OwnDisp && Disp) DelDispClass(Disp); OwnDisp = false; Disp = 0L;
+ if(frm_g) DeleteGO(frm_g); if(frm_d) DeleteGO(frm_d);
+ if(x_axis.breaks && x_axis.owner == this) free(x_axis.breaks);
+ if(y_axis.breaks && y_axis.owner == this) free(y_axis.breaks);
+ if(tl_pts) free(tl_pts);
+ if(nscp > 0 && nscp <= NumPlots && Sc_Plots) free(Sc_Plots);
+ nscp = 0; Sc_Plots = 0L;
+ if(name) free(name); name = 0L;
+ if(filename) free(filename); filename= 0L;
+}
+
+double
+Graph::GetSize(int select)
+{
+ switch(select) {
+ case SIZE_LB_XDIST:
+ case SIZE_LB_YDIST: return 0.0f;
+ case SIZE_GRECT_TOP: return GRect.Ymin;
+ case SIZE_GRECT_BOTTOM: return GRect.Ymax;
+ case SIZE_GRECT_LEFT: return GRect.Xmin;
+ case SIZE_GRECT_RIGHT: return GRect.Xmax;
+ case SIZE_DRECT_TOP: return DRect.Ymin;
+ case SIZE_DRECT_BOTTOM: return DRect.Ymax;
+ case SIZE_DRECT_LEFT: return DRect.Xmin;
+ case SIZE_DRECT_RIGHT: return DRect.Xmax;
+ case SIZE_BOUNDS_XMIN: return Bounds.Xmin;
+ case SIZE_BOUNDS_XMAX: return Bounds.Xmax;
+ case SIZE_BOUNDS_YMIN: return Bounds.Ymin;
+ case SIZE_BOUNDS_YMAX: return Bounds.Ymax;
+ case SIZE_BOUNDS_LEFT: return x_axis.flags & AXIS_INVERT ? x_axis.max : x_axis.min;
+ case SIZE_BOUNDS_RIGHT: return x_axis.flags & AXIS_INVERT ? x_axis.min : x_axis.max;
+ case SIZE_BOUNDS_TOP: return y_axis.flags & AXIS_INVERT ? y_axis.min : y_axis.max;
+ case SIZE_BOUNDS_BOTTOM: return y_axis.flags & AXIS_INVERT ? y_axis.max : y_axis.min;
+ case SIZE_YAXISX:
+ if(y_axis.flags & AXIS_X_DATA) return CurrDisp->fx2fix(y_axis.loc[0].fx);
+ else return CurrDisp->co2fix(y_axis.loc[0].fx);
+ case SIZE_XAXISY:
+ if(x_axis.flags & AXIS_Y_DATA) return CurrDisp->fy2fiy(x_axis.loc[0].fy);
+ else return CurrDisp->co2fiy(x_axis.loc[0].fy);
+ default: return defs.GetSize(select);
+ }
+}
+
+bool
+Graph::SetSize(int select, double val)
+{
+ switch(select & 0xfff) {
+ case SIZE_GRECT_TOP: GRect.Ymin = val; return true;
+ case SIZE_GRECT_BOTTOM: GRect.Ymax = val; return true;
+ case SIZE_GRECT_LEFT: GRect.Xmin = val; return true;
+ case SIZE_GRECT_RIGHT: GRect.Xmax = val; return true;
+ case SIZE_DRECT_TOP: DRect.Ymin = val; return true;
+ case SIZE_DRECT_BOTTOM: DRect.Ymax = val; return true;
+ case SIZE_DRECT_LEFT: DRect.Xmin = val; return true;
+ case SIZE_DRECT_RIGHT: DRect.Xmax = val; return true;
+ default: return false;
+ }
+}
+
+DWORD
+Graph::GetColor(int select)
+{
+ switch(select & 0xfff) {
+ case COL_AXIS: return ColAX;
+ case COL_BG: return ColDR;
+ }
+ if(parent) return parent->GetColor(select);
+ else return defs.Color(select);
+}
+
+
+void
+Graph::DoPlot(anyOutput *target)
+{
+ int i;
+ AxisDEF *ax;
+
+ if(nscp > 0 && nscp <= NumPlots && Sc_Plots) free(Sc_Plots);
+ nscp = 0; Sc_Plots = 0L;
+ rc_mrk.left = rc_mrk.right = rc_mrk.top = rc_mrk.bottom = -1;
+ CurrAxes = Axes;
+ if(data) do_formula(data, 0L); //init mfcalc
+ //verify ownership of axes
+ if(Axes) for (i = 0; i < NumAxes; i++){
+ if(Axes[i] && (ax = Axes[i]->GetAxis()))
+ if(ax == &x_axis || ax == &y_axis) ax->owner = this;
+ }
+ if(!name){
+ sprintf(TmpTxt, "Graph %d", cGraphs);
+ name = strdup(TmpTxt);
+ }
+ if(!target && !Disp) {
+ Disp = NewDispClass(this);
+ Disp->SetMenu(MENU_GRAPH);
+ if(name) Disp->Caption(name);
+ Disp->VPorg.fy = (double)Disp->MenuHeight;
+ Disp->CheckMenu(ToolMode, true);
+ OwnDisp = true; defs.SetDisp(Disp);
+ if(GRect.Xmin > 0.0001 || GRect.Xmin < -0.0001) {
+ GRect.Xmax -= GRect.Xmin; GRect.Xmin = 0.0;
+ }
+ if(GRect.Ymin > 0.0001 || GRect.Ymin < -0.0001) {
+ GRect.Ymax -= GRect.Ymin; GRect.Ymin = 0.0;
+ }
+ }
+ //the first output class is the display class
+ if(!Disp && (!(Disp = target))) return;
+ Disp->ActualSize(&defs.clipRC);
+ if(OwnDisp) Disp->Erase(Disp->dFillCol = defs.Color(COL_BG));
+ CurrDisp = target ? target : Disp;
+ CurrDisp->MrkMode = MRK_NONE;
+ CurrRect.Xmin=GRect.Xmin + DRect.Xmin; CurrRect.Xmax=GRect.Xmin + DRect.Xmax;
+ CurrRect.Ymin=GRect.Ymin + DRect.Ymax; CurrRect.Ymax=GRect.Ymin + DRect.Ymin;
+ if(dirty) DoAutoscale();
+ CurrDisp->SetRect(CurrRect, units, &x_axis, &y_axis);
+ CurrDisp->disp_x = CurrDisp->un2fix(GRect.Xmin);
+ CurrDisp->disp_y = CurrDisp->un2fiy(GRect.Ymin);
+ if(!frm_g && !(frm_g = new FrmRect(this, 0L, &GRect, 0L))) return;
+ frm_g->SetColor(COL_GRECT, ColGR); frm_g->SetColor(COL_GRECTLINE, ColGRL);
+ frm_g->DoPlot(CurrDisp);
+ if(type == GT_STANDARD) {
+ if(!frm_d && !(frm_d = new FrmRect(this, &GRect, &DRect, 0L))) return;
+ SetMinMaxRect(&rDims, CurrDisp->co2ix(CurrRect.Xmin), CurrDisp->co2iy(CurrRect.Ymax),
+ CurrDisp->co2ix(CurrRect.Xmax), CurrDisp->co2iy(CurrRect.Ymin));
+ frm_g->Command(CMD_MINRC, &rDims, CurrDisp);
+ SetMinMaxRect(&rDims, CurrDisp->co2ix(GRect.Xmin), CurrDisp->co2iy(GRect.Ymax),
+ CurrDisp->co2ix(GRect.Xmax), CurrDisp->co2iy(GRect.Ymin));
+ frm_d->Command(CMD_MAXRC, &rDims, CurrDisp);
+ frm_d->SetColor(COL_DRECT, ColDR); frm_d->DoPlot(CurrDisp);
+ frm_g->Command(CMD_SETCHILD, &DRect, CurrDisp);
+ }
+ //do all axes
+ if(Axes) for(i = 0; i< NumAxes; i++) if(Axes[i]){
+ Axes[i]->SetColor(COL_BG, ColGR);
+ Axes[i]->DoPlot(CurrDisp);
+ }
+ //do all plots
+ if(Plots) for(i = 0; i < NumPlots; i++) if(Plots[i]) {
+ if(Plots[i]->Id >= GO_PLOT && Plots[i]->Id < GO_GRAPH) {
+ if(((Plot*)Plots[i])->hidden == 0) Plots[i]->DoPlot(CurrDisp);
+ }
+ else {
+ Plots[i]->DoPlot(CurrDisp);
+ }
+ }
+ if(target && ToolMode == TM_STANDARD) target->MouseCursor(MC_ARROW, false);
+}
+
+bool
+Graph::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ GraphObj **tmpPlots;
+ char *f_name;
+ RECT rc;
+ int i, j;
+ DWORD delflg = 0L;
+
+ if(!o) o = CurrDisp;
+ switch (cmd){
+ case CMD_CAN_DELETE:
+ HideTextCursor();
+ if(bModified) {
+ sprintf(TmpTxt, "%s has not been saved.\nDo you want to save it now?", name);
+ if(YesNoBox(TmpTxt)) SaveGraphAs(this);
+ }
+ bModified = false;
+ if(OwnDisp && Disp && parent){ //be careful not to reenter
+ OwnDisp = false; DelDispClass(Disp); Disp = CurrDisp = 0L;
+ if(Axes) for(i = 0; i< NumAxes; i++) if(Axes[i]) DeleteGO(Axes[i]);
+ if(Plots) for(i = 0; i< NumPlots; i++) if(Plots[i]) DeleteGO(Plots[i]);
+ Axes = 0L; Plots = 0L; NumPlots = 0; NumAxes = 0;
+ if(parent) parent->Command(CMD_DELOBJ, this, 0L);
+ }
+ return true;
+ case CMD_LAYERS:
+ Undo.SetDisp(o ? o : CurrDisp);
+ return ShowLayers(this);
+ case CMD_HASSTACK:
+ return(NumPlots > 1);
+ case CMD_SAVEPOS:
+ Undo.ValRect(this, &GRect, 0L);
+ Undo.ValRect(this, &DRect, UNDO_CONTINUE);
+ return true;
+ case CMD_LEGEND:
+ if(Id == GO_PAGE) {
+ if(CurrGraph && CurrGraph->parent == this) return CurrGraph->Command(cmd, tmpl, o);
+ if(!CurrGraph && NumPlots == 1 && Plots[0] && Plots[0]->Id == GO_GRAPH){
+ CurrGraph = (Graph*)Plots[0];
+ return CurrGraph->Command(cmd, tmpl, o);
+ }
+ InfoBox("No graph selected!\nCreate a new graph first or select\n"
+ "a graph before you can add a legend.");
+ return false;
+ }
+ if(Id == GO_GRAPH && !tmpl && Plots) {
+ for(i = 0; i< NumPlots; i++){
+ if(Plots[i] && Plots[i]->Id == GO_LEGEND) {
+ tmpl = (void*)Plots[i];
+ Undo.ObjConf(Plots[i], 0L);
+ break;
+ }
+ }
+ if(!tmpl) {
+ if(!(tmpl = (void*) new Legend(this, data)))return false;
+ tmpPlots = (GraphObj**)memdup(Plots, sizeof(GraphObj*) * (NumPlots+2), 0);
+ if(!tmpPlots) return false;
+ Undo.ListGOmoved(Plots, tmpPlots, NumPlots);
+ Undo.SetGO(this, &tmpPlots[NumPlots++], (Plot *)tmpl, 0L);
+ free(Plots); Plots = tmpPlots; bModified = true;
+ }
+ if(type == GT_CIRCCHART)((Legend*)tmpl)->SetSize(SIZE_XPOS, DRect.Xmin*3.0);
+ for(i = 0; i< NumPlots; i++) if(Plots[i]) Plots[i]->Command(cmd, tmpl,o);
+ Command(CMD_REDRAW, 0L, CurrDisp);
+ }
+ return true;
+ case CMD_REPL_GO:
+ if(!(tmpPlots = (GraphObj **)tmpl) || !tmpPlots[0] || !tmpPlots[1]) return false;
+ if(Axes) for(i = 0; i < NumAxes; i++) if(Axes[i] && Axes[i] == tmpPlots[0]){
+ tmpPlots[1]->parent = this;
+ tmpPlots[1]->Command(CMD_SET_DATAOBJ, data, o);
+ Axes[i] = (Axis *)tmpPlots[1];
+ tmpPlots[0]->parent = 0L; //disable messaging
+ //check for default axes
+ if(((Axis*)tmpPlots[0])->GetAxis() == &x_axis) {
+ if(x_axis.breaks) free(x_axis.breaks);
+ memcpy(&x_axis, Axes[i]->axis, sizeof(AxisDEF));
+ if(x_axis.owner == Axes[i]) free(Axes[i]->axis);
+ Axes[i]->axis = &x_axis; x_axis.owner = this;
+ }
+ else if(((Axis*)tmpPlots[0])->GetAxis() == &y_axis) {
+ if(y_axis.breaks) free(y_axis.breaks);
+ memcpy(&y_axis, Axes[i]->axis, sizeof(AxisDEF));
+ if(y_axis.owner == Axes[i]) free(Axes[i]->axis);
+ Axes[i]->axis = &y_axis; y_axis.owner = this;
+ }
+ DeleteGO(tmpPlots[0]);
+ return bModified = dirty = true;
+ }
+ if(Plots) for(i = 0; i < NumPlots; i++) if(Plots[i] && Plots[i] == tmpPlots[0]) {
+ return bModified = dirty = ReplaceGO((GraphObj**)&Plots[i], tmpPlots);
+ }
+ return false;
+ case CMD_MUTATE:
+ if(!parent || !(tmpPlots = (GraphObj **)tmpl) || !tmpPlots[0] || !tmpPlots[1]) return false;
+ if(Plots) for (i = 0; i < NumPlots; i++) if(Plots[i] && Plots[i] == tmpPlots[0]) {
+ Undo.MutateGO((GraphObj**)&Plots[i], tmpPlots[1], 0L, o);
+ if(ToolMode) Command(CMD_TOOLMODE, 0L, o);
+ return bModified = true;
+ }
+ break;
+ case CMD_HIDE_MARK:
+ if(!tmpl || !o) return false;
+ //do frame rectangles
+ if(frm_g && tmpl == (void*)frm_g) {
+ frm_g->DoMark(o, false); return true;
+ }
+ if(frm_d && tmpl == (void*)frm_d) {
+ frm_d->DoMark(o, false); return true;
+ }
+ //do all axes
+ if(Axes)for(i = NumAxes-1; i>=0; i--) {
+ if(tmpl == (void*)Axes[i]){
+ Axes[i]->DoMark(CurrDisp, false); return true;
+ }
+ else if(Axes[i]->Id == GO_AXIS) {
+ if(Axes[i]->Command(cmd, tmpl, o)) return true;
+ }
+ }
+ //do all plots
+ if(Plots)for(i = NumPlots-1; i>=0; i--) {
+ if(tmpl == (void*)Plots[i]){
+ Plots[i]->DoMark(CurrDisp, false); return true;
+ }
+ else if(Plots[i] && (Plots[i]->Id == GO_MLABEL || Plots[i]->Id == GO_LEGEND ||
+ (Plots[i]->Id >= GO_PLOT && Plots[i]->Id < GO_GRAPH))) {
+ if(Plots[i]->Command(cmd, tmpl, o)) return true;
+ }
+ }
+ return false;
+ case CMD_REDRAW:
+ if(!CurrDisp) {
+ DoPlot(CurrDisp);
+ return true;
+ }
+ if(parent && parent->Id == GO_PAGE) return parent->Command(cmd, tmpl, o);
+ if(CurrDisp && CurrDisp->Erase(ColBG)) CurrDisp->StartPage();
+ CurrDisp->MrkMode = MRK_NONE;
+ DoPlot(CurrDisp);
+ if(CurrDisp) CurrDisp->EndPage();
+ if(CurrGO && CurrGO == CurrLabel && CurrLabel->Id == GO_LABEL)
+ CurrDisp->ShowMark(CurrLabel, MRK_GODRAW);
+ return true;
+ case CMD_ZOOM:
+ return DoZoom((char*)tmpl);
+ case CMD_MOUSECURSOR:
+ if(Disp)Disp->MouseCursor(MC_ARROW, false);
+ return true;
+ case CMD_AXIS: //one of the plots has changed scaling: reset
+ if(o)o->SetRect(CurrRect, units, &x_axis, &y_axis);
+ return true;
+ case CMD_REG_AXISPLOT: //notification: plot can hnadle its own axes
+ if(nscp > 0 && nscp <= NumPlots && Sc_Plots) {
+ for(i = 0; i < nscp; i++)
+ if(Sc_Plots[i] == (GraphObj*)tmpl) return true;
+ if(tmpPlots = (GraphObj**)realloc(Sc_Plots, (nscp+1)*sizeof(GraphObj*))){
+ tmpPlots[nscp++] = (GraphObj *)tmpl;
+ Sc_Plots = tmpPlots;
+ }
+ else { //memory allocation error
+ nscp = 0;
+ Sc_Plots = 0L;
+ }
+ }
+ else {
+ if(Sc_Plots = (GraphObj **)calloc(1, sizeof(GraphObj*))){
+ Sc_Plots[0] = (GraphObj *)tmpl;
+ nscp = 1;
+ }
+ else nscp = 0;
+ }
+ return true;
+ case CMD_BUSY:
+ if(Disp) Disp->MouseCursor(MC_WAIT, true);
+ break;
+ case CMD_UNDO:
+ Command(CMD_TOOLMODE, 0L, o);
+ if(CurrDisp) CurrDisp->MouseCursor(MC_WAIT, true);
+ Undo.Restore(true, CurrDisp);
+ if(CurrDisp) CurrDisp->MouseCursor(MC_ARROW, true);
+ return true;
+ case CMD_ADDAXIS:
+ Command(CMD_TOOLMODE, 0L, o);
+ if(Id == GO_PAGE) {
+ if(CurrGraph && CurrGraph->parent == this) return CurrGraph->Command(cmd, tmpl, o);
+ if(!CurrGraph && NumPlots == 1 && Plots[0] && Plots[0]->Id == GO_GRAPH){
+ CurrGraph = (Graph*)Plots[0];
+ return CurrGraph->Command(cmd, tmpl, o);
+ }
+ InfoBox("No graph selected!\nCreate a new graph first or select\n"
+ "a graph before you can add an axis.");
+ return false;
+ }
+ else {
+ if(type == GT_3D && Plots){
+ for(i = 0; i < NumPlots; i++)
+ if(Plots[i] && Plots[i]->Id == GO_PLOT3D) return Plots[i]->Command(cmd, tmpl, o);
+ }
+ else if(AddAxis()) {
+ Command(CMD_REDRAW, tmpl, o);
+ return true;
+ }
+ }
+ return false;
+ case CMD_CONFIG:
+ Command(CMD_TOOLMODE, 0L, o);
+ return Configure();
+ case CMD_FILENAME:
+ if(tmpl) {
+ if(filename) free(filename);
+ filename=strdup((char*)tmpl);
+ }
+ break;
+ case CMD_SETNAME:
+ if(OwnDisp && CurrDisp && tmpl){
+ CurrDisp->Caption((char*)tmpl);
+ if(name) free(name); name = strdup((char*)tmpl);
+ }
+ else return false;
+ return true;
+ case CMD_SET_DATAOBJ:
+ Id = GO_GRAPH;
+ data = (DataObj *)tmpl;
+ //do axes
+ if(Axes) for(i = 0; i< NumAxes; i++) if(Axes[i]) Axes[i]->Command(cmd, tmpl, o);
+ //do all plots
+ if(Plots) for(i = 0; i< NumPlots; i++) if(Plots[i]) Plots[i]->Command(cmd, tmpl,o);
+ return true;
+ case CMD_OPEN:
+ Command(CMD_TOOLMODE, 0L, o);
+ if(!parent) return false;
+ f_name = OpenGraphName(filename);
+ if(f_name && f_name[0]) {
+ if(data) data->Command(CMD_UPDHISTORY, 0L, 0L);
+ return OpenGraph(Id == GO_PAGE ? this : parent, f_name, 0L);
+ }
+ return true;
+ case CMD_UPDHISTORY:
+ if(data) data->Command(CMD_UPDHISTORY, 0L, 0L);
+ return true;
+ case CMD_UPDATE:
+ Command(CMD_TOOLMODE, 0L, o);
+ if(parent && parent->Id != GO_PAGE){
+ Undo.ValInt(this, &ToolMode, 0L); //stub, all plots have UNDO_CONTINUE
+ }
+ if(CurrDisp) CurrDisp->MouseCursor(MC_WAIT, true);
+ for(i = 0; i < NumAxes; i++) if(Axes[i]) Axes[i]->Command(cmd, tmpl, o);
+ if(CurrDisp) CurrDisp->MouseCursor(MC_WAIT, false);
+ for(i = 0; Plots && i < NumPlots; i++)
+ if(Plots[i]) Plots[i]->Command(cmd, tmpl, o);
+ dirty = bModified = true; CurrDisp->StartPage();
+ if(CurrDisp) CurrDisp->MouseCursor(MC_WAIT, false);
+ DoPlot(CurrDisp); CurrDisp->EndPage(); CurrGO = 0L;
+ return true;
+ case CMD_DELOBJ_CONT:
+ delflg = UNDO_CONTINUE;
+ case CMD_DELOBJ:
+ Command(CMD_TOOLMODE, 0L, o);
+ bModified = true;
+ if(!tmpl) return false;
+ for(i = 0; i < NumAxes; i++) if(Axes[i] && (void*)Axes[i] == tmpl){
+ if(Axes[i]->Command(CMD_CAN_DELETE, 0L, o)) {
+ Undo.DeleteGO((GraphObj**)(&Axes[i]), delflg, o);
+ return Command(CMD_REDRAW, 0L, o);
+ }
+ else {
+ InfoBox("Axes used for scaling\ncan not be deleted.");
+ return false;
+ }
+ }
+ for(i = 0; Plots && i < NumPlots; i++) if(Plots[i] && (void*)Plots[i] == tmpl) {
+ Undo.DeleteGO(&Plots[i], delflg, o);
+ Undo.StoreListGO(this, &Plots, &NumPlots, UNDO_CONTINUE);
+ for(i = j = 0; i < NumPlots; i++) if(Plots[i]) Plots[j++] = Plots[i];
+ NumPlots = j; //compress list of objects
+ return Command(CMD_REDRAW, NULL, o);
+ }
+ if(tmpl == (void*)frm_g && parent && parent->Id == GO_PAGE)
+ return parent->Command(CMD_DELOBJ_CONT, (void*)this, o);
+ return false;
+ case CMD_TOOLMODE:
+ if(o) {
+ o->CheckMenu(ToolMode & 0x0f, false);
+ o->CheckMenu(ToolMode = tmpl ? (*((int*)tmpl)) & 0x0f : TM_STANDARD, true);
+ }
+ if(tl_pts && tl_nPts) free(tl_pts);
+ tl_pts = 0L; tl_nPts = 0;
+ if(CurrDisp) CurrDisp->MrkMode = MRK_NONE;
+ if(o) switch(ToolMode & 0x0f) {
+ case TM_TEXT: o->MouseCursor(MC_TEXT, false); break;
+ case TM_DRAW: case TM_POLYLINE: case TM_POLYGON:
+ case TM_RECTANGLE: case TM_ELLIPSE: case TM_ROUNDREC:
+ case TM_ARROW:
+ o->MouseCursor(MC_CROSS, false);
+ break;
+ default: o->MouseCursor(MC_ARROW, true); break;
+ }
+ return Command(CMD_REDRAW, 0L, CurrDisp);
+ case CMD_ADDPLOT:
+ if(Id == GO_PAGE) {
+ if(CurrGraph && CurrGraph->parent == this) return CurrGraph->Command(cmd, tmpl, o);
+ if(!CurrGraph && NumPlots == 1 && Plots[0] && Plots[0]->Id == GO_GRAPH){
+ CurrGraph = (Graph*)Plots[0];
+ return CurrGraph->Command(cmd, tmpl, o);
+ }
+ InfoBox("No graph selected!\nCreate a new graph first or select\n"
+ "a graph before you can add a plot.");
+ return false;
+ }
+ else if(Id == GO_GRAPH) {
+ if(type == GT_3D && Plots){
+ for(i = 0; i < NumPlots; i++) {
+ if(Plots[i] && Plots[i]->Id == GO_PLOT3D)
+ return Plots[i]->Command(cmd, tmpl, CurrDisp);
+ }
+ }
+ else return AddPlot(0x0);
+ }
+ return false;
+ case CMD_MRK_DIRTY:
+ return (dirty = true);
+ case CMD_CURRLEFT: case CMD_CURRIGHT: case CMD_ADDCHAR:
+ case CMD_BACKSP: case CMD_POS_FIRST: case CMD_POS_LAST:
+ defs.SetDisp(o);
+ if(CurrLabel) return CurrLabel->Command(cmd, tmpl, o);
+ if(CurrGO && tmpl && *((int*)tmpl) == 13) {
+ CurrGO->PropertyDlg();
+ }
+ case CMD_CURRUP: case CMD_CURRDOWN:
+ if(CurrLabel && CurrLabel == CurrGO){
+ if(CurrLabel->parent && CurrLabel->parent->Id == GO_MLABEL)
+ return CurrLabel->parent->Command(cmd, tmpl, o);
+ return true;
+ }
+ case CMD_SHIFTLEFT: case CMD_SHIFTRIGHT: case CMD_SHIFTUP: case CMD_SHIFTDOWN:
+ if(Id == GO_PAGE) {
+ if(CurrGraph && CurrGraph->parent == this)
+ return CurrGraph->Command(cmd, tmpl, o);
+ }
+ else {
+ if(type == GT_3D && Plots) {
+ for(i = 0; i < NumPlots; i++) {
+ if(Plots[i] && Plots[i]->Id == GO_PLOT3D)
+ return Plots[i]->Command(cmd, tmpl, CurrDisp);
+ }
+ }
+ }
+ return false;
+ case CMD_MOVE_TOP: case CMD_MOVE_UP:
+ case CMD_MOVE_DOWN: case CMD_MOVE_BOTTOM:
+ Undo.StoreListGO(this, &Plots, &NumPlots, 0L);
+ if(MoveObj(cmd, (GraphObj *)tmpl)){
+ bModified = true;
+ CurrDisp->StartPage(); DoPlot(CurrDisp);
+ CurrDisp->EndPage(); return true;
+ }
+ return false;
+ case CMD_DELETE:
+ if(!CurrGO) return false;
+ bModified = true;
+ if(CurrGO == CurrLabel) return CurrLabel->Command(cmd, tmpl, o);
+ if(CurrGO->parent)return CurrGO->parent->Command(CMD_DELOBJ, (void*)CurrGO, o);
+ return false;
+ case CMD_DROP_PLOT:
+ if(!tmpl || ((GraphObj*)tmpl)->Id < GO_PLOT) return false;
+ if(Id == GO_GRAPH) CurrGraph = this; bModified =true;
+ if(!NumPlots) {
+ Plots = (GraphObj**)calloc(2, sizeof(GraphObj*));
+ if(Plots) {
+ Plots[0] = (Plot *)tmpl;
+ switch(Plots[0]->Id) {
+ case GO_PIECHART:
+ case GO_RINGCHART:
+ case GO_STARCHART:
+ type = GT_CIRCCHART;
+ break;
+ case GO_POLARPLOT:
+ type = GT_POLARPLOT;
+ break;
+ case GO_SCATT3D:
+ case GO_PLOT3D:
+ type = GT_3D;
+ break;
+ default:
+ type = GT_STANDARD;
+ break;
+ }
+ Bounds.Xmin = x_axis.min = ((Plot*)Plots[0])->Bounds.Xmin;
+ Bounds.Xmax = x_axis.max = ((Plot*)Plots[0])->Bounds.Xmax;
+ Bounds.Ymin = y_axis.min = ((Plot*)Plots[0])->Bounds.Ymin;
+ Bounds.Ymax = y_axis.max = ((Plot*)Plots[0])->Bounds.Ymax;
+ if(Bounds.Ymax == Bounds.Ymin) {
+ if(Bounds.Ymax != 0.0f) {
+ Bounds.Ymax = y_axis.max = Bounds.Ymax + (Bounds.Ymax)/10.0f;
+ Bounds.Ymin = y_axis.min = Bounds.Ymin - (Bounds.Ymax)/10.0f;
+ }
+ else {
+ Bounds.Ymax = y_axis.max = 1.0f;
+ Bounds.Ymin = y_axis.min = -1.0f;
+ }
+ }
+ if(Bounds.Xmax == Bounds.Xmin) {
+ if(Bounds.Xmax != 0.0f) {
+ Bounds.Xmax = x_axis.max = Bounds.Xmax + (Bounds.Xmax)/10.0f;
+ Bounds.Xmin = x_axis.min = Bounds.Xmin - (Bounds.Xmax)/10.0f;
+ }
+ else {
+ Bounds.Xmax = 1.0f;
+ Bounds.Xmin = -1.0f;
+ }
+ }
+ NiceAxis(&x_axis, 4); NiceAxis(&y_axis, 4);
+ NumPlots = 1;
+ if(type == GT_STANDARD && !NumAxes) CreateAxes(AxisTempl);
+ dirty = false;
+ return true;
+ }
+ return false;
+ }
+ else {
+ tmpPlots = (GraphObj**)memdup(Plots, sizeof(GraphObj*) * (NumPlots+2), 0);
+ Undo.ListGOmoved(Plots, tmpPlots, NumPlots);
+ Undo.SetGO(this, &tmpPlots[NumPlots++], (Plot *)tmpl, 0L);
+ free(Plots); Plots = tmpPlots;
+ if(type == GT_STANDARD && ((x_axis.flags & AXIS_AUTOSCALE) ||
+ (y_axis.flags & AXIS_AUTOSCALE))) {
+ if(x_axis.flags & AXIS_AUTOSCALE) {
+ Bounds.Xmin = x_axis.min = ((Plot *)tmpl)->Bounds.Xmin < Bounds.Xmin ?
+ ((Plot *)tmpl)->Bounds.Xmin : Bounds.Xmin;
+ Bounds.Xmax = x_axis.max = ((Plot *)tmpl)->Bounds.Xmax > Bounds.Xmax ?
+ ((Plot *)tmpl)->Bounds.Xmax : Bounds.Xmax;
+ NiceAxis(&x_axis, 4);
+ if(Axes)for(i = 0; i < NumAxes; i++)
+ if(Axes[i]) Axes[i]->Command(CMD_AUTOSCALE, &x_axis, o);
+ }
+ if(y_axis.flags & AXIS_AUTOSCALE) {
+ Bounds.Ymin = y_axis.min = ((Plot *)tmpl)->Bounds.Ymin < Bounds.Ymin ?
+ ((Plot *)tmpl)->Bounds.Ymin : Bounds.Ymin;
+ Bounds.Ymax = y_axis.max = ((Plot *)tmpl)->Bounds.Ymax > Bounds.Ymax ?
+ ((Plot *)tmpl)->Bounds.Ymax : Bounds.Ymax;
+ NiceAxis(&y_axis, 4);
+ if(Axes)for(i = 0; i < NumAxes; i++)
+ if(Axes[i]) Axes[i]->Command(CMD_AUTOSCALE, &y_axis, o);
+ }
+ }
+ dirty = false;
+ //Redraw graph to show all plots
+ CurrDisp->StartPage();
+ DoPlot(CurrDisp);
+ CurrDisp->EndPage();
+ return true;
+ }
+ break;
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *)tmpl; defs.SetDisp(o);
+ if(CurrGO && CurrGO->moveable && mev->Action == MOUSE_LBDOWN &&
+ (TrackGO = (GraphObj*)CurrGO->ObjThere(mev->x, mev->y))){
+ ToolMode |= TM_MOVE;
+ }
+ else if(mev->Action == MOUSE_LBDOWN){
+ CurrGO = 0L;
+ if((ToolMode & 0xff) == TM_STANDARD || (ToolMode & 0xff) == TM_ZOOMIN){
+ rc_mrk.left = mev->x; rc_mrk.top = mev->y;
+ }
+ }
+ if(ToolMode != TM_STANDARD && ExecTool(mev)) return true;
+ switch(mev->Action) {
+ case MOUSE_RBUP:
+ Undo.SetDisp(o);
+ i = ToolMode;
+ ToolMode = TM_STANDARD;
+ mev->Action = MOUSE_LBUP; //fake select
+ Command(cmd, tmpl, o);
+ ToolMode = i;
+ //the default behaviour for right button click is the same as for
+ // double click: execute properties dialog, just continue.
+ case MOUSE_LBDOUBLECLICK:
+ if(!CurrGO){
+ mev->Action = MOUSE_LBUP;
+ Command(CMD_MOUSE_EVENT, mev, CurrDisp);
+ mev->Action = MOUSE_LBDOUBLECLICK;
+ }
+ if(CurrGO) {
+ if(CurrGO->PropertyDlg()) {
+ bModified = true;
+ return Command(CMD_REDRAW, 0L, o);
+ }
+ }
+ else if (Id == GO_PAGE) return Command(CMD_CONFIG, 0L, o);
+ else o->HideMark();
+ CurrGO = TrackGO = 0L; CurrLabel = 0L;
+ return false;
+ case MOUSE_LBUP:
+ Undo.SetDisp(o);
+ if(Id == GO_GRAPH){
+ CurrGO = TrackGO = 0L;
+ CurrGraph = this;
+ }
+ case MOUSE_MOVE:
+ if(mev->Action == MOUSE_MOVE && !(mev->StateFlags & 0x01)) return false;
+ //do all axes
+ for(i = 0; Axes && i< NumAxes; i++)
+ if(Axes[i] && Axes[i]->Command(cmd, tmpl,o)) return true;
+ //do all plots
+ if(Plots)for(i = NumPlots-1; i>=0; i--)
+ if(Plots[i] && Plots[i]->Command(cmd, tmpl,o)) return true;
+ if(frm_d && frm_d->Command(cmd, tmpl, o)) return true;
+ if(frm_g && frm_g->Command(cmd, tmpl, o)) return true;
+ if(mev->Action == MOUSE_MOVE && ToolMode == TM_STANDARD &&
+ rc_mrk.left >=0 && rc_mrk.top >=0) ToolMode = TM_MARK;
+ if(!CurrGO) CurrGraph = 0L;
+ return false;
+ }
+ break;
+ case CMD_SETSCROLL:
+ if(o) {
+ o->ActualSize(&rc);
+ i = o->un2iy(GRect.Ymax);
+ o->SetScroll(true, -(i>>3), i+(i>>3), (rc.bottom -rc.top)>>1, - iround(o->VPorg.fy));
+ i = o->un2ix(GRect.Xmax);
+ o->SetScroll(false, -(i>>3), i+(i>>3), (rc.right -rc.left)>>1, - iround(o->VPorg.fx));
+ if(CurrDisp && o->Erase(ColBG)) Command(CMD_REDRAW, 0L, o);
+ return true;
+ }
+ return false;
+ case CMD_SETHPOS:
+ if(o && tmpl) o->VPorg.fx = - (double)(*((int*)tmpl));
+ return Command(CMD_SETSCROLL, tmpl, o);
+ case CMD_SETVPOS:
+ if(o && tmpl) o->VPorg.fy = - (double)(*((int*)tmpl));
+ return Command(CMD_SETSCROLL, tmpl, o);
+ case CMD_OBJTREE:
+ for(i = 0; Plots && i < NumPlots; i++) if(Plots[i]) {
+ ((ObjTree*)tmpl)->Command(CMD_UPDATE, Plots[i], 0L);
+ if(Plots[i]->Id == GO_STACKBAR || Plots[i]->Id == GO_GRAPH ||
+ Plots[i]->Id == GO_PLOT3D || Plots[i]->Id == GO_POLARPLOT) Plots[i]->Command(cmd, tmpl, o);
+ }
+ return true;
+ }
+ return false;
+}
+
+void
+Graph::DoAutoscale()
+{
+ int i;
+ fRECT oB;
+
+ memcpy(&oB, &Bounds, sizeof(fRECT));
+ if(type == GT_STANDARD && ((x_axis.flags & AXIS_AUTOSCALE) ||
+ (y_axis.flags & AXIS_AUTOSCALE))) {
+ for(i = 0; i < NumPlots; i++) {
+ if(Plots[i] && (Plots[i]->Id == GO_PLOTSCATT || Plots[i]->Id == GO_BUBBLEPLOT ||
+ Plots[i]->Id == GO_BOXPLOT || Plots[i]->Id == GO_STACKBAR ||
+ Plots[i]->Id == GO_STACKPG || Plots[i]->Id == GO_DENSDISP ||
+ Plots[i]->Id == GO_LIMITS || Plots[i]->Id == GO_FUNCTION ||
+ Plots[i]->Id == GO_FITFUNC || Plots[i]->Id== GO_FREQDIST)) {
+ bModified = true;
+ if(dirty) {
+ if(x_axis.flags & AXIS_AUTOSCALE) {
+ Bounds.Xmin = HUGE_VAL; Bounds.Xmax = -HUGE_VAL;
+ }
+ if(y_axis.flags & AXIS_AUTOSCALE) {
+ Bounds.Ymin = HUGE_VAL; Bounds.Ymax = -HUGE_VAL;
+ }
+ dirty = false;
+ }
+ Plots[i]->Command(CMD_AUTOSCALE, 0L, CurrDisp);
+ if(!((Plot*)Plots[i])->hidden) {
+ if(x_axis.flags & AXIS_AUTOSCALE) {
+ Bounds.Xmin = ((Plot*)Plots[i])->Bounds.Xmin < Bounds.Xmin ?
+ ((Plot*)Plots[i])->Bounds.Xmin : Bounds.Xmin;
+ Bounds.Xmax = ((Plot*)Plots[i])->Bounds.Xmax > Bounds.Xmax ?
+ ((Plot*)Plots[i])->Bounds.Xmax : Bounds.Xmax;
+ }
+ if(y_axis.flags & AXIS_AUTOSCALE) {
+ Bounds.Ymin = ((Plot*)Plots[i])->Bounds.Ymin < Bounds.Ymin ?
+ ((Plot*)Plots[i])->Bounds.Ymin : Bounds.Ymin;
+ Bounds.Ymax = ((Plot*)Plots[i])->Bounds.Ymax > Bounds.Ymax ?
+ ((Plot*)Plots[i])->Bounds.Ymax : Bounds.Ymax;
+ }
+ }
+ }
+ }
+ if(Bounds.Xmax <= Bounds.Xmin) {
+ Bounds.Xmax = oB.Xmax > oB.Xmin ? oB.Xmax : oB.Xmax + 1.0;
+ Bounds.Xmin = oB.Xmin < oB.Xmax ? oB.Xmin : oB.Xmin - 1.0;
+ }
+ if(Bounds.Ymax <= Bounds.Ymin) {
+ Bounds.Ymax = oB.Ymax > oB.Ymin ? oB.Ymax : oB.Ymax + 1.0;
+ Bounds.Ymin = oB.Ymin < oB.Ymax ? oB.Ymin : oB.Ymin - 1.0;
+ }
+ if(x_axis.flags & AXIS_AUTOSCALE){
+ x_axis.min = Bounds.Xmin; x_axis.max = Bounds.Xmax;
+ NiceAxis(&x_axis, 4);
+ if(x_axis.min <= 0.0 && ((x_axis.flags & 0xf000) == AXIS_LOG ||
+ (x_axis.flags & 0xf000) == AXIS_RECI)) {
+ x_axis.min = base4log(&x_axis, 0);
+ }
+ if(Axes)for(i = 0; i < NumAxes; i++)
+ if(Axes[i]) Axes[i]->Command(CMD_AUTOSCALE, &x_axis, 0L);
+ }
+ if(y_axis.flags & AXIS_AUTOSCALE){
+ y_axis.min = Bounds.Ymin; y_axis.max = Bounds.Ymax;
+ NiceAxis(&y_axis, 4);
+ if(y_axis.min <= 0.0 && ((y_axis.flags & 0xf000) == AXIS_LOG ||
+ (y_axis.flags & 0xf000) == AXIS_RECI)) {
+ y_axis.min = base4log(&y_axis, 1);
+ }
+ if(Axes)for(i = 0; i < NumAxes; i++)
+ if(Axes[i]) Axes[i]->Command(CMD_AUTOSCALE, &y_axis, 0L);
+ }
+ }
+ dirty = false;
+}
+
+void
+Graph::CreateAxes(int templ)
+{
+ AxisDEF tmp_axis;
+ TextDEF label_def, tlbdef;
+ char label_text[20];
+ Label *label;
+ double ts, lb_ydist, lb_xdist, tlb_dist;
+ DWORD ptick, ntick, utick;
+
+ if(Axes && NumAxes) return;
+ label_def.ColTxt = defs.Color(COL_AXIS);
+ label_def.ColBg = 0x00ffffffL;
+ label_def.fSize = defs.GetSize(SIZE_TICK_LABELS)*1.2;
+ label_def.RotBL = label_def.RotCHAR = 0.0;
+ label_def.iSize = 0;
+ label_def.Align = TXA_VTOP | TXA_HCENTER;
+ label_def.Mode = TXM_TRANSPARENT;
+ label_def.Style = TXS_NORMAL;
+ label_def.Font = FONT_HELVETICA;
+ label_def.text = label_text;
+ tlbdef.ColTxt = defs.Color(COL_AXIS);
+ tlbdef.ColBg = 0x00ffffffL;
+ tlbdef.RotBL = tlbdef.RotCHAR = 0.0;
+ tlbdef.iSize = 0;
+ tlbdef.fSize = defs.GetSize(SIZE_TICK_LABELS);
+ tlbdef.Align = TXA_VCENTER | TXA_HCENTER;
+ tlbdef.Style = TXS_NORMAL;
+ tlbdef.Mode = TXM_TRANSPARENT;
+ tlbdef.Font = FONT_HELVETICA;
+ tlbdef.text = 0L;
+ ts = defs.GetSize(SIZE_AXIS_TICKS);
+ switch (tickstyle & 0x07){
+ case 1: //ticks inside
+ ntick = AXIS_POSTICKS; ptick = AXIS_POSTICKS; utick = AXIS_NEGTICKS;
+ ts *= 0.5;
+ break;
+ case 2: //centered, symetrical
+ ptick = ntick = utick = AXIS_SYMTICKS;
+ ts *= 0.75;
+ break;
+ default: //ticks outside
+ ptick = AXIS_NEGTICKS; ntick = AXIS_NEGTICKS; utick = AXIS_POSTICKS;
+ break;
+ }
+ tlb_dist = NiceValue(ts * 2.0);
+ lb_ydist = NiceValue((ts+defs.GetSize(SIZE_AXIS_TICKS))*2.0);
+ lb_xdist = NiceValue((ts+defs.GetSize(SIZE_AXIS_TICKS))*3.0);
+ switch(templ) {
+ case 0:
+ Axes = (Axis**)calloc(5, sizeof(Axis *));
+ x_axis.loc[0].fx = GRect.Xmin + DRect.Xmin;
+ x_axis.loc[1].fx = GRect.Xmin + DRect.Xmax;
+ x_axis.loc[0].fy = x_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
+ y_axis.loc[0].fy = GRect.Ymin + DRect.Ymin;
+ y_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
+ y_axis.loc[0].fx = y_axis.loc[1].fx = GRect.Xmin + DRect.Xmin;;
+ if((Axes[0] = new Axis(this, data, &x_axis, AXIS_BOTTOM | ptick |
+ AXIS_AUTOTICK | AXIS_AUTOSCALE | ((tickstyle & 0x100) ? AXIS_GRIDLINE : 0)))){
+ Axes[0]->SetSize(SIZE_LB_YDIST, lb_ydist);
+ Axes[0]->SetSize(SIZE_TLB_YDIST, tlb_dist);
+ strcpy(label_text, "x-axis");
+ label = new Label(Axes[0], data, GRect.Xmin + (DRect.Xmin+DRect.Xmax)/2.0f,
+ GRect.Ymin+DRect.Ymax+defs.GetSize(SIZE_AXIS_TICKS)*4.0f, &label_def, LB_Y_PARENT);
+ if(label && Axes[0]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
+ else if(label) DeleteGO(label);
+ tlbdef.Align = TXA_VTOP | TXA_HCENTER;
+ Axes[0]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+ }
+ if((Axes[1] = new Axis(this, data, &y_axis, AXIS_LEFT | ntick | AXIS_AUTOTICK |
+ AXIS_AUTOSCALE | ((tickstyle & 0x200) ? AXIS_GRIDLINE : 0)))){
+ Axes[1]->SetSize(SIZE_LB_XDIST, -lb_xdist);
+ Axes[1]->SetSize(SIZE_TLB_XDIST, -tlb_dist);
+ strcpy(label_text, "y-axis");
+ label_def.RotBL = 90.0; label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
+ label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - defs.GetSize(SIZE_AXIS_TICKS)*6.0,
+ GRect.Ymin+(DRect.Ymax+DRect.Ymin)/2.0, &label_def, LB_X_PARENT);
+ if(label && Axes[1]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
+ else if(label) DeleteGO(label);
+ tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
+ Axes[1]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+ }
+ label = 0L;
+ memcpy(&tmp_axis, &x_axis, sizeof(AxisDEF));
+ tmp_axis.owner = NULL;
+ tmp_axis.loc[0].fy = tmp_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
+ if((Axes[2] = new Axis(this, data, &tmp_axis, AXIS_TOP | AXIS_NOTICKS | AXIS_AUTOTICK))){
+ Axes[2]->SetSize(SIZE_LB_YDIST, -lb_ydist);
+ Axes[2]->SetSize(SIZE_TLB_YDIST, -tlb_dist);
+ tlbdef.Align = TXA_VBOTTOM | TXA_HCENTER;
+ Axes[2]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+ }
+ memcpy(&tmp_axis, &y_axis, sizeof(AxisDEF));
+ tmp_axis.owner = NULL;
+ tmp_axis.loc[0].fx = tmp_axis.loc[1].fx = GRect.Xmin + DRect.Xmax;
+ if((Axes[3] = new Axis(this, data, &tmp_axis, AXIS_RIGHT | AXIS_NOTICKS | AXIS_AUTOTICK))){
+ Axes[3]->SetSize(SIZE_LB_XDIST, lb_xdist);
+ Axes[3]->SetSize(SIZE_TLB_XDIST, tlb_dist);
+ tlbdef.Align = TXA_VCENTER | TXA_HLEFT;
+ Axes[3]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+ }
+ NumAxes = 4;
+ break;
+ case 1:
+ Axes = (Axis**)calloc(7, sizeof(Axis *));
+ if(x_axis.Start >= 0.0f) x_axis.min = x_axis.Start = -x_axis.Step;
+ if(y_axis.Start >= 0.0f) y_axis.min = y_axis.Start = -y_axis.Step;
+ x_axis.loc[0].fx = GRect.Xmin + DRect.Xmin;
+ x_axis.loc[1].fx = GRect.Xmin + DRect.Xmax;
+ x_axis.loc[0].fy = x_axis.loc[1].fy = 0.0f;
+ y_axis.loc[0].fy = GRect.Ymin + DRect.Ymin;
+ y_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
+ y_axis.loc[0].fx = y_axis.loc[1].fx = 0.0f;
+ if((Axes[0] = new Axis(this, data, &x_axis, ptick | AXIS_Y_DATA |
+ AXIS_AUTOTICK | AXIS_AUTOSCALE | ((tickstyle & 0x100) ? AXIS_GRIDLINE : 0)))){
+ Axes[0]->SetSize(SIZE_LB_YDIST, lb_ydist);
+ Axes[0]->SetSize(SIZE_TLB_YDIST, tlb_dist);
+ strcpy(label_text, "x-axis");
+ label_def.Align = TXA_VTOP | TXA_HRIGHT;
+ label = new Label(Axes[0], data, GRect.Xmin + DRect.Xmax - defs.GetSize(SIZE_AXIS_TICKS)*2.0,
+ GRect.Ymin+DRect.Ymax+defs.GetSize(SIZE_AXIS_TICKS)*4.0f, &label_def, LB_Y_PARENT);
+ if(label && Axes[0]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
+ else if(label) DeleteGO(label);
+ tlbdef.Align = TXA_VTOP | TXA_HCENTER;
+ Axes[0]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+ }
+ if((Axes[1] = new Axis(this, data, &y_axis, ntick | AXIS_AUTOTICK | AXIS_X_DATA |
+ AXIS_AUTOSCALE | ((tickstyle & 0x200) ? AXIS_GRIDLINE : 0)))){
+ Axes[1]->SetSize(SIZE_LB_XDIST, -lb_xdist);
+ Axes[1]->SetSize(SIZE_TLB_XDIST, -tlb_dist);
+ strcpy(label_text, "y-axis");
+ label_def.RotBL = 90.0; label_def.Align = TXA_VBOTTOM | TXA_HRIGHT;
+ label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - defs.GetSize(SIZE_AXIS_TICKS)*6.0,
+ GRect.Ymin + DRect.Ymin + defs.GetSize(SIZE_AXIS_TICKS)*2.0,
+ &label_def, LB_X_PARENT);
+ if(label && Axes[1]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
+ else if(label) DeleteGO(label);
+ tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
+ Axes[1]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+ }
+ memcpy(&tmp_axis, &x_axis, sizeof(AxisDEF));
+ tmp_axis.owner = NULL;
+ tmp_axis.loc[0].fy = tmp_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
+ if(Axes[2] = new Axis(this, data, &tmp_axis, AXIS_TOP | AXIS_NOTICKS | AXIS_AUTOTICK)){
+ Axes[2]->SetSize(SIZE_LB_YDIST, -lb_ydist);
+ Axes[2]->SetSize(SIZE_TLB_YDIST, -tlb_dist);
+ tlbdef.Align = TXA_VBOTTOM | TXA_HCENTER;
+ Axes[2]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+ }
+ tmp_axis.loc[0].fy = tmp_axis.loc[1].fy = GRect.Ymin + DRect.Ymin;
+ if(Axes[3] = new Axis(this, data, &tmp_axis, AXIS_BOTTOM | AXIS_NOTICKS | AXIS_AUTOTICK)){
+ Axes[3]->SetSize(SIZE_LB_YDIST, lb_xdist);
+ Axes[3]->SetSize(SIZE_TLB_YDIST, tlb_dist);
+ tlbdef.Align = TXA_VTOP | TXA_HCENTER;
+ Axes[3]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+ }
+ memcpy(&tmp_axis, &y_axis, sizeof(AxisDEF));
+ tmp_axis.owner = NULL;
+ tmp_axis.loc[0].fx = tmp_axis.loc[1].fx = GRect.Xmin + DRect.Xmin;
+ if(Axes[4] = new Axis(this, data, &tmp_axis, AXIS_LEFT | AXIS_NOTICKS | AXIS_AUTOTICK)){
+ Axes[4]->SetSize(SIZE_LB_XDIST, -lb_xdist);
+ Axes[4]->SetSize(SIZE_TLB_XDIST, -tlb_dist);
+ tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
+ Axes[4]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+ }
+ tmp_axis.loc[0].fx = tmp_axis.loc[1].fx = GRect.Xmin + DRect.Xmax;
+ if(Axes[5] = new Axis(this, data, &tmp_axis, AXIS_RIGHT | AXIS_NOTICKS | AXIS_AUTOTICK)){
+ Axes[5]->SetSize(SIZE_LB_XDIST, lb_xdist);
+ Axes[5]->SetSize(SIZE_TLB_XDIST, tlb_dist);
+ tlbdef.Align = TXA_VCENTER | TXA_HLEFT;
+ Axes[5]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+ }
+ NumAxes = 6;
+ break;
+ case 2:
+ Axes = (Axis**)calloc(3, sizeof(Axis *));
+ x_axis.loc[0].fx = GRect.Xmin + DRect.Xmin;
+ x_axis.loc[1].fx = GRect.Xmin + DRect.Xmax;
+ x_axis.loc[0].fy = x_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
+ y_axis.loc[0].fy = GRect.Ymin + DRect.Ymin;
+ y_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
+ y_axis.loc[0].fx = y_axis.loc[1].fx = GRect.Xmin + DRect.Xmin;
+ if((Axes[0] = new Axis(this, data, &x_axis, AXIS_BOTTOM | ptick |
+ AXIS_AUTOTICK | AXIS_AUTOSCALE | ((tickstyle & 0x100) ? AXIS_GRIDLINE : 0)))){
+ Axes[0]->SetSize(SIZE_LB_YDIST, lb_ydist);
+ Axes[0]->SetSize(SIZE_TLB_YDIST, tlb_dist);
+ strcpy(label_text, "x-axis");
+ label = new Label(Axes[0], data, GRect.Xmin + (DRect.Xmin+DRect.Xmax)/2.0f,
+ GRect.Ymin+DRect.Ymax+defs.GetSize(SIZE_AXIS_TICKS)*4.0f, &label_def, LB_Y_PARENT);
+ if(label && Axes[0]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
+ else if(label) DeleteGO(label);
+ tlbdef.Align = TXA_VTOP | TXA_HCENTER;
+ Axes[0]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+ }
+ if((Axes[1] = new Axis(this, data, &y_axis, AXIS_LEFT | ntick | AXIS_AUTOTICK |
+ AXIS_AUTOSCALE | ((tickstyle & 0x200) ? AXIS_GRIDLINE : 0)))){
+ Axes[1]->SetSize(SIZE_LB_XDIST, -lb_xdist);
+ Axes[1]->SetSize(SIZE_TLB_XDIST, -tlb_dist);
+ strcpy(label_text, "y-axis");
+ label_def.RotBL = 90.0; label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
+ label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - defs.GetSize(SIZE_AXIS_TICKS)*6.0,
+ GRect.Ymin+(DRect.Ymax+DRect.Ymin)/2.0, &label_def, LB_X_PARENT);
+ if(label && Axes[1]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
+ else if(label) DeleteGO(label);
+ tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
+ Axes[1]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+ }
+ label = 0L;
+ NumAxes = 2;
+ break;
+ case 3:
+ label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
+ Axes = (Axis**)calloc(3, sizeof(Axis *));
+ x_axis.loc[0].fx = GRect.Xmin + DRect.Xmin;
+ x_axis.loc[1].fx = GRect.Xmin + DRect.Xmax;
+ x_axis.loc[0].fy = x_axis.loc[1].fy = GRect.Ymin + DRect.Ymin;
+ y_axis.loc[0].fy = GRect.Ymin + DRect.Ymin;
+ y_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
+ y_axis.loc[0].fx = y_axis.loc[1].fx = GRect.Xmin + DRect.Xmin;
+ if((Axes[0] = new Axis(this, data, &x_axis, AXIS_TOP | utick |
+ AXIS_AUTOTICK | AXIS_AUTOSCALE | ((tickstyle & 0x100) ? AXIS_GRIDLINE : 0)))){
+ Axes[0]->SetSize(SIZE_LB_YDIST, -lb_ydist);
+ Axes[0]->SetSize(SIZE_TLB_YDIST, -tlb_dist);
+ strcpy(label_text, "x-axis");
+ label = new Label(Axes[0], data, GRect.Xmin + (DRect.Xmin+DRect.Xmax)/2.0f,
+ GRect.Ymin+DRect.Ymax+defs.GetSize(SIZE_AXIS_TICKS)*4.0f, &label_def, LB_Y_PARENT);
+ if(label && Axes[0]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
+ else if(label) DeleteGO(label);
+ tlbdef.Align = TXA_VBOTTOM | TXA_HCENTER;
+ Axes[0]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+ }
+ if((Axes[1] = new Axis(this, data, &y_axis, AXIS_LEFT | ntick | AXIS_AUTOTICK |
+ AXIS_AUTOSCALE | AXIS_INVERT | ((tickstyle & 0x200) ? AXIS_GRIDLINE : 0)))){
+ Axes[1]->SetSize(SIZE_LB_XDIST, -lb_xdist);
+ Axes[1]->SetSize(SIZE_TLB_XDIST, -tlb_dist);
+ strcpy(label_text, "y-axis");
+ label_def.RotBL = 90.0; label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
+ label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - defs.GetSize(SIZE_AXIS_TICKS)*6.0,
+ GRect.Ymin+(DRect.Ymax+DRect.Ymin)/2.0, &label_def, LB_X_PARENT);
+ if(label && Axes[1]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
+ else if(label) DeleteGO(label);
+ tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
+ Axes[1]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+ }
+ label = 0L;
+ NumAxes = 2;
+ break;
+ case 4:
+ Axes = (Axis**)calloc(3, sizeof(Axis *));
+ if(x_axis.Start >= 0.0f) x_axis.min = -x_axis.Step;
+ x_axis.loc[0].fx = GRect.Xmin + DRect.Xmin;
+ x_axis.loc[1].fx = GRect.Xmin + DRect.Xmax;
+ x_axis.loc[0].fy = x_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
+ y_axis.loc[0].fy = GRect.Ymin + DRect.Ymin;
+ y_axis.loc[1].fy = GRect.Ymin + DRect.Ymax;
+ y_axis.loc[0].fx = y_axis.loc[1].fx = 0.0f;
+ if((Axes[0] = new Axis(this, data, &x_axis, AXIS_BOTTOM | ptick |
+ AXIS_AUTOTICK | AXIS_AUTOSCALE | ((tickstyle & 0x100) ? AXIS_GRIDLINE : 0)))){
+ Axes[0]->SetSize(SIZE_LB_YDIST, lb_ydist);
+ Axes[0]->SetSize(SIZE_TLB_YDIST, tlb_dist);
+ strcpy(label_text, "x-axis");
+ label = new Label(Axes[0], data, GRect.Xmin + (DRect.Xmin+DRect.Xmax)/2.0f,
+ GRect.Ymin+DRect.Ymax+defs.GetSize(SIZE_AXIS_TICKS)*4.0f, &label_def, LB_Y_PARENT);
+ if(label && Axes[0]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
+ else if(label) DeleteGO(label);
+ tlbdef.Align = TXA_VTOP | TXA_HCENTER;
+ Axes[0]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+ }
+ if((Axes[1] = new Axis(this, data, &y_axis, ntick | AXIS_AUTOTICK | AXIS_X_DATA |
+ AXIS_AUTOSCALE | ((tickstyle & 0x200) ? AXIS_GRIDLINE : 0)))){
+ Axes[1]->SetSize(SIZE_LB_XDIST, -lb_xdist);
+ Axes[1]->SetSize(SIZE_TLB_XDIST, -tlb_dist);
+ strcpy(label_text, "y-axis");
+ label_def.RotBL = 90.0; label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
+ label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - defs.GetSize(SIZE_AXIS_TICKS)*6.0,
+ GRect.Ymin+(DRect.Ymax+DRect.Ymin)/2.0, &label_def, LB_X_PARENT);
+ if(label && Axes[1]->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
+ else if(label) DeleteGO(label);
+ tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
+ Axes[1]->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+ }
+ label = 0L;
+ NumAxes = 2;
+ break;
+ }
+}
+
+bool
+Graph::ExecTool(MouseEvent *mev)
+{
+ static POINT pl = {0, 0}, pc = {0, 0};
+ static DWORD color = 0L;
+ POINT line[5];
+ GraphObj **tmpPlots, *new_go;
+ TextDEF *td;
+ lfPOINT *lfp, lf;
+ int i, j;
+ double x, y;
+
+ if(!mev || !CurrDisp) return false;
+ td = 0L;
+ if(ToolMode & TM_MOVE) switch (mev->Action) {
+ case MOUSE_LBDOWN:
+ pl.x = pc.x = mev->x; pl.y = pc.y = mev->y;
+ CurrDisp->HideMark();
+ if(TrackGO && TrackGO->Command(CMD_MOUSECURSOR, 0L, CurrDisp))
+ return true;
+ else CurrDisp->MouseCursor(MC_MOVE, false);
+ return true;
+ case MOUSE_MOVE:
+ if(TrackGO) {
+ if(TrackGO->Id == GO_DRAGHANDLE && TrackGO->type >= DH_18 &&
+ TrackGO->type <= DH_88) {
+ lf.fx = CurrDisp->fix2un((double)(mev->x-pl.x));
+ lf.fy = CurrDisp->fiy2un((double)(mev->y-pl.y));
+ TrackGO->Track((POINT*)&lf, CurrDisp);
+ }
+ else {
+ pc.x = mev->x-pl.x; pc.y = mev->y-pl.y;
+ TrackGO->Track(&pc, CurrDisp);
+ }
+ }
+ return true;
+ case MOUSE_LBUP:
+ if(TrackGO) {
+ ToolMode &= ~TM_MOVE;
+ pc.x = mev->x-pl.x; pc.y = mev->y-pl.y;
+ if(!pc.x && !pc.y){
+ Command(CMD_TOOLMODE, (void*)(& ToolMode), CurrDisp);
+ return false;
+ }
+ TrackGO->Track(&pc, CurrDisp);
+ lf.fx = CurrDisp->fix2un((double)(mev->x-pl.x));
+ lf.fy = CurrDisp->fiy2un((double)(mev->y-pl.y));
+ TrackGO->Command(CMD_MOVE, &lf, CurrDisp);
+ bModified = true;
+ }
+ Command(CMD_TOOLMODE, (void*)(& ToolMode), CurrDisp);
+ return true;
+ default:
+ return true;
+ }
+ if(ToolMode == TM_MARK || ToolMode == TM_ZOOMIN) {
+ switch (mev->Action) {
+ case MOUSE_LBDOWN: //we should not receive that !
+ rc_mrk.left = mev->x; rc_mrk.top = mev->y;
+ return false;
+ case MOUSE_LBUP:
+ j = (i = rc_mrk.left - mev->x)*i;
+ j += ((i = rc_mrk.top - mev->y)*i);
+ if(j < 20) { //glitch
+ ToolMode = TM_STANDARD;
+ return false;
+ }
+ if(ToolMode == TM_ZOOMIN) {
+ rc_mrk.right = mev->x; rc_mrk.bottom = mev->y;
+ ToolMode = TM_STANDARD;
+ return Command(CMD_ZOOM, (void*) &"+", 0L);
+ }
+ default:
+ ToolMode = TM_STANDARD;
+ case MOUSE_MOVE:
+ if((mev->StateFlags &1) && rc_mrk.left >= 0 && rc_mrk.top >= 0) {
+ if(rcUpd.left != rcUpd.right && rcUpd.top != rcUpd.bottom)
+ CurrDisp->UpdateRect(&rcUpd, false);
+ line[0].x = line[3].x = line[4].x = rc_mrk.left;
+ line[0].y = line[1].y = line[4].y = rc_mrk.top;
+ line[1].x = line[2].x = mev->x;
+ line[2].y = line[3].y = mev->y;
+ CurrDisp->ShowLine(line, 5, 0x00c0c0c0L);
+ rcUpd.left = rcUpd.right = rc_mrk.left;
+ rcUpd.top = rcUpd.bottom = rc_mrk.top;
+ UpdateMinMaxRect(&rcUpd, rc_mrk.right = mev->x, rc_mrk.bottom = mev->y);
+ IncrementMinMaxRect(&rcUpd,2);
+ }
+ return true;
+ }
+ }
+ if(NumPlots && !Plots[NumPlots-1]) {
+ Undo.StoreListGO(this, &Plots, &NumPlots, UNDO_CONTINUE);
+ for(i = j = 0; i < NumPlots; i++) if(Plots[i]) Plots[j++] = Plots[i];
+ NumPlots = j;
+ }
+ else if(!Plots && !(Plots = (GraphObj**)calloc(2, sizeof(GraphObj*))))return false;
+ else if(Plots[NumPlots]){
+ if(tmpPlots = (GraphObj**)memdup(Plots, (NumPlots+2) * sizeof(GraphObj*), 0L)){
+ Undo.ListGOmoved(Plots, tmpPlots, NumPlots);
+ free(Plots); Plots = tmpPlots;
+ Plots[NumPlots] = Plots[NumPlots+1] = 0L;
+ }
+ else return false;
+ }
+ switch(ToolMode & 0x0f) {
+ case TM_DRAW:
+ switch (mev->Action) {
+ case MOUSE_LBDOWN:
+ CurrGO = 0L;
+ CurrDisp->MrkMode = MRK_NONE;
+ Command(CMD_REDRAW, 0L, CurrDisp);
+ color = defs.Color(COL_POLYLINE);
+ pl.x = pc.x = mev->x; pl.y = pc.y = mev->y;
+ if(tl_pts) free(tl_pts);
+ tl_nPts = 0;
+ if(tl_pts = (POINT*)malloc(4096 * sizeof(POINT)))
+ AddToPolygon(&tl_nPts, tl_pts, &pc);
+ return true;
+ case MOUSE_LBUP:
+ pl.x = mev->x; pl.y = mev->y;
+ if(tl_pts) AddToPolygon(&tl_nPts, tl_pts, &pc);
+ // create line object
+ if(tl_pts && tl_nPts >1) { //DEBUG: check for plausibility
+ if(lfp = (lfPOINT*)malloc(tl_nPts * sizeof(lfPOINT))){
+ for(i = 0; i < tl_nPts; i++) {
+ lfp[i].fx = CurrDisp->fix2un(tl_pts[i].x - CurrDisp->VPorg.fx);
+ lfp[i].fy = CurrDisp->fiy2un(tl_pts[i].y - CurrDisp->VPorg.fy);
+ }
+ if(Plots[NumPlots]) i = NumPlots+1;
+ else i = NumPlots;
+ Undo.SetGO(this, &Plots[i], new polyline(this, data, lfp, (int)tl_nPts), 0L);
+ if(Plots[i]){
+ NumPlots = i+1;
+ Plots[i]->moveable = 1;
+ Plots[i]->DoPlot(CurrDisp); //init
+ CurrDisp->ShowMark(CurrGO = Plots[i], MRK_GODRAW); //edit
+ bModified = true;
+ }
+ free(lfp);
+ }
+ if(tl_pts) free(tl_pts); tl_pts = 0L; tl_nPts = 0;
+ return true;
+ }
+ if(tl_pts) free(tl_pts); tl_pts = 0L; tl_nPts = 0;
+ return false;
+ case MOUSE_MOVE:
+ if((mev->StateFlags &1) && tl_pts && tl_nPts < 4095) {
+ memcpy(&pl, &pc, sizeof(POINT));
+ line[1].x = pc.x = mev->x; line[1].y = pc.y = mev->y;
+ line[0].x = pl.x; line[0].y = pl.y;
+ CurrDisp->ShowLine(line, 2, color);
+ AddToPolygon(&tl_nPts, tl_pts, &pc);
+ return true;
+ }
+ break;
+ }
+ break;
+ case TM_POLYLINE:
+ case TM_POLYGON:
+ switch (mev->Action) {
+ case MOUSE_LBDOWN:
+ if(!tl_pts) {
+ CurrGO = 0L;
+ CurrDisp->MrkMode = MRK_NONE;
+ Command(CMD_REDRAW, 0L, CurrDisp);
+ color = defs.Color((ToolMode & 0x0f) == TM_POLYLINE ? COL_POLYLINE : COL_POLYGON);
+ pl.x = pc.x = mev->x; pl.y = pc.y = mev->y;
+ tl_nPts = 0;
+ if(tl_pts = (POINT*)malloc(4096 * sizeof(POINT)))
+ AddToPolygon(&tl_nPts, tl_pts, &pc);
+ rcDim.left = rcDim.right = rcUpd.left = rcUpd.right = mev->x;
+ rcDim.top = rcDim.bottom = rcUpd.top = rcUpd.bottom = mev->y;
+ }
+ return true;
+ case MOUSE_MOVE:
+ if(tl_pts && tl_nPts) {
+ if(rcUpd.left != rcUpd.right && rcUpd.top != rcUpd.bottom)
+ CurrDisp->UpdateRect(&rcUpd, false);
+ CurrDisp->ShowLine(tl_pts, tl_nPts, color);
+ line[1].x = mev->x; line[1].y = mev->y;
+ line[0].x = pc.x; line[0].y = pc.y;
+ CurrDisp->ShowLine(line, 2, color);
+ UpdateMinMaxRect(&rcUpd, mev->x, mev->y);
+ memcpy(&rcUpd, &rcDim, sizeof(RECT));
+ UpdateMinMaxRect(&rcUpd, mev->x, mev->y);
+ IncrementMinMaxRect(&rcUpd, 2);
+ return true;
+ }
+ break;
+ case MOUSE_LBUP:
+ if(tl_pts && tl_nPts) {
+ memcpy(&pl, &pc, sizeof(POINT));
+ pc.x = mev->x; pc.y = mev->y;
+ UpdateMinMaxRect(&rcDim, mev->x, mev->y);
+ AddToPolygon(&tl_nPts, tl_pts, &pc);
+ }
+ return true;
+ default: // create line or polygon object
+ if(tl_pts && tl_nPts >0) { //DEBUG: check for plausibility
+ pc.x = mev->x; pc.y = mev->y;
+ AddToPolygon(&tl_nPts, tl_pts, &pc);
+ if(lfp = (lfPOINT*)malloc(tl_nPts * sizeof(lfPOINT))){
+ for(i = 0; i < tl_nPts; i++) {
+ lfp[i].fx = CurrDisp->fix2un(tl_pts[i].x-CurrDisp->VPorg.fx);
+ lfp[i].fy = CurrDisp->fiy2un(tl_pts[i].y-CurrDisp->VPorg.fy);
+ }
+ if(Plots[NumPlots]) i = NumPlots+1;
+ else i = NumPlots;
+ Undo.SetGO(this, &Plots[i], ToolMode == TM_POLYLINE ?
+ new polyline(this, data, lfp, (int)tl_nPts) :
+ new polygon(this, data, lfp, (int)tl_nPts), 0L);
+ if(Plots[i]){
+ NumPlots = i+1;
+ Plots[i]->moveable = 1;
+ Plots[i]->DoPlot(CurrDisp); //init
+ CurrDisp->ShowMark(CurrGO = Plots[i], MRK_GODRAW); //edit
+ bModified = true;
+ }
+ free(lfp);
+ }
+ free(tl_pts); tl_pts = 0L; tl_nPts = 0;
+ return true;
+ }
+ }
+ if(mev->x == pc.x && mev->y == pc.y) return true; //rebounce
+ break;
+ case TM_RECTANGLE:
+ case TM_ELLIPSE:
+ case TM_ROUNDREC:
+ case TM_ARROW:
+ switch (mev->Action) {
+ case MOUSE_LBDOWN:
+ CurrGO = 0L;
+ CurrDisp->MrkMode = MRK_NONE;
+ Command(CMD_REDRAW, 0L, CurrDisp);
+ color = defs.Color((ToolMode & 0x0f) != TM_ARROW ? COL_POLYGON : COL_DATA_LINE);
+ pl.x = pc.x = mev->x; pl.y = pc.y = mev->y;
+ rcDim.left = rcDim.right = rcUpd.left = rcUpd.right = mev->x;
+ rcDim.top = rcDim.bottom = rcUpd.top = rcUpd.bottom = mev->y;
+ return true;
+ case MOUSE_MOVE:
+ if(mev->StateFlags &1) {
+ if(rcUpd.left != rcUpd.right && rcUpd.top != rcUpd.bottom)
+ CurrDisp->UpdateRect(&rcUpd, false);
+ line[0].x = line[4].x = pl.x; line[0].y = line[4].y = pl.y;
+ if((ToolMode & 0x0f)==TM_ARROW) {
+ line[1].x = pc.x = mev->x; line[1].y = pc.y = mev->y;
+ CurrDisp->ShowLine(line, 2, color);
+ }
+ else {
+ line[1].x = pc.x = mev->x; line[1].y = pl.y;
+ line[2].x = mev->x; line[2].y = pc.y = mev->y;
+ line[3].x = pl.x; line[3].y = mev->y;
+ CurrDisp->ShowLine(line, 5, color);
+ if((ToolMode & 0x0f) == TM_ELLIPSE)
+ CurrDisp->ShowEllipse(pc, pl, color);
+ }
+ memcpy(&rcUpd, &rcDim, sizeof(RECT));
+ UpdateMinMaxRect(&rcUpd, mev->x, mev->y);
+ IncrementMinMaxRect(&rcUpd, 2);
+ return true;
+ }
+ break;
+ case MOUSE_LBUP:
+ pc.x = mev->x; pc.y = mev->y;
+ if(((ToolMode & 0x0f)==TM_ARROW || (abs(pc.x-pl.x) >5 && abs(pc.y-pl.y) >5)) &&
+ (lfp = (lfPOINT*)malloc(2 * sizeof(lfPOINT)))){
+ lfp[0].fx = CurrDisp->fix2un(pl.x - CurrDisp->VPorg.fx);
+ lfp[0].fy = CurrDisp->fiy2un(pl.y - CurrDisp->VPorg.fy);
+ lfp[1].fx = CurrDisp->fix2un(pc.x - CurrDisp->VPorg.fx);
+ lfp[1].fy = CurrDisp->fiy2un(pc.y - CurrDisp->VPorg.fy);
+ if(Plots[NumPlots]) i = NumPlots+1;
+ else i = NumPlots;
+ if(ToolMode == TM_RECTANGLE) new_go = new rectangle(this, data,
+ &lfp[0], &lfp[1]);
+ else if(ToolMode == TM_ELLIPSE) new_go = new ellipse(this, data,
+ &lfp[0], &lfp[1]);
+ else if(ToolMode == TM_ROUNDREC) new_go = new roundrec(this, data,
+ &lfp[0], &lfp[1]);
+ else if(ToolMode == TM_ARROW) new_go = new Arrow(this, data,
+ lfp[0], lfp[1], ARROW_UNITS | ARROW_LINE);
+ else new_go = 0L;
+ if(new_go) Undo.SetGO(this, &Plots[i], new_go, 0L);
+ if(Plots[i]){
+ NumPlots = i+1;
+ Plots[i]->DoPlot(CurrDisp); //init
+ CurrDisp->ShowMark(CurrGO = Plots[i], MRK_GODRAW); //edit
+ Plots[i]->moveable = 1;
+ bModified = true;
+ }
+ free(lfp);
+ }
+ else if(rcUpd.left != rcUpd.right && rcUpd.top != rcUpd.bottom) {
+ CurrDisp->UpdateRect(&rcUpd, false);
+ }
+ }
+ break;
+ case TM_TEXT:
+ if(Plots[NumPlots]) i = NumPlots+1;
+ else i = NumPlots;
+ switch(mev->Action) {
+ case MOUSE_LBUP:
+ if(!(td = (TextDEF *)calloc(1, sizeof(TextDEF))))return false;
+ x = CurrDisp->fix2un(mev->x-CurrDisp->VPorg.fx);
+ y = CurrDisp->fiy2un(mev->y-CurrDisp->VPorg.fy);
+ td->ColTxt = defs.Color(COL_TEXT); td->ColBg = defs.Color(COL_BG);
+ td->RotBL = td->RotCHAR = 0.0f; td->fSize = defs.GetSize(SIZE_TEXT);
+ td->Align = TXA_VTOP | TXA_HLEFT; td->Style = TXS_NORMAL;
+ td->Mode = TXM_TRANSPARENT; td->Font = FONT_HELVETICA;
+ td->text = 0L;
+ CurrGO = 0L;
+ CurrDisp->MrkMode = MRK_NONE;
+ Command(CMD_REDRAW, 0L, CurrDisp);
+ y -= td->fSize/2.0;
+ Undo.SetGO(this, &Plots[i], new Label(this, data, x, y, td, 0L), 0L);
+ if(Plots[i]){
+ NumPlots = i+1;
+ Plots[i]->DoPlot(CurrDisp); //init
+ CurrDisp->ShowMark(CurrGO = Plots[i], MRK_GODRAW); //edit
+ Plots[i]->moveable = 1;
+ }
+ free(td);
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
+bool
+Graph::MoveObj(int cmd, GraphObj *g)
+{
+ int i, j;
+ GraphObj *g1 = 0;
+
+ if(!g || NumPlots <2 || g->parent != this) return false;
+ switch(cmd) {
+ case CMD_MOVE_TOP:
+ for(i = j = 0; i <NumPlots; i++){
+ if(g == Plots[i]) g1 = Plots[i];
+ else Plots[j++] = Plots[i];
+ }
+ if(g1) {
+ Plots[j++] = g1;
+ return true;
+ }
+ break;
+ case CMD_MOVE_UP:
+ for(i = 0; i<NumPlots-1; i++){
+ if(g == Plots[i]){
+ g1 = Plots[i]; Plots[i] = Plots[i+1]; Plots[i+1] = g1;
+ return true;
+ }
+ }
+ break;
+ case CMD_MOVE_DOWN:
+ for(i = 1; i<NumPlots; i++){
+ if(g == Plots[i]){
+ g1 = Plots[i]; Plots[i] = Plots[i-1]; Plots[i-1] = g1;
+ return true;
+ }
+ }
+ break;
+ case CMD_MOVE_BOTTOM:
+ if(Plots[0] == g) return false;
+ for(i = j = NumPlots-1; i >= 0; i--) {
+ if(g == Plots[i]) g1 = Plots[i];
+ else Plots[j--] = Plots[i];
+ }
+ if(g1) {
+ Plots[j--] = g1;
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
+bool
+Graph::DoZoom(char *z)
+{
+ RECT cw;
+ double fac, f1, f2;
+ ZoomDEF *tz;
+ Graph *cg;
+
+ if(!z) return false;
+ if(0==strcmp("fit", z)) {
+ if(CurrGraph) cg = CurrGraph;
+ else cg = this;
+ rc_mrk.left = CurrDisp->un2ix(cg->GetSize(SIZE_GRECT_LEFT))-4;
+ rc_mrk.right = CurrDisp->un2ix(cg->GetSize(SIZE_GRECT_RIGHT))+4
+ + iround(CurrDisp->MenuHeight);
+ rc_mrk.top = CurrDisp->un2ix(cg->GetSize(SIZE_GRECT_TOP))-4
+ - iround(CurrDisp->MenuHeight);
+ rc_mrk.bottom = CurrDisp->un2ix(cg->GetSize(SIZE_GRECT_BOTTOM))+4;
+ CurrDisp->ActualSize(&cw);
+ f1 = (double)(cw.bottom - cw.top)/(double)(rc_mrk.bottom - rc_mrk.top);
+ f2 = ((double)(cw.right - cw.left)/(double)(rc_mrk.right - rc_mrk.left));
+ fac = f1 < f2 ? f1 : f2;
+ if((CurrDisp->VPscale * fac) > 100.0) fac = 100.0/CurrDisp->VPscale;
+ if((CurrDisp->VPscale * fac) < 0.05) fac = 0.05/CurrDisp->VPscale;
+ if(fac == 1.0) return false;
+ if(tz = (ZoomDEF*)memdup(zoom_def, sizeof(ZoomDEF)*(zoom_level+1), 0)){
+ if(zoom_def) free(zoom_def);
+ zoom_def = tz;
+ zoom_def[zoom_level].org.fx = CurrDisp->VPorg.fx;
+ zoom_def[zoom_level].org.fy = CurrDisp->VPorg.fy;
+ zoom_def[zoom_level].scale = CurrDisp->VPscale;
+ zoom_level++;
+ }
+ CurrDisp->VPscale *= fac;
+ if(CurrDisp->VPscale < 0.05) CurrDisp->VPscale = 0.05;
+ if(CurrDisp->VPscale > 100.0) CurrDisp->VPscale = 100.0;
+ CurrDisp->VPorg.fx = -rc_mrk.left * fac;
+ CurrDisp->VPorg.fy = -rc_mrk.top * fac;
+ HideTextCursor();
+ Command(CMD_SETSCROLL, 0L, CurrDisp);
+ return true;
+ }
+ else if(0==strcmp("+", z)) {
+ if(rc_mrk.left >= 0 && rc_mrk.right >= 0 && rc_mrk.top >= 0 && rc_mrk.bottom >= 0) {
+ if(rc_mrk.left > rc_mrk.right) Swap(rc_mrk.left, rc_mrk.right);
+ if(rc_mrk.top > rc_mrk.bottom) Swap(rc_mrk.top, rc_mrk.bottom);
+ if(5 > (rc_mrk.right - rc_mrk.left) || 5 > (rc_mrk.bottom - rc_mrk.top)) {
+ rc_mrk.left = rc_mrk.left = rc_mrk.left = rc_mrk.left = -1;
+ ToolMode = TM_STANDARD; Command(CMD_TOOLMODE, &ToolMode, CurrDisp);
+ return false;
+ }
+ CurrDisp->ActualSize(&cw);
+ fac = (double)(cw.bottom - cw.top)/(double)(rc_mrk.bottom - rc_mrk.top);
+ fac += ((double)(cw.right - cw.left)/(double)(rc_mrk.right - rc_mrk.left));
+ fac /= 2.0;
+ if((CurrDisp->VPscale * fac) > 100.0) fac = 100.0/CurrDisp->VPscale;
+ if((CurrDisp->VPscale * fac) < 0.05) fac = 0.05/CurrDisp->VPscale;
+ if(fac == 1.0) return false;
+ if(tz = (ZoomDEF*)memdup(zoom_def, sizeof(ZoomDEF)*(zoom_level+1), 0)){
+ if(zoom_def) free(zoom_def);
+ zoom_def = tz;
+ zoom_def[zoom_level].org.fx = CurrDisp->VPorg.fx;
+ zoom_def[zoom_level].org.fy = CurrDisp->VPorg.fy;
+ zoom_def[zoom_level].scale = CurrDisp->VPscale;
+ zoom_level++;
+ }
+ CurrDisp->VPscale *= fac;
+ if(CurrDisp->VPscale < 0.05) CurrDisp->VPscale = 0.05;
+ if(CurrDisp->VPscale > 100.0) CurrDisp->VPscale = 100.0;
+ CurrDisp->VPorg.fx = CurrDisp->VPorg.fx * fac - rc_mrk.left * fac;
+ CurrDisp->VPorg.fy = CurrDisp->VPorg.fy * fac - rc_mrk.top * fac;
+ HideTextCursor();
+ Command(CMD_SETSCROLL, 0L, CurrDisp);
+ CurrDisp->MouseCursor(MC_ARROW, false);
+ rc_mrk.left = rc_mrk.left = rc_mrk.left = rc_mrk.left = -1;
+ ToolMode = TM_STANDARD; Command(CMD_TOOLMODE, &ToolMode, CurrDisp);
+ return true;
+ }
+ else {
+ ToolMode = TM_ZOOMIN; CurrDisp->MouseCursor(MC_ZOOM, true);
+ }
+ }
+ else if(0==strcmp("-", z)) {
+ HideTextCursor();
+ if(zoom_def && zoom_level > 0) {
+ zoom_level--;
+ if(CurrDisp->VPscale == zoom_def[zoom_level].scale &&
+ CurrDisp->VPorg.fx == zoom_def[zoom_level].org.fx &&
+ CurrDisp->VPorg.fy == zoom_def[zoom_level].org.fy) {
+ DoZoom(z);
+ }
+ else {
+ CurrDisp->VPscale = zoom_def[zoom_level].scale;
+ CurrDisp->VPorg.fx = zoom_def[zoom_level].org.fx;
+ CurrDisp->VPorg.fy = zoom_def[zoom_level].org.fy;
+ }
+ }
+ else {
+ CurrDisp->VPorg.fx = CurrDisp->VPorg.fy = 0.0;
+ CurrDisp->VPscale = Id == GO_PAGE ? 0.5 : 1.0;
+ }
+ Command(CMD_SETSCROLL, 0L, CurrDisp);
+ return true;
+ }
+ else if(0==strcmp("25", z)){
+ CurrDisp->VPscale = 0.25; return DoZoom("org");
+ }
+ else if(0==strcmp("50", z)){
+ CurrDisp->VPscale = 0.50; return DoZoom("org");
+ }
+ else if(0==strcmp("100", z)){
+ CurrDisp->VPscale = 1.00; return DoZoom("org");
+ }
+ else if(0==strcmp("200", z)){
+ CurrDisp->VPscale = 2.00; return DoZoom("org");
+ }
+ else if(0==strcmp("400", z)){
+ CurrDisp->VPscale = 4.00; return DoZoom("org");
+ }
+ else if(0==strcmp("org", z)){
+ CurrDisp->VPorg.fx = 0.0; CurrDisp->VPorg.fy = iround(CurrDisp->MenuHeight);
+ HideTextCursor();
+ Command(CMD_SETSCROLL, 0L, CurrDisp);
+ return DoZoom("reset");
+ }
+ else if(0==strcmp("reset", z)){
+ if(zoom_def && zoom_level > 0) free(zoom_def);
+ zoom_def = 0L; zoom_level = 0;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Pages are graphic objects containing graphs and drawn objects
+Page::Page(GraphObj *par, DataObj *d):Graph(par, d, 0L)
+{
+ FileIO(INIT_VARS);
+ cGraphs--; cPages++; Id = GO_PAGE; bModified = true;
+}
+
+Page::Page(int src):Graph(src)
+{
+ int i;
+
+ //most of the object is read by Graph::FileIO()
+ ColBG = 0x00e8e8e8L;
+ LineDef.width = 0.0; LineDef.patlength = 1.0;
+ LineDef.color = LineDef.pattern = 0x0L;
+ FillDef.type = FILL_NONE;
+ FillDef.color = 0x00ffffffL; //use white paper
+ FillDef.scale = 1.0;
+ FillDef.hatch = 0L;
+ cGraphs--; cPages++; bModified = false;
+ if(Plots) for(i = 0; i < NumPlots; i++) if(Plots[i]) Plots[i]->moveable = 1;
+}
+
+void
+Page::DoPlot(anyOutput *o)
+{
+ int i;
+ POINT pts[3];
+
+ if(!o && !Disp) {
+ Disp = NewDispClass(this);
+ Disp->SetMenu(MENU_PAGE);
+ sprintf(TmpTxt, "Page %d", cPages);
+ if(!name) name = strdup(TmpTxt); Disp->Caption(TmpTxt);
+ Disp->VPorg.fy = iround(Disp->MenuHeight);
+ Disp->VPscale = 0.5;
+ Disp->CheckMenu(ToolMode, true);
+ OwnDisp = true;
+ }
+ //the first output class is the display class
+ if(!Disp && (!(Disp = o))) return;
+ CurrDisp = o ? o : Disp;
+ CurrDisp->Erase(CurrDisp->dFillCol = ColBG);
+ if(OwnDisp && CurrDisp == Disp)LineDef.color = 0x0L;
+ else LineDef.color = FillDef.color;
+ CurrDisp->SetLine(&LineDef);
+ CurrDisp->SetFill(&FillDef);
+ CurrDisp->oRectangle(rDims.left = CurrDisp->co2ix(GRect.Xmin),
+ rDims.top = CurrDisp->co2iy(GRect.Ymin), rDims.right = CurrDisp->co2ix(GRect.Xmax),
+ rDims.bottom = CurrDisp->co2iy(GRect.Ymax));
+ pts[0].x = rDims.left+7; pts[0].y = pts[1].y = rDims.bottom;
+ pts[1].x = pts[2].x = rDims.right; pts[2].y = rDims.top +3;
+ CurrDisp->oPolyline(pts, 3);
+ //do all plots
+ if(Plots) for(i = 0; i < NumPlots; i++) if(Plots[i]) Plots[i]->DoPlot(CurrDisp);
+
+}
+
+bool
+Page::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ GraphObj **tmpPlots;
+ Graph *g;
+
+ switch(cmd) {
+ case CMD_MOUSE_EVENT:
+ return Graph::Command(cmd, tmpl, o);
+ case CMD_REDRAW:
+ Disp->StartPage(); DoPlot(Disp); Disp->EndPage();
+ return true;
+ case CMD_CONFIG:
+ return Configure();
+ case CMD_DROP_GRAPH:
+ if(!(tmpPlots = (GraphObj**)memdup(Plots, (NumPlots+2)*sizeof(GraphObj*), 0)))
+ return false;
+ Undo.ListGOmoved(Plots, tmpPlots, NumPlots);
+ free(Plots); Plots = tmpPlots; Plots[NumPlots] = Plots[NumPlots+1] = 0L;
+ Undo.SetGO(this, &Plots[NumPlots], (GraphObj*)tmpl, 0L);
+ if(Plots[NumPlots]){
+ Plots[NumPlots]->parent = this;
+ Plots[NumPlots]->Command(CMD_SET_DATAOBJ, data, 0L);
+ if(Plots[NumPlots]->Id == GO_GRAPH) CurrGraph = (Graph*)Plots[NumPlots];
+ Plots[NumPlots]->moveable = 1; //all page items should be freely
+ } // moveable by user
+ NumPlots++;
+ if(CurrDisp) {
+ CurrDisp->StartPage(); DoPlot(CurrDisp); CurrDisp->EndPage();
+ }
+ return true;
+ case CMD_NEWGRAPH:
+ if((g = new Graph(this, data, Disp)) && g->PropertyDlg() &&
+ Command(CMD_DROP_GRAPH, g, o))return true;
+ else if(g) DeleteGO(g);
+ return false;
+ case CMD_SET_DATAOBJ:
+ Graph::Command(cmd, tmpl, o);
+ Id = GO_PAGE;
+ return true;
+ default:
+ return Graph::Command(cmd, tmpl, o);
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Create a tree structure of all interesting objects
+// This object is used e.g. for layer control
+ObjTree::ObjTree(GraphObj *par, DataObj *d, GraphObj *root):GraphObj(par, d)
+{
+ Id = GO_OBJTREE; base = root; list=0L;
+ TextDef.ColTxt = 0x00000000L; TextDef.ColBg = 0x00ffffffL;
+ TextDef.fSize = 4.0; TextDef.RotBL = TextDef.RotCHAR = 0.0;
+ TextDef.iSize = 0; TextDef.Align = TXA_HLEFT | TXA_VTOP;
+ TextDef.Mode = TXM_TRANSPARENT; TextDef.Style = TXS_NORMAL;
+ TextDef.Font = FONT_HELVETICA; TextDef.text = 0L;
+ Command(CMD_LAYERS, 0L, 0L);
+}
+
+ObjTree::~ObjTree()
+{
+ if(list) free(list); list = 0L;
+}
+
+void
+ObjTree::DoPlot(anyOutput *o)
+{
+ int i, n, ix, iy;
+ GraphObj *curr_obj;
+
+ if(!o || !list) return;
+ o->Erase(0x00ffffffL);
+ ix = 10; iy = 0;
+ for(i = 0; i < count; i++, iy += TextDef.iSize) {
+ if(list[i]) {
+ curr_obj = list[i]; n = 0;
+ if(i) while(curr_obj && curr_obj != list[0]) {
+ if(curr_obj != list[0]) n += sprintf(TmpTxt + n, " -");
+ if(curr_obj) curr_obj = curr_obj->parent;
+ }
+ sprintf(TmpTxt + n, "%s%s", n ? " " : "", get_name(i));
+ if(list[i]->Id >= GO_PLOT && list[i]->Id < GO_GRAPH) {
+ TextDef.ColTxt = ((Plot*)list[i])->hidden ? 0x00000080L : 0x00008000L;
+ }
+ else TextDef.ColTxt = 0x00000000L;
+ o->SetTextSpec(&TextDef);
+ o->oTextOut(ix, iy, TmpTxt, 0);
+ }
+ }
+}
+
+bool
+ObjTree::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ switch(cmd){
+ case CMD_LAYERS:
+ if(list) free(list);
+ count = 0; maxcount = 100;
+ if(base) {
+ if(list = (GraphObj**) malloc(100 * sizeof(GraphObj*))) {
+ list[count++] = base;
+ }
+ base->Command(CMD_OBJTREE, this, 0L);
+ }
+ break;
+ case CMD_SET_DATAOBJ:
+ Id = GO_OBJTREE;
+ return true;
+ case CMD_UPDATE:
+ if(tmpl && (((GraphObj*)tmpl)->Id >= GO_PLOT && ((GraphObj*)tmpl)->Id < GO_SPREADDATA)
+ || ((GraphObj*)tmpl)->Id == GO_LEGEND) {
+ if(count >= maxcount) {
+ maxcount += 100;
+ list = (GraphObj**) realloc(list, maxcount);
+ }
+ if(list) list[count++] = (GraphObj*)tmpl;
+ }
+ return true;
+ case CMD_TEXTDEF:
+ if(tmpl) memcpy(&TextDef, tmpl, sizeof(TextDEF));
+ TextDef.text = 0L;
+ return true;
+ }
+ return false;
+}
+
+anyOutput *
+ObjTree::CreateBitmap(int *bw, int *bh, anyOutput *tmpl)
+{
+ anyOutput *bmp = 0L;
+ int h;
+
+ h = tmpl->un2iy(TextDef.fSize) * count;
+ if(h > *bh) *bh = h;
+ if(bmp = NewBitmapClass(*bw, *bh, tmpl->hres, tmpl->vres)) DoPlot(bmp);
+ return bmp;
+}
+
+char *
+ObjTree::get_name(int li)
+{
+ if(li < count && list[li] && list[li]->name) return list[li]->name;
+ else return "(unknown)";
+}
+
+int
+ObjTree::get_vis(int li)
+{
+ if(li < count && list[li] && list[li]->Id >= GO_PLOT && list[li]->Id < GO_GRAPH)
+ return ((Plot*)list[li])->hidden ? 0 : 1;
+ return 2;
+}
+
+bool
+ObjTree::set_vis(int li, bool vis)
+{
+ if(li < count && list[li] && list[li]->Id >= GO_PLOT && list[li]->Id < GO_GRAPH) {
+ ((Plot*)list[li])->hidden = vis ? 0 : 1;
+ list[li]->Command(CMD_MRK_DIRTY, 0L, 0L);
+ list[li]->Command(CMD_REDRAW, 0L, 0L);
+ }
+ return false;
+}
+
+GraphObj*
+ObjTree::get_obj(int li)
+{
+ if(li < count && list[li]) return list[li];
+ return 0L;
+}
diff --git a/rlplot.h b/rlplot.h
new file mode 100755
index 0000000..ca03fa0
--- /dev/null
+++ b/rlplot.h
@@ -0,0 +1,2495 @@
+//RLPlot.h, Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005 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
+//
+#define NUM_UNITS 3
+#define TMP_TXT_SIZE 4096
+
+#include <stdio.h>
+#include "Version.h"
+
+#define Swap(a,b) {a^=b;b^=a;a^=b;}
+inline int iround(double a) {return a < 0.0 ?(int)(a-0.499) : (int)(a+0.499);}
+inline int WriteFloatToBuff(char *buff, double val) {return sprintf(buff, " %g", val);}
+
+#ifdef _WINDOWS
+#include <windows.h>
+#define w_char unsigned short
+
+#else
+#define DWORD unsigned long
+#define w_char unsigned short
+
+typedef struct tagPOINT { // pt
+ long x;
+ long y;
+} POINT;
+
+typedef struct _RECT { // rc
+ long left;
+ long top;
+ long right;
+ long bottom;
+} RECT;
+
+#endif //_WINDOWS
+
+enum {SIZE_MINE, SIZE_SYMBOL, SIZE_SYM_LINE, SIZE_DATA_LINE, SIZE_TEXT,
+ SIZE_GRECT_TOP, SIZE_GRECT_BOTTOM, SIZE_GRECT_LEFT, SIZE_GRECT_RIGHT,
+ SIZE_DRECT_LEFT, SIZE_DRECT_RIGHT, SIZE_DRECT_TOP, SIZE_DRECT_BOTTOM,
+ SIZE_DATA_LINE_PAT, SIZE_XPOS, SIZE_XPOS_LAST = SIZE_XPOS+200,
+ SIZE_YPOS, SIZE_YPOS_LAST = SIZE_YPOS+200, SIZE_ZPOS,
+ SIZE_ZPOS_LAST = SIZE_ZPOS+200, SIZE_BOUNDS_XMIN,
+ SIZE_BOUNDS_XMAX, SIZE_BOUNDS_YMIN, SIZE_BOUNDS_YMAX, SIZE_BOUNDS_ZMIN,
+ SIZE_BOUNDS_ZMAX, SIZE_BOUNDS_LEFT, SIZE_BAR_BASE,
+ SIZE_BOUNDS_RIGHT, SIZE_BOUNDS_TOP, SIZE_BOUNDS_BOTTOM, SIZE_XAXISY,
+ SIZE_YAXISX, SIZE_AXIS_LINE, SIZE_PATLENGTH, SIZE_BAR_DEPTH,
+ SIZE_AXIS_TICKS, SIZE_TICK_LABELS, SIZE_ERRBAR, SIZE_ERRBAR_LINE,
+ SIZE_BAR_LINE, SIZE_BAR, SIZE_XBASE, SIZE_YBASE, SIZE_ZBASE, SIZE_BUBBLE_LINE,
+ SIZE_BUBBLE_HATCH_LINE, SIZE_BARMINX, SIZE_BARMINY, SIZE_ARROW_LINE,
+ SIZE_ARROW_CAPWIDTH, SIZE_ARROW_CAPLENGTH, SIZE_HAIRLINE, SIZE_WHISKER,
+ SIZE_WHISKER_LINE, SIZE_BOX_LINE, SIZE_BOXMINX, SIZE_BOXMINY, SIZE_BOX,
+ SIZE_RADIUS1, SIZE_RADIUS2, SIZE_SEGLINE, SIZE_LB_XPOS, SIZE_LB_YPOS,
+ SIZE_LB_XDIST, SIZE_LB_YDIST, SIZE_TLB_XDIST, SIZE_TLB_YDIST, SIZE_ANGLE1,
+ SIZE_ANGLE2, SIZE_XCENTER, SIZE_YCENTER, SIZE_ZCENTER, SIZE_CELLWIDTH, SIZE_CELLTEXT,
+ SIZE_A, SIZE_B, SIZE_MX, SIZE_MY, SIZE_MIN_Z, SIZE_MAX_Z, SIZE_MIN_X, SIZE_MAX_X,
+ SIZE_MIN_Y, SIZE_MAX_Y, SIZE_TICK_ANGLE, SIZE_RRECT_RAD, SIZE_XCENT, SIZE_YCENT,
+ SIZE_ZCENT, SIZE_DRADIUS, SIZE_CURSORPOS, SIZE_CURSOR_XMIN, SIZE_CURSOR_YMIN,
+ SIZE_CURSOR_XMAX, SIZE_CURSOR_YMAX, SIZE_XSTEP};
+enum {COL_SYM_LINE, COL_SYM_FILL, COL_DATA_LINE, COL_TEXT, COL_BG,
+ COL_AXIS, COL_BAR_LINE, COL_BAR_FILL, COL_ERROR_LINE, COL_BUBBLE_LINE,
+ COL_BUBBLE_FILLLINE, COL_BUBBLE_FILL, COL_ARROW, COL_WHISKER, COL_BOX_LINE,
+ COL_DRECT, COL_GRECT, COL_GRECTLINE, COL_POLYLINE, COL_POLYGON};
+enum {MRK_NONE, MRK_INVERT, MRK_GODRAW, MRK_SSB_DRAW};
+enum {CMD_NONE, CMD_ADDCHAR, CMD_SETFOCUS, CMD_KILLFOCUS, CMD_DELETE,
+ CMD_BACKSP, CMD_CURRLEFT, CMD_CURRIGHT, CMD_CURRUP, CMD_CURRDOWN,
+ CMD_SHIFTLEFT, CMD_SHIFTRIGHT, CMD_SHIFTUP, CMD_SHIFTDOWN,
+ CMD_NEWGRAPH, CMD_DELGRAPH, CMD_DELOBJ, CMD_DROP_PLOT, CMD_DROP_GRAPH, CMD_OPEN,
+ CMD_SAVEDATAAS, CMD_ADDROWCOL, CMD_MOUSE_EVENT, CMD_REDRAW, CMD_DOPLOT,
+ CMD_LBUP, CMD_ENDDIALOG, CMD_RADIOBUTT, CMD_ADDCHILD, CMD_BAR_TYPE,
+ CMD_BAR_FILL, CMD_SET_AXDEF, CMD_SET_DATAOBJ, CMD_SETTEXT, CMD_GETTEXT,
+ CMD_SETTEXTDEF, CMD_GETTEXTDEF, CMD_ADDPLOT, CMD_SYM_TYPE, CMD_SYMTEXT,
+ CMD_SYMTEXTDEF, CMD_RANGETEXT, CMD_SYM_RANGETEXT, CMD_FOCTXT, CMD_CONTINUE,
+ CMD_ERR_TYPE, CMD_ARROW_ORG, CMD_ARROW_TYPE, CMD_FLUSH, CMD_BOX_FILL,
+ CMD_TABDLG, CMD_NOTABDLG, CMD_TAB, CMD_SHTAB, CMD_BOX_TYPE, CMD_BUBBLE_TYPE,
+ CMD_BUBBLE_ATTRIB, CMD_BUBBLE_FILL, CMD_BUBBLE_LINE, CMD_DL_LINE,
+ CMD_DL_TYPE, CMD_SEG_FILL, CMD_SEG_LINE, CMD_SELECT, CMD_MOVE, CMD_CUT,
+ CMD_SETSCROLL, CMD_SETHPOS, CMD_SETVPOS, CMD_PG_FILL, CMD_BOUNDS,
+ CMD_SHIFT_OUT, CMD_CAN_DELETE, CMD_RESET_LINE, CMD_SET_TICKSTYLE,
+ CMD_GET_GRIDLINE, CMD_SET_GRIDLINE, CMD_SET_GRIDTYPE, CMD_TLB_TXTDEF,
+ CMD_DROP_LABEL, CMD_DROP_OBJECT, CMD_PAGEUP, CMD_PAGEDOWN, CMD_AUTOSCALE,
+ CMD_MRK_DIRTY, CMD_SETNAME, CMD_TOOLMODE, CMD_DROPFILE, CMD_AXIS, CMD_INIT,
+ CMD_GET_CELLDIMS, CMD_SET_CELLDIMS, CMD_TEXTSIZE, CMD_PASTE_TSV, CMD_PASTE_XML,
+ CMD_PASTE_CSV, CMD_COPY_TSV, CMD_COPY_XML, CMD_COPY_SYLK, CMD_QUERY_COPY,
+ CMD_MOUSECURSOR, CMD_NEWPAGE, CMD_MINRC, CMD_MAXRC,CMD_SETCHILD, CMD_SYM_FILL,
+ CMD_LINEUP, CMD_LINEDOWN, CMD_CONFIG, CMD_FINDTEXT, CMD_MOVE_TOP, CMD_MOVE_UP,
+ CMD_MOVE_DOWN, CMD_MOVE_BOTTOM, CMD_UPDATE, CMD_CURRPOS, CMD_POS_FIRST, CMD_POS_LAST,
+ CMD_ADDAXIS, CMD_REG_AXISPLOT, CMD_USEAXIS, CMD_SET_GO3D, CMD_UNDO, CMD_DELOBJ_CONT,
+ CMD_RMU, CMD_REPL_GO, CMD_UNDO_MOVE, CMD_SAVEPOS, CMD_WHISKER_STYLE, CMD_TICK_TYPE,
+ CMD_ZOOM, CMD_CLIP, CMD_STARTLINE, CMD_ADDTOLINE, CMD_REQ_POINT, CMD_DRAW_LATER,
+ CMD_SEG_MOVEABLE, CMD_ARROW_ORG3D, CMD_MUTATE, CMD_PRINT, CMD_UPDHISTORY, CMD_ALLTEXT,
+ CMD_SET_LINE, CMD_SAVE_SYMBOLS, CMD_SAVE_TICKS, CMD_SAVE_BARS, CMD_SAVE_BARS_CONT,
+ CMD_SAVE_ERRS, CMD_SAVE_ARROWS, CMD_SAVE_DROPLINES, CMD_UNLOCK, CMD_SYMTEXT_UNDO,
+ CMD_FILLRANGE, CMD_BUSY, CMD_ERROR, CMD_CLEAR_ERROR, CMD_SETPARAM, CMD_SETFUNC,
+ CMD_HIDE_MARK, CMD_LEGEND, CMD_FILENAME, CMD_LAYERS, CMD_OBJTREE, CMD_TEXTDEF,
+ CMD_HASSTACK, CMD_WRITE_GRAPHS, CMD_SETFONT, CMD_SETSTYLE};
+enum {SYM_CIRCLE, SYM_CIRCLEF, SYM_RECT, SYM_RECTF, SYM_TRIAU, SYM_TRIAUF,
+ SYM_TRIAD, SYM_TRIADF, SYM_DIAMOND, SYM_DIAMONDF, SYM_PLUS, SYM_CROSS,
+ SYM_STAR, SYM_HLINE, SYM_VLINE, SYM_TEXT, SYM_POS_PARENT = 0x1000};
+//types of graphic objects: stored in Id and used for proper destruction of objects
+// and retrieving information.
+enum {GO_UNKNOWN, GO_AXIS, GO_TICK, GO_GRIDLINE, GO_SYMBOL, GO_BUBBLE, GO_BAR,
+ GO_ERRBAR, GO_ARROW, GO_BOX, GO_LABEL, GO_MLABEL, GO_WHISKER, GO_DROPLINE,
+ GO_DATALINE, GO_DATAPOLYGON, GO_REGLINE, GO_SDELLIPSE, GO_SEGMENT,
+ GO_POLYLINE, GO_POLYGON, GO_RECTANGLE, GO_ELLIPSE, GO_ROUNDREC,
+ GO_DRAGHANDLE, GO_DRAGRECT, GO_DRAG3D, GO_FRAMERECT, GO_SPHERE, GO_SVGOPTIONS,
+ GO_PLANE, GO_BRICK, GO_LINESEG, GO_LINE3D, GO_GRIDLINE3D, GO_GRIDRADIAL,
+ GO_SPHSCANL, GO_DROPL3D, GO_ARROW3D, GO_PLANE3D, GO_LEGITEM, GO_LEGEND,
+ GO_OBJTREE,
+ GO_PLOT = 0x100, GO_PLOTSCATT, GO_REGRESSION, GO_BARCHART, GO_BUBBLEPLOT,
+ GO_BOXPLOT, GO_DENSDISP, GO_STACKBAR, GO_STACKPG, GO_WATERFALL, GO_POLARPLOT,
+ GO_PIECHART, GO_RINGCHART, GO_GROUP, GO_STARCHART, GO_SCATT3D, GO_PLOT3D,
+ GO_RIBBON, GO_LIMITS, GO_FUNCTION, GO_FITFUNC, GO_FREQDIST, GO_GRID3D,
+ GO_GRAPH = 0x200, GO_PAGE, GO_SPREADDATA = 0x300, GO_DEFRW};
+enum {FILL_NONE, FILL_HLINES, FILL_VLINES, FILL_HVCROSS, FILL_DLINEU, FILL_DLINED,
+ FILL_DCROSS, FILL_STIPPLE1, FILL_STIPPLE2, FILL_STIPPLE3, FILL_STIPPLE4,
+ FILL_STIPPLE5, FILL_ZIGZAG, FILL_COMBS, FILL_BRICKH, FILL_BRICKV, FILL_BRICKDU,
+ FILL_BRICKDD, FILL_TEXTURE1, FILL_TEXTURE2, FILL_WAVES1, FILL_SCALES, FILL_SHINGLES,
+ FILL_WAVES2, FILL_HERRING, FILL_CIRCLES, FILL_GRASS, FILL_FOAM, FILL_RECS,
+ NUM_FILLS, FILL_LIGHT3D = 0x100};
+enum {ERRBAR_VSYM, ERRBAR_VUP, ERRBAR_VDOWN, ERRBAR_HSYM, ERRBAR_HLEFT,
+ ERRBAR_HRIGHT};
+enum {BAR_NONE, BAR_VERTB, BAR_VERTT, BAR_VERTU, BAR_HORL, BAR_HORR, BAR_HORU,
+ BAR_RELWIDTH = 0x100, BAR_CENTERED = 0x200, BAR_WIDTHDATA = 0x400};
+enum {TM_STANDARD, TM_DRAW, TM_POLYLINE, TM_POLYGON, TM_RECTANGLE, TM_ELLIPSE,
+ TM_ROUNDREC, TM_ARROW, TM_TEXT, TM_MARK, TM_ZOOMIN, TM_MOVE = 0x100};
+enum {MC_LAST, MC_ARROW, MC_CROSS, MC_TEXT, MC_WAIT, MC_MOVE, MC_NORTH,
+ MC_NE, MC_EAST, MC_SE, MC_SALL, MC_ZOOM};
+enum {FILE_ERROR, FILE_READ, FILE_WRITE, INIT_VARS, SAVE_VARS};
+enum {ARROW_NOCAP, ARROW_LINE, ARROW_TRIANGLE, ARROW_UNITS = 0x100};
+enum {MENU_NONE, MENU_SPREAD, MENU_GRAPH, MENU_PAGE};
+enum {GT_UNKNOWN, GT_STANDARD, GT_CIRCCHART, GT_POLARPLOT, GT_3D};
+enum {ICO_NONE, ICO_INFO, ICO_ERROR, ICO_RLPLOT, ICO_QT};
+enum {FF_UNKNOWN, FF_CSV, FF_TSV, FF_XML, FF_SYLK, FF_RLP, FF_SVG, FF_EPS,
+ FF_WMF, FF_RLW};
+enum {LB_X_DATA = 0x01, LB_X_PARENT = 0x02, LB_Y_DATA = 0x10, LB_Y_PARENT = 0x20};
+enum {BUBBLE_CIRCLE = 0x000, BUBBLE_SQUARE = 0x001, BUBBLE_UPTRIA = 0x002,
+ BUBBLE_DOWNTRIA = 0x003, BUBBLE_UNITS = 0x000, BUBBLE_XAXIS = 0x010,
+ BUBBLE_YAXIS = 0x020, BUBBLE_DIAMET = 0x000, BUBBLE_CIRCUM = 0x100,
+ BUBBLE_AREA = 0x200};
+enum {DH_UNKNOWN, DH_12, DH_22, DH_19, DH_29, DH_39, DH_49, DH_59, DH_69, DH_79,
+ DH_89, DH_99, DH_18, DH_28, DH_38, DH_48, DH_58, DH_68, DH_78, DH_88, DH_DATA};
+
+//drop line styles
+#define DL_LEFT 0x001
+#define DL_RIGHT 0x002
+#define DL_YAXIS 0x004
+#define DL_TOP 0x010
+#define DL_BOTTOM 0x020
+#define DL_XAXIS 0x040
+#define DL_CIRCULAR 0x100
+
+typedef struct {
+ int num;
+ char* display;
+ float convert; //multiply to get mm
+ }tag_Units;
+
+typedef struct {
+ int x, y, z;
+ }POINT3D;
+
+typedef struct {
+ double Xmin;
+ double Ymax;
+ double Xmax;
+ double Ymin;
+ }fRECT;
+
+typedef struct {
+ double fx;
+ double fy;
+ double fz;
+ }fPOINT3D;
+
+typedef struct {
+ double fx;
+ double fy;
+ }lfPOINT;
+
+typedef struct {
+ double finc, fp;
+ }RunLinePat; //used for line patterns
+
+typedef struct {
+ double width, patlength;
+ DWORD color, pattern;
+ }LineDEF;
+
+typedef struct {
+ int type; //pattern
+ DWORD color;
+ double scale;
+ LineDEF *hatch;
+ DWORD color2;
+ }FillDEF;
+
+typedef struct {
+ lfPOINT org; //zoom origin
+ double scale; //zoom factor
+ }ZoomDEF;
+
+// Axis definitions are stored in the following structure
+// not to be confused with the Axis class grapic object
+// bits stored in flags havethe following meaning
+#define AXIS_NOTICKS 0x0 // no ticks at all
+#define AXIS_POSTICKS 0x1 // positive direction of ticks
+#define AXIS_NEGTICKS 0x2 // negative direction
+#define AXIS_SYMTICKS 0x3 // ticks are symmetrical
+#define AXIS_GRIDLINE 0x4 // ticks control a gridline
+#define AXIS_MINORTICK 0x8 // its a small tick only
+#define AXIS_USER 0x00 // axis placement by user
+#define AXIS_LEFT 0x10 // left of plot
+#define AXIS_RIGHT 0x20 // right -"-
+#define AXIS_TOP 0x30 // top -"-
+#define AXIS_BOTTOM 0x40 // bottom -"-
+#define AXIS_AUTOSCALE 0x80 // rescale upon editing
+#define AXIS_INVERT 0x100 // axis top->bottom, right to left
+#define AXIS_AUTOTICK 0x200 // select tick s automatically
+#define AXIS_DEFRECT 0x400 // use axis to define drawing rectangle
+#define AXIS_LINEAR 0x0000 // transforms ...
+#define AXIS_LOG 0x1000
+#define AXIS_RECI 0x2000
+#define AXIS_SQR 0x3000
+#define AXIS_X_DATA 0x10000 // loc.x is data coordinates
+#define AXIS_Y_DATA 0x20000 // loc.y is data coordinates
+#define AXIS_Z_DATA 0x40000 // loc.z is data coordinates
+#define AXIS_ANGULAR 0x100000 // angular (circular) axis
+#define AXIS_RADIAL 0x200000 // radial axis
+#define AXIS_3D 0x400000 // three dimensional axis
+
+typedef struct {
+ void *owner; //owners are usually graph, output or axis classes
+ DWORD flags;
+ double min, max;
+ fPOINT3D loc[2]; //placement of axis coordinates
+ double Start, Step; //used for linear axis
+ lfPOINT Center; //of polar plot
+ double Radius; // -"-
+ int nBreaks; //axis break ...
+ lfPOINT *breaks;
+ }AxisDEF;
+
+//Attributes for text properties
+//Text fonts
+enum {FONT_HELVETICA, FONT_TIMES, FONT_COURIER, FONT_GREEK};
+//Text styles
+#define TXA_VTOP 0
+#define TXA_VCENTER 4
+#define TXA_VBOTTOM 8
+#define TXA_HLEFT 0
+#define TXA_HCENTER 1
+#define TXA_HRIGHT 2
+#define TXM_OPAQUE 0
+#define TXM_TRANSPARENT 1
+#define TXS_NORMAL 0
+#define TXS_ITALIC 1
+#define TXS_BOLD 2
+#define TXS_UNDERLINE 4
+#define TXS_SUPER 8
+#define TXS_SUB 16
+typedef struct {
+ DWORD ColTxt, ColBg; //colors ..
+ double fSize; //Text size in units
+ double RotBL, RotCHAR; //Rotation in degrees
+ int iSize; //Text size is given in iSize as pix
+ int Align, Mode, Style; //Text Alignement 0 1 2
+ // 4 5 6
+ // 8 9 10
+ //Mode 0 = opaque, 1 = transparent
+ int Font;
+ char *text;
+ }TextDEF;
+
+// Store mouse events in the following structure
+// Action defines the type of event:
+enum {MOUSE_LBDOWN, MOUSE_LBUP, MOUSE_LBDOUBLECLICK, MOUSE_MBDOWN, MOUSE_MBUP,
+ MOUSE_MBDOUBLECLICK, MOUSE_RBDOWN, MOUSE_RBUP, MOUSE_RBDOUBLECLICK,
+ MOUSE_MOVE};
+typedef struct {
+ unsigned short StateFlags; // 1 Mouse left button down
+ // 2 middle button down
+ // 4 right button down
+ // 8 shift pressed
+ // 16 control pressed
+ unsigned short Action;
+ int x, y;
+ } MouseEvent;
+
+//use this structure if type of data is not known
+typedef struct {
+ int type;
+ double value;
+ char *text;
+ } anyResult;
+
+//the AccRange class allows to access data objects with a 'a1:b1' style
+class AccRange{
+public:
+ AccRange(char *asc);
+ ~AccRange();
+ int CountItems();
+ bool GetFirst(int *x, int *y);
+ bool GetNext(int *x, int *y);
+ bool IsInRange(int x, int y);
+ bool BoundRec(RECT *rec);
+
+private:
+ char *txt;
+ int x1, y1, x2, y2, cx, cy, curridx;
+
+ bool Reset();
+ bool Parse(int start);
+};
+
+class anyOutput{
+public:
+ int units; //use units mm, inch ...
+ int MrkMode; //existing mark on screen
+ void *MrkRect; //pointer to e.g. the marked rectangle
+ fRECT Box1; //User drawing rectangle
+ lfPOINT Box1z; // add 3D to Box1
+ RECT DeskRect; //this is maximum size Rectangle
+ double ddx, ddy, ddz; //convert to device coordinates
+ double hres, vres; //resolution in dpi
+ double LineWidth; //line width in units
+ int iLine; //current width of line in pixels
+ DWORD dLineCol; //current color of line;
+ DWORD dBgCol; //color of background
+ DWORD dFillCol, dFillCol2;
+ DWORD dPattern; //current line bit-pattern
+ TextDEF TxtSet; //store current text settings here
+ RunLinePat RLP; //continuous setings of pattern line
+ AxisDEF xAxis, yAxis, zAxis; //axis and transform definitions
+ lfPOINT VPorg; //zoom origin
+ double VPscale; //zoom factor
+ int MenuHeight; //ofset due to pull down menus
+ int cCursor; //mouse coursor identifier
+ double rotM[3][3]; //rotation matrix for 3D
+ fPOINT3D rotC; //rotation center
+ bool hasHistMenu; //File History List
+ int HistMenuSize; // -"-
+ lfPOINT light_source; //angles for shading
+ double light_vec[3][3]; // -"-
+ double disp_x, disp_y; //displacement on page
+
+ anyOutput();
+ void SetRect(fRECT rec, int units, AxisDEF *x_ax, AxisDEF *y_ax);
+ void SetSpace(fPOINT3D*,fPOINT3D*,int,double*,fPOINT3D*,AxisDEF*,AxisDEF*,AxisDEF*);
+ void LightSource(double x, double y);
+ DWORD VecColor(double *plane_vec, DWORD col1, DWORD col2);
+ bool GetSize(RECT *rc);
+ virtual bool ActualSize(RECT *rc) {return GetSize(rc);};
+ double fx2fix(double x);
+ int fx2ix(double x){return (int)(0.5 + fx2fix(x));};
+ double fy2fiy(double y);
+ int fy2iy(double y){return (int)(0.5 + fy2fiy(y));};
+ bool fp2fip(lfPOINT *fdp, lfPOINT *fip);
+ bool fvec2ivec(fPOINT3D *v, fPOINT3D *iv);
+ bool cvec2ivec(fPOINT3D *v, fPOINT3D *iv);
+ bool uvec2ivec(fPOINT3D *v, fPOINT3D *iv);
+ double un2fix(double x);
+ int un2ix(double x) {return (int)(0.5 + un2fix(x));};
+ int co2ix(double x) {return un2ix(x) + iround(VPorg.fx);};
+ double co2fix(double x) {return un2fix(x) + VPorg.fx;};
+ double un2fiy(double y);
+ int un2iy(double y) {return (int)(0.5 + un2fiy(y));};
+ int co2iy(double y) {return un2iy(y) + iround(VPorg.fy);};
+ double co2fiy(double y) {return un2fiy(y) + VPorg.fy;};
+ double un2fiz(double z);
+ double fz2fiz(double z);
+ double fix2un(double fix);
+ double fiy2un(double fiy);
+ virtual bool SetLine(LineDEF *lDef){return false;};
+ bool GetLine(LineDEF *lDef);
+ virtual void Caption(char *txt){return;};
+ virtual void MouseCursor(int cid, bool force){return;};
+ virtual bool SetScroll(bool, int, int, int, int){return false;};
+ virtual bool SetFill(FillDEF *fill){return false;};
+ virtual bool SetTextSpec(TextDEF *set);
+ virtual bool Erase(DWORD Color){return false;};
+ virtual bool StartPage(){return false;};
+ virtual bool EndPage(){return false;};
+ virtual bool Eject() {return false;}; //printers only
+ virtual bool UpdateRect(RECT *rc, bool invert){return false;};
+ virtual bool CopyBitmap(int x, int y, anyOutput* src, int sx, int sy,
+ int sw, int sh, bool invert){return false;};
+ virtual void ShowBitmap(int x, int y, anyOutput* src){return;};
+ bool ShowMark(void *rc, int Mode);
+ bool HideMark();
+ int CalcCursorPos(char *txt, POINT p, POINT *fit);
+ bool TextCursor(char *txt, POINT p, POINT *fit, int *pos, int disp);
+ bool PatLine(POINT p1, POINT p2);
+ virtual void ShowLine(POINT * pts, int cp, DWORD color) {return;};
+ virtual void ShowEllipse(POINT p1, POINT p2, DWORD color){return;};
+ virtual bool SetMenu(int type){return false;};
+ virtual void CheckMenu(int mid, bool check){return;};
+ virtual void FileHistory(){return;};
+ virtual bool oGetPix(int x, int y, DWORD *col){return false;};
+ virtual bool oDrawIcon(int type, int x, int y) {return false;};
+ virtual bool oGetTextExtent(char *text, int cb, int *width, int *height);
+ virtual bool oCircle(int x1, int y1, int x2, int y2, char *nam = 0L){return false;};
+ virtual bool oSphere(int cx, int cy, int r, POINT *pts, int cp, char *nam = 0L);
+ virtual bool oPolyline(POINT * pts, int cp, char *nam = 0L){return false;};
+ virtual bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L){return false;};
+ virtual bool oSolidLine(POINT *p){return false;};
+ virtual bool oTextOut(int x, int y, char *txt, int cb){return false;};
+ virtual bool oPolygon(POINT *pts, int cp, char *nam = 0L){return false;};
+ virtual bool oArc(int x1, int y1, int x2, int y2, int quads){return false;};
+};
+
+enum {ET_UNKNOWN, ET_VALUE, ET_TEXT, ET_FORMULA, ET_ERROR, ET_BUSY=0x100,
+ ET_CIRCULAR=0x200};
+
+class EditText {
+public:
+ char *text;
+ int Align, type;
+ void *parent; //points to a data object: defined below
+
+ EditText(void *par, POINT where, POINT right, char *msg);
+ EditText(void *par, char *msg);
+ ~EditText();
+ bool AddChar(int c, anyOutput *Out, void *data_obj);
+ void Update(int select, anyOutput *Out, POINT *MousePos);
+ bool Redraw(anyOutput *Out, bool display);
+ void Mark(anyOutput *Out, int mark);
+ bool Command(int cmd, anyOutput *Out, void *data_obj);
+ bool GetValue(double *v);
+ bool GetText(char *t, int size);
+ bool GetResult(anyResult *r);
+ bool SetValue(double v);
+ bool SetText(char *t);
+ bool GetItem(char *text, int size);
+ void SetRec(RECT *rc);
+ int GetX() {return loc.x;};
+ int GetY() {return loc.y;};
+ int Cursor() {return CursorPos;};
+ bool isValue();
+ bool isFormula();
+ bool isInRect(POINT *p) {return (p->x>loc.x && p->x<crb.x && p->y>loc.y && p->y<rb.y);};
+
+private:
+ LineDEF *bgLine;
+ FillDEF *bgFill;
+ int length, CursorPos, m1, m2, mx1, mx2;
+ POINT loc, rb, crb;
+ DWORD TextCol;
+ double Value;
+
+ void FindType();
+};
+
+class fmtText {
+
+typedef struct _fmt_txt_info {
+ int tag;
+ char *txt;
+}fmt_txt_info;
+
+public:
+ fmtText(anyOutput *o, int x, int y, char *txt);
+ ~fmtText();
+ bool StyleAt(int idx, TextDEF *txt_def, int *style, int *font);
+ int rightTag(char *txt, int cb);
+ int leftTag(char *txt, int cb);
+ void cur_right(int *pos);
+ void cur_left(int *pos);
+ bool oGetTextExtent(anyOutput *o, int *width, int *height, int cb);
+ void SetText(anyOutput *o, char *txt, int *px, int *py);
+ void DrawText(anyOutput *o);
+
+private:
+ bool SetTextDef(TextDEF *td, int idx);
+ bool Parse();
+ void DrawBullet(anyOutput *o, int x, int y, int type, double size, DWORD lc, DWORD fc);
+ void DrawFormatted(anyOutput *o);
+
+ char *src;
+ POINT pos;
+ int n_split;
+ fmt_txt_info *split_text;
+};
+
+class DataObj{
+public:
+ int cRows, cCols;
+ EditText ***etRows;
+
+ DataObj();
+ ~DataObj();
+ virtual bool Init(int nRows, int nCols);
+ virtual bool SetValue(int row, int col, double val);
+ virtual bool SetText(int row, int col, char *txt);
+ virtual bool GetValue(int row, int col, double *v);
+ virtual bool GetText(int row, int col, char *txt, int len);
+ char ** GetTextPtr(int row, int col);
+ virtual bool GetResult(anyResult *r, int row, int col);
+ virtual bool GetSize(int *width, int *height);
+ virtual bool Select(POINT *p){return false;};
+ virtual bool WriteData(char *FileName) {return false;};
+ virtual bool AddCols(int nCols){return false;};
+ virtual bool AddRows(int nRows){return false;};
+ virtual bool ChangeSize(int nCols, int nRows, bool bUndo){return false;};
+ virtual bool Command(int cmd, void *tmpl, anyOutput *o){return false;};
+ virtual bool ReadData(char *, unsigned char *, int){return false;};
+ virtual void FlushData();
+};
+
+class StrData {
+public:
+ StrData(DataObj *par);
+ ~StrData();
+ bool GetSize(int *w, int *h);
+ void StrData::RestoreData(DataObj *dest);
+
+private:
+ int pw, ph, h, w;
+ DataObj *src;
+ char ***str_data;
+};
+
+class HatchOut:public anyOutput {
+public:
+ HatchOut(anyOutput *Parent);
+ ~HatchOut();
+ bool SetFill(FillDEF *fill);
+ bool StartPage();
+ bool oCircle(int x1, int y1, int x2, int y2, char *nam = 0L);
+ bool oSphere(int cx, int cy, int r, POINT *pts, int cp, char *nam = 0L);
+ bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
+ bool oPolygon(POINT *pts, int cp, char *nam = 0L);
+
+private:
+ anyOutput *out;
+ double xbase, ybase;
+ LineDEF ParLineDef, MyLineDef;
+ bool ParInit;
+ int ho, ht;
+ DWORD ParLinPat;
+ RECT UseRect;
+ struct {
+ int cx, cy, r;
+ }circ_grad;
+
+ bool PrepareParent(bool Restore);
+ bool DoHatch();
+ bool MkPolyLine(POINT *p, anyOutput *o);
+ bool HatchLine(POINT p1, POINT p2);
+ bool HatchArc(int x, int y, int r, int qad, bool start);
+ bool IsInside(POINT p);
+ void Lines000();
+ void Lines090();
+ void Lines045();
+ void Lines315();
+ void Stipple(int type);
+ void Zigzag();
+ void Combs();
+ void BricksH();
+ void BricksV();
+ void Bricks045();
+ void Bricks315();
+ void Texture1();
+ void Texture2();
+ void Arcs(int type);
+ void Waves2();
+ void Herringbone();
+ void Circles();
+ void Grass();
+ void Foam();
+ void Recs();
+ void CircGrad();
+};
+
+class GraphObj {
+public:
+ unsigned long Id; //accepts an identifier during read from file
+ // it is set to an object identifier after
+ // construction
+ GraphObj *parent;
+ DataObj *data;
+ int type, moveable;
+ RECT rDims;
+ char *name;
+
+ GraphObj(GraphObj *par, DataObj *d);
+ virtual ~GraphObj();
+ virtual double GetSize(int select);
+ virtual bool SetSize(int select, double value){return false;};
+ virtual DWORD GetColor(int select);
+ virtual bool SetColor(int select, DWORD col) {return false;};
+ virtual void DoPlot(anyOutput *target){return;};
+ virtual void DoMark(anyOutput *target, bool mark){return;};
+ virtual bool Command(int cmd, void *tmpl, anyOutput *o){return false;};
+ virtual bool PropertyDlg(){return false;};
+ virtual void RegGO(void *n);
+ virtual bool FileIO(int rw) {return false;};
+ virtual void * ObjThere(int x, int y);
+ virtual void Track(POINT *p, anyOutput *o);
+};
+
+class ssButton:public GraphObj {
+public:
+
+ ssButton(GraphObj *par, int x, int y, int w, int h);
+ ~ssButton();
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *target, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+
+private:
+ bool bLBdown;
+ TextDEF TextDef;
+ LineDEF Line;
+ FillDEF Fill;
+};
+
+class dragHandle:public GraphObj {
+public:
+
+ dragHandle(GraphObj *par, int type);
+ ~dragHandle();
+ void DoPlot(anyOutput *o);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void * ObjThere(int x, int y);
+ void Track(POINT *p, anyOutput *o);
+
+private:
+ RECT upd, drec, *minRC, *maxRC;
+ LineDEF LineDef;
+ FillDEF FillDef;
+};
+
+class dragRect:public GraphObj {
+public:
+
+ dragRect(GraphObj *par, int type);
+ ~dragRect();
+ double GetSize(int select){return parent->GetSize(select);};
+ DWORD GetColor(int select){return parent->GetColor(select);};
+ void DoPlot(anyOutput *o);
+ bool Command(int cmd, void*tmpl, anyOutput *o);
+ void * ObjThere(int x, int y);
+
+private:
+ dragHandle **handles;
+};
+
+class Drag3D:public GraphObj {
+public:
+ Drag3D(GraphObj *par);
+ ~Drag3D();
+ double GetSize(int select){return parent->GetSize(select);};
+ void DoPlot(anyOutput *o);
+ void * ObjThere(int x, int y);
+
+private:
+ dragHandle **handles;
+};
+
+class FrmRect:public GraphObj {
+public:
+
+ FrmRect(GraphObj *par, fRECT *limRC, fRECT *cRC, fRECT *chld);
+ ~FrmRect();
+ double GetSize(int select);
+ bool SetSize(int select, double value);
+ bool SetColor(int select, DWORD col);
+ void DoMark(anyOutput *o, bool mark);
+ void DoPlot(anyOutput *o);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg(){return parent ? parent->Command(CMD_CONFIG, 0L, 0L) : false;};
+ void * ObjThere(int x, int y);
+ void Track(POINT *p, anyOutput *o);
+
+private:
+ RECT *minRC, *maxRC;
+ anyOutput *mo;
+ RECT mrc;
+ dragRect *drag;
+ bool swapX, swapY;
+ fRECT *limRC, *cRC, *chldRC, CurrRect;
+ LineDEF Line, FillLine;
+ FillDEF Fill;
+};
+
+class svgOptions:public GraphObj{
+public:
+ svgOptions(int src);
+ ~svgOptions();
+ bool FileIO(int rw);
+
+private:
+ char *script, *svgattr;
+};
+
+class Symbol:public GraphObj{
+public:
+ int idx;
+
+ Symbol(GraphObj *par, DataObj *d, double x, double y, int which,
+ int xc = -1, int xr = -1, int yc = -1, int yr = -1);
+ Symbol(int src);
+ ~Symbol();
+ double GetSize(int select);
+ bool SetSize(int select, double value);
+ DWORD GetColor(int select);
+ bool SetColor(int select, DWORD col);
+ void DoPlot(anyOutput *target);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ bool FileIO(int rw);
+
+private:
+ lfPOINT fPos;
+ POINT *ssRef;
+ long cssRef;
+ double size;
+ LineDEF SymLine;
+ FillDEF SymFill;
+ TextDEF *SymTxt;
+};
+
+class Bubble:public GraphObj{
+public:
+ Bubble(GraphObj *par, DataObj *d, double x, double y, double s,
+ int which, FillDEF *fill, LineDEF *outline, int xc = -1,
+ int xr = -1, int yc = -1, int yr = -1, int sc = -1, int sr = -1);
+ Bubble(int src);
+ ~Bubble();
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ bool FileIO(int rw);
+
+private:
+ lfPOINT fPos;
+ double fs;
+ LineDEF BubbleLine, BubbleFillLine;
+ FillDEF BubbleFill;
+ POINT pts[5];
+ POINT *ssRef;
+ long cssRef;
+};
+
+class Bar:public GraphObj {
+public:
+ Bar(GraphObj *par, DataObj *d, double x, double y, int which,
+ int xc = -1, int xr = -1, int yc = -1, int yr = -1);
+ Bar(int src);
+ ~Bar();
+ double GetSize(int select);
+ bool SetSize(int select, double value);
+ bool SetColor(int select, DWORD col);
+ void DoPlot(anyOutput *target);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ bool FileIO(int rw);
+
+private:
+ double size;
+ LineDEF BarLine, HatchLine;
+ FillDEF BarFill;
+ lfPOINT fPos, BarBase;
+ POINT *ssRef;
+ long cssRef;
+};
+
+class DataLine:public GraphObj{
+public:
+ bool isPolygon, dirty;
+ lfPOINT *Values;
+ lfPOINT min, max;
+ LineDEF LineDef;
+ long nPnt, nPntSet, cp;
+ DWORD BgColor;
+ POINT *pts;
+ char *ssXref, *ssYref;
+ anyOutput *mo;
+ RECT mrc;
+
+ DataLine(GraphObj *par, DataObj *d, char *xrange=0L, char *yrange=0L);
+ DataLine(GraphObj *par, DataObj *d, lfPOINT *val, long nval);
+ DataLine(int src);
+ ~DataLine();
+ bool SetColor(int select, DWORD col);
+ virtual void DoPlot(anyOutput *target);
+ virtual void DoMark(anyOutput *o, bool mark);
+ virtual bool Command(int cmd, void *tmpl, anyOutput *o);
+ virtual bool PropertyDlg();
+ virtual bool FileIO(int rw);
+
+ void FileValues(char *name, int type, double start, double step);
+ void SetValues();
+ void LineData(lfPOINT *val, long nval);
+};
+
+class DataPolygon:public DataLine{
+public:
+ DataPolygon(GraphObj *par, DataObj *d, char *xrange=0L, char *yrange=0L);
+ DataPolygon(int src);
+ ~DataPolygon();
+ void DoPlot(anyOutput *target);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ bool FileIO(int rw);
+
+private:
+ FillDEF pgFill;
+ LineDEF pgFillLine;
+};
+
+class RegLine:public GraphObj{
+public:
+ RegLine(GraphObj *par, DataObj *d, lfPOINT *values, long n, int type);
+ RegLine(int src);
+ ~RegLine();
+ double GetSize(int select);
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ bool FileIO(int rw);
+
+ void Recalc(lfPOINT *values, long n);
+ LineDEF *GetLine(){return &LineDef;};
+
+private:
+ long nPoints, cp;
+ double mx, my;
+ LineDEF LineDef;
+ fRECT lim, uclip;
+ lfPOINT l1, l2, l3, l4, l5;
+ DWORD BgColor;
+ POINT *pts;
+};
+
+class SDellipse:public GraphObj{
+public:
+ SDellipse(GraphObj *par, DataObj *d, lfPOINT *values, long n, int sel);
+ SDellipse(int src);
+ ~SDellipse();
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ void RegGO(void *n);
+ bool FileIO(int rw);
+
+ void Recalc(lfPOINT *values, long n);
+
+private:
+ long nPoints, cp;
+ double sd1, sd2, mx, my;
+ POINT *pts;
+ LineDEF LineDef;
+ fRECT lim;
+ lfPOINT *val;
+ RegLine *rl;
+};
+
+class ErrorBar:public GraphObj{
+public:
+ ErrorBar(GraphObj *par, DataObj *d, double x, double y, double err, int type,
+ int xc=-1, int xr=-1, int yc=-1, int yr=-1, int ec=-1, int er=-1);
+ ErrorBar(int src);
+ ~ErrorBar();
+ bool SetSize(int select, double value);
+ bool SetColor(int select, DWORD col);
+ void DoPlot(anyOutput *target);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ bool FileIO(int rw);
+
+private:
+ lfPOINT fPos;
+ double ferr, SizeBar;
+ POINT ebpts[6];
+ LineDEF ErrLine;
+ POINT *ssRef;
+ long cssRef;
+};
+
+class Arrow:public GraphObj {
+public:
+ Arrow(GraphObj *par, DataObj *d, lfPOINT fp1, lfPOINT fp2, int which = 0,
+ int xc1=-1, int xr1=-1, int yc1=-1, int yr1=-1, int xc2=-1, int xr2=-1,
+ int yc2=-1, int yr2=-1);
+ Arrow(int src);
+ ~Arrow();
+ double GetSize(int select);
+ bool SetSize(int select, double value);
+ DWORD GetColor(int select){return LineDef.color;};
+ bool SetColor(int select, DWORD col);
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ bool FileIO(int rw);
+ void * ObjThere(int x, int y);
+ void Track(POINT *p, anyOutput *o);
+
+private:
+ dragHandle *dh1, *dh2;
+ POINT pts[5];
+ lfPOINT pos1, pos2;
+ double cw, cl;
+ LineDEF LineDef;
+ POINT *ssRef;
+ long cssRef;
+ bool bModified;
+
+ void Redraw(anyOutput *o);
+};
+
+class Box:public GraphObj {
+public:
+ Box(GraphObj *par, DataObj *d, lfPOINT fp1, lfPOINT fp2, int which,
+ int xc1=-1, int xr1=-1, int yc1=-1, int yr1=-1, int xc2=-1, int xr2=-1,
+ int yc2=-1, int yr2=-1);
+ Box(int src);
+ ~Box();
+ double GetSize(int select);
+ bool SetSize(int select, double value);
+ bool SetColor(int select, DWORD col);
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ bool FileIO(int rw);
+
+private:
+ double size;
+ lfPOINT pos1, pos2;
+ POINT pts[5];
+ LineDEF Outline, Hatchline;
+ FillDEF Fill;
+ POINT *ssRef;
+ long cssRef;
+};
+
+class Whisker:public GraphObj {
+public:
+ Whisker(GraphObj *par, DataObj *d, lfPOINT fp1, lfPOINT fp2, int which,
+ int xc1=-1, int xr1=-1, int yc1=-1, int yr1=-1, int xc2=-1, int xr2=-1,
+ int yc2=-1, int yr2=-1);
+ Whisker(int src);
+ bool SetSize(int select, double value);
+ bool SetColor(int select, DWORD col);
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ bool FileIO(int rw);
+
+private:
+ double size;
+ POINT pts[6];
+ lfPOINT pos1, pos2;
+ LineDEF LineDef;
+ POINT *ssRef;
+ long cssRef;
+};
+
+class DropLine:public GraphObj{
+public:
+ DropLine(GraphObj *par, DataObj *d, double x, double y, int which, int xc = -1,
+ int xr = -1, int yc = -1, int yr = -1);
+ DropLine(int src);
+ ~DropLine();
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ bool FileIO(int rw);
+
+private:
+ lfPOINT fPos;
+ POINT pts[4];
+ LineDEF LineDef;
+ POINT *ssRef;
+ long cssRef;
+ bool bModified;
+};
+
+class line_segment:public GraphObj{
+public:
+ line_segment(GraphObj *par, DataObj *d, LineDEF *ld, POINT3D *p1, POINT3D *p2);
+ ~line_segment();
+ double GetSize(int select);
+ void DoPlot(anyOutput *o);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void * ObjThere(int x, int y);
+
+private:
+ LineDEF Line;
+ POINT3D **ldata;
+ fPOINT3D fmin, fmax;
+ int *nldata, nli, ndf_go;
+ double prop;
+ bool bDrawDone;
+ GraphObj *co, **df_go;
+
+ void DoClip(GraphObj *co);
+};
+
+class sph_scanline:public GraphObj{
+public:
+ int rad;
+ bool vert;
+
+ sph_scanline(POINT3D *center, int radius, bool bVert);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+
+ void DoClip(GraphObj *co);
+ bool GetPoint(POINT *p, int sel);
+
+private:
+ POINT3D p1, p2, cent;
+ bool bValid1, bValid2;
+};
+
+class Sphere:public GraphObj{
+public:
+ Sphere(GraphObj *par, DataObj *d, int sel, double x, double y, double z, double r,
+ int xc = -1, int xr = -1, int yc = -1, int yr = -1, int zc = -1, int zr = -1,
+ int rc = -1, int rr = -1);
+ Sphere(int src);
+ ~Sphere();
+ double GetSize(int select);
+ bool SetSize(int select, double value);
+ DWORD GetColor(int select);
+ bool SetColor(int select, DWORD col);
+ void DoPlot(anyOutput *o);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ bool FileIO(int rw);
+
+private:
+ int ix, iy, rx, ry, nscl;
+ LineDEF Line;
+ FillDEF Fill;
+ fPOINT3D fPos, fip;
+ double size;
+ POINT *ssRef;
+ long cssRef;
+ GraphObj *co;
+ bool bModified, bDrawDone;
+ sph_scanline **scl;
+
+ void DoClip(GraphObj *co);
+ void DrawPG(anyOutput *o, int start);
+};
+
+class plane:public GraphObj{
+public:
+ plane(GraphObj *par, DataObj *d, fPOINT3D *pts, int nPts, LineDEF *line,
+ FillDEF *fill);
+ ~plane();
+ double GetSize(int select);
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void * ObjThere(int x, int y);
+
+ bool GetPolygon(POINT3D **pla, int *npt, int sel);
+ double *GetVec() {return PlaneVec;};
+
+private:
+ LineDEF Line;
+ FillDEF Fill;
+ double *PlaneVec;
+ POINT3D **ldata, ReqPoint;
+ int *nldata, nli, n_ipts, n_lines;
+ POINT *ipts;
+ lfPOINT xBounds, yBounds, zBounds;
+ bool bDrawDone, bReqPoint;
+ GraphObj *co;
+ line_segment **lines;
+ long totalArea;
+
+ void DoClip(GraphObj *co);
+ bool IsValidPG(POINT3D *pg, int npg);
+};
+
+class Plane3D:public GraphObj {
+public:
+ Plane3D(GraphObj *par, DataObj *da, fPOINT3D *pt, long npt);
+ Plane3D(int src);
+ ~Plane3D();
+ bool SetSize(int select, double value);
+ bool SetColor(int select, DWORD col);
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ bool FileIO(int rw);
+
+private:
+ plane *ipl;
+ fPOINT3D *dt, *pts;
+ long ndt;
+ LineDEF Line;
+ FillDEF Fill;
+};
+
+class Brick:public GraphObj{
+public:
+ Brick(GraphObj *par, DataObj *da, double x, double y, double z,
+ double d, double w, double h, DWORD flags, int xc = -1,
+ int xr = -1, int yc = -1, int yr = -1, int zc = -1, int zr = -1,
+ int dc = -1, int dr = -1, int wc = -1, int wr = -1, int hc = -1,
+ int hr = -1);
+ Brick(int src);
+ ~Brick();
+ bool SetSize(int select, double value);
+ bool SetColor(int select, DWORD col);
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ bool FileIO(int rw);
+
+private:
+ LineDEF Line;
+ FillDEF Fill;
+ fPOINT3D fPos;
+ double depth, width, height;
+ DWORD flags;
+ POINT *ssRef;
+ long cssRef;
+ plane **faces;
+ anyOutput *mo;
+ RECT mrc;
+ bool bModified;
+};
+
+class DropLine3D:public GraphObj{
+public:
+ DropLine3D(GraphObj *par, DataObj *d, fPOINT3D *p1, int xc = -1,
+ int xr = -1, int yc = -1, int yr = -1, int zc = -1, int zr = -1);
+ DropLine3D(int src);
+ ~DropLine3D();
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ bool FileIO(int rw);
+
+private:
+ line_segment *ls[6];
+ POINT mpts[6][2];
+ LineDEF Line;
+ fPOINT3D fPos;
+ POINT *ssRef;
+ long cssRef;
+ bool bModified;
+ anyOutput *mo;
+ RECT mrc;
+};
+
+class Arrow3D:public GraphObj{
+public:
+ Arrow3D(GraphObj *par, DataObj *d, fPOINT3D *p1, fPOINT3D *p2, int xc1 = -1,
+ int xr1 = -1, int yc1 = -1, int yr1 = -1, int zc1 = -1, int zr1 = -1,
+ int xc2 = -1, int xr2 = -1, int yc2 = -1, int yr2 = -1, int zc2 = -1,
+ int zr2 = -1);
+ Arrow3D(int src);
+ ~Arrow3D();
+ bool SetSize(int select, double value);
+ bool SetColor(int select, DWORD col);
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ bool FileIO(int rw);
+
+private:
+ line_segment *ls[3];
+ plane *cap;
+ double cw, cl;
+ POINT mpts[3][2];
+ LineDEF Line;
+ fPOINT3D fPos1, fPos2;
+ POINT *ssRef;
+ long cssRef;
+ bool bModified;
+};
+
+class Line3D:public GraphObj{
+public:
+ LineDEF Line;
+
+ Line3D(GraphObj *par, DataObj *d, char *rx, char *ry, char *rz);
+ Line3D::Line3D(GraphObj *par, DataObj *d, fPOINT3D *pt, int n_pt);
+ Line3D(int src);
+ ~Line3D();
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ bool FileIO(int rw);
+
+private:
+ line_segment **ls;
+ fPOINT3D *values, min, max;
+ POINT *pts;
+ char *x_range, *y_range, *z_range;
+ long nPts, npts;
+ bool bModified;
+ anyOutput *mo;
+ RECT mrc;
+
+ void DoUpdate();
+};
+
+class Label:public GraphObj{
+public:
+ Label(GraphObj *par, DataObj *d, double x, double y, TextDEF *td, DWORD flg,
+ int xc = -1, int xr = -1, int yc = -1, int yr = -1, int tc = -1, int tr = -1);
+ Label(int src);
+ ~Label();
+ double GetSize(int select);
+ bool SetSize(int select, double value);
+ bool SetColor(int select, DWORD col);
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ bool FileIO(int rw);
+ void * ObjThere(int x, int y);
+ void Track(POINT *p, anyOutput *o);
+
+ bool CalcRect(anyOutput *o);
+ void RedrawEdit(anyOutput *o);
+ void ShowCursor(anyOutput *o);
+ bool AddChar(int ci, anyOutput *o);
+ void CalcCursorPos(int x, int y, anyOutput *o);
+ void SetModified();
+ void DoPlotText(anyOutput *o);
+ TextDEF *GetTextDef(){return &TextDef;};
+
+private:
+ lfPOINT fPos, fDist;
+ double si, csi, curr_z;
+ DWORD flags, bgcolor;
+ TextDEF TextDef;
+ LineDEF bgLine;
+ int ix, iy, CursorPos;
+ bool is3D;
+ RECT Cursor;
+ POINT pts[5];
+ POINT *ssRef;
+ long cssRef;
+ anyOutput *defDisp;
+ bool bModified, bBGvalid;
+ fmtText *fmt_txt;
+};
+
+class mLabel:public GraphObj{
+public:
+ mLabel(GraphObj *, DataObj *, double, double, TextDEF *, char *, int, DWORD);
+ mLabel(GraphObj *, DataObj *, double, double, TextDEF *, char *);
+ mLabel(int src);
+ ~mLabel();
+ double GetSize(int select);
+ bool SetSize(int select, double value);
+ void DoPlot(anyOutput *o);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void RegGO(void *n);
+ bool FileIO(int rw);
+ void Track(POINT *p, anyOutput *o);
+
+private:
+ lfPOINT fPos, fDist, cPos, cPos1, dist;
+ double si, csi, curr_z;
+ DWORD flags, undo_flags;
+ TextDEF TextDef;
+ long nLines;
+ int cli;
+ bool is3D;
+ Label **Lines;
+};
+
+class segment:public GraphObj{
+public:
+ segment(GraphObj *par, DataObj *d, lfPOINT *c, double r1, double r2, double a1, double a2);
+ segment(int src);
+ ~segment();
+ bool SetSize(int select, double value);
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ bool FileIO(int rw);
+ void * ObjThere(int x, int y);
+ void Track(POINT *p, anyOutput *o);
+
+private:
+ lfPOINT fCent;
+ long nPts;
+ double radius1, radius2, angle1, angle2, shift;
+ LineDEF segLine, segFillLine;
+ FillDEF segFill;
+ POINT *pts;
+ bool bModified;
+};
+
+class polyline:public GraphObj {
+public:
+ lfPOINT *Values;
+ long nPoints, nPts;
+ POINT *pts;
+ LineDEF pgLine, pgFillLine;
+ FillDEF pgFill;
+ bool bModified;
+
+ polyline(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts);
+ polyline(int src);
+ ~polyline();
+ double GetSize(int select);
+ bool SetSize(int select, double value);
+ DWORD GetColor(int select);
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ virtual bool PropertyDlg();
+ bool FileIO(int rw);
+ void * ObjThere(int x, int y);
+ void Track(POINT *p, anyOutput *o);
+
+private:
+ dragHandle **pHandles;
+
+ void ShowPoints(anyOutput *o);
+};
+
+class polygon:public polyline {
+public:
+ polygon(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts);
+ polygon(int src):polyline(src){};
+ bool PropertyDlg();
+};
+
+class rectangle:public GraphObj {
+public:
+ lfPOINT fp1, fp2;
+ LineDEF Line, FillLine;
+ FillDEF Fill;
+ double rad;
+ bool bModified;
+
+ rectangle(GraphObj *par, DataObj *d, lfPOINT *p1, lfPOINT *p2);
+ rectangle(int src);
+ ~rectangle();
+ double GetSize(int select);
+ bool SetSize(int select, double value);
+ DWORD GetColor(int select){return Line.color;};
+ void DoMark(anyOutput *o, bool mark);
+ void DoPlot(anyOutput *o);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ bool FileIO(int rw);
+ void * ObjThere(int x, int y);
+ void Track(POINT *p, anyOutput *o);
+
+private:
+ POINT *pts;
+ long nPts;
+ dragRect *drc;
+ void PlotRoundRect(anyOutput *o);
+};
+
+class ellipse:public rectangle {
+public:
+ ellipse(GraphObj *par, DataObj *d, lfPOINT *p1, lfPOINT *p2);
+ ellipse(int src);
+};
+
+class roundrec:public rectangle {
+public:
+ roundrec(GraphObj *par, DataObj *d, lfPOINT *p1, lfPOINT *p2);
+ roundrec(int src);
+};
+
+class LegItem:public GraphObj{
+public:
+ LegItem(GraphObj *par, DataObj *d, LineDEF *ld, LineDEF *lf, FillDEF *fill);
+ LegItem(GraphObj *par, DataObj *d, LineDEF *ld, Symbol *sy);
+ LegItem(int src);
+ ~LegItem();
+ double GetSize(int select);
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void RegGO(void *n);
+ bool FileIO(int rw);
+ void Track(POINT *p, anyOutput *o);
+
+ bool HasFill(LineDEF *ld, FillDEF *fd);
+ bool HasSym(LineDEF *ld, GraphObj *sy);
+
+private:
+ LineDEF DataLine, OutLine, HatchLine;
+ FillDEF Fill;
+ Symbol *Sym;
+ Label *Desc;
+ DWORD flags;
+ RECT hcr;
+
+ void DefDesc(char *txt);
+};
+
+class Legend:public GraphObj{
+public:
+ Legend(GraphObj *par, DataObj *d);
+ Legend(int src);
+ ~Legend();
+ double GetSize(int select);
+ bool SetSize(int select, double value);
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void RegGO(void *n);
+ bool FileIO(int rw);
+ void Track(POINT *p, anyOutput *o);
+
+ bool HasFill(LineDEF *ld, FillDEF *fd);
+ bool HasSym(LineDEF *ld, GraphObj *sy);
+
+private:
+ lfPOINT pos, lb_pos;
+ RECT trc;
+ anyOutput *to;
+ fRECT B_Rect, C_Rect, D_Rect, E_Rect, F_Rect;
+ long nItems;
+ LegItem **Items;
+};
+
+class Plot:public GraphObj{
+public:
+ fRECT Bounds; //contains minima and maxima for x and y
+ bool dirty; //rescale before redraw;
+ int use_xaxis, use_yaxis; //this plot uses its own axes
+ lfPOINT xBounds, yBounds, zBounds; //like Bounds but in 3D space
+ int hidden; //plot (layer) is not visible
+
+ Plot(GraphObj *par, DataObj *d);
+ virtual double GetSize(int select);
+ virtual bool SetSize(int select, double value){return false;};
+ virtual DWORD GetColor(int select);
+ virtual bool SetColor(int select, DWORD col){return false;};
+ virtual void DoPlot(anyOutput *o){return;};
+ virtual bool Command(int cmd, void *tmpl, anyOutput *o){return false;};
+ virtual bool PropertyDlg(){return false;};
+
+ void CheckBounds(double x, double y);
+ bool UseAxis(int idx);
+ void ApplyAxes(anyOutput *o);
+ void CheckBounds3D(double x, double y, double z);
+ bool SavVarObs(GraphObj **gol, long ngo, DWORD flags);
+ DataObj *CreaCumData(char *xr, char *yr, int mode, double base);
+};
+
+class PlotScatt:public Plot{
+public:
+ PlotScatt(GraphObj *par, DataObj *d, DWORD presel);
+ PlotScatt(GraphObj *par, DataObj *d, int cBars, Bar **bars);
+ PlotScatt(GraphObj *par, DataObj *d, int nPts, Symbol **sym, DataLine *lin);
+ PlotScatt(int src);
+ ~PlotScatt();
+ double GetSize(int select);
+ bool SetSize(int select, double value);
+ bool SetColor(int select, DWORD col);
+ void DoPlot(anyOutput *target);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ virtual bool PropertyDlg();
+ void RegGO(void *n);
+ bool FileIO(int rw);
+
+private:
+ DWORD DefSel;
+ lfPOINT BarDist;
+ char *xRange, *yRange, *ErrRange, *LbRange;
+ int DefSym;
+ long nPoints;
+ Bar **Bars;
+ Symbol **Symbols;
+ DataLine *TheLine;
+ ErrorBar **Errors;
+ Arrow **Arrows;
+ DropLine **DropLines;
+ Label **Labels;
+
+ bool CreateBarChart();
+ enum {FE_NONE = 0x1000, FE_PARENT, FE_PLOT, FE_FLUSH, FE_DELOBJ,
+ FE_REPLGO, FE_MUTATE};
+ bool ForEach(int cmd, void *tmp, anyOutput *o);
+};
+
+class BarChart:public PlotScatt{
+public:
+ BarChart(GraphObj *par, DataObj *d);
+};
+
+class FreqDist:public Plot {
+public:
+ FreqDist(GraphObj *par, DataObj *d);
+ FreqDist(int src);
+ ~FreqDist();
+ void DoPlot(anyOutput *o);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ void RegGO(void *n);
+ bool FileIO(int rw);
+
+private:
+ double start, step;
+ long nPlots;
+ char *ssRef;
+ LineDEF BarLine, HatchLine;
+ FillDEF BarFill;
+ DataObj *curr_data;
+ GraphObj **plots;
+
+ void ProcData(int sel);
+};
+
+class Regression:public Plot{
+public:
+ Regression(GraphObj *par, DataObj *d);
+ Regression(int src);
+ ~Regression();
+ double GetSize(int select);
+ bool SetSize(int select, double value);
+ bool SetColor(int select, DWORD col);
+ void DoPlot(anyOutput *target);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ void RegGO(void *n);
+ bool FileIO(int rw);
+
+private:
+ long nPoints;
+ char *xRange, *yRange;
+ Symbol **Symbols;
+ RegLine *rLine;
+ SDellipse *sde;
+
+ void Recalc();
+};
+
+class BubblePlot:public Plot{
+public:
+ BubblePlot(GraphObj *par, DataObj *d);
+ BubblePlot(int src);
+ ~BubblePlot();
+ void DoPlot(anyOutput *target);
+ DWORD GetColor(int select);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ void RegGO(void *n);
+ bool FileIO(int rw);
+
+private:
+ long nPoints;
+ LineDEF BubbleLine, BubbleFillLine;
+ FillDEF BubbleFill;
+ Bubble **Bubbles;
+};
+
+class PolarPlot:public Plot{
+public:
+ PolarPlot(GraphObj *par, DataObj *d);
+ PolarPlot(int src);
+ ~PolarPlot();
+ double GetSize(int select);
+ void DoPlot(anyOutput *o);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ void RegGO(void *n);
+ bool FileIO(int rw);
+
+ bool AddPlot();
+ bool Config();
+
+private:
+ int nPlots, nAxes;
+ double offs;
+ anyOutput *CurrDisp;
+ fRECT CurrRect;
+ LineDEF FillLine;
+ FillDEF Fill;
+ Plot **Plots;
+ GraphObj **Axes; //Axis not yet defined
+};
+
+class BoxPlot:public Plot {
+public:
+ BoxPlot(GraphObj *par, DataObj *d);
+ BoxPlot(int src);
+ BoxPlot(GraphObj *par, DataObj *dt, int mode, int c1, int c2, int c3);
+ ~BoxPlot();
+ double GetSize(int select);
+ bool SetSize(int select, double value);
+ bool SetColor(int select, DWORD col);
+ void DoPlot(anyOutput *o);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ void RegGO(void *n);
+ bool FileIO(int rw);
+
+private:
+ long nPoints;
+ lfPOINT BoxDist;
+ Box **Boxes;
+ Whisker **Whiskers;
+ Symbol **Symbols;
+ DataLine *TheLine;
+};
+
+class DensDisp:public Plot {
+public:
+ DensDisp(GraphObj *par, DataObj *d);
+ DensDisp(int src);
+ ~DensDisp();
+ bool SetSize(int select, double value);
+ bool SetColor(int select, DWORD col);
+ void DoPlot(anyOutput *o);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ void RegGO(void *n);
+ bool FileIO(int rw);
+
+private:
+ LineDEF DefLine, DefFillLine;
+ FillDEF DefFill;
+ long nPoints;
+ char *xRange, *yRange;
+ Box **Boxes;
+
+ void DoUpdate();
+
+};
+
+class StackBar:public Plot{
+public:
+ int numPlots, numXY, numPG, numPL;
+ BoxPlot **Boxes;
+ PlotScatt **xyPlots;
+ DataPolygon **Polygons;
+ DataLine **Lines;
+ lfPOINT dspm;
+
+ StackBar(GraphObj *par, DataObj *d);
+ StackBar(int src);
+ ~StackBar();
+ bool SetSize(int select, double value);
+ void DoPlot(anyOutput *o);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ void RegGO(void *n);
+ bool FileIO(int rw);
+
+private:
+ char *ssXrange, *ssYrange;
+ double StartVal;
+ int cum_data_mode;
+ DataObj *CumData;
+};
+
+class StackPG:public StackBar{
+public:
+ StackPG(GraphObj *par, DataObj *d);
+};
+
+class GroupBars:public StackBar{
+public:
+ GroupBars(GraphObj *par, DataObj *d):StackBar(par, d){};
+ bool PropertyDlg();
+};
+
+class Waterfall:public StackBar{
+public:
+ Waterfall(GraphObj *par, DataObj *d);
+ bool PropertyDlg();
+};
+
+class MultiLines:public StackBar{
+public:
+ MultiLines(GraphObj *par, DataObj *d);
+ bool PropertyDlg();
+};
+
+class PieChart:public Plot {
+public:
+ PieChart(GraphObj *par, DataObj *d);
+ PieChart(int src);
+ ~PieChart();
+ bool SetSize(int select, double value);
+ void DoPlot(anyOutput *o);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ void RegGO(void *n);
+ bool FileIO(int rw);
+ void DoUpdate();
+
+private:
+ int nPts;
+ char *ssRefA, *ssRefR;
+ lfPOINT CtDef;
+ double FacRad;
+ segment **Segments;
+};
+
+class RingChart:public PieChart {
+public:
+ RingChart(GraphObj *par, DataObj *d);
+};
+
+class GoGroup:public Plot {
+public:
+ GraphObj **Objects;
+ int nObs;
+ lfPOINT fPos;
+
+ GoGroup(GraphObj *par, DataObj *d);
+ GoGroup(int src);
+ ~GoGroup();
+ double GetSize(int select);
+ void DoPlot(anyOutput *o);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void RegGO(void *n);
+ bool FileIO(int rw);
+};
+
+class StarChart:public GoGroup {
+public:
+ StarChart(GraphObj *par, DataObj *d);
+ bool PropertyDlg();
+
+private:
+};
+
+class Ribbon:public Plot {
+public:
+ Ribbon(GraphObj *par, DataObj *d, double z, double width, char *xr, char *yr);
+ Ribbon(GraphObj *par, DataObj *d, char *xr, char *yr, char *zr);
+ Ribbon(int src);
+ ~Ribbon();
+ double GetSize(int select);
+ bool SetSize(int select, double value);
+ bool SetColor(int select, DWORD col);
+ void DoPlot(anyOutput *o);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void RegGO(void *n);
+ bool FileIO(int rw);
+
+private:
+ long nPlanes, nVal;
+ double z_value, z_width, relwidth;
+ char *ssRefX, *ssRefY, *ssRefZ;
+ FillDEF Fill;
+ LineDEF Line;
+ fPOINT3D *values;
+ Plane3D **planes;
+
+ void CreateObs();
+ void UpdateObs(bool bNewData);
+};
+
+class Grid3D:public Plot {
+public:
+ Grid3D(GraphObj *par, DataObj *d);
+ Grid3D(int src);
+ ~Grid3D();
+ void DoPlot(anyOutput *o);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void RegGO(void *n);
+ bool FileIO(int rw);
+
+ void CreateObs();
+
+private:
+ long nLines;
+ fPOINT3D start, step;
+ LineDEF Line;
+ Line3D **lines;
+};
+
+class Scatt3D:public Plot{
+public:
+ Scatt3D(GraphObj *par, DataObj *d, DWORD flags);
+ Scatt3D(GraphObj *par, DataObj *d, Brick **cols, long nob);
+ Scatt3D(GraphObj *par, DataObj *d, Sphere **ba, long nob);
+ Scatt3D(int src);
+ ~Scatt3D();
+ double GetSize(int select);
+ bool SetSize(int select, double value);
+ bool SetColor(int select, DWORD col);
+ void DoPlot(anyOutput *o);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ void RegGO(void *n);
+ bool FileIO(int rw);
+
+private:
+ long nBalls, nColumns, nDropLines, nArrows;
+ DWORD c_flags;
+ char *ssRefX, *ssRefY, *ssRefZ;
+ Line3D *Line;
+ Sphere **Balls;
+ Brick **Columns;
+ DropLine3D **DropLines;
+ Arrow3D **Arrows;
+ Ribbon *rib;
+};
+
+class Limits:public Plot {
+public:
+ Limits(int src);
+ ~Limits();
+ double GetSize(int select);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool FileIO(int rw);
+};
+
+class Function:public Plot{
+public:
+ Function(GraphObj *par, DataObj *d);
+ Function(int src);
+ ~Function();
+ bool SetSize(int select, double value);
+ void DoPlot(anyOutput *o);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ void RegGO(void *n);
+ bool FileIO(int rw);
+
+ bool Update(anyOutput *o, DWORD flags);
+ LineDEF *GetLine() {return &Line;};
+
+private:
+ double x1,x2, xstep;
+ LineDEF Line;
+ char *param;
+ char *cmdxy;
+ DataLine *dl;
+};
+
+class FitFunc:public Plot{
+public:
+ FitFunc(GraphObj *par, DataObj *d);
+ FitFunc(int src);
+ ~FitFunc();
+ bool SetSize(int select, double value);
+ bool SetColor(int select, DWORD col);
+ void DoPlot(anyOutput *o);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ void RegGO(void *n);
+ bool FileIO(int rw);
+
+private:
+ double x1, x2, xstep, conv, chi2;
+ char *ssXref, *ssYref;
+ long nPoints;
+ int maxiter;
+ LineDEF Line;
+ Symbol **Symbols;
+ char *cmdxy, *parxy;
+ Function *dl;
+};
+
+class GridLine:public GraphObj{
+public:
+ DWORD flags;
+ long ncpts;
+ POINT pts[6], *cpts;
+ LineDEF LineDef;
+ POINT3D *gl1, *gl2, *gl3;
+ line_segment **ls;
+ bool bModified;
+ anyOutput *mo;
+ RECT mrc;
+
+ GridLine(GraphObj *par, DataObj *d, int type, DWORD df);
+ GridLine(int src);
+ ~GridLine();
+ virtual void DoPlot(anyOutput *o);
+ virtual void DoMark(anyOutput *o, bool mark);
+ virtual bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ bool FileIO(int rw);
+};
+
+class GridLine3D:public GridLine {
+public:
+ GridLine3D(GraphObj *par, DataObj *d, int type, DWORD df);
+ GridLine3D(int src);
+ ~GridLine3D();
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+};
+
+class GridRadial:public GridLine {
+public:
+ GridRadial(GraphObj *par, DataObj *d, int type, DWORD df);
+ GridRadial(int src);
+ ~GridRadial();
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+};
+
+class Tick:public GraphObj{
+public:
+ Tick(GraphObj *par, DataObj *d, double val, DWORD Flags);
+ Tick(int src);
+ ~Tick();
+ double GetSize(int select);
+ bool SetSize(int select, double value);
+ bool SetColor(int select, DWORD col);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ void RegGO(void *n);
+ bool FileIO(int rw);
+
+ void DoPlot(double six, double csx, anyOutput *o);
+
+private:
+ double value, size, fix, fiy, fiz, lsi, lcsi, angle, lbx, lby;
+ bool bModified;
+ anyOutput *mo;
+ RECT mrc;
+ int gl_type;
+ GridLine *Grid;
+ Label *label;
+ DWORD flags;
+ POINT pts[2];
+ line_segment *ls;
+};
+
+class Axis:public GraphObj{
+public:
+ AxisDEF *axis;
+ LineDEF axline;
+
+ Axis(GraphObj *par, DataObj *d, AxisDEF *ax, DWORD flags);
+ Axis(int src);
+ ~Axis();
+ double GetSize(int select);
+ bool SetSize(int select, double value);
+ DWORD GetColor(int select);
+ bool SetColor(int select, DWORD col);
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ void RegGO(void *n);
+ bool FileIO(int rw);
+
+ AxisDEF *GetAxis() {return axis;};
+ bool GetValuePos(double val, double *fix, double *fiy, double *fiz, anyOutput *o);
+ void TickFile(char *name);
+ void BreakSymbol(POINT3D *p1, double dsi, double dcsi, bool connect, anyOutput *o);
+ void DrawBreaks(anyOutput *o);
+
+private:
+ double sizAxLine, sizAxTick, sizAxTickLabel;
+ double si, csi;
+ double brksymsize, brkgap, tick_angle;
+ int brksym, nl_segs, gl_type, tick_type;
+ bool bModified;
+ DWORD colAxis;
+ LineDEF GridLine;
+ Tick **Ticks;
+ GraphObj *axisLabel;
+ long NumTicks;
+ POINT pts[2];
+ POINT3D pts3D[2];
+ fPOINT3D flim[2];
+ lfPOINT lbdist, tlbdist;
+ TextDEF tlbdef;
+ anyOutput *drawOut, *scaleOut;
+ line_segment **l_segs;
+ char *ssMATval, *ssMATlbl, *ssMITval;
+ anyOutput *mo;
+ RECT mrc;
+
+ void SetTick(long idx, double val, DWORD flags, char *txt);
+ void CreateTicks();
+ void ManuTicks(double sa, double st, int n, DWORD flags);
+ void UpdateTicks();
+ bool ssTicks();
+
+};
+
+class Plot3D:public Plot{
+ typedef struct {
+ double Zmin, Zmax;
+ GraphObj *go;
+ }obj_desc;
+public:
+ long nPlots, nAxes;
+ Axis **Axes;
+ GraphObj **plots;
+ double *RotDef;
+
+ Plot3D(GraphObj *par, DataObj *d, DWORD flags);
+ Plot3D(int src);
+ ~Plot3D();
+ double GetSize(int select);
+ bool SetColor(int select, DWORD col);
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ void RegGO(void *n);
+ bool FileIO(int rw);
+
+ void * ObjThere(int x, int y);
+ void Track(POINT *p, anyOutput *o);
+ void CreateAxes();
+ void DoAutoscale();
+ void CalcRotation(double dx, double dy, anyOutput *o, bool accept);
+ bool AcceptObj(GraphObj *go);
+ void SortObj();
+ bool Rotate(double dx, double dy, double dz, anyOutput *o, bool accept);
+
+private:
+ long nObs, nmaxObs;
+ DWORD crea_flags;
+ Drag3D *drag;
+ fPOINT3D cub1, cub2, rotC, cu1, cu2, rc;
+ obj_desc **dispObs;
+
+ bool AddPlot(int family);
+};
+
+class Chart25D:public Plot3D {
+public:
+ Chart25D(GraphObj *par, DataObj *d, DWORD flags);
+ ~Chart25D();
+ bool PropertyDlg();
+
+private:
+ fPOINT3D dspm;
+};
+
+class Ribbon25D:public Plot3D {
+public:
+ Ribbon25D(GraphObj *par, DataObj *d, DWORD flags);
+ ~Ribbon25D();
+ bool PropertyDlg();
+
+private:
+ fPOINT3D dspm;
+};
+
+class BubblePlot3D:public Plot3D {
+public:
+ BubblePlot3D(GraphObj *par, DataObj *d);
+ ~BubblePlot3D();
+ bool PropertyDlg();
+};
+
+class Graph:public GraphObj{
+public:
+ long NumPlots;
+ int ToolMode, units, nscp;
+ anyOutput *Disp, *CurrDisp;
+ fRECT GRect, DRect, Bounds;
+ bool OwnDisp, bModified;
+ fRECT CurrRect;
+ GraphObj **Plots;
+ DWORD ColBG, ColAX;
+ GraphObj **Sc_Plots;
+ Axis **Axes;
+ char *filename;
+
+ Graph(GraphObj *par, DataObj *d, anyOutput *o);
+ Graph(int src);
+ ~Graph();
+ double GetSize(int select);
+ bool SetSize(int select, double value);
+ DWORD GetColor(int select);
+ virtual void DoPlot(anyOutput *o);
+ virtual bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ void RegGO(void *n);
+ virtual bool FileIO(int rw);
+
+private:
+ int NumAxes, AxisTempl, tickstyle, zoom_level;
+ RECT rcDim, rcUpd, rc_mrk;
+ DWORD ColDR, ColGR, ColGRL;
+ AxisDEF x_axis, y_axis;
+ FrmRect *frm_g, *frm_d;
+ bool dirty;
+ POINT *tl_pts;
+ long tl_nPts;
+ ZoomDEF *zoom_def;
+
+ bool AddPlot(int family);
+ void DoAutoscale();
+ void CreateAxes(int templ);
+ bool ExecTool(MouseEvent *mev);
+ bool Configure();
+ bool AddAxis();
+ bool MoveObj(int cmd, GraphObj *g);
+ bool DoZoom(char *z);
+};
+
+class Page:public Graph{
+public:
+ Page(GraphObj *par, DataObj *d);
+ Page(int src);
+ void DoPlot(anyOutput *o);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ void RegGO(void *n);
+ bool FileIO(int rw);
+
+private:
+ LineDEF LineDef;
+ FillDEF FillDef;
+
+ bool Configure();
+};
+
+class ObjTree:public GraphObj {
+public:
+ ObjTree(GraphObj *par, DataObj *d, GraphObj *root);
+ ~ObjTree();
+ void DoPlot(anyOutput *o);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+
+ anyOutput *CreateBitmap(int *w, int *h, anyOutput *tmpl);
+ int count_lines(){ return count;};
+ char *get_name(int line);
+ int get_vis(int line);
+ bool set_vis(int line, bool vis);
+ GraphObj *get_obj(int line);
+
+private:
+ GraphObj **list, *base;
+ int count, maxcount;
+ TextDEF TextDef;
+};
+
+class notary{
+public:
+ notary();
+ ~notary();
+ unsigned long RegisterGO(GraphObj *go);
+ void AddRegGO(GraphObj *go);
+ bool PushGO(unsigned long id, GraphObj *go);
+ GraphObj *PopGO(unsigned long id);
+ void FreeStack();
+
+private:
+ unsigned long NextPopGO, NextPushGO, NextRegGO;
+ GraphObj ***gObs;
+ GraphObj ***goStack;
+};
+
+class Default{
+public:
+ int dUnits, cUnits;
+ char DecPoint[2], ColSep[2];
+ char *svgAttr, *svgScript, *currPath, *IniFile;
+ char *File1, *File2, *File3, *File4, *File5, *File6;
+ double min4log;
+ RECT clipRC;
+
+ Default();
+ ~Default();
+ void SetDisp(anyOutput *o);
+ double GetSize(int select);
+ DWORD Color(int select);
+ LineDEF *GetLine();
+ void SetLine(int u, LineDEF *l, int which);
+ FillDEF *GetFill();
+ void SetFill(int u, FillDEF *fd);
+ LineDEF *GetOutLine();
+ bool PropertyDlg();
+ LineDEF *plLineDEF(LineDEF *ld);
+ LineDEF *pgLineDEF(LineDEF *ol);
+ FillDEF *pgFillDEF(FillDEF *fd);
+ double rrectRad(double rad);
+ void FileHistory(char *path);
+
+private:
+ LineDEF Line_0, Line_1, Line_2, *pl, *pgl;
+ FillDEF Fill_0, Fill_1, Fill_2, *pg;
+ LineDEF FillLine_0, FillLine_1, FillLine_2, *pg_fl;
+ LineDEF OutLine_0, OutLine_1, OutLine_2;
+ double *rrect_rad;
+ anyOutput *cdisp;
+ DWORD axis_color;
+};
+
+class DefsRW:public GraphObj{
+public:
+ DefsRW():GraphObj(0, 0){Id = 0; return;};
+ DefsRW(int rw):GraphObj(0,0){FileIO(rw);Id=GO_DEFRW;return;};
+ ~DefsRW() {return;};
+ bool FileIO(int rw);
+};
+
+class ReadCache{
+public:
+ unsigned char last, *Cache, Line[4096];
+ int iFile, idx, max;
+ bool eof;
+
+ ReadCache();
+ ~ReadCache();
+ virtual bool Open(char *name);
+ virtual void Close();
+ virtual unsigned char Getc();
+ virtual unsigned char *GetField();
+ void ReadLine(char *dest, int size);
+ bool GetInt(long *in);
+ bool GetFloat(double *fn);
+ unsigned char Lastc();
+ bool IsEOF();
+};
+
+class MemCache:public ReadCache{
+public:
+ MemCache(unsigned char *ptr);
+ ~MemCache();
+ bool Open(char *name){return false;};
+ void Close(){return;};
+ unsigned char Getc();
+ unsigned char *GetField();
+};
+
+#define UNDO_CONTINUE 0x01
+#define UNDO_STORESET 0x1000
+class UndoObj {
+ enum {UNDO_UNDEFINED, UNDO_DEL_GO, UNDO_GOLIST, UNDO_DROPMEM,
+ UNDO_VALDWORD, UNDO_VALINT, UNDO_OBJCONF, UNDO_OBJCONF_1,
+ UNDO_LFP, UNDO_MOVE, UNDO_RECT, UNDO_STRING, UNDO_ROTDEF,
+ UNDO_SETGO, UNDO_LINEDEF, UNDO_FILLDEF, UNDO_AXISDEF,
+ UNDO_LFP3D, UNDO_FLOAT, UNDO_MEM, UNDO_MUTATE, UNDO_DROPGOLIST,
+ UNDO_TEXTDEF, UNDO_SAVVAR, UNDO_DATA, UNDO_ET};
+ typedef struct _UndoInfo {
+ int cmd;
+ DWORD flags;
+ GraphObj *owner;
+ void *data;
+ void **loc;
+ ZoomDEF zd;
+ }UndoInfo;
+
+ typedef struct _UndoList {
+ void *array;
+ void **loc_arr;
+ long count, size;
+ long *loc_count;
+ }UndoList;
+
+ typedef struct _UndoBuff {
+ int count;
+ UndoInfo **buff;
+ anyOutput *disp;
+ }UndoBuff;
+
+ typedef struct _EtBuff {
+ char *txt;
+ DataObj *DaO;
+ int *cur, *m1, *m2, vcur, vm1, vm2, row, col;
+ }EtBuff;
+
+public:
+ int *pcb;
+
+ UndoObj();
+ ~UndoObj();
+ void Flush();
+ void SetDisp(anyOutput *o);
+ void KillDisp(anyOutput *o);
+ void InvalidGO(GraphObj *go);
+ void Pop();
+ void Restore(bool redraw, anyOutput *o);
+ void ListGOmoved(GraphObj **oldlist, GraphObj **newlist, long size);
+ void DeleteGO(GraphObj **go, DWORD flags, anyOutput *o);
+ void MutateGO(GraphObj **old, GraphObj *repl, DWORD flags, anyOutput *o);
+ void StoreListGO(GraphObj *parent, GraphObj ***go, long *count, DWORD flags);
+ void DropListGO(GraphObj *parent, GraphObj ***go, long *count, DWORD flags);
+ void DropMemory(GraphObj *parent, void **mem, DWORD flags);
+ void SavVarBlock(GraphObj *parent, void **mem, DWORD flags);
+ void ValDword(GraphObj *parent, DWORD *val, DWORD flags);
+ void ValInt(GraphObj *parent, int *val, DWORD flags);
+ void ObjConf(GraphObj *go, DWORD flags);
+ int SaveLFP(GraphObj *go, lfPOINT *lfp, DWORD flags);
+ void MoveObj(GraphObj *go, lfPOINT *lfp, DWORD flags);
+ void ValRect(GraphObj *go, fRECT *rec, DWORD flags);
+ void String(GraphObj *go, char **s, DWORD flags);
+ void RotDef(GraphObj *go, double **d, DWORD flags);
+ void SetGO(GraphObj *parent, GraphObj **where, GraphObj *go, DWORD flags);
+ void Line(GraphObj *go, LineDEF *ld, DWORD flags);
+ void Fill(GraphObj *go, FillDEF *fd, DWORD flags);
+ void AxisDef(GraphObj *go, AxisDEF *ad, DWORD flags);
+ void TextDef(GraphObj *go, TextDEF *td, DWORD flags);
+ void ValLFP3D(GraphObj *go, fPOINT3D *lfp, DWORD flags);
+ void ValFloat(GraphObj *parent, double *val, DWORD flags);
+ void DataMem(GraphObj *go, void **mem, int size, long *count, DWORD flags);
+ void DataObject(GraphObj *go, anyOutput *o, DataObj *d, DWORD flags);
+ void TextCell(EditText *et, anyOutput *o, char *text, int *cur, int *m1, int *m2, void* DaO, DWORD flags);
+
+private:
+ UndoInfo **buff, **buff0;
+ int stub1, ndisp;
+ anyOutput *cdisp, *ldisp;
+ UndoBuff **buffers;
+
+ int NewItem(int cmd, DWORD flags, GraphObj *owner, void *data, void **loc);
+ void FreeInfo(UndoInfo** inf);
+ void RestoreConf(UndoInfo *inf);
+ void RestoreData(UndoInfo *inf);
+};
+
+//prototypes: spreadwi.cpp
+int ProcMemData(GraphObj *g, unsigned char *ptr, bool dispatch);
+void SpreadMain(bool show);
+
+//prototypes: WinSpec.cpp or QT_Spec.cpp
+char *SaveDataAsName(char *oldname);
+char *SaveGraphAsName(char *oldname);
+char *OpenGraphName(char *oldname);
+char *OpenDataName(char *oldname);
+void InfoBox(char *Msg);
+void ErrorBox(char *Msg);
+bool YesNoBox(char *Msg);
+void Qt_Box();
+void HideTextCursor();
+void HideTextCursorObj(anyOutput *out);
+void ShowTextCursor(anyOutput *out, RECT *disp, DWORD color);
+void HideCopyMark();
+void ShowCopyMark(anyOutput *out, RECT *mrk, int nRec);
+void InitTextCursor(bool init);
+void EmptyClip();
+void GetDesktopSize(int *width, int *height);
+void FindBrowser();
+void LoopDlgWnd();
+void CloseDlgWnd(void *hDlg);
+void ShowDlgWnd(void *hDlg);
+anyOutput *NewDispClass(GraphObj *g);
+bool DelDispClass(anyOutput *w);
+anyOutput *NewBitmapClass(int w, int h, double hr, double vr);
+bool DelBitmapClass(anyOutput *w);
+
+//prototypes: FileIO.cpp
+bool SaveGraphAs(GraphObj *g);
+char *GraphToMem(GraphObj *g, long *size);
+void UpdGOfromMem(GraphObj *go, unsigned char *buff);
+bool OpenGraph(GraphObj *root, char *name, unsigned char *mem);
+void SavVarInit(long len);
+void *SavVarFetch();
+
+//prototypes:TheDialog.cpp
+DWORD GetNewColor(DWORD oldcol);
+bool ShowLayers(GraphObj *root);
+void GetNewFill(FillDEF *oldfill);
+void ShowBanner(bool show);
+void RLPlotInfo();
+bool DoSpShSize(DataObj *dt);
+bool FillSsRange(DataObj *d, char **range);
+bool GetCopyRange(RECT *rc, DataObj *d);
+bool GetBitmapRes(double *res, double *width, double *height, char *header);
+void OD_scheme(int, void *, RECT *, anyOutput *, void *, int);
+FillDEF *GetSchemeFill(int *i);
+void OD_linedef(int, void *, RECT *, anyOutput *o, void *, int);
+void OD_filldef(int, void *, RECT *, anyOutput *o, void *, int);
+void OD_paperdef(int, void *, RECT *, anyOutput *o, void *, int);
+void FindPaper(double w, double h, double tol);
+bool GetPaper(double *w, double *h);
+void OD_axisplot(int, void *, RECT *, anyOutput *o, void *, int);
+
+//prototypes: Utils.cpp
+anyOutput *GetRectBitmap(RECT *rc, anyOutput *src);
+void RestoreRectBitmap(anyOutput **pmo, RECT *mrc, anyOutput *o);
+void NiceAxis(AxisDEF *axis, int nTick);
+void NiceStep(AxisDEF *axis, int nTick);
+double base4log(AxisDEF *axis, int direc);
+double TransformValue(AxisDEF *axis, double val, bool transform);
+void SortAxisBreaks(AxisDEF *axis);
+double GetAxisFac(AxisDEF *axis, double delta, int direc);
+void ReshapeFormula(char **text);
+void CleanTags(char *txt, int *i1, int *i2, int *i3);
+void ChangeChar(char *text, char c1, char c2);
+char *Int2Nat(char *Text);
+char *Nat2Int(char *Text);
+void WriteNatFloatToBuff(char *buff, double val);
+bool Txt2Flt(char *txt, double *val);
+void RmTrail(char *txt);
+double NiceValue(double fv);
+char *Int2ColLabel(int nr, bool uc);
+char *str2xml(char *str);
+char **split(char *str, char sep, int *nl);
+void SetMinMaxRect(RECT *rc, int x1, int y1, int x2, int y2);
+void UpdateMinMaxRect(RECT *rc, int x, int y);
+void IncrementMinMaxRect(RECT *rc, int i);
+bool IsInRect(RECT *rc, int x, int y);
+bool IsCloseToLine(POINT *p1, POINT *p2, int x, int y);
+bool IsCloseToPL(POINT p, POINT *pts, int cp);
+bool IsInPolygon(POINT *p, POINT *pts, int cp);
+bool OverlapRect(RECT *rc1, RECT *rc2);
+void AddToPolygon(long *cp, POINT *pts, POINT *np);
+POINT *MakeArc(int ix, int iy, int r, int qad, long *npts);
+void InvertPolygon(POINT*, int, LineDEF*, FillDEF*, RECT*, anyOutput*, bool);
+void InvertLine(POINT*, int, LineDEF*, RECT*, anyOutput*, bool);
+unsigned int ColDiff(DWORD col1, DWORD col2);
+DWORD IpolCol(DWORD color1, DWORD color2, double fact);
+double ran2(long *idum);
+unsigned long isqr(unsigned long n);
+bool MatMul(double a[3][3], double b[3][3], double c[3][3]);
+char *GetNumFormat(double Magn);
+void DeleteGO(GraphObj *go);
+bool BackupFile(char *FileName);
+bool IsRlpFile(char *FileName);
+bool IsXmlFile(char *FileName);
+bool FileExist(char *FileName);
+void *memdup(void *ptr, int cb_old, int cb_new);
+double sininv(double val);
+double trig2deg(double si, double csi);
+bool ReplaceGO(GraphObj **oldobj, GraphObj **newobj);
+unsigned int HashValue(unsigned char *str);
+bool cmpLineDEF(LineDEF *l1, LineDEF *l2);
+bool cmpFillDEF(FillDEF *f1, FillDEF *f2);
+bool cmpAxisDEF(AxisDEF *a1, AxisDEF *a2);
+bool cmpTextDEF(TextDEF *t1, TextDEF *t2);
+DWORD CheckNewFloat(double *loc, double old_v, double new_v, GraphObj *par, DWORD flags);
+DWORD CheckNewInt(int *loc, int old_v, int new_v, GraphObj *par, DWORD flags);
+DWORD CheckNewDword(DWORD *loc, DWORD old_v, DWORD new_v, GraphObj *par, DWORD flags);
+DWORD CheckNewLFPoint(lfPOINT *loc, lfPOINT *old_v, lfPOINT *new_v, GraphObj *par, DWORD flags);
+void clip_line_sphere(GraphObj *par, POINT3D **li, int r, int cx, int cy, int cz);
+void clip_line_plane(GraphObj *par, POINT3D **li, POINT3D *pg, int np, double *vec);
+void clip_sphline_sphere(GraphObj *par, POINT3D *lim1, POINT3D *lim2, POINT3D *cent,
+ int r1, int r2, int cx, int cy, int cz);
+void clip_sphline_plane(GraphObj *par, POINT3D *lim1, POINT3D *lim2, POINT3D *cent,
+ int r1, POINT3D *pg, int np, double *vec);
+void clip_plane_plane(GraphObj *par, POINT3D *pg1, int n1, double *v1, POINT3D *pg2,
+ int n2, double *v2, POINT *m, int nm);
+
+//prototypes Export.cpp
+void DoExportWmf(GraphObj *g, char *FileName, float res, DWORD flags);
+void DoExportSvg(GraphObj *g, char *FileName, DWORD flags);
+void DoExportEps(GraphObj *g, char *FileName, DWORD flags);
+
+//prototypes Output.cpp
+void DoExportTif(GraphObj *g, char *FileName, DWORD flags);
+
+//prototypes mfcalc.cpp
+bool do_xyfunc(DataObj *, double, double, double, char *, lfPOINT **, long *, char *);
+anyResult *do_formula(DataObj *, char *);
+bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy);
+int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
+ double conv, int maxiter, double *chi_2);
+
+//prototypes rlp_math.cp
+double **dmatrix(int nrl, int nrh, int ncl, int nch);
+void free_dmatrix(double **m, int nrl, int nrh, int ncl, int);
+bool mrqmin(double *, double *, double *, int, double **, int, int *, int, double **, double **, double *,
+ void (*funcs)(double, double, double **, double *, double *, int), double *);
+bool Check_MRQerror();
+double gammln(double xx);
+double factrl(int n);
+double t_dist(double t, double df);
+double f_dist(double f, double df1, double df2);
+void d_quartile(int n, double *v, double *q1, double *q2, double *q3);
+double d_amean(int n, double *v);
+double d_gmean(int n, double *v);
+double d_hmean(int n, double *v);
diff --git a/rlplot.spec b/rlplot.spec
new file mode 100755
index 0000000..aaaff29
--- /dev/null
+++ b/rlplot.spec
@@ -0,0 +1,62 @@
+Name: rlplot
+Version: 0.99.12b
+Release: 1
+Summary: A plotting program to create high quality graphs from data.
+License: GPL
+URL: http://rlplot.sourceforge.net
+Group: Applications/Engineering
+Prefix: %{_prefix}
+BuildRoot: %{_tmppath}/%{name}-buildroot
+Source: %{name}_%{version}.tar.gz
+
+%description
+RLPlot is is a plotting program to create high quality graphs from data.
+Based on values stored in a spreadsheet several menus help you to create
+graphs of your choice. The Graphs are displayed as you get them (WYSIWIG).
+Double click any element of the graph (or a single click with the right
+mouse button) to modify its properties. RLPlot is a cross platform
+development for Linux and Windows. Exported file formats include
+Scalable Vector Graphics (SVG), Windows Metafile (WMF), Encapsulated
+Postscript (EPS).
+
+%prep
+%setup -q -n %{name}
+
+%build
+make -e
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir -p ${RPM_BUILD_ROOT}%{_bindir}
+install -m 755 %{name} $RPM_BUILD_ROOT%{_prefix}/bin
+install -m 755 exprlp $RPM_BUILD_ROOT%{_prefix}/bin
+
+%clean
+rm -rf "$RPM_BUILD_ROOT"
+
+%files
+%defattr(-,root,root)
+%doc README RLPlot.bmp RLPLOT.ICO RLPlot.xpm gpl.txt
+%{_bindir}/rlplot
+%{_bindir}/exprlp
+
+%changelog
+* Tue Dec 21 2004 Reinhard Lackner
+- release canditate 2, version 0.99.12b
+
+* Sat May 31 2003 Reinhard Lackner
+- modified for RLPlot 0.97b
+
+* Sun Dec 29 2002 Reinhard Lackner
+- modified for RLPlot 0.96b
+
+* Mon Nov 25 2002 Guido Gonzato
+- initial
+
+
+
+
+
+
+
+
diff --git a/spreadwi.cpp b/spreadwi.cpp
new file mode 100755
index 0000000..40e32b8
--- /dev/null
+++ b/spreadwi.cpp
@@ -0,0 +1,1833 @@
+//spreadwin.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 <time.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
+
+extern const LineDEF BlackLine;
+extern EditText *CurrText;
+extern char *LoadFile;
+extern char TmpTxt[];
+extern Default defs;
+extern UndoObj Undo;
+static ReadCache *Cache = 0L;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get item from *.csv file
+bool GetItemCSV(char *Text, int cbText)
+{
+ char c;
+ int i;
+
+ for (i = 0, *Text = 0; i < cbText; ) {
+ c = Cache->Getc();
+ switch(c) {
+ case ',': //column separator
+ Text[i] = 0;
+ return true;
+ case 0x0a: //end of line: mark by false return but text o.k.
+ Text[i] = 0;
+ return false;
+ default:
+ if(c > 0x20) Text[i++] = c; //printable character
+ else if(i >0 && c == 0x20) Text[i++] = c;
+ else if(!c && Cache->IsEOF()) {
+ Text[i] = 0;
+ return false;
+ }
+ else Text[i] = 0; //ignore non printing characters
+ }
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// process a memory block (i.e. clipboard data) as if file input
+int ProcMemData(GraphObj *g, unsigned char *ptr, bool dispatch)
+{
+ int i, RetVal = FF_UNKNOWN, nt, nl, nc, cc;
+
+ if(ptr) {
+ for(i = nt = nl = nc = 0; ptr[i]; i++) {
+ switch(ptr[i]) {
+ case 0x09: //tab
+ nt++;
+ break;
+ case 0x0a: //LF
+ nl++;
+ break;
+ case ',':
+ nc++;
+ break;
+ }
+ }
+ if(dispatch && i && !nt && !nl)
+ for(i = 0; ptr[i]; i++){
+ cc = ptr[i];
+ g->Command(CMD_ADDCHAR, (void*)(& cc), 0L);
+ }
+ else if(nt) RetVal = FF_TSV;
+ else if(nl && ptr[0] == '<') RetVal = FF_XML;
+ else if(nc == nl && defs.DecPoint[0] == ',') RetVal = FF_TSV;
+ else if(nl && nc && 0 == (nc % nl)) RetVal = FF_CSV;
+ else if(nl) RetVal = FF_TSV;
+ if(dispatch) switch(RetVal) {
+ case FF_CSV: g->Command(CMD_PASTE_CSV, ptr, 0L); break;
+ case FF_TSV: g->Command(CMD_PASTE_TSV, ptr, 0L); break;
+ case FF_XML: g->Command(CMD_PASTE_XML, ptr, 0L); break;
+ }
+ }
+ return RetVal;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// This graphic object displays a spreadsheet
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class SpreadWin:public GraphObj{
+public:
+ anyOutput *w;
+ POINT ssOrg;
+ RECT currRC;
+
+ SpreadWin(DataObj *Data);
+ ~SpreadWin();
+ void DoPlot(anyOutput *target);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+
+ bool ShowGrid(int CellWidth, int CellHeight, int FirstWidth);
+ bool PrintData(anyOutput *o);
+ void WriteGraphXML(unsigned char **ptr, long *cbd);
+
+private:
+ int ch, cw, fw; //cell height and width, row button width
+ bool is_modified;
+ char *filename;
+ TextDEF ssText;
+ ssButton **cButtons, **rButtons;
+ ssButton *aButton;
+ DataObj *d;
+ int NumGraphs;
+ Graph **g;
+};
+
+SpreadWin::SpreadWin(DataObj *Data):GraphObj(0L, Data)
+{
+ d = Data; g = 0L; ssOrg.x = ssOrg.y = 0; NumGraphs = 0;
+ ch = 19; cw = 76; fw = 32; filename=0L; aButton = 0L;
+ if(w = NewDispClass(this)){
+ w->hasHistMenu = true;
+ ssText.RotBL = ssText.RotCHAR = 0.0;
+ ssText.fSize = 0.0f;
+#ifdef _WINDOWS
+ ssText.iSize = w->un2iy(defs.GetSize(SIZE_CELLTEXT));
+#else
+ ssText.iSize = w->un2iy(defs.GetSize(SIZE_CELLTEXT)*.8f);
+#endif
+ ssText.Align = TXA_VTOP | TXA_HLEFT; ssText.Mode = TXM_TRANSPARENT;
+ ssText.Style = TXS_NORMAL; ssText.ColBg = 0x00d8d8d8L;
+ ssText.ColTxt = 0x00000000L; ssText.text = 0L;
+ ssText.Font = FONT_HELVETICA; w->SetTextSpec(&ssText);
+ w->SetMenu(MENU_SPREAD); w->FileHistory();
+ w->Erase(0x00d8d8d8L); w->Caption("RLPlot data");
+ cw = w->un2ix(defs.GetSize(SIZE_CELLWIDTH));
+ ch = w->un2iy(defs.GetSize(SIZE_CELLTEXT)) + 2;
+ fw = 32;
+ }
+ cButtons = rButtons = 0L;
+ Id = GO_SPREADDATA;
+ is_modified = false;
+}
+
+SpreadWin::~SpreadWin()
+{
+ int i;
+
+ if(cButtons) {
+ for(i = 0; cButtons[i]; i++) if(cButtons[i]) delete(cButtons[i]);
+ free(cButtons);
+ }
+ if(rButtons) {
+ for(i = 0; rButtons[i]; i++) if(rButtons[i]) delete(rButtons[i]);
+ free(rButtons);
+ }
+ if (aButton) delete(aButton);
+ if (w) delete w;
+ if (g && NumGraphs) {
+ for(i = 0; i < NumGraphs; i++) if(g[i]) {
+ g[i]->Command(CMD_CAN_DELETE, 0L, 0L);
+ delete(g[i]);
+ }
+ free (g);
+ }
+ if(filename) free(filename); filename=0L;
+}
+
+void
+SpreadWin::DoPlot(anyOutput *o)
+{
+ o->ActualSize(&currRC);
+ o->StartPage();
+ d->Command(CMD_DOPLOT, (void*)this, o);
+ o->EndPage();
+}
+
+bool
+SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ char *Name;
+ Graph **g1, *g2;
+ int i, j, k;
+ MouseEvent *mev;
+
+ if(d) {
+ switch(cmd) {
+ case CMD_UNDO:
+ if(w) {
+ w->MouseCursor(MC_WAIT, true);
+ Undo.Restore(true, w);
+ w->MouseCursor(MC_ARROW, true);
+ }
+ return true;
+ case CMD_CAN_DELETE:
+ HideTextCursor();
+ if(is_modified && YesNoBox("The spreadsheet has been modified!\n\nDo you want to save it now?")){
+ is_modified=false;
+ return Command(CMD_SAVEDATAAS, tmpl, o);
+ }
+ Undo.KillDisp(w);
+ is_modified=false;
+ return true;
+ case CMD_MRK_DIRTY:
+ is_modified=true;
+ return true;
+ case CMD_WRITE_GRAPHS:
+ if (g && NumGraphs) WriteGraphXML((unsigned char**)tmpl, (long*)o);
+ return true;
+ case CMD_DROP_GRAPH:
+ if(o) o->FileHistory();
+ if(!g) g = (Graph **)calloc(2, sizeof(Graph*));
+ else {
+ g1 = (Graph **)calloc(NumGraphs+2, sizeof(Graph*));
+ if(!g1) return false;
+ for(i = 0; i < NumGraphs; i++) g1[i] = g[i];
+ free(g);
+ g = g1;
+ }
+ if(!g) return false;
+ g[NumGraphs] = (Graph *)tmpl;
+ if(g[NumGraphs]){
+ g[NumGraphs]->parent = this;
+ NumGraphs++;
+ g[NumGraphs-1]->Command(CMD_SET_DATAOBJ, (void *)d, 0L);
+ g[NumGraphs-1]->DoPlot(NULL);
+ }
+ return true;
+ case CMD_NEWGRAPH:
+ if((g2 = new Graph(this, d, 0L)) && g2->PropertyDlg() &&
+ Command(CMD_DROP_GRAPH, g2, o))return true;
+ else if(g2) DeleteGO(g2);
+ return false;
+ case CMD_NEWPAGE:
+ if((g2 = new Page(this, d)) &&
+ Command(CMD_DROP_GRAPH, g2, o))return true;
+ else if(g2) DeleteGO(g2);
+ return false;
+ case CMD_DELGRAPH:
+ if (g && NumGraphs) {
+ for(i = 0; i < NumGraphs; i++) if(g[i]){
+ g[i]->Command(CMD_CAN_DELETE, 0L, 0L);
+ DeleteGO(g[i]);
+ }
+ free (g);
+ }
+ g = 0L;
+ NumGraphs = 0;
+ Undo.Flush();
+ return true;
+ case CMD_DELOBJ:
+ if (g) {
+ for(i = 0; i <= NumGraphs; i++) {
+ if(g[i] == (Graph *)tmpl) {
+ delete (g[i]);
+ g[i] = 0L;
+ return true;
+ }
+ }
+ }
+ return false;
+ case CMD_SAVEDATAAS:
+ is_modified=false;
+ if((Name = SaveDataAsName(filename)) && Name[0]){
+ if(o) o->FileHistory();
+ if(Name && d->WriteData(Name)) {
+ if(filename) free(filename);
+ filename = strdup(Name);
+ }
+ }
+ return true;
+ case CMD_DROPFILE:
+ if(IsRlpFile((char*)tmpl)) return OpenGraph(this, (char*)tmpl, 0L);
+ else if(d->ReadData((char*)tmpl, 0L, FF_UNKNOWN)){
+ if(filename) free(filename);
+ filename = strdup((char*)tmpl);
+ return Command(CMD_SETSCROLL, 0L, w);
+ }
+ return false;
+ case CMD_OPEN:
+ if((Name = OpenDataName(filename)) && Name[0]){
+ if(o) o->FileHistory();
+ if(IsRlpFile(Name)) return OpenGraph(this, Name, 0L);
+ else if(d->ReadData(Name, 0L, FF_UNKNOWN)){
+ if(filename) free(filename);
+ filename = strdup(Name);
+ return Command(CMD_SETSCROLL, 0L, w);
+ }
+ }
+ return false;
+ case CMD_ADDROWCOL:
+ DoSpShSize(d);
+ return true;
+ case CMD_MOUSE_EVENT:
+ if(o && (mev = (MouseEvent*)tmpl) && mev->y > o->MenuHeight) {
+ if(mev->x < fw && mev->y < (o->MenuHeight + ch) && aButton) {
+ aButton->Command(cmd, tmpl, o);
+ }
+ else if(mev->x < fw && rButtons) {
+ i = (mev->y - o->MenuHeight - ch)/ch;
+ if(rButtons[i]) rButtons[i]->Command(cmd, tmpl, o);
+ }
+ else if(mev->y < (o->MenuHeight + ch) && cButtons) {
+ i = (mev->x - fw)/cw;
+ if(cButtons[i]) cButtons[i]->Command(cmd, tmpl, o);
+ }
+ else if(o->MrkMode == MRK_SSB_DRAW) o->HideMark();
+ }
+ return d->Command(cmd, tmpl, o);
+ case CMD_PASTE_TSV: case CMD_PASTE_XML: case CMD_PASTE_CSV:
+ Undo.DataObject(this, w, d, 0L);
+ case CMD_COPY_SYLK: case CMD_ADDCHAR: case CMD_SHIFTUP:
+ case CMD_COPY_TSV: case CMD_COPY_XML: case CMD_QUERY_COPY:
+ case CMD_TAB: case CMD_SHTAB: case CMD_SHIFTDOWN:
+ case CMD_CURRLEFT: case CMD_CURRIGHT: case CMD_CURRUP:
+ case CMD_CURRDOWN: case CMD_SHIFTRIGHT: case CMD_POS_FIRST:
+ case CMD_POS_LAST: case CMD_SHIFTLEFT: case CMD_DELETE:
+ case CMD_TOOLMODE: case CMD_FILLRANGE: case CMD_CUT:
+ case CMD_REDRAW:
+ return d->Command(cmd, tmpl, o);
+ case CMD_SETSCROLL:
+ HideTextCursor();
+ o->ActualSize(&currRC);
+ k = (currRC.bottom-currRC.top)/ch;
+ d->GetSize(&i, &j);
+ o->SetScroll(true, 0, j, k, ssOrg.y);
+ k = (currRC.right-currRC.left)/cw;
+ o->SetScroll(false, 0, i, k, ssOrg.x);
+ DoPlot(o);
+ return true;
+ case CMD_PAGEUP:
+ k = (currRC.bottom-currRC.top)/ch;
+ k = k > 3 ? k-2 : 1;
+ ssOrg.y = ssOrg.y > k ? ssOrg.y-k : 0;
+ return Command(CMD_SETSCROLL, tmpl, o);
+ case CMD_PAGEDOWN:
+ k = (currRC.bottom-currRC.top)/ch;
+ k = k > 3 ? k-2 : 1;
+ d->GetSize(&i, &j);
+ ssOrg.y = ssOrg.y < j-k*2 ? ssOrg.y+k : j > k ? j-k : 0;
+ return Command(CMD_SETSCROLL, tmpl, o);
+ case CMD_SETHPOS:
+ ssOrg.x = *((int*)tmpl) >= 0 ? *((long*)tmpl) : 0L;
+ return Command(CMD_SETSCROLL, tmpl, o);
+ case CMD_SETVPOS:
+ ssOrg.y = *((int*)tmpl) >= 0 ? *((long*)tmpl) : 0L;
+ return Command(CMD_SETSCROLL, tmpl, o);
+ case CMD_SETFOCUS:
+ return true;
+ case CMD_KILLFOCUS:
+ return true;
+ case CMD_TEXTSIZE:
+ if(tmpl)ssText.iSize = *((int*)tmpl);
+ break;
+ case CMD_CONFIG:
+ return defs.PropertyDlg();
+ case CMD_NONE:
+ return true;
+ case CMD_PRINT:
+ return PrintData(o);
+ }
+ }
+ return false;
+}
+
+bool
+SpreadWin::ShowGrid(int CellWidth, int CellHeight, int FirstWidth)
+{
+ int i, c, nr, nc;
+ RECT rc;
+ char text[20];
+ POINT grid[2];
+ TextDEF ButtText;
+ bool redim = false;
+
+ //DEBUG: Make sure not to draw the grid much larger than the dektop
+ if(ch != CellHeight || cw != CellWidth || fw != FirstWidth) redim = true;
+ ch = CellHeight; cw = CellWidth; fw = FirstWidth;
+ if(redim){
+ if(cButtons) {
+ for(i = 0; cButtons[i]; i++) if(cButtons[i]) delete(cButtons[i]);
+ free(cButtons);
+ }
+ if(rButtons) {
+ for(i = 0; rButtons[i]; i++) if(rButtons[i]) delete(rButtons[i]);
+ free(rButtons);
+ }
+ if(aButton) delete(aButton); aButton = 0L;
+ cButtons = rButtons = 0L;
+ }
+ if(!aButton) aButton = new ssButton(this, 0, w->MenuHeight, FirstWidth, CellHeight);
+ memcpy(&ButtText, &ssText, sizeof(TextDEF));
+ ButtText.Align = TXA_HCENTER | TXA_VCENTER;
+ w->GetSize(&rc);
+ if(!cButtons) {
+ c = (rc.right/CellWidth)+1;
+ cButtons = (ssButton **)calloc(c, sizeof(ssButton*));
+ for(i = 0; i < (c-1); i++) cButtons[i] =
+ new ssButton(this, i*CellWidth+FirstWidth, w->MenuHeight,
+ CellWidth+1, CellHeight);
+ }
+ if(!rButtons) {
+ c = (rc.bottom/CellHeight)+1;
+ rButtons = (ssButton**)calloc(c, sizeof(ssButton*));
+ for(i = 0; i < (c-1); i++) rButtons[i] =
+ new ssButton(this, 0, i*CellHeight+CellHeight+w->MenuHeight,
+ FirstWidth, CellHeight);
+ }
+ w->SetLine((LineDEF *)&BlackLine);
+ d->GetSize(&nc, &nr);
+ grid[0].x = rc.left+FirstWidth;
+ i = (nc-ssOrg.x)*CellWidth+FirstWidth;
+ grid[1].x = i < rc.right ? i : rc.right;
+ if(rButtons) for(i = 0; rButtons[i]; i++) {
+ sprintf(text, "%d", i+1+ssOrg.y);
+ if(rButtons[i]) {
+ rButtons[i]->Command(CMD_SETTEXTDEF, &ButtText, w);
+ rButtons[i]->Command(CMD_SETTEXT, text, w);
+ rButtons[i]->DoPlot(w);
+ w->SetLine((LineDEF *)&BlackLine);
+ }
+ grid[0].y = grid[1].y = w->MenuHeight + i*CellHeight - 1;
+ if(i < (2+nr-ssOrg.y)) w->oSolidLine(grid);
+ }
+ grid[0].y = rc.top+CellHeight+w->MenuHeight;
+ i = (1+nr-ssOrg.y)*CellHeight;
+ grid[1].y = (i+w->MenuHeight)< rc.bottom ? i+w->MenuHeight : rc.bottom;
+ if(cButtons) for(i = 0; cButtons[i]; i++) {
+ if(cButtons[i]) {
+ cButtons[i]->Command(CMD_SETTEXTDEF, &ButtText, w);
+ cButtons[i]->Command(CMD_SETTEXT, Int2ColLabel(i+ssOrg.x, true), w);
+ cButtons[i]->DoPlot(w);
+ w->SetLine((LineDEF *)&BlackLine);
+ }
+ grid[0].x = grid[1].x = i*CellWidth+FirstWidth-1;
+ if(i <= (nc-ssOrg.x)) w->oSolidLine(grid);
+ }
+ w->SetTextSpec(&ssText);
+ if(aButton) aButton->DoPlot(w);
+ return true;
+}
+
+bool
+SpreadWin::PrintData(anyOutput *o)
+{
+ int i, j, k, l, pfw, pcw, pch, rpp, cpp, nc, nr, ix, iy, cpages;
+ RECT rc, margin, margin_first;
+ POINT pp_pos, ss_pos, grid[2];
+ LineDEF Line1, Line2;
+ TextDEF td, tdp;
+ bool bContinue;
+ time_t ti = time(0L);
+ double val;
+
+ Line1.patlength = Line2.patlength = 1.0;
+ Line1.color = Line2.color = 0x0; //black gridlines
+ Line1.pattern = Line2.pattern = 0x0; //solid lines
+ switch(defs.cUnits) {
+ case 1: Line1.width = 0.01; break;
+ case 2: Line1.width = 0.003937; break;
+ default: Line1.width = 0.1; break;
+ }
+ Line2.width = Line1.width * 3.0;
+ d->GetSize(&nc, &nr);
+ if(!(o->StartPage())) return false;
+ pfw = iround(o->hres * ((double)fw)/w->hres);
+ pcw = iround(o->hres * ((double)cw)/w->hres);
+ pch = iround(o->vres * ((double)ch)/w->vres + o->vres/20.0);
+ o->ActualSize(&rc);
+ tdp.ColTxt = 0x0; tdp.ColBg = 0x00ffffffL;
+ tdp.fSize = tdp.RotBL = tdp.RotCHAR = 0.0; tdp.Align = TXA_HRIGHT | TXA_VCENTER;
+#ifdef _WINDOWS
+ tdp.iSize = iround(o->hres/6.0);
+#else
+ tdp.iSize = iround(o->hres/7.5);
+#endif
+ tdp.Mode = TXM_TRANSPARENT;
+ tdp.Style = TXS_NORMAL; tdp.Font = FONT_HELVETICA; tdp.text = 0L;
+ memcpy(&td, &ssText, sizeof(TextDEF));
+ td.Align = TXA_HCENTER | TXA_VCENTER;
+ td.Style = TXS_NORMAL; td.iSize = 0;
+#ifdef _WINDOWS
+ td.fSize = defs.GetSize(SIZE_CELLTEXT);
+#else
+ td.fSize = defs.GetSize(SIZE_CELLTEXT)*.8f;
+#endif
+ margin.left = iround(o->hres); margin.right = iround(o->hres/2.0);
+ margin.top = margin.bottom = iround(o->hres);
+ memcpy(&margin_first, &margin, sizeof(RECT));
+ cpp = (rc.right - margin.left - margin.right - pfw)/pcw;
+ rpp = (rc.bottom - margin.top - margin.bottom - pch)/pch;
+ pp_pos.x = margin.left; pp_pos.y = margin.top;
+ ss_pos.x = 0; ss_pos.y = 0; cpages = 1;
+ do {
+ pp_pos.x = margin.left; pp_pos.y = margin.top;
+ k = (ss_pos.x + cpp) > nc ? nc-ss_pos.x : cpp;
+ l = (ss_pos.y + rpp) > nr ? nr-ss_pos.y : rpp;
+ grid[0].y = margin.top +pch; grid[1].y = grid[0].y + l * pch;
+ o->SetLine(&Line2);
+ grid[0].x = grid[1].x = pp_pos.x; o->oSolidLine(grid);
+ grid[0].x = grid[1].x = pp_pos.x+pfw; o->oSolidLine(grid);
+ o->SetLine(&Line1);
+ for(i = 1; i <= k; i++) { //vertical grid
+ grid[0].x = grid[1].x = pp_pos.x + pfw + i * pcw;
+ o->oSolidLine(grid);
+ }
+ grid[0].x = margin.left+pfw; grid[1].x = grid[0].x + k * pcw;
+ o->SetLine(&Line2);
+ grid[0].y = grid[1].y = pp_pos.y; o->oSolidLine(grid);
+ grid[0].y = grid[1].y = pp_pos.y+pch; o->oSolidLine(grid);
+ o->SetLine(&Line1);
+ for(i = 1; i <= l; i++) { //horizontal grid
+ grid[0].y = grid[1].y = pp_pos.y + pch + i * pch;
+ o->oSolidLine(grid);
+ }
+ o->SetLine(&Line2);
+ td.Align = TXA_HCENTER | TXA_VCENTER; o->SetTextSpec(&td);
+ grid[0].y = margin.top; grid[1].y = grid[0].y + pch;
+ iy = margin.top + (pch >>1);
+ for(i = 0; i <= k; i++) { //column headers
+ grid[0].x = grid[1].x = pp_pos.x + pfw + i * pcw;
+ o->oSolidLine(grid); ix = grid[0].x + (pcw >>1);
+ if(i < k) o->oTextOut(ix, iy, Int2ColLabel(i+ss_pos.x, true), 0);
+ }
+ td.Align = TXA_HRIGHT | TXA_VCENTER;
+ o->SetTextSpec(&td); ix = margin.left + pfw - iround(o->hres/20.0);
+ grid[0].x = margin.left; grid[1].x = grid[0].x + pfw;
+ for(i = 0; i <= l; i++) { //row labels
+ grid[0].y = grid[1].y = pp_pos.y + pch + i * pch;
+ o->oSolidLine(grid); iy = grid[0].y + (pch >>1);
+ sprintf(TmpTxt, "%d", i+1+ss_pos.y);
+ if(i < l) o->oTextOut(ix, iy, TmpTxt, 0);
+ }
+ for(i = 0; i < k; i++) { //spreadsheet data
+ for (j = 0; j < l; j++) {
+ if(d->GetText(j+ss_pos.y, i+ss_pos.x, TmpTxt, TMP_TXT_SIZE)){
+ if(d->etRows[j+ss_pos.y][i+ss_pos.x]->isFormula()){
+ td.Align = TXA_HRIGHT | TXA_VCENTER;
+ ix = margin.left+pfw+pcw + i*pcw - iround(o->hres/20.0);
+ d->etRows[j+ss_pos.y][i+ss_pos.x]->GetValue(&val);
+ sprintf(TmpTxt,"%g", val);
+ }
+ else if(d->etRows[j+ss_pos.y][i+ss_pos.x]->isValue()){
+ td.Align = TXA_HRIGHT | TXA_VCENTER;
+ ix = margin.left+pfw+pcw + i*pcw - iround(o->hres/20.0);
+ }
+ else {
+ td.Align = TXA_HLEFT | TXA_VCENTER;
+ ix = margin.left+pfw + i*pcw + iround(o->hres/20.0);
+ }
+ iy = pp_pos.y + pch + (pch>>1) + j * pch;
+ o->SetTextSpec(&td);
+ o->oTextOut(ix, iy, TmpTxt, 0);
+ }
+ }
+ }
+ //prepare for next table
+ ss_pos.x += k; bContinue = false;
+ if(ss_pos.x >= nc) {ss_pos.x = 0; ss_pos.y += l; }
+ if(ss_pos.y < nr) {
+ ix = pfw + (cpp % nc)*pcw + iround(o->hres/3.5);
+ iy = (l+2)*pch;
+ if((margin.left + ix + pfw + k*pcw) < (rc.right-margin.right)) {
+ margin.left += pfw + k*pcw + iround(o->hres/3.5);
+ bContinue = true;
+ }
+ else if((margin.top + iy + pch + l*pch) < (rc.bottom - margin.bottom)) {
+ margin.top += iy; margin.left = margin_first.left;
+ bContinue = true;
+ }
+ else {
+ tdp.Align = TXA_HRIGHT | TXA_VCENTER; o->SetTextSpec(&tdp);
+ sprintf(TmpTxt, "page %d", cpages++);
+ o->oTextOut(rc.right-margin.right, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
+ tdp.Align = TXA_HCENTER | TXA_VCENTER; o->SetTextSpec(&tdp);
+ sprintf(TmpTxt, "%s", ctime(&ti)); TmpTxt[24] = 0;
+ o->oTextOut((rc.right-rc.left)>>1, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
+ tdp.Align = TXA_HLEFT | TXA_VCENTER; o->SetTextSpec(&tdp);
+ sprintf(TmpTxt, "RLPlot %s", SZ_VERSION);
+ o->oTextOut(margin_first.left, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
+ memcpy(&margin, &margin_first, sizeof(RECT));
+ bContinue = true;
+ o->Eject();
+ }
+ }
+ }while(bContinue);
+ tdp.Align = TXA_HRIGHT | TXA_VCENTER; o->SetTextSpec(&tdp);
+ sprintf(TmpTxt, "page %d", cpages++);
+ o->oTextOut(rc.right-margin.right, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
+ tdp.Align = TXA_HCENTER | TXA_VCENTER; o->SetTextSpec(&tdp);
+ sprintf(TmpTxt, "%s", ctime(&ti)); TmpTxt[24] = 0;
+ o->oTextOut((rc.right-rc.left)>>1, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
+ tdp.Align = TXA_HLEFT | TXA_VCENTER; o->SetTextSpec(&tdp);
+ sprintf(TmpTxt, "RLPlot %s", SZ_VERSION);
+ o->oTextOut(margin_first.left, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
+ o->EndPage();
+ return true;
+}
+
+void
+SpreadWin::WriteGraphXML(unsigned char **ptr, long *cbd)
+{
+ unsigned char *pg;
+ long cb = 0, size = 0;
+ int i;
+
+ if(cbd) size = (*cbd / 10000)+ 10000;
+ for(i = 0; i < NumGraphs; i++) if(g[i]) {
+ pg = (unsigned char*)GraphToMem(g[i], &cb);
+ if(pg && cb) {
+ while ((*cbd+cb+100) > size){
+ *ptr = (unsigned char*)realloc(*ptr, size += 10000);
+ }
+ *cbd += sprintf(((char*)*ptr)+*cbd, "<Graph><![CDATA[\n");
+ memcpy(*ptr+*cbd, pg, cb); *cbd += cb;
+ *cbd += sprintf(((char*)*ptr)+*cbd, "]]>\n</Graph>\n");
+ if(pg) free(pg); pg = 0L; cb = 0;
+ }
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// This data object is a spreadsheet
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class SpreadData:public DataObj{
+public:
+ SpreadData();
+ ~SpreadData();
+ bool Init(int nRows, int nCols);
+ bool mpos2dpos(POINT *mp, POINT *dp);
+ bool Select(POINT *p);
+ void MarkRange(char *range);
+ void HideMark(bool cclp);
+ bool WriteData(char *FileName);
+ bool AddCols(int nCols);
+ bool AddRows(int nRows);
+ bool ChangeSize(int nCols, int nRows, bool bUndo);
+ void DoPlot(anyOutput *o);
+ bool DelRange();
+ bool PasteRange(int cmd, char *txt);
+ bool InitCopy(int cmd, void *tmpl, anyOutput *o);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool ReadData(char *FileName, unsigned char *buffer, int type);
+
+ bool ReadXML(char *file, unsigned char *buffer, int type);
+ bool ReadTSV(char *file, unsigned char *buffer, int type);
+ bool MemList(unsigned char **ptr, int type);
+
+private:
+ int CellHeight, CellWidth, FirstWidth, r_disp, c_disp;
+ RECT rcCopy, cp_src_rec; //bounding rectangle for copy range
+ bool bActive, new_mark, bCopyCut;
+ POINT currpos, currpos2;
+ anyOutput *w;
+ SpreadWin *Disp;
+ char *m_range, *c_range; //mark and copy ranges
+ char *err_msg; //error message
+};
+
+SpreadData::SpreadData()
+{
+ Disp = 0L; m_range = 0L; c_range = 0L; w = 0L; err_msg=0;
+ CellWidth = CellHeight = FirstWidth = 0;
+ currpos.x = currpos.y = r_disp = c_disp = 0;
+ bActive = bCopyCut = false;
+ rcCopy.left = rcCopy.right = rcCopy.top = rcCopy.bottom = 0;
+ cp_src_rec.left = cp_src_rec.right = cp_src_rec.top = cp_src_rec.bottom = 0;
+ if(defs.IniFile && FileExist(defs.IniFile)) {
+ OpenGraph(0L, defs.IniFile, 0L);
+ }
+}
+
+SpreadData::~SpreadData()
+{
+ FlushData();
+ if(Disp) delete Disp; Disp = 0L;
+ if(m_range) free(m_range); m_range = 0L;
+ if(c_range) free(c_range); c_range = 0L;
+}
+
+bool
+SpreadData::Init(int nRows, int nCols)
+{
+ int i, j;
+ POINT p1, p2;
+ RECT rc;
+
+ rcCopy.left = rcCopy.top = 0; rcCopy.bottom = cRows = nRows;
+ rcCopy.right = cCols = nCols; currpos.x = currpos.y = 0;
+ new_mark = bCopyCut = false;
+ if(!Disp) {
+ Disp = new SpreadWin(this);
+ w = Disp->w;
+ if(w) {
+ CellWidth = w->un2ix(defs.GetSize(SIZE_CELLWIDTH));
+ CellHeight = w->un2iy(defs.GetSize(SIZE_CELLTEXT)) + 2;
+ FirstWidth = 32;
+ w->ActualSize(&rc);
+ r_disp = (rc.bottom-rc.top)/CellHeight+1;
+ c_disp = (rc.right-rc.left)/CellWidth+1;
+ }
+ else return false;
+ Disp->ShowGrid(CellWidth, CellHeight, FirstWidth);
+ }
+ if(etRows)FlushData();
+ etRows = (EditText ***)calloc (cRows, sizeof(EditText **));
+ if(etRows) for(i = 0, p1.x = FirstWidth, p1.y = CellHeight + w->MenuHeight; i < cRows; i++) {
+ etRows[i] = (EditText **)calloc(cCols, sizeof(EditText *));
+ p2.y = p1.y + CellHeight;
+ if(etRows[i]) for(j = 0; j < cCols; j++) {
+ p2.x = p1.x + CellWidth;
+#ifdef _DEBUG
+ char text[20];
+ sprintf (text, "%.2f", i*10.0 + j);
+ etRows[i][j] = new EditText(this, p1, p2, text);
+#else
+ etRows[i][j] = new EditText(this, p1, p2, 0L);
+#endif
+ if(etRows[i][j]) etRows[i][j]->Redraw(w, false);
+ p1.x += CellWidth;
+ }
+ p1.y += CellHeight;
+ p1.x = FirstWidth;
+ }
+ if (LoadFile) {
+ strcpy(TmpTxt, LoadFile); //we will reenter by recursion !
+ free(LoadFile);
+ LoadFile = 0L;
+ Disp->Command(CMD_DROPFILE, TmpTxt, w);
+ }
+ return true;
+}
+
+bool
+SpreadData::mpos2dpos(POINT *mp, POINT *dp)
+{
+ if(mp->x < (FirstWidth+10) && mp->x > FirstWidth && Disp->ssOrg.x >0) {
+ Disp->ssOrg.x -= 1;
+ if(CurrText) CurrText->Update(2, w, mp); CurrText = 0L;
+ Disp->Command(CMD_SETSCROLL, 0L, w);
+ mp->x += CellWidth;
+ }
+ if(mp->y < (w->MenuHeight + CellHeight+10) && mp->y > (w->MenuHeight + CellHeight) && Disp->ssOrg.y >0) {
+ Disp->ssOrg.y -= 1;
+ if(CurrText) CurrText->Update(2, w, mp); CurrText = 0L;
+ Disp->Command(CMD_SETSCROLL, 0L, w);
+ mp->y += CellHeight;
+ }
+ if(mp->x > (Disp->currRC.right-w->MenuHeight-10) && Disp->ssOrg.x < (cCols-2)) {
+ Disp->ssOrg.x += 1;
+ if(CurrText) CurrText->Update(2, w, mp); CurrText = 0L;
+ Disp->Command(CMD_SETSCROLL, 0L, w);
+ mp->x -= CellWidth;
+ }
+ if(mp->y > (Disp->currRC.bottom-10) && Disp->ssOrg.y < (cRows-5)) {
+ Disp->ssOrg.y += 1;
+ do {
+ mp->y -= CellHeight;
+ } while(mp->y > (Disp->currRC.bottom-CellHeight));
+ if(CurrText) CurrText->Update(2, w, mp); CurrText = 0L;
+ Disp->Command(CMD_SETSCROLL, 0L, w);
+ }
+ dp->y = (mp->y - w->MenuHeight - CellHeight)/CellHeight + Disp->ssOrg.y;
+ dp->x = (mp->x - FirstWidth)/CellWidth + Disp->ssOrg.x;
+ if(dp->y >= cRows) dp->y = cRows-1;
+ if(dp->x >= cCols) dp->x = cCols-1;
+ return true;
+}
+
+bool
+SpreadData::Select(POINT *p)
+{
+ if(CurrText && CurrText->isInRect(p)){
+ CurrText->Update(1, w, p);
+ return true;
+ }
+ mpos2dpos(p, &currpos);
+ if(currpos.y < cRows && currpos.x < cCols && currpos.y >= 0 && currpos.x >= 0) {
+ if(etRows[currpos.y][currpos.x]) {
+ if(etRows[currpos.y][currpos.x] == CurrText) CurrText->Update(1, w, p);
+ else {
+ if(CurrText) CurrText->Update(2, w, p);
+ CurrText = etRows[currpos.y][currpos.x];
+ DoPlot(w);
+ CurrText->Update(1, w, p);
+ }
+ return true;
+ }
+ }
+ if(CurrText) CurrText->Update(2, w, p); CurrText = 0L;
+ return false;
+}
+
+void
+SpreadData::MarkRange(char *range)
+{
+ AccRange *nr, *oldr;
+ int r, c;
+
+ oldr = nr = 0L;
+ if(m_range && range && !strcmp(m_range, range)) return; //no change
+ if(m_range) oldr = new AccRange(m_range);
+ if(range) nr = new AccRange(range);
+ if(oldr && nr && oldr->GetFirst(&c, &r)) {
+ for( ; oldr->GetNext(&c, &r); ) {
+ if(r >= Disp->ssOrg.y && r < (r_disp +Disp->ssOrg.y) && c >= Disp->ssOrg.x
+ && c < (c_disp + Disp->ssOrg.x) && !nr->IsInRange(c, r) && etRows[r] && etRows[r][c]){
+ etRows[r][c]->Mark(w, etRows[r][c] != CurrText ? 0 : 1);
+ }
+ }
+ }
+ if(nr && nr->GetFirst(&c, &r)) {
+ for( ; nr->GetNext(&c, &r); ) {
+ if(r >= Disp->ssOrg.y && r < (r_disp +Disp->ssOrg.y) && c >= Disp->ssOrg.x
+ && c < (c_disp + Disp->ssOrg.x))
+ etRows[r][c]->Mark(w, etRows[r][c] != CurrText ? 2 : 3);
+ }
+ }
+ if (m_range) free(m_range); m_range = 0L;
+ if(range) m_range = strdup(range);
+ if(oldr) delete(oldr); if(nr) delete(nr);
+ new_mark = true;
+}
+
+void
+SpreadData::HideMark(bool cclp)
+{
+ if(cclp && c_range && c_range != m_range){
+ free(c_range); c_range = 0L;
+ rcCopy.left = rcCopy.top = 0;
+ rcCopy.bottom = cRows; rcCopy.right = cCols;
+ }
+ if(m_range){
+ free(m_range); m_range = 0L;
+ DoPlot(w);
+ }
+ if(cclp) EmptyClip();
+ new_mark = bCopyCut = false;
+}
+
+bool
+SpreadData::WriteData(char *FileName)
+{
+ FILE *File;
+ int i, j;
+ char tmp[800];
+ unsigned char *buff = 0L;
+
+ if(!cRows || !cCols || !etRows) return false;
+ BackupFile(FileName);
+ if(!(File = fopen(FileName, "w")))return false;
+ HideMark(true);
+ rcCopy.left = rcCopy.top = 0; rcCopy.bottom = cRows; rcCopy.right = cCols;
+ i = strlen(FileName);
+ //test for xml extension
+ if(!strcmp(".xml", FileName+i-4) || !strcmp(".XML", FileName+i-4)) {
+ MemList(&buff, FF_XML);
+ if(buff){
+ fprintf(File, "%s", buff);
+ free(buff); fclose(File);
+ return true;
+ }
+ return false;
+ }
+ //test for tsv extension
+ if(!strcmp(".tsv", FileName+i-4) || !strcmp(".TSV", FileName+i-4)) {
+ MemList(&buff, FF_TSV);
+ if(buff){
+ fprintf(File, "%s", buff);
+ free(buff); fclose(File);
+ return true;
+ }
+ return false;
+ }
+ //test for rlw extension
+ if(!strcmp(".rlw", FileName+i-4) || !strcmp(".RLW", FileName+i-4)) {
+ MemList(&buff, FF_RLW);
+ if(buff){
+ fprintf(File, "%s", buff);
+ free(buff); fclose(File);
+ return true;
+ }
+ return false;
+ }
+ //else write csv
+ for(i = 0; i < cRows; i++) {
+ for(j = 0; j < cCols; j++) {
+ if(etRows[i][j] && etRows[i][j]->GetItem(tmp, sizeof(tmp)))
+ fprintf(File, "%s", tmp);
+ if(j < (cCols-1)) fprintf(File, ",");
+ }
+ fprintf(File, "\n");
+ }
+ fclose(File);
+ return true;
+}
+
+bool
+SpreadData::ReadData(char *FileName, unsigned char *buffer, int type)
+{
+ int i, j, l;
+ char ItemText[20];
+ bool success;
+ POINT pt;
+
+ if(FileName) { //read disk file
+ if(0 == strcmp(".xml", FileName+strlen(FileName)-4) ||
+ 0 == strcmp(".XML", FileName+strlen(FileName)-4) ||
+ 0 == strcmp(".rlw", FileName+strlen(FileName)-4) ||
+ 0 == strcmp(".RLW", FileName+strlen(FileName)-4) ||
+ IsXmlFile(FileName)){
+ if(ReadXML(FileName, buffer, type)){
+ rcCopy.left = rcCopy.top = 0;
+ rcCopy.right = cCols;
+ rcCopy.bottom = cRows;
+ return true;
+ }
+ return false;
+ }
+ if(0 == strcmp(".tsv", FileName+strlen(FileName)-4) ||
+ 0 == strcmp(".TSV", FileName+strlen(FileName)-4)){
+ if(ReadTSV(FileName, buffer, type)){
+ rcCopy.left = rcCopy.top = 0;
+ rcCopy.right = cCols;
+ rcCopy.bottom = cRows;
+ return true;
+ }
+ return false;
+ }
+ if(!(Cache = new ReadCache())) return false;
+ if(! Cache->Open(FileName)) {
+ delete Cache;
+ sprintf(TmpTxt, "Error open data file\n\"%s\"", FileName);
+ ErrorBox(TmpTxt);
+ return false;
+ }
+ if(!Init(1, 1)) goto ReadError;
+ }
+ else if(buffer) { //read memory buffer
+ switch(type) {
+ case FF_TSV:
+ return ReadTSV(FileName, buffer, type);
+ case FF_XML:
+ return ReadXML(FileName, buffer, type);
+ case FF_CSV:
+ if(!(Cache = new MemCache(buffer))) return false;
+ break;
+ default:
+ ErrorBox("Read from buffer with\nunknown format failed.");
+ return false;
+ }
+ }
+ else return false;
+ i = j = 0;
+ pt.x = pt.y = 0; //pt is a dummy argument only
+ do {
+ if((success = GetItemCSV(ItemText, sizeof(ItemText)-1)) || ItemText[0]){
+ if(j >= cCols && !AddCols(j+1)) goto ReadError;
+ if(i >= cRows && !AddRows(i+1)) goto ReadError;
+ if(etRows[i][j]) etRows[i][j]->SetText("");
+ l = strlen(ItemText);
+ if(l>1 && ItemText[0] == '"') {
+ ItemText[l-1] = 0;
+ etRows[i][j]->SetText(ItemText+1);
+ etRows[i][j]->Update(20, 0L, &pt);
+ }
+ else if(l){
+ etRows[i][j]->SetText(ItemText);
+ etRows[i][j]->Update(10, 0L, &pt);
+ }
+ j++;
+ }
+ if(!success && !Cache->IsEOF()) {i++; j = 0;} //eol
+ }while (ItemText[0] || !Cache->IsEOF()); //eof
+
+ Cache->Close();
+ delete Cache;
+ Cache = 0L;
+ if(FileName) {
+ rcCopy.left = rcCopy.top = 0;
+ rcCopy.right = cCols;
+ rcCopy.bottom = cRows;
+ }
+ Disp->ssOrg.x = Disp->ssOrg.y = 0;
+ return true;
+
+ReadError:
+ Cache->Close();
+ delete Cache;
+ Cache = 0L;
+ return false;
+
+}
+
+bool
+SpreadData::AddCols(int nCols)
+{
+ EditText **NewRow;
+ int i, j;
+ POINT p1, p2;
+
+ if (nCols <= cCols) return false;
+ if(etRows && etRows[0] && etRows[0][cCols-1]) {
+ p1.x = p2.x = (CellWidth + etRows[0][cCols-1]->GetX());
+ p1.y = p2.y = etRows[0][cCols-1]->GetY();
+ p2.x += CellWidth; p2.y += CellHeight;
+ }
+ else return false;
+ for(i = 0; i < cRows; i++) {
+ NewRow = (EditText **)realloc(etRows[i], nCols * sizeof(EditText *));
+ if(NewRow) {
+ for(j = cCols; j < nCols; j++) {
+ NewRow[j] = new EditText(this, p1, p2, NULL);
+ p1.x += CellWidth; p2.x += CellWidth;
+ }
+ etRows[i] = NewRow;
+ }
+ else { //memory allocation error
+ cCols = nCols;
+ //DEBUG: we should warn the user that not all cells are available
+ // or even better we remove some columns up to i rows
+ return false;
+ }
+ p1.x = p2.x = (CellWidth + etRows[0][cCols-1]->GetX());
+ p2.x += CellWidth; p2.y += CellHeight;
+ p1.y += CellHeight;
+ }
+ cCols = nCols;
+ return true;
+}
+
+bool
+SpreadData::AddRows(int nRows)
+{
+ int i, j, x;
+ POINT p1, p2;
+ EditText ***NewRows;
+
+ if (nRows <= cRows) return false;
+ i = cRows-1;
+ if(etRows && etRows[i] && etRows[i][0]) {
+ x = p1.x = p2.x = etRows[i][0]->GetX(); p1.y = etRows[i][0]->GetY();
+ p1.y += CellHeight; p2.y = p1.y + CellHeight;
+ p2.x += CellWidth;
+ }
+ else return false;
+ NewRows = (EditText ***)realloc(etRows, nRows * sizeof(EditText **));
+ if(NewRows) etRows = NewRows;
+ else return false; //memory allocation error
+ for(i = cRows; i < nRows; i++){
+ etRows[i] = (EditText **)calloc(cCols, sizeof(EditText *));
+ if(etRows[i]) {
+ for(j = 0; j < cCols; j++) {
+ etRows[i][j] = new EditText(this, p1, p2, NULL);
+ p1.x += CellWidth; p2.x += CellWidth;
+ }
+ }
+ else { //memory allocation error
+ cRows = i-1;
+ return false;
+ }
+ p1.y += CellHeight; p2.y += CellHeight;
+ p1.x = p2.x = x; p2.x += CellWidth;
+ }
+ cRows = nRows;
+ return true;
+}
+
+bool
+SpreadData::ChangeSize(int nCols, int nRows, bool bUndo)
+{
+ int i, j;
+ bool RetVal = true;
+
+ if(nCols == cCols && nRows == cRows) return true;
+ if(bUndo) Undo.DataObject(Disp, w, this, 0L);
+ if(nRows && nRows < cRows) {
+ for (i = nRows; i < cRows; i++) {
+ if(etRows[i]) for (j = 0; j < cCols; j++) {
+ if(etRows[i][j]) delete etRows[i][j];
+ etRows[i][j] = NULL;
+ }
+ free(etRows[i]);
+ etRows[i] = NULL;
+ }
+ cRows = nRows;
+ }
+ if(nCols && nCols < cCols) {
+ for (i = 0; i < cRows; i++) {
+ for (j = nCols; j < cCols; j++) {
+ if(etRows[i][j]) delete etRows[i][j];
+ etRows[i][j] = NULL;
+ }
+ }
+ cCols = nCols;
+ }
+ if(nCols > cCols) if(!AddCols(nCols))RetVal = false;
+ if(RetVal && nRows > cRows) if(!AddRows(nRows))RetVal = false;
+ if(w) {
+ sprintf(TmpTxt, "%d00", nRows);
+ w->oGetTextExtent(TmpTxt, 0, &i, &j);
+ if(i > FirstWidth) FirstWidth = i;
+ Disp->Command(CMD_SETSCROLL, 0L, w);
+ }
+ rcCopy.left = rcCopy.right = 0;
+ rcCopy.right = cCols;
+ rcCopy.bottom = cRows;
+ return RetVal;
+}
+
+void
+SpreadData::DoPlot(anyOutput *o)
+{
+ RECT rc;
+ int i, j, r, c;
+ AccRange *ar;
+
+ if(!w || !Disp) return;
+ w->Erase(0x00d8d8d8L); w->ActualSize(&rc);
+ r_disp = (rc.bottom-rc.top)/CellHeight+1;
+ c_disp = (rc.right-rc.left)/CellWidth+1;
+ Disp->ShowGrid(CellWidth, CellHeight, FirstWidth);
+ rc.top = w->MenuHeight; rc.bottom = rc.top + CellHeight;
+ for(i = 0; i < (cRows - Disp->ssOrg.y) && i < r_disp; i++) {
+ rc.left = FirstWidth; rc.right = rc.left + CellWidth;
+ rc.top += CellHeight; rc.bottom += CellHeight;
+ for(j = 0; j< (cCols - Disp->ssOrg.x) && j < cCols; j++) {
+ r = i + Disp->ssOrg.y; c = j + Disp->ssOrg.x;
+ if(r < cRows && r >= 0 && c < cCols && c >=0 && etRows[r][c]){
+ etRows[r][c]->SetRec(&rc); etRows[r][c]->Redraw(w, false);
+ }
+ rc.left += CellWidth; rc.right += CellWidth;
+ }
+ }
+ if(m_range && (ar = new AccRange(m_range)) && ar->GetFirst(&c, &r)) {
+ for( ; ar->GetNext(&c, &r); ) {
+ if(r >= Disp->ssOrg.y && r < (r_disp + Disp->ssOrg.y) && c >= Disp->ssOrg.x
+ && c < (c_disp + Disp->ssOrg.x) && etRows[r] && etRows[r][c])
+ etRows[r][c]->Mark(w, etRows[r][c] != CurrText ? 2 : 3);
+ }
+ delete (ar);
+ }
+ if(c_range) InitCopy(0, 0L, w); //move animated rectangle
+ w->ActualSize(&rc); w->UpdateRect(&rc, false);
+ if(err_msg) {
+ ErrorBox(err_msg); err_msg = 0L;
+ }
+}
+
+bool
+SpreadData::DelRange()
+{
+ AccRange *ar;
+ int r, c;
+
+ if(m_range && (ar = new AccRange(m_range)) && ar->GetFirst(&c, &r)) {
+ Undo.DataObject(Disp, w, this, 0L);
+ for( ; ar->GetNext(&c, &r); ) {
+ if(r < cRows && c < cCols){
+ if(CurrText && r == currpos.y && c == currpos.x) {
+ CurrText->Update(2, 0L, 0L);
+ CurrText = 0L;
+ }
+ if(etRows[r][c] && etRows[r][c]->text){
+ etRows[r][c]->SetText("");
+ }
+ }
+ }
+ delete (ar); HideTextCursor();
+ }
+ HideMark(false);
+ return true;
+}
+
+bool
+SpreadData::PasteRange(int cmd, char *txt)
+{
+ AccRange *cr;
+ int r, c;
+ RECT mrk_range;
+
+ if(new_mark && m_range && (cr = new AccRange(m_range)) && cr->GetFirst(&c, &r)) {
+ cr->BoundRec(&mrk_range);
+ for( ; cr->GetNext(&c, &r); ) if(c >= 0 && c < cCols && r >= 0 && r < cRows){
+ currpos.x = c; currpos.y = r;
+ switch(cmd){
+ case CMD_PASTE_TSV: ReadTSV(0L, (unsigned char*)txt, FF_TSV); break;
+ case CMD_PASTE_XML: ReadXML(0L, (unsigned char*)txt, FF_XML); break;
+ case CMD_PASTE_CSV: ReadData(0L, (unsigned char*)txt, FF_CSV); break;
+ }
+ if((mrk_range.right - mrk_range.left) == (cp_src_rec.right - cp_src_rec.left) &&
+ (mrk_range.bottom - mrk_range.top) == (cp_src_rec.bottom - cp_src_rec.top)) break;
+ if((mrk_range.right - mrk_range.left) == 1 && (cp_src_rec.right - cp_src_rec.left) > 1) break;
+ if((mrk_range.bottom - mrk_range.top) == 1 && (cp_src_rec.bottom - cp_src_rec.top) > 1) break;
+ }
+ delete cr; return true;
+ }
+ else switch(cmd){
+ case CMD_PASTE_TSV:
+ return ReadTSV(0L, (unsigned char*)txt, FF_TSV);
+ case CMD_PASTE_XML:
+ return ReadXML(0L, (unsigned char*)txt, FF_XML);
+ case CMD_PASTE_CSV:
+ return ReadData(0L, (unsigned char*)txt, FF_CSV);
+ }
+ return false;
+}
+
+bool
+SpreadData::InitCopy(int cmd, void *tmpl, anyOutput *o)
+{
+ int r, c;
+ AccRange *ar;
+ RECT rc_band;
+ bool bRet = false;
+
+ if(cmd) {
+ bCopyCut = (cmd == CMD_CUT);
+ if(rcCopy.right > cCols) rcCopy.right = cCols;
+ if(rcCopy.bottom > cRows) rcCopy.bottom = cRows;
+ new_mark = false;
+ if(m_range && m_range[0]) {
+ if(c_range) free(c_range); c_range = strdup(m_range);
+ if(c_range && (ar = new AccRange(c_range))) {
+ ar->BoundRec(&rcCopy);
+ delete ar; bRet = true;;
+ }
+ }
+ else if(GetCopyRange(&rcCopy, this)){
+ //The range is stored in TmpTxt
+ if(!TmpTxt[0]) return false;
+ if(m_range) free(m_range); if(c_range) free(c_range);
+ c_range = strdup(TmpTxt); m_range = strdup(TmpTxt);
+ DoPlot(o); bRet = true;
+ }
+ }
+ if(bRet || !cmd) { //calculate animated mark
+ if(rcCopy.right < Disp->ssOrg.x || rcCopy.bottom < Disp->ssOrg.y) {
+ HideCopyMark();
+ return bRet;
+ }
+ c = rcCopy.left >= Disp->ssOrg.x ? rcCopy.left : Disp->ssOrg.x;
+ r = rcCopy.top >= Disp->ssOrg.y ? rcCopy.top : Disp->ssOrg.y;
+ while(!etRows[r] && r) r--; while(!etRows[r][c] && c) c--;
+ if(etRows[r][c]){
+ rc_band.left = etRows[r][c]->GetX()-1; rc_band.top = etRows[r][c]->GetY()-1;
+ }
+ else return bRet;
+ c = rcCopy.right < (Disp->ssOrg.x + c_disp) ? rcCopy.right : Disp->ssOrg.x + c_disp;
+ r = rcCopy.bottom < (Disp->ssOrg.y + r_disp)? rcCopy.bottom : Disp->ssOrg.y + r_disp;
+ if(etRows[r][c]){
+ rc_band.right = etRows[r][c]->GetX()+CellWidth;
+ rc_band.bottom = etRows[r][c]->GetY()+CellHeight;
+ ShowCopyMark(o, &rc_band, 1);
+ }
+ }
+ return bRet;
+}
+
+bool
+SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i;
+ static int move_cr = CMD_CURRDOWN;
+ MouseEvent *mev;
+ POINT p, cp;
+
+ if(!o) o = w;
+ switch(cmd) {
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ p.x = mev->x; p.y = mev->y;
+ if((mev->StateFlags & 1) || mev->Action == MOUSE_LBUP) {
+ mpos2dpos(&p, &cp);
+ if(cp.y >= cRows || cp.x >= cCols || cp.y < 0 || cp.x < 0) return false;
+ }
+ switch (mev->Action) {
+ case MOUSE_LBDOWN:
+ bActive = true;
+ if(CurrText && !CurrText->isInRect(&p)){
+ CurrText->Update(2, w, &p); CurrText = 0L;
+ DoPlot(w);
+ }
+ if(p.x < FirstWidth) cp.x = 0;
+ if(p.y < (w->MenuHeight+CellHeight)) cp.y = 0;
+ currpos.y = currpos2.y = cp.y;
+ currpos.x = currpos2.x = cp.x;
+ case MOUSE_LBDOUBLECLICK: case MOUSE_MOVE:
+ if(!bActive) return false;
+ if(!m_range && !CurrText && cp.y < cRows && cp.x < cCols && cp.y >= 0 && cp.x >= 0)
+ CurrText = etRows[cp.y][cp.x];
+ if(mev->Action == MOUSE_MOVE && (mev->StateFlags & 1)
+ && !(CurrText && CurrText->isInRect(&p))) {
+ //mark rectangular range
+ if(!m_range && CurrText) {
+ CurrText->Update(2, w, &p); CurrText = 0L;
+ }
+ if(p.x < FirstWidth || p.y < (w->MenuHeight+CellHeight)) {
+ i = sprintf(TmpTxt, "%s%d:", Int2ColLabel(p.x < FirstWidth ? 0 : currpos.x, false),
+ p.y < (w->MenuHeight+CellHeight) ? 0 : currpos.y+1);
+ sprintf(TmpTxt+i, "%s%d", Int2ColLabel(p.x < FirstWidth ? cCols-1 : cp.x, false),
+ p.y < (w->MenuHeight+CellHeight) ? cRows : cp.y+1);
+ }
+ else {
+ i = sprintf(TmpTxt, "%s%d:", Int2ColLabel(currpos.x, false), currpos.y+1);
+ sprintf(TmpTxt+i, "%s%d", Int2ColLabel(cp.x, false), cp.y+1);
+ }
+ if(!CurrText)MarkRange(TmpTxt);
+ return true;
+ }
+ if(mev->Action == MOUSE_LBDOUBLECLICK) bActive = false;
+ if(!(mev->StateFlags & 1)) return false;
+ if(CurrText && CurrText->isInRect(&p)) {
+ return CurrText->Command(CMD_MOUSE_EVENT, o, (DataObj *)mev);
+ }
+ if(etRows[cp.y][cp.x])
+ return etRows[cp.y][cp.x]->Command(CMD_MOUSE_EVENT, o, (DataObj *)mev);
+ return false;
+ case MOUSE_LBUP:
+ if(bActive){
+ if(p.x < FirstWidth || p.y < (w->MenuHeight+CellHeight)) {
+ if(p.x < FirstWidth) {
+ currpos.x = 0; cp.x = cCols-1;
+ }
+ if(p.y < (w->MenuHeight+CellHeight)) {
+ currpos.y = 0; cp.y = cRows-1;
+ }
+ i = sprintf(TmpTxt, "%s%d:", Int2ColLabel(currpos.x, false), currpos.y+1);
+ sprintf(TmpTxt+i, "%s%d", Int2ColLabel(cp.x, false), cp.y+1);
+ MarkRange(TmpTxt);
+ currpos2.x = cp.x; currpos2.y = cp.y + 1;
+ }
+ if(m_range) {
+ CurrText = etRows[currpos.y][currpos.x]; CurrText->Update(1, w, &p);
+ DoPlot(w);
+ currpos2.x = cp.x; currpos2.y = cp.y;
+ }
+ else return Select(&p);
+ }
+ }
+ break;
+ case CMD_PASTE_TSV: case CMD_PASTE_XML: case CMD_PASTE_CSV:
+ if(PasteRange(cmd, (char*)tmpl)) return Disp->Command(CMD_SETSCROLL, 0L, w);
+ return false;
+ case CMD_CURRPOS:
+ if(tmpl) {
+ if(((POINT*)tmpl)->x < 0 && ((POINT*)tmpl)->y < 0) {
+ ((POINT*)tmpl)->x = currpos.x; ((POINT*)tmpl)->y = currpos.y;
+ return true;
+ }
+ }
+ return false;
+ case CMD_UNLOCK:
+ HideMark(false);
+ currpos2.x = currpos.x; currpos2.y = currpos.y;
+ break;
+ case CMD_ERROR:
+ err_msg = (char*)tmpl;
+ break;
+ case CMD_CLEAR_ERROR:
+ err_msg = 0L;
+ break;
+ case CMD_TOOLMODE:
+ HideMark(true);
+ if(CurrText) CurrText->Update(2, w, 0L);
+ if(CurrText) CurrText->Update(1, w, 0L);
+ break;
+ case CMD_UPDHISTORY:
+ if(w) w->FileHistory();
+ break;
+ case CMD_MRK_DIRTY:
+ if(Disp) return Disp->Command(cmd, tmpl, o);
+ return false;
+ case CMD_ADDCHAR:
+ if(CurrText){
+ if(currpos.y < Disp->ssOrg.y) {
+ Disp->ssOrg.y = currpos.y; DoPlot(o);
+ }
+ else if(currpos.y > (Disp->ssOrg.y + r_disp -3)) {
+ Disp->ssOrg.y = currpos.y - (r_disp-3);
+ if(Disp->ssOrg.y < 0) Disp->ssOrg.y = 0; DoPlot(o);
+ }
+ if(currpos.x < Disp->ssOrg.x) {
+ Disp->ssOrg.x = currpos.x; DoPlot(o);
+ }
+ else if(currpos.x > (Disp->ssOrg.x + c_disp -3)) {
+ Disp->ssOrg.x = currpos.x - (c_disp-3);
+ if(Disp->ssOrg.x < 0) Disp->ssOrg.x = 0; DoPlot(o);
+ }
+ currpos2.x = currpos.x; currpos2.y = currpos.y;
+ i = *((int*)tmpl);
+ if(i == 27) return Command(CMD_TOOLMODE, tmpl, o);
+ if(i !=3 && i != 22 && i != 24) HideMark(true); //Do not hide upon ^C, ^V, ^X
+ if(i == 13) return CurrText->Command(move_cr, w, this);
+ switch(i) {
+ case 8: return CurrText->Command(CMD_BACKSP, w, this); //Backspace
+ default: return CurrText->AddChar(*((int*)tmpl), w, Disp);
+ }
+ }
+ else {
+ currpos.x = currpos2.x = Disp->ssOrg.x; currpos.y = currpos2.y = Disp->ssOrg.y;
+ if(etRows[currpos.x] && (CurrText = etRows[currpos.x][currpos.y]))
+ CurrText->Update(1, w, &p);;
+ }
+ break;
+ case CMD_SHIFTUP:
+ currpos2.y -= 2;
+ case CMD_SHIFTDOWN:
+ currpos2.y ++;
+ if(currpos2.y >= cRows) currpos2.y --; if(currpos2.y < 0) currpos2.y ++;
+ //mark rectangular range
+ i = sprintf(TmpTxt, "%s%d:", Int2ColLabel(currpos.x, false), currpos.y+1);
+ sprintf(TmpTxt+i, "%s%d", Int2ColLabel(currpos2.x, false), currpos2.y+1);
+ MarkRange(TmpTxt);
+ break;
+ case CMD_SHIFTRIGHT: case CMD_SHIFTLEFT:
+ if(!m_range && CurrText && CurrText->Command(cmd, w, this)) break;
+ if(cmd == CMD_SHIFTLEFT) currpos2.x --;
+ else currpos2.x ++;
+ if(currpos2.x >= cCols) currpos2.x --; if(currpos2.x < 0) currpos2.x ++;
+ //mark rectangular range
+ i = sprintf(TmpTxt, "%s%d:", Int2ColLabel(currpos.x, false), currpos.y+1);
+ sprintf(TmpTxt+i, "%s%d", Int2ColLabel(currpos2.x, false), currpos2.y+1);
+ MarkRange(TmpTxt);
+ break;
+ case CMD_CURRIGHT: case CMD_CURRDOWN:
+ move_cr = cmd;
+ case CMD_CURRLEFT: case CMD_CURRUP: case CMD_POS_FIRST: case CMD_POS_LAST:
+ if(cmd == CMD_CURRUP && Disp->ssOrg.y && CurrText && currpos.y == Disp->ssOrg.y) {
+ Disp->ssOrg.y --; currpos.y --;
+ DoPlot(o);
+ }
+ if(cmd == CMD_CURRLEFT && Disp->ssOrg.x && CurrText && (!CurrText->Cursor()) && (currpos.x == Disp->ssOrg.x)) {
+ Disp->ssOrg.x --; currpos.x --;
+ CurrText->Update(2, o, 0L);
+ if(etRows && etRows[currpos.y] && etRows[currpos.y][currpos.x])
+ CurrText = etRows[currpos.y][currpos.x];
+ if(CurrText){
+ CurrText->Command(CMD_POS_LAST, o, this); CurrText->Update(1, o, 0L);
+ }
+ DoPlot(o); return false;
+ }
+ if(cmd == CMD_CURRIGHT && c_disp > 3 && (currpos.x-Disp->ssOrg.x) >= (c_disp-3)) {
+ Disp->ssOrg.x ++; currpos.y ++; DoPlot(o);
+ if(CurrText) CurrText->Command(CMD_POS_FIRST, o, this);
+ }
+ if(cmd == CMD_CURRDOWN && r_disp > 3 && (currpos.y-Disp->ssOrg.y) >= (r_disp-3)) {
+ Disp->ssOrg.y ++; currpos.y ++; DoPlot(o);
+ }
+ if(err_msg) ErrorBox(err_msg); err_msg = 0L;
+ HideMark(false);
+ if(CurrText)return CurrText->Command(cmd, w, this);
+ else {
+ currpos.x = currpos2.x = Disp->ssOrg.x; currpos.y = currpos2.y = Disp->ssOrg.y;
+ if(etRows[currpos.y] && (CurrText = etRows[currpos.y][currpos.x]))
+ CurrText->Update(1, w, &p);;
+ }
+ return false;
+ case CMD_SHTAB:
+ if(currpos.y >= cRows) currpos.y = cRows-1;
+ if(currpos.x == Disp->ssOrg.x && Disp->ssOrg.x > 0) {
+ Disp->ssOrg.x -= 1;
+ Disp->Command(CMD_SETSCROLL, 0L, w);
+ }
+ if(currpos.x > Disp->ssOrg.x && etRows[currpos.y][currpos.x]) {
+ currpos.x -=1;
+ }
+ case CMD_TAB:
+ if(currpos.y >= cRows) currpos.y = cRows-1;
+ if(cmd == CMD_TAB && currpos.x < (cCols-1) && etRows[currpos.y][currpos.x]) {
+ if((FirstWidth+(currpos.x - Disp->ssOrg.x +2)*CellWidth) > Disp->currRC.right){
+ Disp->ssOrg.x += 1;
+ Disp->Command(CMD_SETSCROLL, 0L, w);
+ }
+ currpos.x +=1;
+ }
+ if(CurrText) CurrText->Update(2, w, &p);
+ CurrText = etRows[currpos.y][currpos.x];
+ if(CurrText){
+ CurrText->Update(1, w, &p);
+ CurrText->Command(cmd == CMD_TAB ? CMD_POS_FIRST : CMD_POS_LAST, o, this);
+ }
+ return true;
+ case CMD_DELETE:
+ if(m_range) DelRange();
+ else if(CurrText) return CurrText->Command(cmd, o, this);
+ return true;
+ case CMD_QUERY_COPY: case CMD_CUT:
+ return InitCopy(cmd, tmpl, w);
+ case CMD_GET_CELLDIMS:
+ if(tmpl) {
+ ((int*)tmpl)[0] = FirstWidth; ((int*)tmpl)[1] = CellWidth;
+ ((int*)tmpl)[2] = CellHeight;
+ }
+ break;
+ case CMD_SET_CELLDIMS:
+ if(tmpl) {
+ FirstWidth = ((int*)tmpl)[0]; CellWidth = ((int*)tmpl)[1];
+ CellHeight = ((int*)tmpl)[2];
+ }
+ break;
+ case CMD_TEXTSIZE:
+ if(tmpl){
+ CellHeight = *((int*)tmpl);
+ return Disp->Command(cmd, tmpl, o);
+ }
+ return false;
+ case CMD_COPY_TSV:
+ return MemList((unsigned char**)tmpl, FF_TSV);
+ case CMD_COPY_SYLK:
+ return MemList((unsigned char**)tmpl, FF_SYLK);
+ case CMD_COPY_XML:
+ return MemList((unsigned char**)tmpl, FF_XML);
+ case CMD_REDRAW: case CMD_DOPLOT:
+ DoPlot(o);
+ break;
+ case CMD_FILLRANGE:
+ FillSsRange(this, &m_range);
+ DoPlot(o);
+ break;
+ }
+ return true;
+}
+
+bool
+SpreadData::ReadXML(char *file, unsigned char *buffer, int type)
+{
+ int i, row, col, tag, cpgr, spgr;
+ bool bContinue, bRet = false;
+ ReadCache *XMLcache;
+ POINT pt, mov;
+ char TmpTxt[1024], *tmp_range;
+ unsigned char *pgr = 0L;
+
+ if(file) {
+ if(!(XMLcache = new ReadCache())) return false;
+ if(! XMLcache->Open(file)) {
+ delete XMLcache;
+ sprintf(TmpTxt, "Error open file\n\"%s\"", file);
+ ErrorBox(TmpTxt);
+ return false;
+ }
+ if(!Init(1, 1)) goto XMLError;
+ etRows[0][0]->SetText("");
+ }
+ else if(buffer && type == FF_XML){
+ if(!(XMLcache = new MemCache(buffer))) return false;
+ if(buffer && bCopyCut) {
+ tmp_range = m_range; m_range = c_range;
+ c_range = 0L; DelRange();
+ m_range = tmp_range;
+ }
+ }
+ else return false;
+ pt.x = pt.y = mov.x = mov.y = 0;
+ cp_src_rec.left = cp_src_rec.right = cp_src_rec.top = cp_src_rec.bottom = 0;
+ do {
+ row = col = 0;
+ do {
+ TmpTxt[0] = XMLcache->Getc();
+ }while(TmpTxt[0] && TmpTxt[0] != '<');
+ for(i = 1; i < 5; TmpTxt[i++] = XMLcache->Getc());
+ TmpTxt[i] = 0;
+ if(!strcmp("<cell", TmpTxt)) tag = 1;
+ else if(!strcmp("<pos1", TmpTxt)) tag = 2;
+ else if(!strcmp("<pos2", TmpTxt)) tag = 3;
+ else if(!strcmp("<Grap", TmpTxt)){
+ while(XMLcache->Getc() != '[');
+ pgr = (unsigned char*)malloc(spgr = 1000);
+ pgr[0] = '['; cpgr = 1;
+ do {
+ pgr[cpgr++] = XMLcache->Getc();
+ if(cpgr >= spgr) pgr = (unsigned char*)realloc(pgr, spgr +=1000);
+ }while(!(pgr[cpgr-1] == '<' && pgr[cpgr-2] == 0x0a));
+ pgr[cpgr-2] = 0;
+ while(XMLcache->Getc() != 0x0a);
+ OpenGraph(Disp, 0L, pgr);
+ free(pgr); tag = 0;
+ }
+ else tag = 0;
+ if(tag) {
+ do {
+ TmpTxt[0] = XMLcache->Getc();
+ }while(TmpTxt[0] && TmpTxt[0] != '"');
+ if (TmpTxt[0]) for (i =0; i <10 && ('"' != (TmpTxt[i] =XMLcache->Getc())); i++){
+ TmpTxt[i+1] = 0;
+ row = (int)atoi(TmpTxt);
+ }
+ do {
+ TmpTxt[0] = XMLcache->Getc();
+ }while(TmpTxt[0] && TmpTxt[0] != '"');
+ if (TmpTxt[0]) for (i =0; i <10 && ('"' != (TmpTxt[i] =XMLcache->Getc())); i++){
+ TmpTxt[i+1] = 0;
+ col = (int)atoi(TmpTxt);
+ }
+ if(tag ==2) {
+ mov.x = col; mov.y = row;
+ cp_src_rec.left = col; cp_src_rec.top = row;
+ }
+ else if(tag ==3) {
+ cp_src_rec.right = col; cp_src_rec.bottom = row;
+ }
+ else if(row && col) do {
+ do {
+ TmpTxt[0] = XMLcache->Getc();
+ }while(TmpTxt[0] && TmpTxt[0] != '<');
+ for(i = 1; i < 6; TmpTxt[i++] = XMLcache->Getc());
+ TmpTxt[i] = 0;
+ if(bContinue =(0 == strcmp("<text>", TmpTxt))) {
+ for(i = 0; i < 1023 && ('<' != (TmpTxt[i] =XMLcache->Getc())); i++);
+ TmpTxt[i] = 0;
+ //xml indices start at 1:1 !
+ row += currpos.y-1; col += currpos.x-1;
+ if(row >= cRows)AddRows(row+1);
+ if(col >= cCols)AddCols(col+1);
+ if(i && etRows[row] && etRows[row][col]) {
+ if(TmpTxt[0] == '=') {
+ MoveFormula(this, TmpTxt, TmpTxt, currpos.x-mov.x, currpos.y-mov.y);
+ }
+ etRows[row][col]->SetText(TmpTxt);
+ etRows[row][col]->Update(20, 0L, &pt);
+ }
+ }
+ }while(!bContinue);
+ }
+ }while(!XMLcache->IsEOF());
+ bRet = true;
+XMLError:
+ XMLcache->Close();
+ delete XMLcache;
+ bCopyCut = false;
+ return bRet;
+}
+
+bool
+SpreadData::ReadTSV(char *file, unsigned char *buffer, int type)
+{
+ int i, row, col;
+ char c;
+ bool bRet = false;
+ ReadCache *TSVcache;
+ POINT pt;
+
+ if(file) {
+ if(!(TSVcache = new ReadCache())) return false;
+ if(! TSVcache->Open(file)) {
+ delete TSVcache;
+ sprintf(TmpTxt, "Error open file\n\"%s\"", file);
+ ErrorBox(TmpTxt);
+ return false;
+ }
+ if(!Init(1, 1)) goto TSVError;
+ etRows[0][0]->SetText("");
+ }
+ else if(buffer && type == FF_TSV) {
+ if(!(TSVcache = new MemCache(buffer))) return false;
+ }
+ else return false;
+ row = currpos.y; col = currpos.x;
+ pt.x = pt.y = 0;
+ do {
+ do {
+ TmpTxt[0] = TSVcache->Getc();
+ switch(TmpTxt[0]) {
+ case 0x0d: //CR
+ case 0x0a: //LF
+ if(col == currpos.x) break;
+ row ++; col = currpos.x; break;
+ case 0x09: //tab
+ col ++; break;
+ }
+ }while(TmpTxt[0] && TmpTxt[0] < 33);
+ for(i = 1; (TmpTxt[i] = c = TSVcache->Getc())>=32; i++)
+ if(i >= 4094) i = 4094;
+ if(TmpTxt[0] && row >= cRows)AddRows(row+1);
+ if(TmpTxt[0] && col >= cCols)AddCols(col+1);
+ TmpTxt[i] = 0;
+ if(TmpTxt[0] && etRows[row] && etRows[row][col]) {
+ etRows[row][col]->SetText(TmpTxt);
+ etRows[row][col]->Update(20, 0L, &pt);
+ switch(c) {
+ case 0x0d: //CR
+ case 0x0a: //LF
+ row ++; col = currpos.x; break;
+ case 0x09: //tab
+ col ++; break;
+ }
+ }
+ }while(!TSVcache->IsEOF());
+ bRet = true;
+TSVError:
+ TSVcache->Close();
+ delete TSVcache;
+ return bRet;
+}
+
+bool
+SpreadData::MemList(unsigned char **ptr, int type)
+{
+ int i, j, k, nc, nl, cb = 0;
+ long cbd = 0, size;
+ char tmptxt[8000];
+ double val;
+ *ptr = (unsigned char *)malloc(size = 10000);
+ unsigned char *tmpptr;
+ bool bLimit = true;
+
+ if(!(*ptr))return false;
+ if(rcCopy.left < 0) rcCopy.left = 0;
+ if(rcCopy.right >= cCols) rcCopy.right = cCols-1;
+ if(rcCopy.top < 0) rcCopy.top = 0;
+ if(rcCopy.bottom >= cRows) rcCopy.bottom = cRows-1;
+ if(type == FF_SYLK) cbd = sprintf((char*)*ptr, "ID;\n");
+ else if(type == FF_XML) {
+ cbd = sprintf((char*)*ptr, "<?xml version=\"1.0\"?><!DOCTYPE spreadsheet-snippet>"
+ "<spreadsheet-snippet rows=\"%d\" columns=\"%d\" >\n", cRows, cCols);
+ if(rcCopy.left || rcCopy.top || rcCopy.bottom || rcCopy.right){
+ cbd += sprintf((char*)*ptr+cbd, " <pos1 row=\"%d\" "
+ "column=\"%d\"></pos1>\n", rcCopy.top, rcCopy.left);
+ cbd += sprintf((char*)*ptr+cbd, " <pos2 row=\"%d\" "
+ "column=\"%d\"></pos2>\n", rcCopy.bottom, rcCopy.right);
+ }
+ }
+ else if(type == FF_RLW) {
+ cbd = sprintf((char*)*ptr, "<?xml version=\"1.0\"?><!DOCTYPE RLPlot-workbook>\n"
+ "<RLPlot-data rows=\"%d\" columns=\"%d\" >\n", cRows, cCols);
+ }
+ for(nl =0, i = rcCopy.top; i <= rcCopy.bottom; i++, nl++) {
+ for(nc = 0, j = rcCopy.left; j <= rcCopy.right; cb = 0, j++, nc++) {
+ switch (type) {
+ case FF_TSV:
+ if(nl || nc) cb = sprintf(tmptxt,"%s", nc ? "\t" : "\n");
+ if(etRows[i] && etRows[i][j] && etRows[i][j]->text){
+ for(k = 0; k < 7990 && (etRows[i][j]->text[k]); k++)
+ tmptxt[cb++] = etRows[i][j]->text[k];
+ tmptxt[cb] = 0;
+ }
+ break;
+ case FF_SYLK:
+ if(etRows[i] && etRows[i][j] && etRows[i][j]->text){
+ cb = sprintf(tmptxt, "C;Y%d;X%d;K", nl+1, nc+1);
+ if(etRows[i][j]->GetValue(&val)){
+ cb += sprintf(tmptxt+cb, "%lf", val);
+ while(tmptxt[cb-1] == '0') tmptxt[--cb] = 0;
+ if(tmptxt[cb-1] == '.') tmptxt[--cb] = 0;
+ cb += sprintf(tmptxt+cb, "\n");
+ }
+ else {
+ etRows[i][j]->GetItem(TmpTxt, 258);
+ cb += sprintf(tmptxt+cb, "%s\n", TmpTxt);
+ if(cb >= 267) bLimit = false;
+ }
+ }
+ break;
+ case FF_RLW: case FF_XML:
+ if(etRows[i] && etRows[i][j] && etRows[i][j]->text){
+ cb = sprintf(tmptxt, " <cell row=\"%d\" column=\"%d\" >\n", nl+1, nc+1);
+ cb += sprintf(tmptxt+cb, " <text>");
+ for(k = 0; k < 7880 && (etRows[i][j]->text[k]); k++)
+ tmptxt[cb++] = etRows[i][j]->text[k];
+ cb += sprintf(tmptxt+cb, "</text>\n </cell>\n");
+ }
+ break;
+ }
+ if((cbd+cb+100) > size){
+ if(tmpptr = (unsigned char*)realloc(*ptr, size+10000)) {
+ *ptr = tmpptr; size += 10000;
+ }
+ else return true; //not all but something on clipboard
+ }
+ memcpy(*ptr+cbd, tmptxt, cb+1);
+ cbd += cb;
+ }
+ if(type == FF_SYLK) {
+ if(!bLimit) {
+ cbd += sprintf((char*)*ptr+cbd, "C;Y%d;X1;K\"long strings were"
+ " truncated to 256 characters due to limitations of the SYLK format!\"\n", i+2);
+ }
+ sprintf((char*)*ptr+cbd, "E\n");
+ }
+ else if(type == FF_TSV) sprintf((char*)*ptr+cbd,"\n");
+ }
+ if(type == FF_XML) sprintf((char*)*ptr+cbd,"</spreadsheet-snippet>\n");
+ else if(type == FF_RLW){
+ Disp->Command(CMD_WRITE_GRAPHS, ptr, (anyOutput*)&cbd);
+ sprintf((char*)*ptr+cbd,"</RLPlot-data>\n");
+ //note: cbd may be greater than size !
+ }
+ return true;
+}
+
+void SpreadMain(bool show)
+{
+ static SpreadData *w = 0L;
+
+ if(show) {
+ w = new SpreadData();
+ if(!w ||!(w->Init(10, 10))){
+ delete w;
+ w = 0L;
+ }
+ do_formula(w, 0L); //init mfcalc
+ }
+ else if (w) {
+ delete(w);
+ }
+}
+
+
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/rlplot.git
More information about the debian-science-commits
mailing list