[rlplot] 18/23: Imported Upstream version 1.5
Andreas Tille
tille at debian.org
Wed Jun 29 09:50:58 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 2b3b5e36c7bb7c21c334e92a26b71c69939ec67e
Author: Andreas Tille <tille at debian.org>
Date: Wed Jun 29 11:43:58 2016 +0200
Imported Upstream version 1.5
---
.kdbgrc.rlplot | 18 +
Axes.cpp | 4130 ++++++-----
Export.cpp | 2170 +++---
Fileio.cpp | 7985 ++++++++++-----------
Makefile | 42 +-
ODbuttons.cpp | 3084 ++++----
Output.cpp | 3919 +++++------
PlotObs.cpp | 11865 ++++++++++++++++---------------
PropertyDlg.cpp | 19991 ++++++++++++++++++++++++++--------------------------
QT3_Spec.h | 17 +-
QT_Spec.cpp | 411 +-
QT_Spec.h | 16 +-
RLPLOT.RC | 307 +
TheDialog.cpp | 9974 +++++++++++++-------------
TheDialog.h | 1120 +--
UtilObj.cpp | 8115 ++++++++++-----------
Utils.cpp | 5022 ++++++-------
Version.h | 4 +-
WinSpec.cpp | 378 +-
WinSpec.h | 9 +-
exprlp.cpp | 488 +-
menu.h | 213 +-
mfcalc.cpp | 1096 +--
mfcalc.y | 241 +-
no_gui.cpp | 1175 ++--
reports.cpp | 6323 +++++++++--------
rlp_math.cpp | 5235 +++++++-------
rlplot.cpp | 20483 +++++++++++++++++++++++++++---------------------------
rlplot.h | 6018 ++++++++--------
rlplot.spec | 5 +-
rlplot.spec~ | 70 -
spreadwi.cpp | 5293 +++++++-------
use_gui.cpp | 3870 ++++++-----
33 files changed, 65888 insertions(+), 63199 deletions(-)
diff --git a/.kdbgrc.rlplot b/.kdbgrc.rlplot
new file mode 100644
index 0000000..284dc15
--- /dev/null
+++ b/.kdbgrc.rlplot
@@ -0,0 +1,18 @@
+[Breakpoint 0]
+Enabled=true
+File=/home/c71960/rlplot/Axes.cpp
+Line=684
+Temporary=false
+
+[General]
+DebuggerCmdStr=
+DriverName=GDB
+FileVersion=1
+OptionsSelected=
+ProgramArgs=
+TTYLevel=7
+WorkingDirectory=
+
+[Memory]
+ColumnWidths=80,0
+NumExprs=0
diff --git a/Axes.cpp b/Axes.cpp
index 7d81b99..90255a7 100755
--- a/Axes.cpp
+++ b/Axes.cpp
@@ -1,1888 +1,2242 @@
-//Axes.cpp, Copyright 2000-2007 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;
- }
- if(pts[0].x != pts[1].x || pts[0].y != pts[1].y){
- o->oPolyline(pts, 2);
- SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
- }
- if(pts[2].x != pts[3].x || pts[2].y != pts[3].y){
- o->oPolyline(pts+2, 2);
- SetMinMaxRect(&rDims, pts[2].x, pts[2].y, pts[3].x, pts[3].y);
- }
- IncrementMinMaxRect(&rDims, 3);
- }
-}
-
-void
-GridLine::DoMark(anyOutput *o, bool mark)
-{
- if(mark){
- if(mo) DelBitmapClass(mo); mo = 0L;
- memcpy(&mrc, &rDims, sizeof(RECT));
- IncrementMinMaxRect(&mrc, 6 + o->un2ix(LineDef.width));
- mo = GetRectBitmap(&mrc, o);
- if(type & DL_CIRCULAR) {
- InvertLine(cpts, ncpts, &LineDef, &rDims, o, mark);
- }
- else {
- if(pts[0].x != pts[1].x || pts[0].y != pts[1].y)InvertLine(pts, 2, &LineDef, &rDims, o, mark);
- if(pts[2].x != pts[3].x || pts[2].y != pts[3].y)InvertLine(pts+2, 2, &LineDef, &rDims, o, mark);
- }
- }
- else RestoreRectBitmap(&mo, &mrc, o);
-}
-
-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_SCALE:
- LineDef.patlength *= ((scaleINFO*)tmpl)->sy.fy;
- LineDef.width *= ((scaleINFO*)tmpl)->sy.fy;
- 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(CurrGO = this, MRK_GODRAW);
- return true;
- }
- else if(!(type & DL_CIRCULAR)){
- o->ShowMark(CurrGO = this, MRK_GODRAW);
- 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(mo) DelBitmapClass(mo); mo = 0L;
- 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*));
- if(!(o->ActualSize(&rDims)))return;
- 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) {
- if(mo) DelBitmapClass(mo); mo = 0L;
- 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){
- if(mo) DelBitmapClass(mo); mo = 0L;
- memcpy(&mrc, &rDims, sizeof(RECT));
- IncrementMinMaxRect(&mrc, 6 + (parent && parent->Id == GO_AXIS) ? o->un2ix(((Axis*)parent)->axline.width):o->iLine);
- 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;
- AxisDEF *axis;
-
- switch(cmd){
- case CMD_SCALE:
- if(label) label->Command(cmd, tmpl, o);
- if(Grid) Grid->Command(cmd, tmpl, o);
- size *= ((scaleINFO*)tmpl)->sy.fy;
- break;
- case CMD_SET_AXDEF:
- if(axis = (AxisDEF*)tmpl) {
- flags = (flags & AXIS_MINORTICK) | axis->flags;
- }
- break;
- 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_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_TEXTTHERE:
- if(label && label->Command(cmd, tmpl, o)) return true;
- return false;
- 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)) {
- 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) : DefSize(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) ? (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1, 0) : 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;
- ip2.x = ip2.y = ip2.z = 0;
- 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(DefSize(SIZE_AXIS_TICKS)*3.0*six));
- lby -= (o->un2fiy(DefSize(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;
- if(atv) delete atv; atv = 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;
- case SIZE_BOUNDS_XMIN: case SIZE_BOUNDS_XMAX: case SIZE_BOUNDS_YMIN:
- case SIZE_BOUNDS_YMAX: case SIZE_BOUNDS_ZMIN: case SIZE_BOUNDS_ZMAX:
- if(parent) return parent->GetSize(select);
- break;
- }
- return DefSize(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(IsPlot3D(parent) && (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);
-}
-
-bool
-Axis::Command(int cmd, void *tmpl, anyOutput *o)
-{
- MouseEvent *mev;
- GraphObj **tmpPlots;
- void *sv_ptr;
- scaleINFO *scale;
- int i;
-
- switch (cmd) {
- case CMD_SCALE:
- if(!Ticks && (axis->flags & 0x03) != AXIS_NOTICKS)CreateTicks();
- scale = (scaleINFO*)tmpl;
- lbdist.fx *= scale->sx.fy; lbdist.fy *= scale->sy.fy;
- tlbdist.fx *= scale->sx.fy; tlbdist.fy *= scale->sy.fy;
- sizAxTickLabel *= scale->sy.fy; sizAxTick *= scale->sy.fy;
- sizAxLine *= scale->sy.fy; brksymsize *= scale->sy.fy;
- brkgap *= scale->sy.fy; GridLine.patlength *= scale->sy.fy;
- GridLine.width *= scale->sy.fy; tlbdef.fSize *= scale->sy.fy;
- axis->loc[0].fx *= scale->sx.fy; axis->loc[1].fx *= scale->sx.fy;
- axis->loc[0].fy *= scale->sy.fy; axis->loc[1].fy *= scale->sy.fy;
- axis->loc[0].fz *= scale->sz.fy; axis->loc[1].fz *= scale->sz.fy;
- axis->Center.fx *= scale->sx.fy; axis->Center.fy *= scale->sy.fy;
- axis->Radius *= scale->sy.fy; tlbdef.iSize = 0;
- if(axisLabel) axisLabel->Command(cmd, tmpl, o);
- if(Ticks) for(i = 0; i < NumTicks; i++) if(Ticks[i]) Ticks[i]->Command(cmd, tmpl, o);
- return true;
- 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)) {
- 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_TEXTTHERE:
- 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(axis = (AxisDEF*)tmpl) {
- if(axis && axis->owner == (void*)this) {
- if(axis->breaks) free(axis->breaks);
- free(axis);
- }
- if(Ticks) for(i = 0; i < NumTicks; i++)
- if(Ticks[i]) {
- Ticks[i]->Command(cmd, tmpl, o);
- Ticks[i]->Command(CMD_SET_GRIDTYPE, (void*) &gl_type, 0L);
- Ticks[i]->Command(CMD_TLB_TXTDEF, &tlbdef, 0L);
- if(axis->flags & AXIS_GRIDLINE) Ticks[i]->Command(CMD_SET_GRIDLINE, &GridLine, 0L);
- Ticks[i]->SetSize(SIZE_TICK_ANGLE, tick_angle);
- Ticks[i]->SetSize(SIZE_AXIS_TICKS, sizAxTick);
- Ticks[i]->SetSize(SIZE_LB_XDIST, tlbdist.fx);
- Ticks[i]->SetSize(SIZE_LB_YDIST, tlbdist.fy);
- Ticks[i]->Command(CMD_TICK_TYPE, &tick_type, 0L);
- }
- return true;
- }
- return false;
- case CMD_CAN_CLOSE:
- 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(DeleteGOL((GraphObj***) &Ticks, NumTicks, (GraphObj *)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);
- }
- if(Ticks && NumTicks) for(i = 0; i < NumTicks; i++){
- if(Ticks[i] && Ticks[i]->Command(cmd, tmpl, 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;
- 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 = (char*)memdup(TmpTxt+1, (int)strlen(TmpTxt+1)+1, 0);
- }
- else l = (char*)memdup(txt, (int)strlen(txt)+1, 0);
- 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::mkTimeAxis()
-{
- int nstep, mode;
- double span, val;
- rlp_datetime start, step;
- static char *tick_formats[] = {"y", "Y", "W", "x", "Z.V.", "d", "H:M", "d"};
-
- span = axis->max - axis->min;
- memset(&step, 0, sizeof(rlp_datetime)); parse_datevalue(&start, axis->Start);
- start.hours=start.minutes=start.doy = 0; start.seconds = val = 0.0;
- if(span > 60.0) start.dow = 1;
- if(span > 24000.0) {
- step.year = start.month = start.dom = 1;
- nstep = 2 + (int)(span / 364.0); mode = 0;
- }
- else if(span > 700.0) {
- step.month = start.month = start.dom = 1;
- nstep = 2 + (int)(span / 28.0); mode = 1;
- }
- else if(span > 300.0) {
- step.month = start.dom = 1;
- nstep = 2 + (int)(span / 28.0); mode = 2;
- }
- else if(span > 150.0) {
- step.month = start.dom = 1;
- nstep = 2 + (int)(span / 28.0); mode = 3;
- }
- else if(span > 60.0) {
- step.dom = 1;
- nstep = 6 + (int)(span/7.0); mode = 4;
- }
- else if(span > 8.0) {
- step.dom = 1;
- nstep = 2+(int)(span); mode = 5;
- }
- else if(span > 2.0) {
- step.hours = 6;
- nstep = 4+(int)(span*4.0); mode = 6;
- }
- else if(span > 0.5) {
- step.hours = (span > 0.9 ? 2 : 1);
- nstep = 4+(int)(span*24.0); mode = 7;
- }
- else if(span > 0.05) {
- step.minutes = (span > 0.3 ? (span > 0.4 ? 30 : 15) : (span <= 0.1 ? 5 : 10));
- nstep = 100; mode = 8;
- }
- else if(span > 0.005) {
- step.minutes = 1;
- nstep = 100; mode = 8;
- }
- else return;
- if(nstep < 50) nstep = 50; add_date(&start, 0L);
- if(!(Ticks = (Tick**)calloc(nstep, sizeof(Tick*))))return;
- for(NumTicks = 0; NumTicks < nstep && val <= axis->max; NumTicks++) {
- val = date2value(&start);
- switch(mode) {
- case 0:
- if((start.year%10) == 0) SetTick(NumTicks, val, axis->flags, date2text(&start, tick_formats[0]));
- else NumTicks--; break;
- case 1:
- if(start.month == 1){
- if(span <= 6000.0 || (span <= 12000.0 && (start.year%5) == 0) || (span <= 24000.0 && (start.year%10) == 0))
- SetTick(NumTicks, val, axis->flags, date2text(&start,
- (span > 3000.0 && span < 12000.0)?tick_formats[0] : tick_formats[1]));
- else NumTicks--;
- }
- else if(span <= 1500.0) SetTick(NumTicks, val, axis->flags | AXIS_MINORTICK,
- date2text(&start, tick_formats[4]));
- else NumTicks--; break;
- case 2:
- SetTick(NumTicks, val, axis->flags, date2text(&start, start.month==1 ? tick_formats[0]:tick_formats[2]));
- break;
- case 3:
- SetTick(NumTicks, val, axis->flags, date2text(&start, tick_formats[3]));
- break;
- case 4:
- if(start.dom == 1)SetTick(NumTicks, val, axis->flags, date2text(&start, tick_formats[3]));
- else if(start.dow == 1) SetTick(NumTicks, val, axis->flags | AXIS_MINORTICK, date2text(&start, tick_formats[4]));
- else NumTicks--; break;
- case 5:
- if(start.dow == 1) SetTick(NumTicks, val, axis->flags, date2text(&start, tick_formats[4]));
- else if(span < 30.0)SetTick(NumTicks, val, axis->flags | AXIS_MINORTICK, date2text(&start, tick_formats[7]));
- else NumTicks--; break;
- case 6:
- if(start.hours == 0) SetTick(NumTicks, val, axis->flags, date2text(&start, tick_formats[4]));
- else SetTick(NumTicks, val, axis->flags | AXIS_MINORTICK, date2text(&start, tick_formats[6]));
- break;
- case 7:
- if(start.hours == 0) SetTick(NumTicks, val, axis->flags, date2text(&start, tick_formats[5]));
- else if((start.hours % 6) == 0) SetTick(NumTicks, val, axis->flags, date2text(&start, tick_formats[6]));
- else SetTick(NumTicks, val, axis->flags | AXIS_MINORTICK, date2text(&start, tick_formats[6]));
- break;
- case 8:
- if(start.minutes == 0){
- if(span <= 0.3 || (start.hours %2) == 0) SetTick(NumTicks, val, axis->flags,
- date2text(&start, tick_formats[6]));
- else SetTick(NumTicks, val, axis->flags, "");
- }
- else SetTick(NumTicks, val, axis->flags | AXIS_MINORTICK, date2text(&start, tick_formats[6]));
- break;
- }
- add_date(&start, &step);
- }
-}
-
-void
-Axis::CreateTicks()
-{
- int i, n, nstep;
- char *format, *tick_label;
- double fVal, tmp;
- DWORD flags;
-
- if(axis->min == -HUGE_VAL || axis->min == HUGE_VAL) return;
- if(axis->max == -HUGE_VAL || axis->max == HUGE_VAL) return;
- if(axis->min >= axis->max) return;
- 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_DATETIME) {
- mkTimeAxis(); return;
- }
- if(atv && (nstep = atv->Count()) && (Ticks = (Tick**)calloc(nstep+1, sizeof(Tick*)))) {
- for(NumTicks = i = n = 0; NumTicks < nstep && atv->GetItem(i, &tick_label, &fVal); i++) {
- SetTick(NumTicks, fVal, axis->flags, tick_label);
- NumTicks++; n += (int)strlen(tick_label);
- }
- type = type;
-#ifdef _WINDOWS
- if(type == 1 && n > 40) {
- tlbdef.RotBL = n >100 ? 90.0 : 45.0; tlbdef.Align = TXA_HRIGHT | TXA_VCENTER;
- tlbdist.fy = sizAxTick; SetSize(SIZE_TLB_YDIST, tlbdist.fy);
- Command(CMD_TLB_TXTDEF, &tlbdef, 0L);
- }
-#else
- if(type == 1 && n > 30) {
- tlbdef.RotBL = n >70 ? 90.0 : 45.0; tlbdef.Align = TXA_HRIGHT | TXA_VCENTER;
- tlbdist.fy = sizAxTick; SetSize(SIZE_TLB_YDIST, tlbdist.fy);
- Command(CMD_TLB_TXTDEF, &tlbdef, 0L);
- }
-#endif
- return;
- }
- 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) {
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, format, fVal);
-#else
- sprintf(TmpTxt, format, fVal);
-#endif
- 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++) {
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, format, fVal);
-#else
- sprintf(TmpTxt, format, fVal);
-#endif
- SetTick(NumTicks, fVal, flags, TmpTxt);
- for(j = 0; j < n; j++) {
- mival = fVal+mist*(double)j +mist;
- if(mival < axis->max) {
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, format, mival);
-#else
- sprintf(TmpTxt, format, mival);
-#endif
- NumTicks++;
- SetTick(NumTicks, mival, flags | AXIS_MINORTICK, TmpTxt);
- }
- }
- fVal += st;
- }
-}
-
-bool
-Axis::GetValuePos(double val, double *fix, double *fiy, double *fiz, anyOutput *op)
-{
- double temp, tmp1 = 1.0;
- int i;
- bool bRet = true;
- anyOutput *o;
- fPOINT3D p1, p2;
- lfPOINT fdp, fip;
- AxisDEF caxis;
-
- *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) {
- //Get a copy of the axis because GetAxisFac() modifies its contents
- memcpy(&caxis, axis, sizeof(AxisDEF));
- p1.fx = op->un2fix(axis->loc[1].fx - caxis.loc[0].fx);
- p1.fy = op->un2fiy(axis->loc[1].fy - caxis.loc[0].fy);
- p1.fz = op->un2fiz(axis->loc[1].fz - caxis.loc[0].fz);
- tmp1 = sqrt(p1.fx*p1.fx + p1.fy*p1.fy + p1.fz*p1.fz);
- p1.fx /= tmp1; p1.fy /= tmp1; p1.fz /= tmp1;
- tmp1 = GetAxisFac(&caxis, tmp1, (type&0xf)-1);
- temp = TransformValue(&caxis, val, true);
- temp = (temp - caxis.min)*tmp1;
- if(axis->flags & AXIS_INVERT) {
- p1.fx = op->fix2un(op->un2fix(axis->loc[1].fx) - p1.fx*temp);
- p1.fy = op->fiy2un(op->un2fiy(axis->loc[1].fy) - p1.fy*temp);
- p1.fz = op->fix2un(op->un2fiz(axis->loc[1].fz) - p1.fz*temp);
- }
- else {
- p1.fx = op->fix2un(p1.fx*temp+op->un2fix(axis->loc[0].fx));
- p1.fy = op->fiy2un(p1.fy*temp+op->un2fiy(axis->loc[0].fy));
- p1.fz = op->fix2un(p1.fz*temp+op->un2fiz(axis->loc[0].fz));
- }
- 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 < -.005 || 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);
-}
+//Axes.cpp, Copyright 2000-2008 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, 6 + o->un2ix(LineDef.width));
+ 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;
+ }
+ if(pts[0].x != pts[1].x || pts[0].y != pts[1].y){
+ o->oPolyline(pts, 2);
+ SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+ }
+ if(pts[2].x != pts[3].x || pts[2].y != pts[3].y){
+ o->oPolyline(pts+2, 2);
+ SetMinMaxRect(&rDims, pts[2].x, pts[2].y, pts[3].x, pts[3].y);
+ }
+ IncrementMinMaxRect(&rDims, 6 + o->un2ix(LineDef.width));
+ }
+}
+
+void
+GridLine::DoMark(anyOutput *o, bool mark)
+{
+ if(mark){
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ memcpy(&mrc, &rDims, sizeof(RECT));
+ IncrementMinMaxRect(&mrc, 6 + o->un2ix(LineDef.width));
+ mo = GetRectBitmap(&mrc, o);
+ if(type & DL_CIRCULAR) {
+ InvertLine(cpts, ncpts, &LineDef, &rDims, o, mark);
+ }
+ else {
+ if(pts[0].x != pts[1].x || pts[0].y != pts[1].y)InvertLine(pts, 2, &LineDef, &rDims, o, mark);
+ if(pts[2].x != pts[3].x || pts[2].y != pts[3].y)InvertLine(pts+2, 2, &LineDef, &rDims, o, mark);
+ }
+ }
+ else RestoreRectBitmap(&mo, &mrc, o);
+}
+
+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_SCALE:
+ LineDef.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+ LineDef.width *= ((scaleINFO*)tmpl)->sy.fy;
+ 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(CurrGO = this, MRK_GODRAW);
+ return true;
+ }
+ else if(!(type & DL_CIRCULAR)){
+ o->ShowMark(CurrGO = this, MRK_GODRAW);
+ 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(mo) DelBitmapClass(mo); mo = 0L;
+ 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*));
+ if(!(o->ActualSize(&rDims)))return;
+ 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, 6 + o->un2ix(LineDef.width));
+}
+
+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, 6 + o->un2ix(LineDef.width));
+ o->oPolyline(pts, 2);
+ }
+}
+
+void
+GridRadial::DoMark(anyOutput *o, bool mark)
+{
+ if(mark) {
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ 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()
+{
+ int i;
+
+ if(Polygons) {
+ for(i = 0; i < numPG; i++) if(Polygons[i]) DeleteGO(Polygons[i]);
+ free(Polygons); Polygons = 0L; numPG = 0;
+ }
+ Command(CMD_FLUSH, 0L, 0L);
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ if(bModified) Undo.InvalidGO(this);
+ if(seg) free(seg); seg = 0L;
+}
+
+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(!bValidTick) return;
+ if(mark){
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ memcpy(&mrc, &rDims, sizeof(RECT));
+ IncrementMinMaxRect(&mrc, 6 + (parent && parent->Id == GO_AXIS) ? o->un2ix(((Axis*)parent)->axline.width):o->iLine);
+ 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;
+ AxisDEF *axis;
+ DWORD pg_color;
+ int i;
+
+ switch(cmd){
+ case CMD_SCALE:
+ if(label) label->Command(cmd, tmpl, o);
+ if(Grid) Grid->Command(cmd, tmpl, o);
+ size *= ((scaleINFO*)tmpl)->sy.fy;
+ if(Polygons) for(i = 0; i < numPG; i++) if(Polygons[i]) (Polygons[i])->Command(cmd, tmpl, o);;
+ break;
+ case CMD_ADDTOLINE:
+ return StoreSeg((lfPOINT*)tmpl);
+ case CMD_RECALC:
+ if(Polygons) Undo.DropListGO(this, (GraphObj***)&Polygons, &numPG, UNDO_CONTINUE);
+ n_seg = 0; bModified = true;
+ return true;
+ case CMD_SET_AXDEF:
+ if(axis = (AxisDEF*)tmpl) {
+ flags = (flags & AXIS_MINORTICK) | axis->flags;
+ }
+ break;
+ 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_SET_TICKSTYLE:
+ flags &= ~0x07;
+ flags |= (0x07 & *((DWORD*)tmpl));
+ return true;
+ case CMD_UPDPG:
+ if(parent && parent->Id == GO_AXIS) pg_color = ((Axis*)parent)->GradColor(value);
+ else pg_color = 0x00ffffff;
+ if(Polygons) for(i = 0; i < numPG; i++) if(Polygons[i]) {
+ Polygons[i]->SetColor(COL_POLYGON, pg_color);
+ }
+ return true;
+ case CMD_DRAWPG:
+ if(Polygons) for(i = 0; i < numPG; i++) if(Polygons[i]) {
+ Polygons[i]->DoPlot(o);
+ }
+ // we lost the line definition from the parent axis
+ if(parent) parent->Command(CMD_RESET_LINE, 0L, o);
+ 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);
+ }
+ if(DeleteGOL((GraphObj***) &Polygons, numPG, (GraphObj *)tmpl, o))
+ 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);
+ if(Polygons) for(i = 0; i < numPG; i++) if(Polygons[i]) (Polygons[i])->Command(cmd, tmpl, o);;
+ return true;
+ case CMD_TEXTTHERE:
+ if(label && label->Command(cmd, tmpl, o)) return true;
+ return false;
+ 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)) {
+ o->ShowMark(this, MRK_GODRAW);
+ return true;
+ }
+ if(Polygons && !CurrGO) for(i = numPG-1; i >= 0; i--)
+ if(Polygons[i]) if(Polygons[i]->Command(cmd, tmpl, o))return true;
+ break;
+ }
+ return false;
+ case CMD_TLB_TXTDEF:
+ if(label) return label->Command(CMD_SETTEXTDEF, tmpl, o);
+ return false;
+ case CMD_GETTEXT:
+ if(label) return label->Command(cmd, tmpl, o);
+ 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) : DefSize(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) ? (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1, 0) : 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::Track(POINT *p, anyOutput *o)
+{
+ POINT tpts[2];
+ int iw;
+
+ if(!bValidTick || !parent || !o) return;
+ iw = 6 + o->un2ix(o->LineWidth);
+ defs.UpdRect(o, rDims.left, rDims.top, rDims.right, rDims.bottom);
+ tpts[0].x = pts[0].x+p->x; tpts[0].y = pts[0].y+p->y;
+ tpts[1].x = pts[1].x+p->x; tpts[1].y = pts[1].y+p->y;
+ defs.UpdRect(o, tpts[0].x-iw, tpts[0].y-iw, tpts[1].x-iw, tpts[1].y-iw);
+ defs.UpdRect(o, tpts[0].x+iw, tpts[0].y+iw, tpts[1].x+iw, tpts[1].y+iw);
+ o->ShowLine(tpts, 2, parent->GetColor(COL_AXIS));
+ if((flags & AXIS_MINORTICK) == 0 && label) label->Track(p, o);
+}
+
+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;
+ ip2.x = ip2.y = ip2.z = 0;
+ if(!(bValidTick = ((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(DefSize(SIZE_AXIS_TICKS)*3.0*six));
+ lby -= (o->un2fiy(DefSize(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 + o->un2ix(o->LineWidth));
+ 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)){
+ 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);
+ }
+ }
+}
+
+//return true if two points are close together
+#define X_TOL 1.0E-12
+#define Y_TOL 1.0E-12
+bool
+Tick::CmpPoints(double x1, double y1, double x2, double y2)
+{
+ if(fabs(x2 - x1) > X_TOL) return false;
+ if(fabs(y2 - y1) > Y_TOL) return false;
+ return true;
+}
+#undef X_TOL
+#undef Y_TOL
+
+bool
+Tick::StoreSeg(lfPOINT *line)
+{
+ int i;
+
+ if(n_seg >= s_seg) {
+ if(!(seg = (double*)realloc(seg, ((s_seg += 50)<<2)*sizeof(double))))return false;
+ }
+ i = n_seg << 2;
+ seg[i++] = line[0].fx; seg[i++] = line[0].fy;
+ seg[i++] = line[1].fx; seg[i++] = line[1].fy;
+ n_seg++; return false;
+}
+
+//collect line segments to polygons
+bool
+Tick::ProcSeg()
+{
+ lfPOINT *pg;
+ int i, j, l, n, n0, n1, n_pg, level;
+ bool cont1, cont2;
+ FillDEF pg_fill = {0, 0x0, 1.0, 0L, 0x0L};
+ LineDEF pg_line = {defs.GetSize(SIZE_HAIRLINE), 1.0, 0x0L, 0x0L};
+
+ if(n_seg < 3) {
+ n_seg = 0; return false;
+ }
+ if(!(pg = (lfPOINT*)malloc((n_seg+2)*sizeof(lfPOINT)))) return false;
+ if(!parent || parent->Id != GO_AXIS) return false;
+ pg_fill.color = pg_fill.color2 = ((Axis*)parent)->GradColor(value);
+ pg_line.color = ((pg_fill.color & 0x00fefefeL)>>1);
+ while(n_seg > 2) {
+ pg[0].fx = seg[0]; pg[0].fy = seg[1];
+ pg[1].fx = seg[2]; pg[1].fy = seg[3];
+ n0 = level = 0; n = 1; n_pg = 2;
+ do {
+ do {
+ cont2 = cont1 = false; n1 = (n<<2);
+ if(CmpPoints(pg[n_pg-1].fx, pg[n_pg-1].fy, seg[n1], seg[n1+1])) {
+ pg[n_pg].fx = seg[n1+2]; pg[n_pg].fy = seg[n1+3];
+ n++; n_pg++; cont2=true;
+ }
+ else if(CmpPoints(pg[n_pg-1].fx, pg[n_pg-1].fy, seg[n1+2], seg[n1+3] )) {
+ pg[n_pg].fx = seg[n1]; pg[n_pg].fy = seg[n1+1];
+ n++; n_pg++; cont2=true;
+ }
+ else if(CmpPoints(pg[0].fx, pg[0].fy, seg[n1], seg[n1+1])) {
+ for(i = n_pg; i > 0; i--) {
+ pg[i].fx = pg[i-1].fx; pg[i].fy = pg[i-1].fy;
+ }
+ pg[0].fx = seg[n1+2]; pg[0].fy = seg[n1+3];
+ n++; n_pg++; cont2=true;
+ }
+ else if(CmpPoints(pg[0].fx, pg[0].fy, seg[n1+2], seg[n1+3])) {
+ for(i = n_pg; i > 0; i--) {
+ pg[i].fx = pg[i-1].fx; pg[i].fy = pg[i-1].fy;
+ }
+ pg[0].fx = seg[n1]; pg[0].fy = seg[n1+1];
+ n++; n_pg++; cont2=true;
+ }
+ if(cont2) level = 0;
+ }while(cont2 && n_pg < s_seg && n < n_seg);
+ if(n > n0 && n < n_seg) {
+ for(i = n0<<2, j = n<<2, l = (n_seg<<2); j < l; i++, j++) {
+ seg[i] = seg[j];
+ }
+ n_seg -= (n-n0); n0 = n = 0;
+ }
+ else if(n == n_seg){
+ n_seg = n0; n0 = n = 0;
+ }
+ else {
+ n0++; n++;
+ }
+ if(CmpPoints(pg[0].fx, pg[0].fy, pg[n_pg-1].fx, pg[n_pg-1].fy)) cont1 = false;
+ else if(n < n_seg && n_seg) cont1 = true;
+ else {
+ if(n_seg && level < 3) {
+ level++; n = 0; cont1 = true;
+ }
+ else cont1 = false;
+ }
+ }while(cont1);
+ if(n_pg > 2) {
+ if(CmpPoints(pg[0].fx, pg[0].fy, pg[n_pg-1].fx, pg[n_pg-1].fy)) n_pg--;
+ if(n_pg > 2) {
+ Polygons = (DataPolygon**)realloc(Polygons, (numPG+2)*sizeof(DataPolygon*));
+ if(Polygons[numPG] = new DataPolygon(this, data, (lfPOINT*)memdup(pg, n_pg*sizeof(lfPOINT), 0), n_pg, 0L)){
+ Polygons[numPG]->type = 12;
+ Polygons[numPG]->Command(CMD_SET_LINE, &pg_line, 0L);
+ Polygons[numPG++]->Command(CMD_PG_FILL, &pg_fill, 0L);
+ }
+ }
+ }
+ }
+ free(pg); n_seg = 0; return true;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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;
+ if(atv) delete atv; atv = 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;
+ case SIZE_BOUNDS_XMIN: case SIZE_BOUNDS_XMAX: case SIZE_BOUNDS_YMIN:
+ case SIZE_BOUNDS_YMAX: case SIZE_BOUNDS_ZMIN: case SIZE_BOUNDS_ZMAX:
+ if(parent) return parent->GetSize(select);
+ break;
+ }
+ return DefSize(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(IsPlot3D(parent) && (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, 6 + o->un2ix(sizAxLine));
+ 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, 6 + o->un2ix(sizAxLine));
+ //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 gradient bar, breaks and axis line
+ if(type == 4) GradientBar(o);
+ else 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]->GetSize(SIZE_MINE) >= (axis->min - 1.0e-16)
+ && Ticks[i]->GetSize(SIZE_MINE) <= (axis->max + 1.0e-16)) Ticks[i]->DoPlot(si, csi, o);
+}
+
+bool
+Axis::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ GraphObj **tmpPlots;
+ void *sv_ptr;
+ scaleINFO *scale;
+ int i;
+
+ switch (cmd) {
+ case CMD_SCALE:
+ if(!Ticks && (axis->flags & 0x03) != AXIS_NOTICKS)CreateTicks();
+ scale = (scaleINFO*)tmpl;
+ lbdist.fx *= scale->sx.fy; lbdist.fy *= scale->sy.fy;
+ tlbdist.fx *= scale->sx.fy; tlbdist.fy *= scale->sy.fy;
+ sizAxTickLabel *= scale->sy.fy; sizAxTick *= scale->sy.fy;
+ sizAxLine *= scale->sy.fy; brksymsize *= scale->sy.fy;
+ brkgap *= scale->sy.fy; GridLine.patlength *= scale->sy.fy;
+ GridLine.width *= scale->sy.fy; tlbdef.fSize *= scale->sy.fy;
+ axis->loc[0].fx *= scale->sx.fy; axis->loc[1].fx *= scale->sx.fy;
+ axis->loc[0].fy *= scale->sy.fy; axis->loc[1].fy *= scale->sy.fy;
+ axis->loc[0].fz *= scale->sz.fy; axis->loc[1].fz *= scale->sz.fy;
+ axis->Center.fx *= scale->sx.fy; axis->Center.fy *= scale->sy.fy;
+ axis->Radius *= scale->sy.fy; tlbdef.iSize = 0;
+ if(axisLabel) axisLabel->Command(cmd, tmpl, o);
+ if(Ticks) for(i = 0; i < NumTicks; i++) if(Ticks[i]) Ticks[i]->Command(cmd, tmpl, o);
+ return true;
+ 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));
+ return true;
+ case CMD_MRK_DIRTY:
+ if((type & 0xf) == 4 && !o) cmd = CMD_UPDPG;
+ else return false;
+ case CMD_DRAWPG: case CMD_UPDPG:
+ if((type & 0xf) == 4 && Ticks) {
+ if(axis->flags & AXIS_INVERT){
+ for(i = NumTicks-1; i >= 0; i--) if(Ticks[i]) Ticks[i]->Command(cmd, tmpl, o);
+ }
+ else {
+ 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(!CurrGO && ObjThere(mev->x, mev->y)) {
+ o->ShowMark(this, MRK_GODRAW);
+ return true;
+ }
+ break;
+ }
+ if(axisLabel && axisLabel->Command(cmd, tmpl, o)) return true;
+ if(Ticks) for(i = (NumTicks-1); i >= 0; i--)
+ if(Ticks[i] && Ticks[i]->Command(cmd, tmpl, o)) return true;
+ return false;
+ case CMD_TEXTTHERE:
+ 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(axis = (AxisDEF*)tmpl) {
+ if(axis && axis->owner == (void*)this) {
+ if(axis->breaks) free(axis->breaks);
+ free(axis);
+ }
+ if(Ticks) for(i = 0; i < NumTicks; i++)
+ if(Ticks[i]) {
+ Ticks[i]->Command(cmd, tmpl, o);
+ Ticks[i]->Command(CMD_SET_GRIDTYPE, (void*) &gl_type, 0L);
+ Ticks[i]->Command(CMD_TLB_TXTDEF, &tlbdef, 0L);
+ if(axis->flags & AXIS_GRIDLINE) Ticks[i]->Command(CMD_SET_GRIDLINE, &GridLine, 0L);
+ Ticks[i]->SetSize(SIZE_TICK_ANGLE, tick_angle);
+ Ticks[i]->SetSize(SIZE_AXIS_TICKS, sizAxTick);
+ Ticks[i]->SetSize(SIZE_LB_XDIST, tlbdist.fx);
+ Ticks[i]->SetSize(SIZE_LB_YDIST, tlbdist.fy);
+ Ticks[i]->Command(CMD_TICK_TYPE, &tick_type, 0L);
+ }
+ return true;
+ }
+ return false;
+ case CMD_CAN_CLOSE:
+ 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(DeleteGOL((GraphObj***) &Ticks, NumTicks, (GraphObj *)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);
+ }
+ if(Ticks && NumTicks) for(i = 0; i < NumTicks; i++){
+ if(Ticks[i] && Ticks[i]->Command(cmd, tmpl, 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_MOVE:
+ if(moveable) {
+ bModified = true;
+ Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
+ }
+ case CMD_UNDO_MOVE:
+ if(moveable) {
+ axis->loc[0].fx += ((lfPOINT*)tmpl)[0].fx; axis->loc[0].fy += ((lfPOINT*)tmpl)[0].fy;
+ axis->loc[1].fx += ((lfPOINT*)tmpl)[0].fx; axis->loc[1].fy += ((lfPOINT*)tmpl)[0].fy;
+ }
+ CurrGO = this;
+ return parent->Command(CMD_REDRAW, 0, o);
+ 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;
+ return true;
+ case CMD_RECALC:
+ if(Ticks) {
+ for(i = 0; i < NumTicks; i++) if(Ticks[i]) Ticks[i]->Command(cmd, tmpl, o);
+ return true;
+ }
+ break;
+ 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::ObjThere(int x, int y)
+{
+ int i;
+ POINT p1 = {x, y};
+
+ if(axis->flags & AXIS_ANGULAR) {
+ i = (x - pts[0].x) * (x - pts[0].x) + (y - pts[0].y) * (y - pts[0].y);
+ i = isqr(i) - pts[1].x;
+ if(i < 4 && i > -4) return this;
+ }
+ else if((type & 0x04) == 4 && IsInPolygon(&p1, gradient_box, 5)) return this;
+ else if(IsInRect(&rDims, x, y) && IsCloseToLine(&pts[0], &pts[1], x, y)) {
+ return this;
+ }
+ return 0L;
+}
+
+void
+Axis::Track(POINT *p, anyOutput *o)
+{
+ POINT tpts[5];
+ int i, iw;
+
+ if(!parent || !o) return;
+ iw = 6 + o->un2ix(sizAxLine);
+ defs.UpdRect(o, rDims.left, rDims.top, rDims.right, rDims.bottom);
+ tpts[0].x = pts[0].x+p->x; tpts[0].y = pts[0].y+p->y;
+ tpts[1].x = pts[1].x+p->x; tpts[1].y = pts[1].y+p->y;
+ defs.UpdRect(o, tpts[0].x-iw, tpts[0].y-iw, tpts[1].x-iw, tpts[1].y-iw);
+ defs.UpdRect(o, tpts[0].x+iw, tpts[0].y+iw, tpts[1].x+iw, tpts[1].y+iw);
+ if(type & 0x04) {
+ for(i = 0; i < 5; i++) {
+ tpts[i].x = gradient_box[i].x + p->x;
+ tpts[i].y = gradient_box[i].y + p->y;
+ defs.UpdRect(o, tpts[i].x-iw, tpts[i].y-iw, tpts[i].x+iw, tpts[i].y+iw);
+ }
+ o->ShowLine(tpts, 5, colAxis);
+ }
+ else o->ShowLine(tpts, 2, colAxis);
+ if(Ticks && NumTicks) for(i = 0; i < NumTicks; i++) {
+ if(Ticks[i] && Ticks[i]->GetSize(SIZE_MINE) >= (axis->min - 1.0e-16)
+ && Ticks[i]->GetSize(SIZE_MINE) <= (axis->max + 1.0e-16)) Ticks[i]->Track(p, o);
+ }
+}
+
+DWORD
+Axis::GradColor(double val)
+{
+ DWORD retcol = 0x00cbcbcbL;
+ double y, f;
+
+ y = (val-axis->min)/(axis->max-axis->min);
+ if(axis->flags & AXIS_INVERT) y = 1.0-y;
+ if(grad_type & 0x10) y = 1.0-y;
+ switch(grad_type & 0x0f) {
+ case 0:
+ retcol = gCol_0; break;
+ case 1: case 4:
+ retcol = 0x00000000L;
+ if(y >= 1.0) retcol = 0x000000ffL;
+ else if(y >= 0.75) {
+ f = (y - 0.75)*1024.0; retcol |= 0x000000ffL;
+ retcol |= (((f < 255.0)?((int)(255.0-f)):0)<<8);
+ }
+ else if(y >= 0.5) {
+ f = (y - 0.5)*1024.0; retcol |= 0x0000ff00L;
+ retcol |= ((f < 255.0)?((int)f):0);
+ }
+ else if(y >= 0.0 && (grad_type &0x0f) == 4) {
+ f = y*512.0;
+ retcol |= (((f < 255.0)?((int)f):0)<<8);
+ retcol |= (((f < 255.0)?((int)(255.0-f)):255)<<16);
+ }
+ else if(y >= 0.25) {
+ f = (y - 0.25)*1024.0; retcol |= 0x0000ff00L;
+ retcol |= (((f < 255.0)?((int)(255.0-f)):255)<<16);
+ }
+ else if(y >= 0.0) {
+ f = y*1024.0; retcol |= 0x00ff0000L;
+ retcol |= (((f < 255.0)?((int)f):0)<<8);
+ }
+ else retcol = 0x00ff0000L;
+ break;
+ case 2:
+ retcol = 0x00000000L;
+ if(y >= 1.0) retcol = 0x00ffffffL;
+ else if(y >= (5.0/6.0)) {
+ f = (y - (5.0/6.0))*1536.0; retcol |= 0x000000ffL;
+ retcol |= (((f < 255.0)?((int)f):0xff)<<8);
+ retcol |= (((f < 255.0)?((int)f):0xff)<<16);
+ }
+ else if(y >= (4.0/6.0)) {
+ f = (y - (4.0/6.0))*1536.0; retcol |= 0x000000ffL;
+ retcol |= (((f < 255.0)?((int)(255.0-f)):0)<<8);
+ }
+ else if(y >= (3.0/6.0)) {
+ f = (y - (3.0/6.0))*1536.0; retcol |= 0x0000ff00L;
+ retcol |= ((f < 255.0)?((int)f):0xff);
+ }
+ else if(y >= (2.0/6.0)) {
+ f = (y - (2.0/6.0))*1536.0; retcol |= 0x0000ff00L;
+ retcol |= (((f < 255.0)?((int)(255.0-f)):0xff)<<16);
+ }
+ else if(y >= (1.0/6.0)) {
+ f = (y - (1.0/6.0))*1536.0; retcol |= 0x00ff0000L;
+ retcol |= (((f < 255.0)?((int)f):0xff)<<8);
+ }
+ else if(y >= 0.0) {
+ f = y*1536.0;
+ retcol |= (((f < 255.0)?((int)f):0xff)<<16);
+ }
+ else retcol = 0x0L;
+ break;
+ case 3:
+ retcol = IpolCol(gCol_2, gCol_1, y);
+ }
+ if(gTrans & 0xff000000) {
+ retcol = (retcol & 0x00ffffff) | (gTrans & 0xff000000);
+ }
+ return retcol;
+}
+
+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 = (char*)memdup(TmpTxt+1, (int)strlen(TmpTxt+1)+1, 0);
+ }
+ else l = (char*)memdup(txt, (int)strlen(txt)+1, 0);
+ 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::mkTimeAxis()
+{
+ int nstep, mode;
+ double span, val;
+ rlp_datetime start, step;
+ static char *tick_formats[] = {"y", "Y", "W", "x", "Z.V.", "d", "H:M", "d"};
+
+ span = axis->max - axis->min;
+ memset(&step, 0, sizeof(rlp_datetime)); parse_datevalue(&start, axis->Start);
+ start.hours=start.minutes=start.doy = 0; start.seconds = val = 0.0;
+ if(span > 60.0) start.dow = 1;
+ if(span > 24000.0) {
+ step.year = start.month = start.dom = 1;
+ nstep = 2 + (int)(span / 364.0); mode = 0;
+ }
+ else if(span > 700.0) {
+ step.month = start.month = start.dom = 1;
+ nstep = 2 + (int)(span / 28.0); mode = 1;
+ }
+ else if(span > 300.0) {
+ step.month = start.dom = 1;
+ nstep = 2 + (int)(span / 28.0); mode = 2;
+ }
+ else if(span > 150.0) {
+ step.month = start.dom = 1;
+ nstep = 2 + (int)(span / 28.0); mode = 3;
+ }
+ else if(span > 60.0) {
+ step.dom = 1;
+ nstep = 6 + (int)(span/7.0); mode = 4;
+ }
+ else if(span > 8.0) {
+ step.dom = 1;
+ nstep = 2+(int)(span); mode = 5;
+ }
+ else if(span > 2.0) {
+ step.hours = 6;
+ nstep = 4+(int)(span*4.0); mode = 6;
+ }
+ else if(span > 0.5) {
+ step.hours = (span > 0.9 ? 2 : 1);
+ nstep = 4+(int)(span*24.0); mode = 7;
+ }
+ else if(span > 0.05) {
+ step.minutes = (span > 0.3 ? (span > 0.4 ? 30 : 15) : (span <= 0.1 ? 5 : 10));
+ nstep = 100; mode = 8;
+ }
+ else if(span > 0.005) {
+ step.minutes = 1;
+ nstep = 100; mode = 8;
+ }
+ else return;
+ if(nstep < 50) nstep = 50; add_date(&start, 0L);
+ if(!(Ticks = (Tick**)calloc(nstep, sizeof(Tick*))))return;
+ for(NumTicks = 0; NumTicks < nstep && val <= axis->max; NumTicks++) {
+ val = date2value(&start);
+ switch(mode) {
+ case 0:
+ if((start.year%10) == 0) SetTick(NumTicks, val, axis->flags, date2text(&start, tick_formats[0]));
+ else NumTicks--; break;
+ case 1:
+ if(start.month == 1){
+ if(span <= 6000.0 || (span <= 12000.0 && (start.year%5) == 0) || (span <= 24000.0 && (start.year%10) == 0))
+ SetTick(NumTicks, val, axis->flags, date2text(&start,
+ (span > 3000.0 && span < 12000.0)?tick_formats[0] : tick_formats[1]));
+ else NumTicks--;
+ }
+ else if(span <= 1500.0) SetTick(NumTicks, val, axis->flags | AXIS_MINORTICK,
+ date2text(&start, tick_formats[4]));
+ else NumTicks--; break;
+ case 2:
+ SetTick(NumTicks, val, axis->flags, date2text(&start, start.month==1 ? tick_formats[0]:tick_formats[2]));
+ break;
+ case 3:
+ SetTick(NumTicks, val, axis->flags, date2text(&start, tick_formats[3]));
+ break;
+ case 4:
+ if(start.dom == 1)SetTick(NumTicks, val, axis->flags, date2text(&start, tick_formats[3]));
+ else if(start.dow == 1) SetTick(NumTicks, val, axis->flags | AXIS_MINORTICK, date2text(&start, tick_formats[4]));
+ else NumTicks--; break;
+ case 5:
+ if(start.dow == 1) SetTick(NumTicks, val, axis->flags, date2text(&start, tick_formats[4]));
+ else if(span < 30.0)SetTick(NumTicks, val, axis->flags | AXIS_MINORTICK, date2text(&start, tick_formats[7]));
+ else NumTicks--; break;
+ case 6:
+ if(start.hours == 0) SetTick(NumTicks, val, axis->flags, date2text(&start, tick_formats[4]));
+ else SetTick(NumTicks, val, axis->flags | AXIS_MINORTICK, date2text(&start, tick_formats[6]));
+ break;
+ case 7:
+ if(start.hours == 0) SetTick(NumTicks, val, axis->flags, date2text(&start, tick_formats[5]));
+ else if((start.hours % 6) == 0) SetTick(NumTicks, val, axis->flags, date2text(&start, tick_formats[6]));
+ else SetTick(NumTicks, val, axis->flags | AXIS_MINORTICK, date2text(&start, tick_formats[6]));
+ break;
+ case 8:
+ if(start.minutes == 0){
+ if(span <= 0.3 || (start.hours %2) == 0) SetTick(NumTicks, val, axis->flags,
+ date2text(&start, tick_formats[6]));
+ else SetTick(NumTicks, val, axis->flags, "");
+ }
+ else SetTick(NumTicks, val, axis->flags | AXIS_MINORTICK, date2text(&start, tick_formats[6]));
+ break;
+ }
+ add_date(&start, &step);
+ }
+}
+
+void
+Axis::CreateTicks()
+{
+ int i, n, nstep;
+ char *format, *tick_label;
+ double fVal, tmp;
+ DWORD flags;
+
+ if(axis->min == -HUGE_VAL || axis->min == HUGE_VAL) return;
+ if(axis->max == -HUGE_VAL || axis->max == HUGE_VAL) return;
+ if(axis->min >= axis->max) return;
+ if(Ticks) {
+ Undo.DropListGO(this, (GraphObj***)&Ticks, &NumTicks, 0L);
+ }
+ 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_DATETIME) {
+ mkTimeAxis(); return;
+ }
+ if(atv && (nstep = atv->Count()) && (Ticks = (Tick**)calloc(nstep+1, sizeof(Tick*)))) {
+ for(NumTicks = i = n = 0; NumTicks < nstep && atv->GetItem(i, &tick_label, &fVal); i++) {
+ SetTick(NumTicks, fVal, axis->flags, tick_label);
+ NumTicks++; n += (int)strlen(tick_label);
+ }
+ type = type;
+#ifdef _WINDOWS
+ if(type == 1 && n > 40) {
+ tlbdef.RotBL = n >100 ? 90.0 : 45.0; tlbdef.Align = TXA_HRIGHT | TXA_VCENTER;
+ tlbdist.fy = sizAxTick; SetSize(SIZE_TLB_YDIST, tlbdist.fy);
+ Command(CMD_TLB_TXTDEF, &tlbdef, 0L);
+ }
+#else
+ if(type == 1 && n > 30) {
+ tlbdef.RotBL = n >70 ? 90.0 : 45.0; tlbdef.Align = TXA_HRIGHT | TXA_VCENTER;
+ tlbdist.fy = sizAxTick; SetSize(SIZE_TLB_YDIST, tlbdist.fy);
+ Command(CMD_TLB_TXTDEF, &tlbdef, 0L);
+ }
+#endif
+ return;
+ }
+ 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) {
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, format, fVal);
+#else
+ sprintf(TmpTxt, format, fVal);
+#endif
+ 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++) {
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, format, fVal);
+#else
+ sprintf(TmpTxt, format, fVal);
+#endif
+ SetTick(NumTicks, fVal, flags, TmpTxt);
+ for(j = 0; j < n; j++) {
+ mival = fVal+mist*(double)j +mist;
+ if(mival < axis->max) {
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, format, mival);
+#else
+ sprintf(TmpTxt, format, mival);
+#endif
+ NumTicks++;
+ SetTick(NumTicks, mival, flags | AXIS_MINORTICK, TmpTxt);
+ }
+ }
+ fVal += st;
+ }
+}
+
+bool
+Axis::GetValuePos(double val, double *fix, double *fiy, double *fiz, anyOutput *op)
+{
+ double temp, tmp1 = 1.0;
+ int i;
+ bool bRet = true;
+ anyOutput *o;
+ fPOINT3D p1, p2;
+ lfPOINT fdp, fip;
+ AxisDEF caxis;
+
+ *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) {
+ //Get a copy of the axis because GetAxisFac() modifies its contents
+ memcpy(&caxis, axis, sizeof(AxisDEF));
+ p1.fx = op->un2fix(axis->loc[1].fx - caxis.loc[0].fx);
+ p1.fy = op->un2fiy(axis->loc[1].fy - caxis.loc[0].fy);
+ p1.fz = op->un2fiz(axis->loc[1].fz - caxis.loc[0].fz);
+ tmp1 = sqrt(p1.fx*p1.fx + p1.fy*p1.fy + p1.fz*p1.fz);
+ p1.fx /= tmp1; p1.fy /= tmp1; p1.fz /= tmp1;
+ tmp1 = GetAxisFac(&caxis, tmp1, (type&0xf)-1);
+ temp = TransformValue(&caxis, val, true);
+ temp = (temp - caxis.min)*tmp1;
+ if(axis->flags & AXIS_INVERT) {
+ p1.fx = op->fix2un(op->un2fix(axis->loc[1].fx) - p1.fx*temp);
+ p1.fy = op->fiy2un(op->un2fiy(axis->loc[1].fy) - p1.fy*temp);
+ p1.fz = op->fix2un(op->un2fiz(axis->loc[1].fz) - p1.fz*temp);
+ }
+ else {
+ p1.fx = op->fix2un(p1.fx*temp+op->un2fix(axis->loc[0].fx));
+ p1.fy = op->fiy2un(p1.fy*temp+op->un2fiy(axis->loc[0].fy));
+ p1.fz = op->fix2un(p1.fz*temp+op->un2fiz(axis->loc[0].fz));
+ }
+ 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 & 0x0f) == 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 & 0x0f) == 2 || (type &0x0f) == 4) && 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);
+ }
+ else return false;
+ if(tmp1 > -1.0e-15 && tmp1 < 1.0 + 1.0e-15) return bRet;
+ return false;
+}
+
+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);
+}
+
+void
+Axis::GradientBar(anyOutput *o)
+{
+ FillDEF gf = {0, 0x0, 1.0, 0L, 0x0};
+ LineDEF gl = {0.0, 1.0, 0x0, 0x0};
+ POINT gpt[5];
+ double v_val, fix, fiy, fiz;
+ int i, iw;
+
+ if(!o || !Ticks || NumTicks < 2) return;
+ iw = o->un2ix(defs.GetSize(SIZE_AXIS_TICKS)*2);
+ GetValuePos(axis->min, &fix, &fiy, &fiz, o);
+ gpt[0].x = gpt[3].x = gpt[4].x = (iround(fix)-iw);
+ gpt[0].y = gpt[1].y = gpt[4].y = iround(fiy);
+ memcpy(&gradient_box, &gpt, sizeof(POINT)*5);
+ gf.color = gf.color2 = gl.color = GradColor(axis->min);
+ for(i = 0; i < NumTicks; i++) if(Ticks[i]) {
+ if(GetValuePos(v_val = Ticks[i]->GetSize(SIZE_MINE), &fix, &fiy, &fiz, o)) {
+ gpt[1].x = gpt[2].x = iround(fix); gpt[2].y = gpt[3].y = iround(fiy);
+ o->SetLine(&gl); o->SetFill(&gf);
+ if(gpt[1].y != gpt[2].y) o->oPolygon(gpt, 5, 0L);
+ gpt[0].x= gpt[3].x= gpt[4].x= (pts[1].x-iw); gpt[0].y = gpt[1].y = gpt[4].y = gpt[2].y;
+ gf.color = gf.color2 = gl.color = GradColor(v_val);
+ }
+ }
+ if(GetValuePos(axis->max, &fix, &fiy, &fiz, o)) {
+ gpt[1].x = gpt[2].x = gradient_box[1].x = gradient_box[2].x = iround(fix);
+ gpt[2].y = gpt[3].y = gradient_box[2].y = gradient_box[3].y = iround(fiy);
+ o->SetLine(&gl); o->SetFill(&gf);
+ if(gpt[1].y != gpt[2].y) {
+ o->oPolygon(gpt, 5, 0L);
+ }
+ UpdateMinMaxRect(&rDims, gpt[0].x, gpt[1].y);
+ o->SetLine(&axline);
+ o->oPolyline(gradient_box, 5);
+ }
+ else o->SetLine(&axline);
+}
diff --git a/Export.cpp b/Export.cpp
index 461ee15..7fabea0 100755
--- a/Export.cpp
+++ b/Export.cpp
@@ -1,1062 +1,1108 @@
-//Export.cpp, Copyright (c) 2002-2007 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 USE_WIN_SECURE
- #include <share.h> //I/O flags
-#endif
-
-#ifdef _WINDOWS
- #include <io.h> //for read/write
-#else
- #define O_BINARY 0x0
- #include <unistd.h>
-#endif
-
-extern char TmpTxt[];
-extern Default defs;
-static char *str_ind = " ";
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Entry point to export graph to Windows Meta File
-void DoExportWmf(GraphObj *g, char *FileName, float res, DWORD flags)
-{
- InfoBox("The export of Windos metafile (*.wmf)\n has been dicontinued.\n\n");
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 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 oTextOutW(int x, int y, w_char *txt, int cb);
- bool oPolygon(POINT *pts, int cp, char * nam = 0L);
-
-private:
- int iLineWidth, cb_out, out_pos, out_size, cb_ind;
- char *out_buff;
- bool bUseGroupLine, bOutputPending;
- GraphObj *go;
- char *name, output[120], tHatchStyle[80];
- DWORD flags;
-
- bool com_TextOut(int x, int y, char *txt, int cb);
- void Indent(bool ind);
- void AddToOutput(char *txt, int len);
- 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 = (char*)memdup(FileName, (int)strlen(FileName)+1, 0);
- else name = 0L;
- out_buff = 0L; out_pos = out_size = 0;
- flags = flg; cb_ind = 3;
- rlp_strcpy(tHatchStyle, 80, "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;
-#ifdef USE_WIN_SECURE
- sprintf_s(tHatchStyle, 80, "style=\"fill:none; stroke:%s; stroke-width:%d\"",
- ColName(fill->hatch->color), iL);
-#else
- sprintf(tHatchStyle, "style=\"fill:none; stroke:%s; stroke-width:%d\"",
- ColName(fill->hatch->color), iL);
-#endif
- }
- }
- else {
- if(hgo) delete hgo;
- hgo = 0L;
- }
- dFillCol = fill->color;
- dFillCol2 = fill->color2;
- return true;
-}
-
-bool
-ExportSVG::SetTextSpec(TextDEF *set)
-{
- if(set->fSize > 0.0) {
- if((set->Style & TXS_SUPER) || (set->Style & TXS_SUB))
- set->iSize = un2iy(set->fSize * 0.71);
- else 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(flags & 0x01) add_to_buff(&out_buff, &out_pos, &out_size, "Content-Type: image/svg+xml\n\n", 0);
- VPorg.fy = -un2fiy(go->GetSize(SIZE_GRECT_TOP));
- VPorg.fx = -un2fix(go->GetSize(SIZE_GRECT_LEFT));
- add_to_buff(&out_buff, &out_pos, &out_size, "<?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<svg ", 0);
- if(defs.svgAttr) add_to_buff(&out_buff, &out_pos, &out_size, defs.svgAttr, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, " width=\"", 0);
- add_int_to_buff(&out_buff, &out_pos, &out_size, w, false, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "\" height=\"", 0);
- add_int_to_buff(&out_buff, &out_pos, &out_size, h, false, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "\" style=\"stroke-linecap:round\">\n", 0);
- if(defs.svgScript) {
- add_to_buff(&out_buff, &out_pos, &out_size, "<defs>\n<script type=\"text/ecmascript\"><![CDATA[\n\n", 0);
- add_to_buff(&out_buff, &out_pos, &out_size, defs.svgScript, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "\n\n]]></script>\n</defs>\n\n", 0);
- }
- add_to_buff(&out_buff, &out_pos, &out_size, "<g transform=\"scale(0.1)\" style=\"font-family:Helvetica\">\n", 0);
- return true;
-}
-
-bool
-ExportSVG::EndPage()
-{
- FILE *oFile;
-
- add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n</svg>\n", 0);
- if(name && out_buff && out_pos > 20) {
-#ifdef USE_WIN_SECURE
- fopen_s(&oFile, name, "w");
-#else
- oFile = fopen(name, "w");
-#endif
- if(!oFile) {
- ErrorBox("Could not open\noutput file!");
- return false;
- }
- fprintf(oFile, "%s", out_buff);
- free(out_buff); 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){
- add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
- add_to_buff(&out_buff, &out_pos, &out_size, "<g> <!-- ", 0);
- add_to_buff(&out_buff, &out_pos, &out_size, (x2-x1) == (y2-y1) ? (char*)"circle" : (char*)"ellipse", 0);
- add_to_buff(&out_buff, &out_pos, &out_size, " with pattern -->\n", 0);
- Indent(true);
- }
- add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
- add_to_buff(&out_buff, &out_pos, &out_size, (x2-x1) == (y2-y1) ? (char*)"<circle" : (char*)"<ellipse", 0);
- if(nam && nam[0]) {
- add_to_buff(&out_buff, &out_pos, &out_size, " name=\"", 0);
- add_to_buff(&out_buff, &out_pos, &out_size, nam, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "\"", 0);
- }
- add_to_buff(&out_buff, &out_pos, &out_size, " cx=\"", 0);
- add_int_to_buff(&out_buff, &out_pos, &out_size, (x1+x2)>>1, false, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "\" cy=\"", 0);
- add_int_to_buff(&out_buff, &out_pos, &out_size, (y1+y2)>>1, false, 0);
- if((x2-x1)==(y2-y1)) {
- add_to_buff(&out_buff, &out_pos, &out_size, "\" r=\"", 0);
- add_int_to_buff(&out_buff, &out_pos, &out_size, (x2-x1)>>1, false, 0);
- }
- else {
- add_to_buff(&out_buff, &out_pos, &out_size, "\" rx=\"", 0);
- add_int_to_buff(&out_buff, &out_pos, &out_size, (x2-x1)>>1, false, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "\" ry=\"", 0);
- add_int_to_buff(&out_buff, &out_pos, &out_size, (y2-y1)>>1, false, 0);
- }
- add_to_buff(&out_buff, &out_pos, &out_size, "\" style=\"fill:", 0);
- add_to_buff(&out_buff, &out_pos, &out_size, ColName(dFillCol), 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "; stroke:", 0);
- add_to_buff(&out_buff, &out_pos, &out_size, ColName(dLineCol), 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "; stroke-width:", 0);
- add_int_to_buff(&out_buff, &out_pos, &out_size, iLineWidth, false, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "\"/>\n", 0);
- if(hgo) {
- add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
- add_to_buff(&out_buff, &out_pos, &out_size, "<g ", 3);
- add_to_buff(&out_buff, &out_pos, &out_size, tHatchStyle, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "> <!-- hatch -->\n", 0);
- Indent(true); bUseGroupLine = true;
- hgo->oCircle(x1, y1, x2, y2);
- Indent(false); bUseGroupLine = false;
- add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
- add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n", 0);
- Indent(false);
- add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
- add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n", 0);
- }
- return true;
-}
-
-bool
-ExportSVG::oPolyline(POINT *pts, int cp, char *nam)
-{
- int i, cb;
- char tmptxt[120];
-
- if(cp < 2) return false;
- if (dPattern){
- add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
- add_to_buff(&out_buff, &out_pos, &out_size, "<g style=\"stroke:", 0);
- add_to_buff(&out_buff, &out_pos, &out_size, ColName(dLineCol), 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "; stroke-width:", 0);
- add_int_to_buff(&out_buff, &out_pos, &out_size, iLineWidth, false, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "; stroke-linecap:round\"><!-- pattern line -->\n", 0);
- Indent(true); bUseGroupLine = true;
- for (i = 1; i < cp; i++) PatLine(pts[i-1], pts[i]);
- Indent(false);
- add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
- add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n", 0);
- bUseGroupLine = false;
- }
- else {
- if(cp == 2) return oSolidLine(pts);
- bOutputPending = false;
- cb_out = rlp_strcpy(output, 20,"<polyline points=\"");
- for(i = 0; i < cp; i++) {
-#ifdef USE_WIN_SECURE
- cb = sprintf_s(tmptxt, 120, "%d %d ", pts[i].x, pts[i].y);
-#else
- cb = sprintf(tmptxt, "%d %d ", pts[i].x, pts[i].y);
-#endif
- AddToOutput(tmptxt, cb);
- }
- if(cb_out) output[cb_out-1] = '"';
- if(!bUseGroupLine) {
- cb = rlp_strcpy(tmptxt, 120, " style = \"fill:none; ");
- AddToOutput(tmptxt, cb);
- cb = rlp_strcpy(tmptxt, 120, "stroke:"); //bug fixed by vefremov
- cb += rlp_strcpy(tmptxt+cb, 120-cb, ColName(dLineCol));
- cb += rlp_strcpy(tmptxt+cb, 120-cb, "; ");
- AddToOutput(tmptxt, cb);
-#ifdef USE_WIN_SECURE
- cb = sprintf_s(tmptxt, 120, "stroke-width:%d\"/>",iLineWidth);
-#else
- cb = sprintf(tmptxt, "stroke-width:%d\"/>",iLineWidth);
-#endif
- AddToOutput(tmptxt, cb);
- }
- else AddToOutput("/>", 2);
- add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
- add_to_buff(&out_buff, &out_pos, &out_size, output, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "\n", 1);
- 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){
- add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
- add_to_buff(&out_buff, &out_pos, &out_size, "<g> <!-- rectangle with pattern -->\n", 0);
- Indent(true);
- }
- add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
- add_to_buff(&out_buff, &out_pos, &out_size, "<rect", 5);
- if(nam && nam[0]) {
- add_to_buff(&out_buff, &out_pos, &out_size, " name=\"", 7);
- add_to_buff(&out_buff, &out_pos, &out_size, nam, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "\"", 1);
- }
- add_to_buff(&out_buff, &out_pos, &out_size, " x=\"", 4);
- add_int_to_buff(&out_buff, &out_pos, &out_size, x1, false, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "\" y=\"", 5);
- add_int_to_buff(&out_buff, &out_pos, &out_size, y1, false, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "\" width=\"", 9);
- add_int_to_buff(&out_buff, &out_pos, &out_size, x2-x1-1, false, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "\" height=\"", 10);
- add_int_to_buff(&out_buff, &out_pos, &out_size, y2-y1-1, false, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "\" style=\"fill:", 0);
- add_to_buff(&out_buff, &out_pos, &out_size, ColName(dFillCol), 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "; stroke:", 0);
- add_to_buff(&out_buff, &out_pos, &out_size, ColName(dLineCol), 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "; stroke-width:", 0);
- add_int_to_buff(&out_buff, &out_pos, &out_size, iLineWidth, false, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "\"/>\n", 0);
- if(hgo) {
- add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
- add_to_buff(&out_buff, &out_pos, &out_size, "<g ", 3);
- add_to_buff(&out_buff, &out_pos, &out_size, tHatchStyle, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "> <!-- hatch -->\n", 0);
- Indent(true); bUseGroupLine = true;
- hgo->oRectangle(x1, y1, x2, y2, 0L);
- Indent(false); bUseGroupLine = false;
- add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
- add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n", 5);
- Indent(false);
- add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
- add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n", 5);
- }
- return true;
-}
-
-bool
-ExportSVG::oSolidLine(POINT *p)
-{
- if(!p) return false;
- add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
- add_to_buff(&out_buff, &out_pos, &out_size, "<line x1=\"", 0);
- add_int_to_buff(&out_buff, &out_pos, &out_size, p[0].x, false, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "\" y1=\"", 6);
- add_int_to_buff(&out_buff, &out_pos, &out_size, p[0].y, false, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "\" x2=\"", 6);
- add_int_to_buff(&out_buff, &out_pos, &out_size, p[1].x, false, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "\" y2=\"", 6);
- add_int_to_buff(&out_buff, &out_pos, &out_size, p[1].y, false, 0);
- if(!bUseGroupLine) {
- add_to_buff(&out_buff, &out_pos, &out_size, "\" style=\"stroke:", 0);
- add_to_buff(&out_buff, &out_pos, &out_size, ColName(dLineCol), 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "; stroke-width:", 0);
- add_int_to_buff(&out_buff, &out_pos, &out_size, iLineWidth, false, 0);
- }
- add_to_buff(&out_buff, &out_pos, &out_size, "\"/>\n", 4);
- return true;
-}
-
-bool
-ExportSVG::com_TextOut(int x, int y, char *txt, int cb)
-{
- int c, h, ix, iy, dy;
- char tmptxt[120];
-
- if(!txt || !txt[0]) return false;
- else 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 * 0.8);
- ix = x; dy = 0;
- if(TxtSet.Style & TXS_SUB) {
- if((TxtSet.Align & TXA_VCENTER) == TXA_VCENTER) dy = un2iy(TxtSet.fSize*0.4);
- else if((TxtSet.Align & TXA_VBOTTOM) == TXA_VBOTTOM) dy = un2iy(TxtSet.fSize*0.2);
- else if((TxtSet.Align & TXA_VTOP) == TXA_VTOP) dy = un2iy(TxtSet.fSize*.6);
- }
- else if(TxtSet.Style & TXS_SUPER) {
- if((TxtSet.Align & TXA_VCENTER) == TXA_VCENTER) dy = -un2iy(TxtSet.fSize*0.4);
- else if((TxtSet.Align & TXA_VBOTTOM) == TXA_VBOTTOM) dy = -un2iy(TxtSet.fSize*0.6);
- else if((TxtSet.Align & TXA_VTOP) == TXA_VTOP) dy = -un2iy(TxtSet.fSize*0.2);
- }
-#ifdef USE_WIN_SECURE
- cb_out = sprintf_s(output, 120, "<text x=\"%d\" y=\"%d\" dy=\"%d\" ", ix, iy, dy);
-#else
- cb_out = sprintf(output, "<text x=\"%d\" y=\"%d\" dy=\"%d\" ", ix, iy, dy);
-#endif
- if(fabs(TxtSet.RotBL) >.01 || fabs(TxtSet.RotCHAR) >.01) {
-#ifdef USE_WIN_SECURE
- cb_out += sprintf_s(output+cb_out, 120-cb_out, "transform=\"rotate(%.0f,%d,%d)\" ", -TxtSet.RotBL, ix, iy);
-#else
- cb_out += sprintf(output+cb_out,"transform=\"rotate(%.0f,%d,%d)\" ", -TxtSet.RotBL, ix, iy);
-#endif
- }
- c = rlp_strcpy(tmptxt, 140, "style=\"font-family:");
- switch(TxtSet.Font) {
- case FONT_TIMES: c += rlp_strcpy(tmptxt+c, 120-c, "Times;"); break;
- case FONT_COURIER: c += rlp_strcpy(tmptxt+c, 120-c, "Courier;"); break;
- default: c += rlp_strcpy(tmptxt+c, 120-c, "Helvetica;"); break;
- }
- if(TxtSet.Style & TXS_ITALIC) c += rlp_strcpy(tmptxt+c, 120-c, " font-style:italic;");
- if(TxtSet.Style & TXS_BOLD) c += rlp_strcpy(tmptxt+c, 120-c, " font-weight:bold;");
- if(TxtSet.Style & TXS_UNDERLINE) c += rlp_strcpy(tmptxt+c, 120-c, " text-decoration:underline;");
- AddToOutput(tmptxt, c);
-#ifdef USE_WIN_SECURE
- c = sprintf_s(tmptxt, 120, " fill:%s; stroke:%s; ", ColName(TxtSet.ColTxt), ColName(TxtSet.ColTxt));
-#else
- c = sprintf(tmptxt, " fill:%s; stroke:%s; ", ColName(TxtSet.ColTxt), ColName(TxtSet.ColTxt));
-#endif
- AddToOutput(tmptxt, c);
-#ifdef USE_WIN_SECURE
- c = sprintf_s(tmptxt, 120, "font-size:%d; text-anchor:%s \">", h,
- (TxtSet.Align & TXA_HRIGHT) ? "end" : (TxtSet.Align & TXA_HCENTER) ? "middle":"start");
-#else
- c = sprintf(tmptxt, "font-size:%d; text-anchor:%s \">", h,
- (TxtSet.Align & TXA_HRIGHT) ? "end" : (TxtSet.Align & TXA_HCENTER) ? "middle":"start");
-#endif
- AddToOutput(tmptxt, c);
- if((cb_ind+strlen(txt)+cb_out) <110) cb_out += rlp_strcpy(output+cb_out, 120-cb_out, txt);
- else {
- add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
- add_to_buff(&out_buff, &out_pos, &out_size, output, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "\n", 1);
- cb_out=rlp_strcpy(output, 120, txt);
- }
- add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
- add_to_buff(&out_buff, &out_pos, &out_size, output, 0);
- if((cb_ind + cb_out) <104) {
- add_to_buff(&out_buff, &out_pos, &out_size, "</text>\n", 0);
- }
- else add_to_buff(&out_buff, &out_pos, &out_size, "\n</text>\n", 0);
- return true;
-}
-
-bool
-ExportSVG::oTextOut(int x, int y, char *txt, int cb)
-{
- char *nt;
-
- if(!txt || !txt[0]) return false;
- nt = str2xml(txt, TxtSet.Font == FONT_GREEK);
- return com_TextOut(x, y, nt, cb);
-}
-
-bool
-ExportSVG::oTextOutW(int x, int y, w_char *txt, int cb)
-{
- int i, j;
- wchar_t wc;
- char c;
-
- for(i = j = 0; txt[i]; i++) {
- switch(txt[i]) {
- case '"':
- j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, """);
- break;
- case '&':
- j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, "&");
- break;
- case '<':
- j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, "<");
- break;
- case '>':
- j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, ">");
- break;
- default:
- if(txt[i] > 255) {
-#ifdef USE_WIN_SECURE
- j += sprintf_s(TmpTxt+j, TMP_TXT_SIZE-j, "&#%d;", txt[i]);
-#else
- j += sprintf(TmpTxt+j, "&#%d;", txt[i]);
-#endif
- }
- else if(txt[i] > 127) {
- c = (char)txt[i];
- if(mbtowc(&wc, &c, 1) >0)
-#ifdef USE_WIN_SECURE
- j += sprintf_s(TmpTxt+j, TMP_TXT_SIZE-j, "&#%d;", ((unsigned short)wc));
-#else
- j += sprintf(TmpTxt+j, "&#%d;", ((unsigned short)wc));
-#endif
- }
- else TmpTxt[j++] = (char)txt[i];
- break;
- }
- }
- TmpTxt[j++] = 0;
- return com_TextOut(x, y, TmpTxt, j-1);
-}
-
-bool
-ExportSVG::oPolygon(POINT *pts, int cp, char *nam)
-{
- int i, cb;
- char tmptxt[40];
-
- if(cp <3) return false;
- if(hgo){
- add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
- add_to_buff(&out_buff, &out_pos, &out_size, "<g> <!-- polygon with pattern -->\n", 0);
- Indent(true);
- }
- bOutputPending = false;
-#ifdef USE_WIN_SECURE
- cb_out = sprintf_s(output, 120, "<polygon%s%s%s points=\"",
- nam? " name=\"" : "", nam ? nam : "", nam ? "\"" : "");
-#else
- cb_out = sprintf(output, "<polygon%s%s%s points=\"",
- nam? " name=\"" : "", nam ? nam : "", nam ? "\"" : "");
-#endif
- for(i = 0; i < cp; i++) {
-#ifdef USE_WIN_SECURE
- cb = sprintf_s(tmptxt, 40, "%d %d ", pts[i].x, pts[i].y);
-#else
- cb = sprintf(tmptxt, "%d %d ", pts[i].x, pts[i].y);
-#endif
- AddToOutput(tmptxt, cb);
- }
- if(cb_out) output[cb_out-1] = '"';
-#ifdef USE_WIN_SECURE
- cb = sprintf_s(tmptxt, 40, " style=\"fill:%s; ", ColName(dFillCol));
- AddToOutput(tmptxt, cb);
- cb = sprintf_s(tmptxt, 40, "stroke:%s; ", ColName(dLineCol));
- AddToOutput(tmptxt, cb);
- cb = sprintf_s(tmptxt, 40, "stroke-width:%d\"/>",iLineWidth);
- AddToOutput(tmptxt, cb);
-#else
- cb = sprintf(tmptxt, " style=\"fill:%s; ", ColName(dFillCol));
- AddToOutput(tmptxt, cb);
- cb = sprintf(tmptxt, "stroke:%s; ", ColName(dLineCol));
- AddToOutput(tmptxt, cb);
- cb = sprintf(tmptxt, "stroke-width:%d\"/>",iLineWidth);
- AddToOutput(tmptxt, cb);
-#endif
- add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
- add_to_buff(&out_buff, &out_pos, &out_size, output, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "\n", 1);
- if(bOutputPending)Indent(false);
- if(hgo) {
- add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
- add_to_buff(&out_buff, &out_pos, &out_size, "<g ", 3);
- add_to_buff(&out_buff, &out_pos, &out_size, tHatchStyle, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "> <!-- hatch -->\n", 0);
- Indent(true); bUseGroupLine = true;
- hgo->oPolygon(pts, cp); Indent(false);
- bUseGroupLine = false;
- add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
- add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n", 5);
- Indent(false);
- add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
- add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n", 5);
- }
- return true;
-}
-
-void
-ExportSVG::Indent(bool ind)
-{
- if(ind) {
- if(cb_ind < 20) cb_ind += 3;
- }
- else {
- if(cb_ind > 5) cb_ind -= 3;
- }
-}
-
-void
-ExportSVG::AddToOutput(char *txt, int len)
-{
- if(!txt || !txt[0]) return;
- if(!len) len = (int)strlen(txt);
- if((len + cb_out + cb_ind) < 110){
- cb_out += rlp_strcpy(output+cb_out, 120, txt);
- }
- else {
- add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
- add_to_buff(&out_buff, &out_pos, &out_size, output, 0);
- add_to_buff(&out_buff, &out_pos, &out_size, "\n", 1);
- if(!bOutputPending) Indent(true);
- bOutputPending = true;
- cb_out = rlp_strcpy(output, 120, txt);
- }
-}
-
-char *
-ExportSVG::ColName(DWORD col)
-{
- static char txt1[20], txt2[20];
- static int sw;
- char *ret;
-
- 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++;
-#ifdef USE_WIN_SECURE
- sprintf_s(ret = (sw & 0x01 ? txt1 : txt2), 20, "rgb(%d,%d,%d)", col & 0xff, (col>>8) & 0xff, (col>>16) &0xff);
-#else
- sprintf(ret = (sw & 0x01 ? txt1 : txt2), "rgb(%d,%d,%d)", col & 0xff, (col>>8) & 0xff, (col>>16) &0xff);
-#endif
- return ret;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 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, FontName[30];
- FILE *oFile;
- DWORD CurrCol;
- bool bFontChange;
-
- 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; bFontChange = false; oFile = 0L;
- if(FileName)name = (char*)memdup(FileName, (int)strlen(FileName)+1,0);
- else name = 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)
-{
- int cb;
-
- if(set->fSize > 0.0) {
- if((set->Style & TXS_SUPER) || (set->Style & TXS_SUB)) set->iSize = un2iy(set->fSize * 0.71);
- else set->iSize = un2iy(set->fSize);
- }
- if(!set->iSize) return false;
- anyOutput::SetTextSpec(set);
- switch(TxtSet.Font) {
- case FONT_TIMES: cb = rlp_strcpy(FontName, 30, "(Times"); break; //Serif
- case FONT_COURIER: cb = rlp_strcpy(FontName, 30, "(Courier"); break; //fixed spaced
- default: cb = rlp_strcpy(FontName, 30, "(Helvetica"); break; //Sans Serif
- }
- if(TxtSet.Style & TXS_BOLD) cb += rlp_strcpy(FontName+cb, 30-cb, "-Bold");
- if(TxtSet.Style & TXS_ITALIC) cb += rlp_strcpy(FontName+cb, 30-cb, "-Italic");
- cb += rlp_strcpy(FontName+cb, 30-cb, ")"); bFontChange = true;
- 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) {
-#ifdef USE_WIN_SECURE
- fopen_s(&oFile, name, "w");
-#else
- oFile = fopen(name, "w");
-#endif
- 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");
-#ifdef USE_WIN_SECURE
- ctime_s(TmpTxt, 50, &ti); TmpTxt[24] = 0;
- fprintf(oFile,"%%%%CreationDate: %s", TmpTxt);
-#else
- fprintf(oFile,"%%%%CreationDate: %s", ctime(&ti));
-#endif
- 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, lw;
-
- FlushSolLines(); if(!txt || !txt[0]) return true;
- oGetTextExtent(txt, cb, &w, &h);
- if(bFontChange) {
- fprintf(oFile, "\n%s findfont %d scalefont setfont ", FontName, TxtSet.iSize/10);
- bFontChange = false;
- }
- 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; lw = (float)(iy-y)/150.0f;
- fprintf(oFile,"\n");
- if(fabs(TxtSet.RotBL) >.01 || fabs(TxtSet.RotCHAR) >.01) {
- if(TxtSet.Style & TXS_SUB) iy += un2iy(TxtSet.fSize*0.6);
- else if(TxtSet.Style & TXS_SUPER) iy -= un2iy(TxtSet.fSize*.2);
- 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);
- fprintf(oFile, "%s ", col2eps(CurrCol = TxtSet.ColTxt));
- fprintf(oFile, "(%s) show ", txt);
- if(TxtSet.Style & TXS_UNDERLINE) {
- fprintf(oFile, "\ncurrentpoint %.1f exch pop moveto", (float)(iy-y)/-10.0f - lw*1.2);
- fprintf(oFile, " 0 %.1f lineto %s %.1f setlinewidth stroke ", (float)(iy-y)/-10.0f -lw*1.2,
- col2eps(TxtSet.ColTxt), lw);
- }
- fprintf(oFile, "grestore\n");
- }
- else {
- if(TxtSet.Style & TXS_SUB) iy += un2iy(TxtSet.fSize*0.6);
- else if(TxtSet.Style & TXS_SUPER) iy -= un2iy(TxtSet.fSize*.2);
- fx = ix2eps(ix); fy = iy2eps(iy);
- fprintf(oFile, "%s ", col2eps(CurrCol = TxtSet.ColTxt));
- fprintf(oFile,"%.1f %.1f moveto (%s) show ", fx, fy, txt);
- if(TxtSet.Style & TXS_UNDERLINE) {
- fprintf(oFile, "\ncurrentpoint %.1f exch pop moveto", fy - lw*1.2);
- fprintf(oFile, " %.1f %.1f lineto %s %.1f setlinewidth stroke\n", fx, fy - lw*1.2,
- col2eps(TxtSet.ColTxt), lw);
- }
- }
- 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];
- float r, g, b;
-
- r = (float)(color & 0xff)/255.0f;
- g = (float)((color>>8)&0xff)/255.0f;
- b = (float)((color>>16)&0xff)/255.0f;
-#ifdef USE_WIN_SECURE
- sprintf_s(txt, 50, "%g %g %g setrgbcolor", r, g, b);
-#else
- sprintf(txt, "%g %g %g setrgbcolor", r, g, b);
-#endif
- 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);
-}
+//Export.cpp, Copyright (c) 2002-2008 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 USE_WIN_SECURE
+ #include <share.h> //I/O flags
+#endif
+
+#ifdef _WINDOWS
+ #include <io.h> //for read/write
+#else
+ #define O_BINARY 0x0
+ #include <unistd.h>
+#endif
+
+extern char TmpTxt[];
+extern Default defs;
+static char *str_ind = " ";
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Entry point to export graph to Windows Meta File
+void DoExportWmf(GraphObj *g, char *FileName, float res, DWORD flags)
+{
+ InfoBox("The export of Windos metafile (*.wmf)\n has been dicontinued.\n\n");
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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 oTextOutW(int x, int y, w_char *txt, int cb);
+ bool oPolygon(POINT *pts, int cp, char * nam = 0L);
+
+private:
+ int iLineWidth, cb_out, out_pos, out_size, cb_ind;
+ char *out_buff;
+ bool bUseGroupLine, bOutputPending;
+ GraphObj *go;
+ char *name, output[120], tHatchStyle[80];
+ DWORD flags;
+
+ bool com_TextOut(int x, int y, char *txt, int cb);
+ void Indent(bool ind);
+ void AddToOutput(char *txt, int len);
+ char *ColName(DWORD col);
+ char *Transparency(DWORD col, int type);
+};
+
+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 = (char*)memdup(FileName, (int)strlen(FileName)+1, 0);
+ else name = 0L;
+ out_buff = 0L; out_pos = out_size = 0;
+ flags = flg; cb_ind = 3;
+ rlp_strcpy(tHatchStyle, 80, "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;
+#ifdef USE_WIN_SECURE
+ sprintf_s(tHatchStyle, 80, "style=\"fill:none; stroke:%s; stroke-width:%d\"",
+ ColName(fill->hatch->color), iL);
+#else
+ sprintf(tHatchStyle, "style=\"fill:none; stroke:%s; stroke-width:%d\"",
+ ColName(fill->hatch->color), iL);
+#endif
+ }
+ }
+ else {
+ if(hgo) delete hgo;
+ hgo = 0L;
+ }
+ dFillCol = fill->color;
+ dFillCol2 = fill->color2;
+ return true;
+}
+
+bool
+ExportSVG::SetTextSpec(TextDEF *set)
+{
+ if(set->fSize > 0.0) {
+ if((set->Style & TXS_SUPER) || (set->Style & TXS_SUB))
+ set->iSize = un2iy(set->fSize * 0.71);
+ else 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(flags & 0x01) add_to_buff(&out_buff, &out_pos, &out_size, "Content-Type: image/svg+xml\n\n", 0);
+ VPorg.fy = -un2fiy(go->GetSize(SIZE_GRECT_TOP));
+ VPorg.fx = -un2fix(go->GetSize(SIZE_GRECT_LEFT));
+ add_to_buff(&out_buff, &out_pos, &out_size, "<?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<svg ", 0);
+ if(defs.svgAttr) add_to_buff(&out_buff, &out_pos, &out_size, defs.svgAttr, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, " width=\"", 0);
+ add_int_to_buff(&out_buff, &out_pos, &out_size, w, false, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "\" height=\"", 0);
+ add_int_to_buff(&out_buff, &out_pos, &out_size, h, false, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "\" style=\"stroke-linecap:round; stroke-linejoin:round\">\n", 0);
+ if(defs.svgScript) {
+ add_to_buff(&out_buff, &out_pos, &out_size, "<defs>\n<script type=\"text/ecmascript\"><![CDATA[\n\n", 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, defs.svgScript, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "\n\n]]></script>\n</defs>\n\n", 0);
+ }
+ add_to_buff(&out_buff, &out_pos, &out_size, "<g transform=\"scale(0.1)\" style=\"font-family:Helvetica\">\n", 0);
+ return true;
+}
+
+bool
+ExportSVG::EndPage()
+{
+ FILE *oFile;
+
+ add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n</svg>\n", 0);
+ if(name && out_buff && out_pos > 20) {
+#ifdef USE_WIN_SECURE
+ fopen_s(&oFile, name, "w");
+#else
+ oFile = fopen(name, "w");
+#endif
+ if(!oFile) {
+ ErrorBox("Could not open\noutput file!");
+ return false;
+ }
+ fprintf(oFile, "%s", out_buff);
+ free(out_buff); 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){
+ add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+ add_to_buff(&out_buff, &out_pos, &out_size, "<g> <!-- ", 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, (x2-x1) == (y2-y1) ? (char*)"circle" : (char*)"ellipse", 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, " with pattern -->\n", 0);
+ Indent(true);
+ }
+ add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+ add_to_buff(&out_buff, &out_pos, &out_size, (x2-x1) == (y2-y1) ? (char*)"<circle" : (char*)"<ellipse", 0);
+ if(nam && nam[0]) {
+ add_to_buff(&out_buff, &out_pos, &out_size, " name=\"", 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, nam, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "\"", 0);
+ }
+ add_to_buff(&out_buff, &out_pos, &out_size, " cx=\"", 0);
+ add_int_to_buff(&out_buff, &out_pos, &out_size, (x1+x2)>>1, false, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "\" cy=\"", 0);
+ add_int_to_buff(&out_buff, &out_pos, &out_size, (y1+y2)>>1, false, 0);
+ if((x2-x1)==(y2-y1)) {
+ add_to_buff(&out_buff, &out_pos, &out_size, "\" r=\"", 0);
+ add_int_to_buff(&out_buff, &out_pos, &out_size, (x2-x1)>>1, false, 0);
+ }
+ else {
+ add_to_buff(&out_buff, &out_pos, &out_size, "\" rx=\"", 0);
+ add_int_to_buff(&out_buff, &out_pos, &out_size, (x2-x1)>>1, false, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "\" ry=\"", 0);
+ add_int_to_buff(&out_buff, &out_pos, &out_size, (y2-y1)>>1, false, 0);
+ }
+ add_to_buff(&out_buff, &out_pos, &out_size, "\" style=\"fill:", 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, ColName(dFillCol), 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "; stroke:", 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, ColName(dLineCol), 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "; stroke-width:", 0);
+ add_int_to_buff(&out_buff, &out_pos, &out_size, iLineWidth, false, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, ";", 1);
+ add_to_buff(&out_buff, &out_pos, &out_size, Transparency(dFillCol, 2), 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, Transparency(dLineCol, 1), 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "\"/>\n", 0);
+ if(hgo) {
+ add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+ add_to_buff(&out_buff, &out_pos, &out_size, "<g ", 3);
+ add_to_buff(&out_buff, &out_pos, &out_size, tHatchStyle, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "> <!-- hatch -->\n", 0);
+ Indent(true); bUseGroupLine = true;
+ hgo->oCircle(x1, y1, x2, y2);
+ Indent(false); bUseGroupLine = false;
+ add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+ add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n", 0);
+ Indent(false);
+ add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+ add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n", 0);
+ }
+ return true;
+}
+
+bool
+ExportSVG::oPolyline(POINT *pts, int cp, char *nam)
+{
+ int i, cb;
+ char tmptxt[120];
+
+ if(cp < 2) return false;
+ if (dPattern){
+ add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+ add_to_buff(&out_buff, &out_pos, &out_size, "<g style=\"stroke:", 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, ColName(dLineCol), 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "; stroke-width:", 0);
+ add_int_to_buff(&out_buff, &out_pos, &out_size, iLineWidth, false, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "; stroke-linecap:round;", 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, Transparency(dLineCol, 1), 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "\"><!-- pattern line -->\n", 0);
+ Indent(true); bUseGroupLine = true;
+ for (i = 1; i < cp; i++) PatLine(pts[i-1], pts[i]);
+ Indent(false);
+ add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+ add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n", 0);
+ bUseGroupLine = false;
+ }
+ else {
+ if(cp == 2) return oSolidLine(pts);
+ bOutputPending = false;
+ cb_out = rlp_strcpy(output, 20,"<polyline points=\"");
+ for(i = 0; i < cp; i++) {
+#ifdef USE_WIN_SECURE
+ cb = sprintf_s(tmptxt, 120, "%d %d ", pts[i].x, pts[i].y);
+#else
+ cb = sprintf(tmptxt, "%d %d ", pts[i].x, pts[i].y);
+#endif
+ AddToOutput(tmptxt, cb);
+ }
+ if(cb_out) output[cb_out-1] = '"';
+ if(!bUseGroupLine) {
+ cb = rlp_strcpy(tmptxt, 120, " style = \"fill:none; ");
+ AddToOutput(tmptxt, cb);
+ cb = rlp_strcpy(tmptxt, 120, "stroke:"); //bug fixed by vefremov
+ cb += rlp_strcpy(tmptxt+cb, 120-cb, ColName(dLineCol));
+ cb += rlp_strcpy(tmptxt+cb, 120-cb, "; ");
+ AddToOutput(tmptxt, cb);
+#ifdef USE_WIN_SECURE
+ cb = sprintf_s(tmptxt, 120, "stroke-width:%d;",iLineWidth);
+#else
+ cb = sprintf(tmptxt, "stroke-width:%d;",iLineWidth);
+#endif
+ AddToOutput(tmptxt, cb);
+ if(cb = rlp_strcpy(tmptxt, 40, Transparency(dLineCol, 1))) AddToOutput(tmptxt, cb);
+ AddToOutput("\"/>", 3);
+ }
+ else AddToOutput("/>", 2);
+ add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+ add_to_buff(&out_buff, &out_pos, &out_size, output, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "\n", 1);
+ 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){
+ add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+ add_to_buff(&out_buff, &out_pos, &out_size, "<g> <!-- rectangle with pattern -->\n", 0);
+ Indent(true);
+ }
+ add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+ add_to_buff(&out_buff, &out_pos, &out_size, "<rect", 5);
+ if(nam && nam[0]) {
+ add_to_buff(&out_buff, &out_pos, &out_size, " name=\"", 7);
+ add_to_buff(&out_buff, &out_pos, &out_size, nam, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "\"", 1);
+ }
+ add_to_buff(&out_buff, &out_pos, &out_size, " x=\"", 4);
+ add_int_to_buff(&out_buff, &out_pos, &out_size, x1, false, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "\" y=\"", 5);
+ add_int_to_buff(&out_buff, &out_pos, &out_size, y1, false, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "\" width=\"", 9);
+ add_int_to_buff(&out_buff, &out_pos, &out_size, x2-x1-1, false, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "\" height=\"", 10);
+ add_int_to_buff(&out_buff, &out_pos, &out_size, y2-y1-1, false, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "\" style=\"fill:", 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, ColName(dFillCol), 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "; stroke:", 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, ColName(dLineCol), 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "; stroke-width:", 0);
+ add_int_to_buff(&out_buff, &out_pos, &out_size, iLineWidth, false, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, ";", 1);
+ add_to_buff(&out_buff, &out_pos, &out_size, Transparency(dFillCol, 2), 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, Transparency(dLineCol, 1), 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "\"/>\n", 0);
+ if(hgo) {
+ add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+ add_to_buff(&out_buff, &out_pos, &out_size, "<g ", 3);
+ add_to_buff(&out_buff, &out_pos, &out_size, tHatchStyle, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "> <!-- hatch -->\n", 0);
+ Indent(true); bUseGroupLine = true;
+ hgo->oRectangle(x1, y1, x2, y2, 0L);
+ Indent(false); bUseGroupLine = false;
+ add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+ add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n", 5);
+ Indent(false);
+ add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+ add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n", 5);
+ }
+ return true;
+}
+
+bool
+ExportSVG::oSolidLine(POINT *p)
+{
+ if(!p) return false;
+ add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+ add_to_buff(&out_buff, &out_pos, &out_size, "<line x1=\"", 0);
+ add_int_to_buff(&out_buff, &out_pos, &out_size, p[0].x, false, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "\" y1=\"", 6);
+ add_int_to_buff(&out_buff, &out_pos, &out_size, p[0].y, false, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "\" x2=\"", 6);
+ add_int_to_buff(&out_buff, &out_pos, &out_size, p[1].x, false, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "\" y2=\"", 6);
+ add_int_to_buff(&out_buff, &out_pos, &out_size, p[1].y, false, 0);
+ if(!bUseGroupLine) {
+ add_to_buff(&out_buff, &out_pos, &out_size, "\" style=\"stroke:", 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, ColName(dLineCol), 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "; stroke-width:", 0);
+ add_int_to_buff(&out_buff, &out_pos, &out_size, iLineWidth, false, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, ";", 1);
+ add_to_buff(&out_buff, &out_pos, &out_size, Transparency(dLineCol, 1), 0);
+ }
+ add_to_buff(&out_buff, &out_pos, &out_size, "\"/>\n", 4);
+ return true;
+}
+
+bool
+ExportSVG::com_TextOut(int x, int y, char *txt, int cb)
+{
+ int c, h, ix, iy, dy;
+ char tmptxt[120];
+
+ if(!txt || !txt[0]) return false;
+ else 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 * 0.8);
+ ix = x; dy = 0;
+ if(TxtSet.Style & TXS_SUB) {
+ if((TxtSet.Align & TXA_VCENTER) == TXA_VCENTER) dy = un2iy(TxtSet.fSize*0.4);
+ else if((TxtSet.Align & TXA_VBOTTOM) == TXA_VBOTTOM) dy = un2iy(TxtSet.fSize*0.2);
+ else if((TxtSet.Align & TXA_VTOP) == TXA_VTOP) dy = un2iy(TxtSet.fSize*.6);
+ }
+ else if(TxtSet.Style & TXS_SUPER) {
+ if((TxtSet.Align & TXA_VCENTER) == TXA_VCENTER) dy = -un2iy(TxtSet.fSize*0.4);
+ else if((TxtSet.Align & TXA_VBOTTOM) == TXA_VBOTTOM) dy = -un2iy(TxtSet.fSize*0.6);
+ else if((TxtSet.Align & TXA_VTOP) == TXA_VTOP) dy = -un2iy(TxtSet.fSize*0.2);
+ }
+#ifdef USE_WIN_SECURE
+ cb_out = sprintf_s(output, 120, "<text x=\"%d\" y=\"%d\" dy=\"%d\" ", ix, iy, dy);
+#else
+ cb_out = sprintf(output, "<text x=\"%d\" y=\"%d\" dy=\"%d\" ", ix, iy, dy);
+#endif
+ if(fabs(TxtSet.RotBL) >.01 || fabs(TxtSet.RotCHAR) >.01) {
+#ifdef USE_WIN_SECURE
+ cb_out += sprintf_s(output+cb_out, 120-cb_out, "transform=\"rotate(%.0f,%d,%d)\" ", -TxtSet.RotBL, ix, iy);
+#else
+ cb_out += sprintf(output+cb_out,"transform=\"rotate(%.0f,%d,%d)\" ", -TxtSet.RotBL, ix, iy);
+#endif
+ }
+ c = rlp_strcpy(tmptxt, 140, "style=\"font-family:");
+ switch(TxtSet.Font) {
+ case FONT_TIMES: c += rlp_strcpy(tmptxt+c, 120-c, "Times;"); break;
+ case FONT_COURIER: c += rlp_strcpy(tmptxt+c, 120-c, "Courier;"); break;
+ default: c += rlp_strcpy(tmptxt+c, 120-c, "Helvetica;"); break;
+ }
+ if(TxtSet.Style & TXS_ITALIC) c += rlp_strcpy(tmptxt+c, 120-c, " font-style:italic;");
+ if(TxtSet.Style & TXS_BOLD) c += rlp_strcpy(tmptxt+c, 120-c, " font-weight:bold;");
+ if(TxtSet.Style & TXS_UNDERLINE) c += rlp_strcpy(tmptxt+c, 120-c, " text-decoration:underline;");
+ AddToOutput(tmptxt, c);
+#ifdef USE_WIN_SECURE
+ c = sprintf_s(tmptxt, 120, " fill:%s; stroke:%s;%s ", ColName(TxtSet.ColTxt), ColName(TxtSet.ColTxt),Transparency(TxtSet.ColTxt, 0));
+#else
+ c = sprintf(tmptxt, " fill:%s; stroke:%s;%s ", ColName(TxtSet.ColTxt), ColName(TxtSet.ColTxt),Transparency(TxtSet.ColTxt, 0));
+#endif
+ AddToOutput(tmptxt, c);
+#ifdef USE_WIN_SECURE
+ c = sprintf_s(tmptxt, 120, "font-size:%d; text-anchor:%s \">", h,
+ (TxtSet.Align & TXA_HRIGHT) ? "end" : (TxtSet.Align & TXA_HCENTER) ? "middle":"start");
+#else
+ c = sprintf(tmptxt, "font-size:%d; text-anchor:%s \">", h,
+ (TxtSet.Align & TXA_HRIGHT) ? "end" : (TxtSet.Align & TXA_HCENTER) ? "middle":"start");
+#endif
+ AddToOutput(tmptxt, c);
+ if((cb_ind+strlen(txt)+cb_out) <110) cb_out += rlp_strcpy(output+cb_out, 120-cb_out, txt);
+ else {
+ add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+ add_to_buff(&out_buff, &out_pos, &out_size, output, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "\n", 1);
+ cb_out=rlp_strcpy(output, 120, txt);
+ }
+ add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+ add_to_buff(&out_buff, &out_pos, &out_size, output, 0);
+ if((cb_ind + cb_out) <104) {
+ add_to_buff(&out_buff, &out_pos, &out_size, "</text>\n", 0);
+ }
+ else add_to_buff(&out_buff, &out_pos, &out_size, "\n</text>\n", 0);
+ return true;
+}
+
+bool
+ExportSVG::oTextOut(int x, int y, char *txt, int cb)
+{
+ char *nt;
+
+ if(!txt || !txt[0]) return false;
+ nt = str2xml(txt, TxtSet.Font == FONT_GREEK);
+ return com_TextOut(x, y, nt, cb);
+}
+
+bool
+ExportSVG::oTextOutW(int x, int y, w_char *txt, int cb)
+{
+ int i, j;
+ wchar_t wc;
+ char c;
+
+ for(i = j = 0; txt[i]; i++) {
+ switch(txt[i]) {
+ case '"':
+ j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, """);
+ break;
+ case '&':
+ j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, "&");
+ break;
+ case '<':
+ j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, "<");
+ break;
+ case '>':
+ j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, ">");
+ break;
+ default:
+ if(txt[i] > 255) {
+#ifdef USE_WIN_SECURE
+ j += sprintf_s(TmpTxt+j, TMP_TXT_SIZE-j, "&#%d;", txt[i]);
+#else
+ j += sprintf(TmpTxt+j, "&#%d;", txt[i]);
+#endif
+ }
+ else if(txt[i] > 127) {
+ c = (char)txt[i];
+ if(mbtowc(&wc, &c, 1) >0)
+#ifdef USE_WIN_SECURE
+ j += sprintf_s(TmpTxt+j, TMP_TXT_SIZE-j, "&#%d;", ((unsigned short)wc));
+#else
+ j += sprintf(TmpTxt+j, "&#%d;", ((unsigned short)wc));
+#endif
+ }
+ else TmpTxt[j++] = (char)txt[i];
+ break;
+ }
+ }
+ TmpTxt[j++] = 0;
+ return com_TextOut(x, y, TmpTxt, j-1);
+}
+
+bool
+ExportSVG::oPolygon(POINT *pts, int cp, char *nam)
+{
+ int i, cb;
+ char tmptxt[40];
+
+ if(cp <3) return false;
+ if(hgo){
+ add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+ add_to_buff(&out_buff, &out_pos, &out_size, "<g> <!-- polygon with pattern -->\n", 0);
+ Indent(true);
+ }
+ bOutputPending = false;
+#ifdef USE_WIN_SECURE
+ cb_out = sprintf_s(output, 120, "<polygon%s%s%s points=\"",
+ nam? " name=\"" : "", nam ? nam : "", nam ? "\"" : "");
+#else
+ cb_out = sprintf(output, "<polygon%s%s%s points=\"",
+ nam? " name=\"" : "", nam ? nam : "", nam ? "\"" : "");
+#endif
+ for(i = 0; i < cp; i++) {
+#ifdef USE_WIN_SECURE
+ cb = sprintf_s(tmptxt, 40, "%d %d ", pts[i].x, pts[i].y);
+#else
+ cb = sprintf(tmptxt, "%d %d ", pts[i].x, pts[i].y);
+#endif
+ AddToOutput(tmptxt, cb);
+ }
+ if(cb_out) output[cb_out-1] = '"';
+#ifdef USE_WIN_SECURE
+ cb = sprintf_s(tmptxt, 40, " style=\"fill:%s; ", ColName(dFillCol));
+ AddToOutput(tmptxt, cb);
+ cb = sprintf_s(tmptxt, 40, "stroke:%s; ", ColName(dLineCol));
+ AddToOutput(tmptxt, cb);
+ cb = sprintf_s(tmptxt, 40, "stroke-width:%d;",iLineWidth);
+ AddToOutput(tmptxt, cb);
+#else
+ cb = sprintf(tmptxt, " style=\"fill:%s; ", ColName(dFillCol));
+ AddToOutput(tmptxt, cb);
+ cb = sprintf(tmptxt, "stroke:%s; ", ColName(dLineCol));
+ AddToOutput(tmptxt, cb);
+ cb = sprintf(tmptxt, "stroke-width:%d;", iLineWidth);
+ AddToOutput(tmptxt, cb);
+#endif
+ if(cb = rlp_strcpy(tmptxt, 40, Transparency(dFillCol, 2))) AddToOutput(tmptxt, cb);
+ if(cb = rlp_strcpy(tmptxt, 40, Transparency(dLineCol, 1))) AddToOutput(tmptxt, cb);
+ AddToOutput("\"/>", 3);
+ add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+ add_to_buff(&out_buff, &out_pos, &out_size, output, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "\n", 1);
+ if(bOutputPending)Indent(false);
+ if(hgo) {
+ add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+ add_to_buff(&out_buff, &out_pos, &out_size, "<g ", 3);
+ add_to_buff(&out_buff, &out_pos, &out_size, tHatchStyle, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "> <!-- hatch -->\n", 0);
+ Indent(true); bUseGroupLine = true;
+ hgo->oPolygon(pts, cp); Indent(false);
+ bUseGroupLine = false;
+ add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+ add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n", 5);
+ Indent(false);
+ add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+ add_to_buff(&out_buff, &out_pos, &out_size, "</g>\n", 5);
+ }
+ return true;
+}
+
+void
+ExportSVG::Indent(bool ind)
+{
+ if(ind) {
+ if(cb_ind < 20) cb_ind += 3;
+ }
+ else {
+ if(cb_ind > 5) cb_ind -= 3;
+ }
+}
+
+void
+ExportSVG::AddToOutput(char *txt, int len)
+{
+ if(!txt || !txt[0]) return;
+ if(!len) len = (int)strlen(txt);
+ if((len + cb_out + cb_ind) < 110){
+ cb_out += rlp_strcpy(output+cb_out, 120, txt);
+ }
+ else {
+ add_to_buff(&out_buff, &out_pos, &out_size, str_ind, cb_ind);
+ add_to_buff(&out_buff, &out_pos, &out_size, output, 0);
+ add_to_buff(&out_buff, &out_pos, &out_size, "\n", 1);
+ if(!bOutputPending) Indent(true);
+ bOutputPending = true;
+ cb_out = rlp_strcpy(output, 120, txt);
+ }
+}
+
+char *
+ExportSVG::ColName(DWORD col)
+{
+ static char txt1[20], txt2[20];
+ static int sw;
+ char *ret;
+
+ 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 = (sw+1) & 0x0f;
+#ifdef USE_WIN_SECURE
+ sprintf_s(ret = (sw & 0x01 ? txt1 : txt2), 20, "rgb(%d,%d,%d)", col & 0xff, (col>>8) & 0xff, (col>>16) &0xff);
+#else
+ sprintf(ret = (sw & 0x01 ? txt1 : txt2), "rgb(%d,%d,%d)", col & 0xff, (col>>8) & 0xff, (col>>16) &0xff);
+#endif
+ return ret;
+}
+
+char *
+ExportSVG::Transparency(DWORD col, int type)
+{
+ static char txt1[30], txt2[30];
+ static int sw;
+ int cb;
+ char *ret;
+ double a;
+
+ if((col & 0xfe000000) == 0) return "";
+ a = ((double)(255-(col>>24)))/256.0;
+ if(a > 0.99) return "";
+ sw = (sw+1) & 0x0f;
+ ret = sw & 0x01 ? txt1 : txt2;
+ switch(type) {
+ case 1:
+ cb = rlp_strcpy(ret, 30, " stroke-opacity:"); break;
+ case 2:
+ cb = rlp_strcpy(ret, 30, " fill-opacity:"); break;
+ default:
+ cb = rlp_strcpy(ret, 30, " opacity:"); break;
+ }
+#ifdef USE_WIN_SECURE
+ sprintf_s(ret+cb, 30-cb, "%0.3lf;", a);
+#else
+ sprintf(ret+cb, "%0.3lf;", a);
+#endif
+ return ret;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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, FontName[30];
+ FILE *oFile;
+ DWORD CurrCol;
+ bool bFontChange;
+
+ 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; bFontChange = false; oFile = 0L;
+ if(FileName)name = (char*)memdup(FileName, (int)strlen(FileName)+1,0);
+ else name = 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)
+{
+ int cb;
+
+ if(set->fSize > 0.0) {
+ if((set->Style & TXS_SUPER) || (set->Style & TXS_SUB)) set->iSize = un2iy(set->fSize * 0.71);
+ else set->iSize = un2iy(set->fSize);
+ }
+ if(!set->iSize) return false;
+ anyOutput::SetTextSpec(set);
+ switch(TxtSet.Font) {
+ case FONT_TIMES: cb = rlp_strcpy(FontName, 30, "(Times"); break; //Serif
+ case FONT_COURIER: cb = rlp_strcpy(FontName, 30, "(Courier"); break; //fixed spaced
+ default: cb = rlp_strcpy(FontName, 30, "(Helvetica"); break; //Sans Serif
+ }
+ if(TxtSet.Style & TXS_BOLD) cb += rlp_strcpy(FontName+cb, 30-cb, "-Bold");
+ if(TxtSet.Style & TXS_ITALIC) cb += rlp_strcpy(FontName+cb, 30-cb, "-Italic");
+ cb += rlp_strcpy(FontName+cb, 30-cb, ")"); bFontChange = true;
+ 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) {
+#ifdef USE_WIN_SECURE
+ fopen_s(&oFile, name, "w");
+#else
+ oFile = fopen(name, "w");
+#endif
+ 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");
+#ifdef USE_WIN_SECURE
+ ctime_s(TmpTxt, 50, &ti); TmpTxt[24] = 0;
+ fprintf(oFile,"%%%%CreationDate: %s", TmpTxt);
+#else
+ fprintf(oFile,"%%%%CreationDate: %s", ctime(&ti));
+#endif
+ 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, lw;
+
+ FlushSolLines(); if(!txt || !txt[0]) return true;
+ oGetTextExtent(txt, cb, &w, &h);
+ if(bFontChange) {
+ fprintf(oFile, "\n%s findfont %d scalefont setfont ", FontName, TxtSet.iSize/10);
+ bFontChange = false;
+ }
+ 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; lw = (float)(iy-y)/150.0f;
+ fprintf(oFile,"\n");
+ if(fabs(TxtSet.RotBL) >.01 || fabs(TxtSet.RotCHAR) >.01) {
+ if(TxtSet.Style & TXS_SUB) iy += un2iy(TxtSet.fSize*0.6);
+ else if(TxtSet.Style & TXS_SUPER) iy -= un2iy(TxtSet.fSize*.2);
+ 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);
+ fprintf(oFile, "%s ", col2eps(CurrCol = TxtSet.ColTxt));
+ fprintf(oFile, "(%s) show ", txt);
+ if(TxtSet.Style & TXS_UNDERLINE) {
+ fprintf(oFile, "\ncurrentpoint %.1f exch pop moveto", (float)(iy-y)/-10.0f - lw*1.2);
+ fprintf(oFile, " 0 %.1f lineto %s %.1f setlinewidth stroke ", (float)(iy-y)/-10.0f -lw*1.2,
+ col2eps(TxtSet.ColTxt), lw);
+ }
+ fprintf(oFile, "grestore\n");
+ }
+ else {
+ if(TxtSet.Style & TXS_SUB) iy += un2iy(TxtSet.fSize*0.6);
+ else if(TxtSet.Style & TXS_SUPER) iy -= un2iy(TxtSet.fSize*.2);
+ fx = ix2eps(ix); fy = iy2eps(iy);
+ fprintf(oFile, "%s ", col2eps(CurrCol = TxtSet.ColTxt));
+ fprintf(oFile,"%.1f %.1f moveto (%s) show ", fx, fy, txt);
+ if(TxtSet.Style & TXS_UNDERLINE) {
+ fprintf(oFile, "\ncurrentpoint %.1f exch pop moveto", fy - lw*1.2);
+ fprintf(oFile, " %.1f %.1f lineto %s %.1f setlinewidth stroke\n", fx, fy - lw*1.2,
+ col2eps(TxtSet.ColTxt), lw);
+ }
+ }
+ 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];
+ float r, g, b;
+
+ r = (float)(color & 0xff)/255.0f;
+ g = (float)((color>>8)&0xff)/255.0f;
+ b = (float)((color>>16)&0xff)/255.0f;
+#ifdef USE_WIN_SECURE
+ sprintf_s(txt, 50, "%g %g %g setrgbcolor", r, g, b);
+#else
+ sprintf(txt, "%g %g %g setrgbcolor", r, g, b);
+#endif
+ 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
index c224279..13a88b3 100755
--- a/Fileio.cpp
+++ b/Fileio.cpp
@@ -1,3951 +1,4034 @@
-//FileIO.cpp, Copyright (c) 2001-2007 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[];
-extern int cPlots;
-GraphObj *LastOpenGO;
-
-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, typFRECT, typNZLFPOINT, typLFPOINT, typPOINT3D,
- typAXDEF, typPTRAXDEF, typLINEDEF, typFILLDEF, typGOBJ, typOBJLST,
- typFPLST, typFPLST3D, typIPLST, typTEXT, typTXTDEF, typPTRTXTDEF,
- typLAST = 0x100};
-
-static char *ptr =0L;
-static int cbOut, sizeOut = 0, iFile = -1;
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// output graph to file, elementary functions
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static int OpenOutputFile(char *file)
-{
- time_t ti;
-
- if(ptr) free(ptr);
- ptr = 0L; cbOut = 0; ti = time(0L);
- if(file && BackupFile(file)) {
-#ifdef USE_WIN_SECURE
- if(_sopen_s(&iFile, file, O_RDWR | O_BINARY | O_CREAT | O_TRUNC,
- 0x40, S_IWRITE) || iFile < 0){
- ErrorBox("Open failed for output file");
- return -1;
- }
-#else
- if(-1 ==(iFile = open(file, O_RDWR | O_BINARY | O_CREAT | O_TRUNC,
- S_IWRITE | S_IREAD))){
- ErrorBox("Open failed for output file");
- return -1;
- }
-#endif
- ptr = (char *)malloc(sizeOut = 2000);
- if(!ptr) goto openerr;
- cbOut = rlp_strcpy(ptr, 20, ";RLP 1.0\n;File \"");
- add_to_buff(&ptr, &cbOut, &sizeOut, file, 0);
- add_to_buff(&ptr, &cbOut, &sizeOut, "\" created by RLPlot version "SZ_VERSION" for ", 0);
-#ifdef _WINDOWS
- add_to_buff(&ptr, &cbOut, &sizeOut, "Windows", 7);
-#else
- add_to_buff(&ptr, &cbOut, &sizeOut, "Qt", 2);
-#endif
- add_to_buff(&ptr, &cbOut, &sizeOut, "\n;Date/Time: ", 13);
-#ifdef USE_WIN_SECURE
- ctime_s(ptr+cbOut, 30, &ti); cbOut += 25;
-#else
- add_to_buff(&ptr, &cbOut, &sizeOut, ctime(&ti), 25);
-#endif
- }
- return iFile;
-openerr:
- ptr = 0L; cbOut = sizeOut = 0;
-#ifdef USE_WIN_SECURE
- if(iFile >=0) _close(iFile);
-#else
- if(iFile >=0) close(iFile);
-#endif
- return iFile = -1;
-}
-
-static void CloseOutputFile()
-{
- if(iFile >= 0){
-#ifdef USE_WIN_SECURE
- if(cbOut) _write(iFile, ptr, cbOut);
- _close(iFile);
-#else
- if(cbOut) write(iFile, ptr, cbOut);
- close(iFile);
-#endif
- }
- if(ptr) free(ptr);
- cbOut = sizeOut = 0;
- ptr = 0L; iFile = -1;
-}
-
-static void WriteTypObjLst(GraphObj **obs, int c1)
-{
- int i, j, no, n, *idx;
-
- if(!obs || !(idx=(int*)malloc(c1*sizeof(int)))) return;
- for(i = no = 0; i < c1; i++) {
- if(j = Notary->RegisterGO(obs[i])) idx[no++] = j;
- }
- add_to_buff(&ptr, &cbOut, &sizeOut, "(", 1);
- add_int_to_buff(&ptr, &cbOut, &sizeOut, no, false, 0);
- add_to_buff(&ptr, &cbOut, &sizeOut, "){", 2);
- for(i = 0; i < no; i += 16) {
- if(i) add_to_buff(&ptr, &cbOut, &sizeOut, " ", 3);
- for(j = 0; (n=i+j) < no && j < 16; j++) {
- add_int_to_buff(&ptr, &cbOut, &sizeOut, idx[n], j != 0, 0);
- }
- if(n >= no) add_to_buff(&ptr, &cbOut, &sizeOut, "}", 1);
- else add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
- }
-}
-
-static void WriteTypIpLst(POINT *ppt, int count)
-{
- long i, j, c, n;
-
- if(!ppt) return;
- add_to_buff(&ptr, &cbOut, &sizeOut, "(", 1);
- add_int_to_buff(&ptr, &cbOut, &sizeOut, count, false, 0);
- add_to_buff(&ptr, &cbOut, &sizeOut, "){", 2);
- for(i = 0; i < count; i += 8) {
- for(j = c = 0; (n = i+j) <count && j < 8; j++) {
- add_int_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].x, (j != 0), 0);
- add_int_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].y, true, 0);
- }
- if(n >= count) add_to_buff(&ptr, &cbOut, &sizeOut, "}", 1);
- else add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
- }
-}
-
-static void WriteTypFpLst(lfPOINT *ppt, long count, bool bPar)
-{
- int i, j, n;
-
- if (bPar){
- if(!ppt) return;
- add_to_buff(&ptr, &cbOut, &sizeOut, "(", 1);
- add_int_to_buff(&ptr, &cbOut, &sizeOut, count, false, 0);
- add_to_buff(&ptr, &cbOut, &sizeOut, "){", 2);
- }
- else {
- if(!ppt) count = 0;
- add_int_to_buff(&ptr, &cbOut, &sizeOut, count, true, 0);
- if(!count) {
- add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
- return;
- }
- add_to_buff(&ptr, &cbOut, &sizeOut, " {", 2);
- }
- for(i = 0; i < count; i += 8) {
- for(j = 0; (n = i+j) <count && j < 8; j++) {
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].fx, (j != 0));
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].fy, true);
- }
- if(n >= count) add_to_buff(&ptr, &cbOut, &sizeOut, "}", 1);
- else add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
- }
-}
-
-static void WriteTypFpLst3D(fPOINT3D *ppt, int count)
-{
- long i, j, c, n;
-
- if(!ppt) return;
- add_to_buff(&ptr, &cbOut, &sizeOut, "(", 1);
- add_int_to_buff(&ptr, &cbOut, &sizeOut, count, false, 0);
- add_to_buff(&ptr, &cbOut, &sizeOut, "){", 2);
- for(i = 0; i < count; i +=5) {
- for(j = c = 0; (n =i+j) <count && j < 5; j++) {
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].fx, (j != 0));
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].fy, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].fz, true);
- }
- if(n >= count) add_to_buff(&ptr, &cbOut, &sizeOut, "}", 1);
- else add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
- }
-}
-
-static char * esc_str = 0L;
-static int esc_str_size = 0;
-static void WriteEscString(char *txt)
-{
- int i, j, l, lim = 60;
-
- if(!txt || !txt[0]) return;
- l = (int)strlen(txt);
- if((l+10) > esc_str_size) if(!(esc_str = (char*)realloc(esc_str, esc_str_size = (l+100))))return;
- j = 0; esc_str[j++] = '"';
- for(i = 0; txt[i]; i++) {
- switch(txt[i]) {
- case '\\':
- esc_str[j++] = '\\'; esc_str[j++] = '\\';
- break;
- case '\n':
- esc_str[j++] = '\\'; esc_str[j++] = 'n';
- break;
- default:
- if(((unsigned char*)txt)[i] >= ' ') esc_str[j++] = txt[i];
- }
- if(j > (esc_str_size -10)) esc_str = (char*)realloc(esc_str, (esc_str_size += 100));
- if(j > lim && (l-i) > 3) {
- esc_str[j++] = '"'; esc_str[j++] = '\\';
- esc_str[j++] = '\n'; esc_str[j++] = ' ';
- esc_str[j++] = ' '; esc_str[j++] = ' ';
- esc_str[j++] = '"';
- lim += 60;
- }
- }
- esc_str[j++] = '"';
- add_to_buff(&ptr, &cbOut, &sizeOut, esc_str, j);
-}
-
-bool ExecOutput(int id, char *Class, descIO *Desc)
-{
- int i, last;
- fRECT *fr;
- AxisDEF *ax;
- LineDEF *ld;
- FillDEF *fd;
- TextDEF *tx;
-
- add_to_buff(&ptr, &cbOut, &sizeOut, "\n[", 2);
- add_int_to_buff(&ptr, &cbOut, &sizeOut, id, false, 0);
- add_to_buff(&ptr, &cbOut, &sizeOut, "=", 1);
- add_to_buff(&ptr, &cbOut, &sizeOut, Class, 0);
- add_to_buff(&ptr, &cbOut, &sizeOut, "]\n", 2);
- cObsW++;
- for(i = 0; Desc[i].label; i++) {
- if(ptr[cbOut-1] != '\n') add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
- last = cbOut;
- add_to_buff(&ptr, &cbOut, &sizeOut, Desc[i].label, 0);
- add_to_buff(&ptr, &cbOut, &sizeOut, "=", 1);
- switch(Desc[i].type & 0xff){
- case typNZINT:
- if(!(*(int*)Desc[i].ptr)) {
- cbOut = last; break;
- }
- //if not zero value continue as if int
- case typINT:
- add_int_to_buff(&ptr, &cbOut, &sizeOut, *(int*)Desc[i].ptr, true, 0);
- break;
- case typNZLFLOAT:
- if(*((double*)Desc[i].ptr) == 0.0) {
- cbOut = last; break;
- }
- //if not zero or negative continue as if float
- case typLFLOAT:
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, *(double*)Desc[i].ptr, true);
- break;
- case typDWORD:
- add_hex_to_buff(&ptr, &cbOut, &sizeOut, *(DWORD *)Desc[i].ptr, true);
- break;
- case typFRECT:
- fr = (fRECT*)Desc[i].ptr;
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, fr->Xmin, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, fr->Ymax, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, fr->Xmax, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, fr->Ymin, true);
- break;
- case typNZLFPOINT:
- if(((lfPOINT *)Desc[i].ptr)->fx == ((lfPOINT *)Desc[i].ptr)->fy &&
- ((lfPOINT *)Desc[i].ptr)->fx == 0.0f){
- cbOut = last; break;
- }
- //if not zero continue as if fPOINT
- case typLFPOINT:
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ((lfPOINT *)Desc[i].ptr)->fx, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ((lfPOINT *)Desc[i].ptr)->fy, true);
- break;
- case typPOINT3D:
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ((fPOINT3D *)Desc[i].ptr)->fx, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ((fPOINT3D *)Desc[i].ptr)->fy, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ((fPOINT3D *)Desc[i].ptr)->fz, true);
- 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
- add_hex_to_buff(&ptr, &cbOut, &sizeOut, ax->flags, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->min, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->max, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[0].fx, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[0].fy, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[0].fz, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[1].fx, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[1].fy, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[1].fz, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->Start, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->Step, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->Center.fx, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->Center.fy, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->Radius, true);
- WriteTypFpLst(ax->breaks, ax->nBreaks, false);
- break;
- case typLINEDEF:
- ld = (LineDEF *)Desc[i].ptr;
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ld->width, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ld->patlength, true);
- add_hex_to_buff(&ptr, &cbOut, &sizeOut, ld->color, true);
- add_hex_to_buff(&ptr, &cbOut, &sizeOut, ld->pattern, true);
- break;
- case typFILLDEF:
- fd = (FillDEF *)Desc[i].ptr;
- //we set the 'hatch' member to zero: reconstruct after read
- add_int_to_buff(&ptr, &cbOut, &sizeOut, fd->type, true, 0);
- add_hex_to_buff(&ptr, &cbOut, &sizeOut, fd->color, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, fd->scale, true);
- add_to_buff(&ptr, &cbOut, &sizeOut, " 0x0", 4);
- add_hex_to_buff(&ptr, &cbOut, &sizeOut, fd->color2, true);
- break;
- case typGOBJ:
- if(*(GraphObj **)(Desc[i].ptr)) add_int_to_buff(&ptr, &cbOut, &sizeOut,
- Notary->RegisterGO(*(GraphObj **)(Desc[i].ptr)), true, 0);
- else cbOut = last;
- break;
- case typOBJLST:
- if(!*(GraphObj ***)(Desc[i].ptr)){
- cbOut = last; break;
- }
- WriteTypObjLst(*(GraphObj ***)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0);
- break;
- case typIPLST:
- if(!*(POINT**)(Desc[i].ptr)){
- cbOut = last; break;
- }
- WriteTypIpLst(*(POINT**)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0L);
- break;
- case typFPLST:
- if(!*(lfPOINT**)(Desc[i].ptr)){
- cbOut = last; break;
- }
- WriteTypFpLst(*(lfPOINT**)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0L, true);
- break;
- case typFPLST3D:
- if(!*(fPOINT3D**)(Desc[i].ptr)){
- cbOut = last; break;
- }
- WriteTypFpLst3D(*(fPOINT3D**)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0);
- break;
- case typTEXT:
- if(!*(char**)(Desc[i].ptr)) cbOut = last;
- else WriteEscString(*((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) {
- cbOut = last; break;
- }
- add_hex_to_buff(&ptr, &cbOut, &sizeOut, tx->ColTxt, true);
- add_hex_to_buff(&ptr, &cbOut, &sizeOut, tx->ColBg, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, tx->fSize, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, tx->RotBL, true);
- add_dbl_to_buff(&ptr, &cbOut, &sizeOut, tx->RotCHAR, true);
- add_int_to_buff(&ptr, &cbOut, &sizeOut, tx->Align, true, 0);
- add_int_to_buff(&ptr, &cbOut, &sizeOut, tx->Mode, true, 0);
- add_int_to_buff(&ptr, &cbOut, &sizeOut, tx->Style, true, 0);
- add_int_to_buff(&ptr, &cbOut, &sizeOut, tx->Font, true, 0);
- if(tx->text && tx->text[0]) {
- add_to_buff(&ptr, &cbOut, &sizeOut, " \"", 2);
- add_to_buff(&ptr, &cbOut, &sizeOut, tx->text, 0);
- add_to_buff(&ptr, &cbOut, &sizeOut, "\"\n", 2);
- }
- break;
- }
- if(Desc[i].type & typLAST) break;
- }
- if(ptr[cbOut-1] != '\n') add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
- return true;
-}
-
-void ReadTypIpLst(POINT *ptr, long count, unsigned char *first)
-{
- int i, j, k, f[20];
-
- if(!ptr || !first) return;
-#ifdef USE_WIN_SECURE
- k = sscanf_s((char*)first, "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
- &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]);
-#else
- k = sscanf((char*)first, "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
- &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]);
-#endif
- 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;
-#ifdef USE_WIN_SECURE
- k = sscanf_s((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]);
-#else
- 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]);
-#endif
- 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;
-#ifdef USE_WIN_SECURE
- k = sscanf_s((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]);
-#else
- 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]);
-#endif
- 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 = (int)strlen(*txt);
-
- do {
- mlines = false;
- Cache->ReadLine(tmp, sizeof(tmp));
- for(i = (int)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 = (int)strlen(tmp+i)) && (ntxt = (char*)realloc(*txt, cb + j + 1))) {
- rlp_strcpy(ntxt+cb, j+1, tmp+i);
- cb += j; *(txt) = ntxt;
- }
- } while (mlines);
-}
-
-bool ExecInput(descIO *Desc)
-{
- unsigned char c, tmp[1000], tmp2[20];
- int i, j, k, l;
- bool match, mlines;
- int 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((char*)tmp, Desc[j].label)) {
- Cache->ReadLine((char*)tmp, sizeof(tmp));
- switch(Desc[j].type & 0xff){
- case typNZINT:
- case typINT:
-#ifdef USE_WIN_SECURE
- sscanf_s((char*)tmp, "%d", (int*)Desc[j].ptr);
-#else
- sscanf((char*)tmp, "%d", (int*)Desc[j].ptr);
-#endif
- break;
- case typNZLFLOAT: case typLFLOAT:
-#ifdef USE_WIN_SECURE
- sscanf_s((char*)tmp, "%lf", (double*)Desc[j].ptr);
-#else
- sscanf((char*)tmp, "%lf", (double*)Desc[j].ptr);
-#endif
- break;
- case typDWORD:
-#ifdef USE_WIN_SECURE
- sscanf_s((char*)tmp, "%x", (DWORD*)Desc[j].ptr);
-#else
- sscanf((char*)tmp, "%x", (DWORD*)Desc[j].ptr);
-#endif
- break;
- case typFRECT:
- fr = (fRECT*) Desc[j].ptr;
-#ifdef USE_WIN_SECURE
- sscanf_s((char*)tmp, "%lf%lf%lf%lf", &fr->Xmin, &fr->Ymax, &fr->Xmax, &fr->Ymin);
-#else
- sscanf((char*)tmp, "%lf%lf%lf%lf", &fr->Xmin, &fr->Ymax, &fr->Xmax, &fr->Ymin);
-#endif
- break;
- case typNZLFPOINT: case typLFPOINT:
- lfp = (lfPOINT*) Desc[j].ptr;
-#ifdef USE_WIN_SECURE
- sscanf_s((char*)tmp, "%lf%lf", &lfp->fx, &lfp->fy);
-#else
- sscanf((char*)tmp, "%lf%lf", &lfp->fx, &lfp->fy);
-#endif
- break;
- case typPOINT3D:
- lfp3d = (fPOINT3D*) Desc[j].ptr;
-#ifdef USE_WIN_SECURE
- sscanf_s((char*)tmp, "%lf%lf%lf", &lfp3d->fx, &lfp3d->fy, &lfp3d->fz);
-#else
- sscanf((char*)tmp, "%lf%lf%lf", &lfp3d->fx, &lfp3d->fy, &lfp3d->fz);
-#endif
- 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;
-#ifdef USE_WIN_SECURE
- sscanf_s((char*)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);
-#else
- sscanf((char*)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);
-#endif
- 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;
-#ifdef USE_WIN_SECURE
- sscanf_s((char*)tmp,"%lf%lf%x%x", &ld->width, &ld->patlength, &ld->color, &ld->pattern);
-#else
- sscanf((char*)tmp,"%lf%lf%x%x", &ld->width, &ld->patlength, &ld->color, &ld->pattern);
-#endif
- break;
- case typFILLDEF:
- fd = (FillDEF*) Desc[j].ptr;
-#ifdef USE_WIN_SECURE
- sscanf_s((char*)tmp, "%d%x%lf%x%x", &fd->type, &fd->color, &fd->scale, &fd->hatch, &fd->color2);
-#else
- sscanf((char*)tmp, "%d%x%lf%x%x", &fd->type, &fd->color, &fd->scale, &fd->hatch, &fd->color2);
-#endif
- fd->hatch = 0L;
- break;
- case typGOBJ:
- *(GraphObj**)(Desc[j].ptr) = Notary->PopGO(atol((char*)tmp));
- break;
- case typOBJLST:
- for(i = 0; i < 10 && tmp[i] != '(' && tmp[i]; i++);
- if(!tmp[i]) break;
-#ifdef USE_WIN_SECURE
- if(sscanf_s((char*)tmp+i+1, "%ld", &il) && il) {
-#else
- if(sscanf((char*)tmp+i+1, "%ld", &il) && il) {
-#endif
- *Desc[j].count = il;
- if(!*(GraphObj***)(Desc[j].ptr)){
- *(GraphObj***)(Desc[j].ptr) = (GraphObj**)calloc(il, sizeof(GraphObj*));
- }
- if((gobs = *(GraphObj***)(Desc[j].ptr))){
- i += 4;
- while(tmp[i-1] != '{') i++; while(tmp[i-1] < 33) i++;
-#ifdef USE_WIN_SECURE
- strcat_s((char*)tmp, 1000, " ");
-#else
- strcat((char*)tmp, " ");
-#endif
- 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;
- }
- }
-#ifdef USE_WIN_SECURE
- sscanf_s((char*)tmp2, "%d", &jl);
-#else
- sscanf((char*)tmp2, "%d", &jl);
-#endif
- *gobs++ = Notary->PopGO(jl);
- if(c == '}') break;
- }
- }
- }
- break;
- case typIPLST:
- for(i = 0; i < 10 && tmp[i] != '(' && tmp[i]; i++);
- if(!tmp[i]) break;
-#ifdef USE_WIN_SECURE
- if(sscanf_s((char*)tmp+i+1, "%d", &il) && il) {
-#else
- if(sscanf((char*)tmp+i+1, "%d", &il) && il) {
-#endif
- *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;
-#ifdef USE_WIN_SECURE
- if(sscanf_s((char*)tmp+i+1, "%d", &il) && il) {
-#else
- if(sscanf((char*)tmp+i+1, "%d", &il) && il) {
-#endif
- *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;
-#ifdef USE_WIN_SECURE
- if(sscanf_s((char*)tmp+i+1, "%d", &il) && il) {
-#else
- if(sscanf((char*)tmp+i+1, "%d", &il) && il) {
-#endif
- *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 = (int)strlen((char*)tmp); i > 0 &&(tmp[i-1] < 32 || (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((char*)tmp);
- if(tmp[0]){
- *(char**)(Desc[j].ptr) = (char*)memdup((char*)tmp+i, (int)strlen((char*)tmp+i)+1, 0);
- 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
- }
-#ifdef USE_WIN_SECURE
- sscanf_s((char*)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);
-#else
- sscanf((char*)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);
-#endif
- tx->iSize = 0;
- for(i = (int)strlen((char*)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 = (char*)memdup((char*)tmp+l+1, (int)strlen((char*)tmp+l+1)+1, 0);
- }
- 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((char*)tmp, sizeof(tmp)); // then continue
- }
- j= 0;
- }
- }
- }while(!match);
- }
-}
-
-bool SaveGraphAs(GraphObj *g)
-{
- char *name = 0L;
- int i;
- bool bRet = true;
-
- 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 = (int)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();
- }
- else bRet = false;
- if(Notary) delete Notary; Notary = 0L;
- return bRet;
-}
-
-char *GraphToMem(GraphObj *g, long *size)
-{
- static char *ret;
-
- if(Notary || !g) {
- ErrorBox("Output pending or\nno graph.");
- return false;
- }
- cObsW = 0; iFile = -1;
- cbOut = sizeOut = 0; ptr = 0L;
- 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 = -1;
- cbOut = sizeOut = 0; ptr = 0L;
- return ret;
- }
- return 0L;
-}
-
-void UpdGOfromMem(GraphObj *go, unsigned char *buff)
-{
- int i=0;
-
- if(!go || !buff) return;
- iFile = -1; 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, bool bPaste)
-{
- unsigned char c, tmp[80];
- char debug[80];
- int i, id, lid;
- unsigned int hv;
- GraphObj *go;
- scaleINFO sc_info;
-
- LastOpenGO = 0L;
- 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;
-#ifdef USE_WIN_SECURE
- sscanf_s((char*)tmp, "%d", &id);
-#else
- sscanf((char*)tmp, "%d", &id);
-#endif
- 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 92534: go = new Bezier(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 117848: go = new xyStat(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;
- case 66848: go = new Func3D(FILE_READ); break;
- case 5001225: go = new TextFrame(FILE_READ); break;
- case 4743132: go = new NormQuant(FILE_READ); break;
- default:
-#ifdef USE_WIN_SECURE
- sprintf_s(debug, 80, "Object %ld in file\n(Class = \"%s\")\nhash #%d\nis unknown.", id, tmp, hv);
-#else
- sprintf(debug, "Object %ld in file\n(Class = \"%s\")\nhash #%d\nis unknown.", id, tmp, hv);
-#endif
- 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((LastOpenGO = go = Notary->PopGO(lid))) {
- go->Command(CMD_SET_DATAOBJ, 0L, 0L);
- delete Notary; Notary = 0L;
- if(bPaste && go->Id == GO_GRAPH) {
- sc_info.sx.fx = -((Graph*)go)->GRect.Xmin; sc_info.sy.fx = -((Graph*)go)->GRect.Ymin;
- sc_info.sx.fy = sc_info.sy.fy = sc_info.sz.fy = 1.0; sc_info.sz.fx = 0.0;
- go->Command(CMD_SCALE, &sc_info, 0L);
- sc_info.sx.fy = sc_info.sy.fy = sc_info.sz.fy = 1.0/go->GetSize(SIZE_SCALE);
- sc_info.sx.fx = sc_info.sy.fx = sc_info.sz.fx = 0.0;
- go->Command(CMD_SCALE, &sc_info, 0L);
- }
- if(bPaste && root->Command(CMD_PASTE_OBJ, (void *)go, 0L)) {
- // object accepted
- }
- else if(go->Id < GO_GRAPH
- && !(root->Command(CMD_DROP_PLOT, (void *)go, 0L))){
- DeleteGO(go); go = 0L;
- }
- else if(go->Id >= GO_GRAPH
- && !(root->Command(CMD_DROP_GRAPH, (void *)go, 0L))){
- DeleteGO(go); go = 0L;
- }
- if(go) go->Command(CMD_FILENAME, name, 0L);
- }
- if(Notary) delete Notary; Notary = 0L;
- delete Cache; Cache = 0L;
- return true;
-
-ReadErr:
- Cache->Close();
-#ifdef USE_WIN_SECURE
- if(iFile >= 0) _close(iFile);
-#else
- if(iFile >= 0) close(iFile);
-#endif
- iFile = -1;
- 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 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 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, (int)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 = DefSize(SIZE_SYMBOL);
- SymLine.color = parent ? parent->GetColor(COL_SYM_LINE) : defs.Color(COL_SYM_LINE);
- SymLine.width = parent ? parent->GetSize(SIZE_SYM_LINE) : DefSize(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 = DefSize(SIZE_BUBBLE_LINE);
- BubbleFillLine.width = DefSize(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 = DefSize(SIZE_BAR);
- mo = 0L;
- mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
- 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;
-
-#ifdef USE_WIN_SECURE
- if(fopen_s(&file, name, "r")) {
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "DataLine: open failed for file \"%s\"", name);
-#else
- if(!(file = fopen(name, "r"))) {
- sprintf(TmpTxt, "DataLine: open failed for file \"%s\"", name);
-#endif
- 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 {
-#ifdef USE_WIN_SECURE
- c = fscanf_s(file, "%lf%lf", &Values[i].fx, &Values[i].fy);
-#else
- c = fscanf(file, "%lf%lf", &Values[i].fx, &Values[i].fy);
-#endif
- 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 {
-#ifdef USE_WIN_SECURE
- c = fscanf_s(file, "%lf", &Values[i].fy);
-#else
- c = fscanf(file, "%lf", &Values[i].fy);
-#endif
- 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", typTEXT, &file1, 0L},
- {"Desc", typLAST | typTEXT, &name, 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.0;
- return true;
- case FILE_READ:
- ExecInput(Desc);
- nPnt = i;
- nPntSet = i-1;
- if(file2)FileValues(file2, 1, 0.0, 1.0);
- 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", typLINEDEF, &ErrLine, 0L},
- {"Desc", typLAST | typTEXT, &name, 0L}};
-
- switch(rw) {
- case SAVE_VARS:
- return SaveVarGO(Desc);
- case INIT_VARS:
- InitVarsGO(Desc);
- SizeBar = DefSize(SIZE_ERRBAR);
- ErrLine.width = DefSize(SIZE_ERRBAR_LINE);
- ErrLine.color = defs.Color(COL_SYM_LINE);
- mo = 0L;
- mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
- 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 = DefSize(SIZE_ARROW_CAPWIDTH);
- cl = DefSize(SIZE_ARROW_CAPLENGTH);
- LineDef.color = parent ? parent->GetColor(COL_DATA_LINE) : defs.Color(COL_DATA_LINE);
- LineDef.width = parent ? parent->GetSize(SIZE_ARROW_LINE) : DefSize(SIZE_ARROW_LINE);
- type = ARROW_LINE; dh1 = dh2 = 0L; mo = 0L;
- mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
- 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 = DefSize(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", typLINEDEF, &LineDef, 0L},
- {"Desc", typLAST | typTEXT, &name, 0L}};
-
- switch(rw) {
- case SAVE_VARS:
- return SaveVarGO(Desc);
- case INIT_VARS:
- InitVarsGO(Desc);
- size = DefSize(SIZE_WHISKER);
- LineDef.width = DefSize(SIZE_WHISKER_LINE);
- LineDef.color = defs.Color(COL_WHISKER);
- mo = 0L;
- mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
- 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 = DefSize(SIZE_SYMBOL);
- Line.color = defs.Color(COL_SYM_LINE);
- Line.width = DefSize(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 = DefSize(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 = DefSize(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 = DefSize(SIZE_ARROW_CAPWIDTH);
- cl = DefSize(SIZE_ARROW_CAPLENGTH);
- Line.color = defs.Color(COL_ARROW);
- Line.width = DefSize(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},
- {"ssRef", typIPLST, &ssRef, &cssRef},
- {"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 = DefSize(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 = DefSize(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;
- return true;
- case FILE_READ:
- return ExecInput(Desc);
- case FILE_WRITE:
- if(parent && parent->Id != GO_MLABEL) {
- if(!TextDef.text || !TextDef.text[0]) return false;
- }
- 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},
- {"lspc", typLFLOAT, &lspc, 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 = DefSize(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; lspc = 1.0;
- 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
-TextFrame::FileIO(int rw)
-{
- descIO Desc[] = {
- {"moveable", typNZINT, &moveable, 0L},
- {"Pos1", typNZLFPOINT, &pos1, 0L},
- {"Pos2", typNZLFPOINT, &pos2, 0L},
- {"lspc", typLFLOAT, &lspc, 0L},
- {"Pad", typFRECT, &pad, 0L},
- {"TxtDef", typTXTDEF, &TextDef, 0L},
- {"Line", typLINEDEF, &Line, 0L},
- {"FillLine", typLINEDEF, &FillLine, 0L},
- {"Fill", typFILLDEF, &Fill, 0L},
- {"Text", typLAST | typTEXT, &text, 0L}};
- switch(rw) {
- case SAVE_VARS:
- return false;
- case INIT_VARS:
- InitVarsGO(Desc);
- TextDef.ColTxt = 0x0L;
- TextDef.ColBg = 0x00ffffffL;
- TextDef.fSize = DefSize(SIZE_TEXT);
- TextDef.RotBL = TextDef.RotCHAR = 0.0;
- TextDef.iSize = 0;
- TextDef.Align = TXA_VBOTTOM | TXA_HLEFT;
- TextDef.Mode = TXM_TRANSPARENT;
- TextDef.Style = TXS_NORMAL;
- TextDef.Font = FONT_HELVETICA;
- TextDef.text = 0L;
- lines = 0L; nlines = 0; drc = 0L;
- cur_pos.x = cur_pos.y = tm_c = 0; tm_rec = 0L;
- bModified = bResize = has_m1 = has_m2 = false;
- if(Fill.hatch) memcpy(&FillLine, Fill.hatch, sizeof(LineDEF));
- Fill.hatch = &FillLine; c_char = m1_char = m2_char = '?';
- pad.Xmin = pad.Xmax = pad.Ymin = pad.Ymax = DefSize(SIZE_SYMBOL)/2.0;
- Cursor.left = Cursor.right = Cursor.top = Cursor.bottom = 0;
- pad.Xmax *= 2.0;
- return true;
- case FILE_READ:
- ExecInput(Desc); Fill.hatch = &FillLine;
- return true;
- case FILE_WRITE:
- if(lines)lines2text();
- if(!text || !text[0]) return false;
- return ExecOutput(Notary->RegisterGO(this), "TextFrame", 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 = DefSize(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
-Bezier::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:
- //assume that all initialization is done by polyline::FileIO(int rw)
- return true;
- case FILE_READ:
- ExecInput(Desc);
- pgFill.hatch = &pgFillLine;
- return true;
- case FILE_WRITE:
- return ExecOutput(Notary->RegisterGO(this), "bezier", 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 = DefSize(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 = DefSize(SIZE_DRECT_TOP); B_Rect.Xmin = DefSize(SIZE_DRECT_LEFT);
- B_Rect.Xmax = B_Rect.Xmin + 1.5*(d = DefSize(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; hasLine = false;
- trc.left = trc.right = trc.top = trc.bottom = 0;
- if(!name) {
- name = (char*)malloc(20 * sizeof(char));
- rlp_strcpy(name, 20, "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[] = {
- {"hide", typNZINT, &hidden, 0L},
- {"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", typOBJLST, &Labels, &nPoints},
- {"x_info", typTEXT, &x_info, 0L},
- {"y_info", typTEXT, &y_info, 0L},
- {"DataDesc", typLAST | typTEXT, &data_desc, 0L}};
- int i;
-
- switch(rw) {
- case INIT_VARS:
- x_info = y_info = z_info = 0L;
- InitVarsGO(Desc);
- DefSym = SYM_CIRCLE;
- DefSel = 0x01;
- dirty = true;
- if(name) {
-#ifdef USE_WIN_SECURE
- i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "xy-plot (%s)", name);
-#else
- i = sprintf(TmpTxt, "xy-plot (%s)", name);
-#endif
- free(name); name = (char*)memdup(TmpTxt, i+1, 0);
- }
- 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;
-}
-
-bool
-xyStat::FileIO(int rw)
-{
- descIO Desc[] = {
- {"Type", typNZINT, &type, 0L},
- {"hide", typNZINT, &hidden, 0L},
- {"Bounds", typFRECT, &Bounds, 0L},
- {"DefSym", typNZINT, &DefSym, 0L},
- {"baDist", typLFPOINT, &BarDist, 0L},
- {"confi", typLFLOAT, &ci, 0L},
- {"xRange", typTEXT, &xRange, 0L},
- {"yRange", typTEXT, &yRange, 0L},
- {"prefix", typTEXT, &case_prefix, 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},
- {"Labels", typOBJLST, &Labels, &nPoints},
- {"x_info", typTEXT, &x_info, 0L},
- {"y_info", typLAST | typTEXT, &y_info, 0L}};
- int i;
-
- switch(rw) {
- case INIT_VARS:
- //most initialistion is done by PlotScatt::FileIO
- curr_data = 0L;
- case_prefix = 0L;
- ci = 95.0;
- 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(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), "xyStat", 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},
- {"hide", typNZINT, &hidden, 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;
- dmin = HUGE_VAL, dmax = -HUGE_VAL;
- if(name) {
-#ifdef USE_WIN_SECURE
- i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "freq. dist. (%s)", name);
-#else
- i = sprintf(TmpTxt, "freq. dist. (%s)", name);
-#endif
- free(name); name = (char*)memdup(TmpTxt, i+1, 0);
- }
- 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},
- {"hide", typNZINT, &hidden, 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) {
-#ifdef USE_WIN_SECURE
- i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "regression (%s)", name);
-#else
- i = sprintf(TmpTxt, "regression (%s)", name);
-#endif
- free(name); name = (char*)memdup(TmpTxt, i+1, 0);
- }
- 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[] = {
- {"hide", typNZINT, &hidden, 0L},
- {"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 = DefSize(SIZE_BUBBLE_LINE);
- BubbleFillLine.color = defs.Color(COL_BUBBLE_FILLLINE);
- BubbleFillLine.width = DefSize(SIZE_BUBBLE_HATCH_LINE);
- BubbleFill.hatch = &BubbleFillLine;
- dirty = true;
- if(name) {
-#ifdef USE_WIN_SECURE
- i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "bubbles (%s)", name);
-#else
- i = sprintf(TmpTxt, "bubbles (%s)", name);
-#endif
- free(name); name = (char*)memdup(TmpTxt, i+1, 0);
- }
- 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},
- {"hide", typNZINT, &hidden, 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) {
-#ifdef USE_WIN_SECURE
- i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "polar root (%s)", name);
-#else
- i = sprintf(TmpTxt, "polar root (%s)", name);
-#endif
- free(name); name = (char*)memdup(TmpTxt, i+1, 0);
- }
- 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(Labels) for(i = 0; i < nPoints; i++) if(Labels[i]) Labels[i]->RegGO(n);
- if(TheLine) TheLine->RegGO(n);
- ((notary*)n)->AddRegGO(this);
- }
-}
-
-bool
-BoxPlot::FileIO(int rw)
-{
- descIO Desc[] = {
- {"Type", typNZINT, &type, 0L},
- {"hide", typNZINT, &hidden, 0L},
- {"Bounds", typFRECT, &Bounds, 0L},
- {"xRange", typTEXT, &xRange, 0L},
- {"yRange", typTEXT, &yRange, 0L},
- {"prefix", typTEXT, &case_prefix, 0L},
- {"boDist", typLFPOINT, &BoxDist, 0L},
- {"ci_box", typNZLFLOAT, &ci_box, 0L},
- {"ci_err", typNZLFLOAT, &ci_err, 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},
- {"Labels", typOBJLST, &Labels, &nPoints},
- {"Line", typLAST | typGOBJ, &TheLine, 0L}};
- int i;
-
- switch(rw) {
- case INIT_VARS:
- dirty = true; InitVarsGO(Desc);
- if(name) {
-#ifdef USE_WIN_SECURE
- i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "boxes (%s)", name);
-#else
- i = sprintf(TmpTxt, "boxes (%s)", name);
-#endif
- free(name); name = (char*)memdup(TmpTxt, i+1, 0);
- }
- curr_data = 0L;
- 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(Labels) for(i = 0; i < nPoints; i++)
- if(Labels[i]) Labels[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},
- {"hide", typNZINT, &hidden, 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},
- {"hide", typNZINT, &hidden, 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) {
-#ifdef USE_WIN_SECURE
- i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "stack (%s)", name);
-#else
- i = sprintf(TmpTxt, "stack (%s)", name);
-#endif
- free(name); name = (char*)memdup(TmpTxt, i+1, 0);
- }
- 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},
- {"hide", typNZINT, &hidden, 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) {
-#ifdef USE_WIN_SECURE
- i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "pie chart (%s)", name);
-#else
- i = sprintf(TmpTxt, "pie chart (%s)", name);
-#endif
- free(name); name = (char*)memdup(TmpTxt, i+1, 0);
- }
- 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},
- {"hide", typNZINT, &hidden, 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},
- {"DataDesc", typTEXT, &data_desc, 0L},
- {"hide", typNZINT, &hidden, 0L},
- {"x_axis", typNZINT, &use_xaxis, 0L},
- {"y_axis", typNZINT, &use_yaxis, 0L},
- {"z_axis", typNZINT, &use_zaxis, 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) {
-#ifdef USE_WIN_SECURE
- i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "xyz-plot (%s)", name);
-#else
- i = sprintf(TmpTxt, "xyz-plot (%s)", name);
-#endif
- free(name); name = (char*)memdup(TmpTxt, i+1, 0);
- }
- 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},
- {"hide", typNZINT, &hidden, 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},
- {"DataDesc", typTEXT, &data_desc, 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) {
-#ifdef USE_WIN_SECURE
- i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "ribbon (%s)", name);
-#else
- i = sprintf(TmpTxt, "ribbon (%s)", name);
-#endif
- free(name); name = (char*)memdup(TmpTxt, i+1, 0);
- }
- 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);
- if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->RegGO(n);
- ((notary*)n)->AddRegGO(this);
- }
-}
-
-bool
-Grid3D::FileIO(int rw)
-{
- descIO Desc[] = {
- {"Type", typNZINT, &type, 0L},
- {"hide", typNZINT, &hidden, 0L},
- {"Start", typPOINT3D, &start, 0L},
- {"Step", typPOINT3D, &step, 0L},
- {"Line", typLINEDEF, &Line, 0L},
- {"Fill", typFILLDEF, &Fill, 0L},
- {"lines", typOBJLST, &lines, &nLines},
- {"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;
- step.fx = step.fz = 1.0;
- if(name) {
-#ifdef USE_WIN_SECURE
- i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "grid (%s)", name);
-#else
- i = sprintf(TmpTxt, "grid (%s)", name);
-#endif
- free(name); name = (char*)memdup(TmpTxt, i+1, 0);
- }
- 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;
- if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->parent = this;
- return true;
- case FILE_WRITE:
- if(lines) for(i = 0; i < nLines; i++) if(lines[i]) lines[i]->FileIO(rw);
- if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->FileIO(rw);
- return ExecOutput(Notary->RegisterGO(this), "Grid3D", Desc);
- }
- return false;
-}
-
-bool
-Limits::FileIO(int rw)
-{
- descIO Desc[] = {
- {"Bounds", typLAST | typFRECT, &Bounds, 0L}};
- int i;
-
- switch(rw) {
- case INIT_VARS:
- if(name) {
-#ifdef USE_WIN_SECURE
- i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "limits (%s)", name);
-#else
- i = sprintf(TmpTxt, "limits (%s)", name);
-#endif
- free(name); name = (char*)memdup(TmpTxt, i+1, 0);
- }
- 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)
-{
- descIO Desc[] = {
- {"hide", typNZINT, &hidden, 0L},
- {"x1", typNZLFLOAT, &x1, 0L},
- {"x2", typNZLFLOAT, &x2, 0L},
- {"xstep", typNZLFLOAT, &xstep, 0L},
- {"Line", typLINEDEF, &Line, 0L},
- {"f_xy", typTEXT, &cmdxy, 0L},
- {"param", typTEXT, ¶m, 0L},
- {"DataLine", typGOBJ, &dl, 0L},
- {"Desc", typLAST | typTEXT, &name, 0L}};
- int i;
-
- switch(rw) {
- case SAVE_VARS:
- return SaveVarGO(Desc);
- case INIT_VARS:
- InitVarsGO(Desc);
- cmdxy = param = 0L;
- memcpy(&Line, defs.GetLine(), sizeof(LineDEF));
- if(name) {
-#ifdef USE_WIN_SECURE
- i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "function (%s)", name);
-#else
- i = sprintf(TmpTxt, "function (%s)", name);
-#endif
- free(name); name = (char*)memdup(TmpTxt, i+1, 0);
- }
- return true;
- case FILE_READ:
- ExecInput(Desc);
- if(dl) dl->parent = this;
- return true;
- case FILE_WRITE:
- if(dl) dl->FileIO(rw);
- ExecOutput(Notary->RegisterGO(this), "Function", Desc);
- }
- 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)
-{
- descIO Desc[] = {
- {"hide", typNZINT, &hidden, 0L},
- {"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, &cmdxy, 0L},
- {"p_xy", typTEXT, &parxy, 0L},
- {"Symbols", typLAST | typOBJLST, &Symbols, &nPoints}};
- int i;
-
- 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) {
-#ifdef USE_WIN_SECURE
- i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "fit function (%s)", name);
-#else
- i = sprintf(TmpTxt, "fit function (%s)", name);
-#endif
- free(name); name = (char*)memdup(TmpTxt, i+1, 0);
- }
- return true;
- case FILE_READ:
- ExecInput(Desc);
- if(Symbols) for(i = 0; i < nPoints; i++)
- if(Symbols[i]) Symbols[i]->parent = this;
- return true;
- case FILE_WRITE:
- 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
-NormQuant::FileIO(int rw)
-{
- lfPOINT *dt;
- long cnt;
- descIO Desc[] = {
- {"Type", typNZINT, &type, 0L},
- {"nData", typINT, &nData, 0L},
- {"Data", typFPLST, &dt, &cnt},
- {"ssRef", typTEXT, &ssRef, 0L},
- {"x_info", typTEXT, &x_info, 0L},
- {"y_info", typLAST | typTEXT, &y_info, 0L}};
- int i, j, l;
-
- if(rw == FILE_WRITE) {
- if(nData < 4) return false;
- l = (nData >>1) +1; cnt = l;
- if(!(dt = (lfPOINT *)calloc(l, sizeof(lfPOINT))))return false;
- for(i = j = 0; i < nData; i += 2, j++) {
- dt[j].fx = src_data[i]; dt[j].fy = src_data[i+1];
- }
- }
- else {
- dt = 0L; cnt = 0;
- }
- switch(rw) {
- case INIT_VARS:
- InitVarsGO(Desc);
- sy = new Symbol(this, data, 0.0, 0.0, SYM_CIRCLE);
- x_vals = y_vals = src_data = 0L;
- if(name) {
-#ifdef USE_WIN_SECURE
- i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "normal quantiles (%s)", name);
-#else
- i = sprintf(TmpTxt, "normal quantiles (%s)", name);
-#endif
- free(name); name = (char*)memdup(TmpTxt, i+1, 0);
- }
- return true;
- case FILE_READ:
- ExecInput(Desc);
- if(dt && cnt > 1 && (src_data = (double*)malloc(nData*sizeof(double)))) {
- for(i = j = 0, l = nData-1; i < nData; i += 2, j++) {
- src_data[i] = dt[j].fx; if(i < l) src_data[i+1] = dt[j].fy;
- }
- free(dt);
- }
- return true;
- case FILE_WRITE:
- ExecOutput(Notary->RegisterGO(this), "NormQuant", Desc);
- free(dt);
- return true;
- }
- 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 = DefSize(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;
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "Error open file \"%s\"\nfor axis ticks", name);
-#else
- sprintf(TmpTxt, "Error open file \"%s\"\nfor axis ticks", name);
-#endif
- 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 = (int)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 = DefSize(SIZE_AXIS_LINE);
- sizAxTick = DefSize(SIZE_AXIS_TICKS);
- sizAxTickLabel = DefSize(SIZE_TICK_LABELS);
- colAxis = parent ? parent->GetColor(COL_AXIS) : defs.Color(COL_AXIS);
- GridLine.color = 0x00808080L;
- GridLine.pattern = 0xf8f8f8f8L;
- brksymsize = DefSize(SIZE_TICK_LABELS);
- brkgap = DefSize(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 = DefSize(SIZE_TICK_LABELS); tlbdef.Align = TXA_VCENTER | TXA_HCENTER;
- tlbdef.Style = TXS_NORMAL; tlbdef.Mode = TXM_TRANSPARENT;
- tlbdef.Font = FONT_HELVETICA; atv = 0L;
- 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) 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;
- descIO Desc[] = {
- {"hide", typNZINT, &hidden, 0L},
- {"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},
- {"x_axis", typNZINT, &use_xaxis, 0L},
- {"y_axis", typNZINT, &use_yaxis, 0L},
- {"z_axis", typNZINT, &use_zaxis, 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 = DefSize(SIZE_GRECT_LEFT) + DefSize(SIZE_DRECT_LEFT);
- cub2.fx = DefSize(SIZE_GRECT_LEFT) + DefSize(SIZE_DRECT_RIGHT);
- cub1.fy = DefSize(SIZE_GRECT_TOP) + DefSize(SIZE_DRECT_BOTTOM);
- cub2.fy = DefSize(SIZE_GRECT_TOP) + DefSize(SIZE_DRECT_TOP);
- cub1.fy += DefSize(SIZE_DRECT_TOP); cub2.fy += DefSize(SIZE_DRECT_TOP);
- cub1.fz = 0.0;
- cub2.fz = DefSize(SIZE_DRECT_BOTTOM) - DefSize(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;
- Sc_Plots = 0L; nscp = 0;
- if(name) {
-#ifdef USE_WIN_SECURE
- i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "3D-root (%s)", name);
-#else
- i = sprintf(TmpTxt, "3D-root (%s)", name);
-#endif
- free(name); name = (char*)memdup(TmpTxt, i+1, 0);
- }
- return true;
- case FILE_READ:
- rot_vec.fx = 0.919384; rot_vec.fy = 0.389104; rot_vec.fz = -0.057709;
- rot_ang.fx = 0.327146; rot_ang.fy = 0.944974; rot_ang.fz = 0.055026;
- 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
-Func3D::RegGO(void *n)
-{
-}
-
-bool
-Func3D::FileIO(int rw)
-{
- fPOINT3D rot_vec, rot_ang;
- descIO Desc[] = {
- {"Type", typNZINT, &type, 0L},
- {"hide", typNZINT, &hidden, 0L},
- {"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},
- {"x_axis", typNZINT, &use_xaxis, 0L},
- {"y_axis", typNZINT, &use_yaxis, 0L},
- {"z_axis", typNZINT, &use_zaxis, 0L},
- {"Axes", typOBJLST, &Axes, (long*)&nAxes},
- {"Plots", typOBJLST, &plots, (long*)&nPlots},
- {"x1", typNZLFLOAT, &x1, 0L},
- {"x2", typNZLFLOAT, &x2, 0L},
- {"xstep", typNZLFLOAT, &xstep, 0L},
- {"z1", typNZLFLOAT, &x1, 0L},
- {"z2", typNZLFLOAT, &x2, 0L},
- {"zstep", typNZLFLOAT, &xstep, 0L},
- {"Line", typLINEDEF, &Line, 0L},
- {"Fill", typFILLDEF, &Fill, 0L},
- {"f_xz", typTEXT, &cmdxy, 0L},
- {"param", typLAST | typTEXT, ¶m, 0L}};
- int i;
-
- switch(rw) {
- case SAVE_VARS:
- return SaveVarGO(Desc);
- case INIT_VARS:
- x1 = -20.0; x2 = 20.0; xstep = 2.0;
- z1 = -20.0; z2 = 20.0; zstep = 2.0;
- gda = 0L; gob = 0L;
- param = cmdxy = 0L;
- Line.width = DefSize(SIZE_HAIRLINE);
- Line.patlength = DefSize(SIZE_PATLENGTH);
- Line.color = Line.pattern = 0x0L;
- Fill.color = 0x00c0c0c0;
- Fill.color2 = 0x00ffffff;
- Fill.hatch = 0L;
- Fill.type = FILL_LIGHT3D;
- if(name) {
-#ifdef USE_WIN_SECURE
- i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "3D function (Plot %d)", cPlots);
-#else
- i = sprintf(TmpTxt, "3D function (Plot %d)", cPlots);
-#endif
- free(name); name = (char*)memdup(TmpTxt, i+1, 0);
- }
- return true;
- case FILE_READ:
- rot_vec.fx = 0.919384; rot_vec.fy = 0.389104; rot_vec.fz = -0.057709;
- rot_ang.fx = 0.327146; rot_ang.fy = 0.944974; rot_ang.fz = 0.055026;
- 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);
- ExecOutput(Notary->RegisterGO(this), "Func3D", Desc);
- }
- return false;
-}
-
-void
-FitFunc3D::RegGO(void *n)
-{
-}
-
-bool
-FitFunc3D::FileIO(int rw)
-{
- fPOINT3D rot_vec, rot_ang;
- descIO Desc[] = {
- {"Type", typNZINT, &type, 0L},
- {"hide", typNZINT, &hidden, 0L},
- {"ssXref", typTEXT, &ssXref, 0L},
- {"ssYref", typTEXT, &ssYref, 0L},
- {"ssZref", typTEXT, &ssZref, 0L},
- {"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},
- {"x_axis", typNZINT, &use_xaxis, 0L},
- {"y_axis", typNZINT, &use_yaxis, 0L},
- {"z_axis", typNZINT, &use_zaxis, 0L},
- {"Axes", typOBJLST, &Axes, (long*)&nAxes},
- {"Plots", typOBJLST, &plots, (long*)&nPlots},
- {"x1", typNZLFLOAT, &x1, 0L},
- {"x2", typNZLFLOAT, &x2, 0L},
- {"xstep", typNZLFLOAT, &xstep, 0L},
- {"z1", typNZLFLOAT, &x1, 0L},
- {"z2", typNZLFLOAT, &x2, 0L},
- {"zstep", typNZLFLOAT, &xstep, 0L},
- {"maxiter", typNZINT, &maxiter, 0L},
- {"Line", typLINEDEF, &Line, 0L},
- {"Fill", typFILLDEF, &Fill, 0L},
- {"f_xz", typTEXT, &cmdxy, 0L},
- {"param", typLAST | typTEXT, ¶m, 0L}};
- int i;
-
- switch(rw) {
- case SAVE_VARS:
- return SaveVarGO(Desc);
- case INIT_VARS:
- x1 = -20.0; x2 = 20.0; xstep = 2.0;
- z1 = -20.0; z2 = 20.0; zstep = 2.0;
- gda = 0L; gob = 0L;
- conv = 1.0e-15; maxiter = 100;
- param = cmdxy = ssXref = ssYref = ssZref = 0L;
- Line.width = DefSize(SIZE_HAIRLINE);
- Line.patlength = DefSize(SIZE_PATLENGTH);
- Line.color = Line.pattern = 0x0L;
- Fill.color = 0x00c0c0c0;
- Fill.color2 = 0x00ffffff;
- Fill.hatch = 0L;
- Fill.type = FILL_LIGHT3D;
- if(name) {
-#ifdef USE_WIN_SECURE
- i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "FitFunc3D (Plot %d)", cPlots);
-#else
- i = sprintf(TmpTxt, "FitFunc3D (Plot %d)", cPlots);
-#endif
- free(name); name = (char*)memdup(TmpTxt, i+1, 0);
- }
- return true;
- case FILE_READ:
- rot_vec.fx = 0.919384; rot_vec.fy = 0.389104; rot_vec.fz = -0.057709;
- rot_ang.fx = 0.327146; rot_ang.fy = 0.944974; rot_ang.fz = 0.055026;
- 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);
- ExecOutput(Notary->RegisterGO(this), "FitFunc3D", 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},
- {"Scale", typNZLFLOAT, &scale, 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 = bDialogOpen = 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; PasteObj = 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; if(scale == 1.0) scale = 0.0;
- //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)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]->Id != GO_GRAPH) 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(Id == GO_PAGE)RegGO(Notary);
- 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.cUnits, 0L},
- {"dtHeight", typINT, &dlgtxtheight, 0L},
- {"ss_txt", typLFLOAT, &defs.ss_txt, 0L},
- {"fmt_date", typTEXT, &defs.fmt_date, 0L},
- {"fmt_datetime", typTEXT, &defs.fmt_datetime, 0L},
- {"fmt_time", typTEXT, &defs.fmt_time, 0L},
- {"curr_path", typTEXT, &defs.currPath, 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);
- //check for plausibility
- if(defs.ss_txt < 0.3 || defs.ss_txt > 3.0) defs.ss_txt = 0.9;
- if(defs.dUnits < 0 || defs.dUnits > 2) defs.dUnits = 0;
- defs.cUnits = defs.dUnits;
-#ifdef _WINDOWS
- if(dlgtxtheight < 5 || dlgtxtheight > 60) dlgtxtheight = 16;
-#else
- if(dlgtxtheight < 5 || dlgtxtheight > 60) dlgtxtheight = 10;
-#endif
- return true;
- case FILE_WRITE:
- Notary = new notary();
-#ifdef USE_WIN_SECURE
- _unlink(defs.IniFile);
-#else
- unlink(defs.IniFile);
-#endif
- iFile = OpenOutputFile(defs.IniFile);
- if(iFile >=0) {
- ExecOutput(-1, "Defaults", Desc);
- }
- CloseOutputFile(); if(Notary) delete Notary; Notary = 0L;
- return true;
- }
- return false;
-}
+//FileIO.cpp, Copyright (c) 2001-2008 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[];
+extern int cPlots;
+GraphObj *LastOpenGO;
+
+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, typFRECT, typNZLFPOINT, typLFPOINT, typPOINT3D,
+ typAXDEF, typPTRAXDEF, typLINEDEF, typFILLDEF, typGOBJ, typOBJLST,
+ typFPLST, typFPLST3D, typIPLST, typTEXT, typTXTDEF, typPTRTXTDEF,
+ typLAST = 0x100};
+
+static char *ptr =0L;
+static int cbOut, sizeOut = 0, iFile = -1;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// output graph to file, elementary functions
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static int OpenOutputFile(char *file)
+{
+ time_t ti;
+
+ if(ptr) free(ptr);
+ ptr = 0L; cbOut = 0; ti = time(0L);
+ if(file && BackupFile(file)) {
+#ifdef USE_WIN_SECURE
+ if(_sopen_s(&iFile, file, O_RDWR | O_BINARY | O_CREAT | O_TRUNC,
+ 0x40, S_IWRITE) || iFile < 0){
+ ErrorBox("Open failed for output file");
+ return -1;
+ }
+#else
+ if(-1 ==(iFile = open(file, O_RDWR | O_BINARY | O_CREAT | O_TRUNC,
+ S_IWRITE | S_IREAD))){
+ ErrorBox("Open failed for output file");
+ return -1;
+ }
+#endif
+ ptr = (char *)malloc(sizeOut = 2000);
+ if(!ptr) goto openerr;
+ cbOut = rlp_strcpy(ptr, 20, ";RLP 1.0\n;File \"");
+ add_to_buff(&ptr, &cbOut, &sizeOut, file, 0);
+ add_to_buff(&ptr, &cbOut, &sizeOut, "\" created by RLPlot version "SZ_VERSION" for ", 0);
+#ifdef _WINDOWS
+ add_to_buff(&ptr, &cbOut, &sizeOut, "Windows", 7);
+#else
+ add_to_buff(&ptr, &cbOut, &sizeOut, "Qt", 2);
+#endif
+ add_to_buff(&ptr, &cbOut, &sizeOut, "\n;Date/Time: ", 13);
+#ifdef USE_WIN_SECURE
+ ctime_s(ptr+cbOut, 30, &ti); cbOut += 25;
+#else
+ add_to_buff(&ptr, &cbOut, &sizeOut, ctime(&ti), 25);
+#endif
+ }
+ return iFile;
+openerr:
+ ptr = 0L; cbOut = sizeOut = 0;
+#ifdef USE_WIN_SECURE
+ if(iFile >=0) _close(iFile);
+#else
+ if(iFile >=0) close(iFile);
+#endif
+ return iFile = -1;
+}
+
+static void CloseOutputFile()
+{
+ if(iFile >= 0){
+#ifdef USE_WIN_SECURE
+ if(cbOut) _write(iFile, ptr, cbOut);
+ _close(iFile);
+#else
+ if(cbOut) write(iFile, ptr, cbOut);
+ close(iFile);
+#endif
+ }
+ if(ptr) free(ptr);
+ cbOut = sizeOut = 0;
+ ptr = 0L; iFile = -1;
+}
+
+static void WriteTypObjLst(GraphObj **obs, int c1)
+{
+ int i, j, no, n, *idx;
+
+ if(!obs || !(idx=(int*)malloc(c1*sizeof(int)))) return;
+ for(i = no = 0; i < c1; i++) {
+ if(j = Notary->RegisterGO(obs[i])) idx[no++] = j;
+ }
+ add_to_buff(&ptr, &cbOut, &sizeOut, "(", 1);
+ add_int_to_buff(&ptr, &cbOut, &sizeOut, no, false, 0);
+ add_to_buff(&ptr, &cbOut, &sizeOut, "){", 2);
+ for(i = 0; i < no; i += 16) {
+ if(i) add_to_buff(&ptr, &cbOut, &sizeOut, " ", 3);
+ for(j = 0; (n=i+j) < no && j < 16; j++) {
+ add_int_to_buff(&ptr, &cbOut, &sizeOut, idx[n], j != 0, 0);
+ }
+ if(n >= no) add_to_buff(&ptr, &cbOut, &sizeOut, "}", 1);
+ else add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
+ }
+}
+
+static void WriteTypIpLst(POINT *ppt, int count)
+{
+ long i, j, c, n;
+
+ if(!ppt) return;
+ add_to_buff(&ptr, &cbOut, &sizeOut, "(", 1);
+ add_int_to_buff(&ptr, &cbOut, &sizeOut, count, false, 0);
+ add_to_buff(&ptr, &cbOut, &sizeOut, "){", 2);
+ for(i = 0; i < count; i += 8) {
+ for(j = c = 0; (n = i+j) <count && j < 8; j++) {
+ add_int_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].x, (j != 0), 0);
+ add_int_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].y, true, 0);
+ }
+ if(n >= count) add_to_buff(&ptr, &cbOut, &sizeOut, "}", 1);
+ else add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
+ }
+}
+
+static void WriteTypFpLst(lfPOINT *ppt, long count, bool bPar)
+{
+ int i, j, n;
+
+ if (bPar){
+ if(!ppt) return;
+ add_to_buff(&ptr, &cbOut, &sizeOut, "(", 1);
+ add_int_to_buff(&ptr, &cbOut, &sizeOut, count, false, 0);
+ add_to_buff(&ptr, &cbOut, &sizeOut, "){", 2);
+ }
+ else {
+ if(!ppt) count = 0;
+ add_int_to_buff(&ptr, &cbOut, &sizeOut, count, true, 0);
+ if(!count) {
+ add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
+ return;
+ }
+ add_to_buff(&ptr, &cbOut, &sizeOut, " {", 2);
+ }
+ for(i = 0; i < count; i += 8) {
+ for(j = 0; (n = i+j) <count && j < 8; j++) {
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].fx, (j != 0));
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].fy, true);
+ }
+ if(n >= count) add_to_buff(&ptr, &cbOut, &sizeOut, "}", 1);
+ else add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
+ }
+}
+
+static void WriteTypFpLst3D(fPOINT3D *ppt, int count)
+{
+ long i, j, c, n;
+
+ if(!ppt) return;
+ add_to_buff(&ptr, &cbOut, &sizeOut, "(", 1);
+ add_int_to_buff(&ptr, &cbOut, &sizeOut, count, false, 0);
+ add_to_buff(&ptr, &cbOut, &sizeOut, "){", 2);
+ for(i = 0; i < count; i +=5) {
+ for(j = c = 0; (n =i+j) <count && j < 5; j++) {
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].fx, (j != 0));
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].fy, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].fz, true);
+ }
+ if(n >= count) add_to_buff(&ptr, &cbOut, &sizeOut, "}", 1);
+ else add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
+ }
+}
+
+static char * esc_str = 0L;
+static int esc_str_size = 0;
+static void WriteEscString(char *txt)
+{
+ int i, j, l, lim = 60;
+
+ if(!txt || !txt[0]) return;
+ l = (int)strlen(txt);
+ if((l+10) > esc_str_size) if(!(esc_str = (char*)realloc(esc_str, esc_str_size = (l+100))))return;
+ j = 0; esc_str[j++] = '"';
+ for(i = 0; txt[i]; i++) {
+ switch(txt[i]) {
+ case '\\':
+ esc_str[j++] = '\\'; esc_str[j++] = '\\';
+ break;
+ case '\n':
+ esc_str[j++] = '\\'; esc_str[j++] = 'n';
+ break;
+ default:
+ if(((unsigned char*)txt)[i] >= ' ') esc_str[j++] = txt[i];
+ }
+ if(j > (esc_str_size -10)) esc_str = (char*)realloc(esc_str, (esc_str_size += 100));
+ if(j > lim && (l-i) > 3) {
+ esc_str[j++] = '"'; esc_str[j++] = '\\';
+ esc_str[j++] = '\n'; esc_str[j++] = ' ';
+ esc_str[j++] = ' '; esc_str[j++] = ' ';
+ esc_str[j++] = '"';
+ lim += 60;
+ }
+ }
+ esc_str[j++] = '"';
+ add_to_buff(&ptr, &cbOut, &sizeOut, esc_str, j);
+}
+
+bool ExecOutput(int id, char *Class, descIO *Desc)
+{
+ int i, last;
+ fRECT *fr;
+ AxisDEF *ax;
+ LineDEF *ld;
+ FillDEF *fd;
+ TextDEF *tx;
+
+ add_to_buff(&ptr, &cbOut, &sizeOut, "\n[", 2);
+ add_int_to_buff(&ptr, &cbOut, &sizeOut, id, false, 0);
+ add_to_buff(&ptr, &cbOut, &sizeOut, "=", 1);
+ add_to_buff(&ptr, &cbOut, &sizeOut, Class, 0);
+ add_to_buff(&ptr, &cbOut, &sizeOut, "]\n", 2);
+ cObsW++;
+ for(i = 0; Desc[i].label; i++) {
+ if(ptr[cbOut-1] != '\n') add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
+ last = cbOut;
+ add_to_buff(&ptr, &cbOut, &sizeOut, Desc[i].label, 0);
+ add_to_buff(&ptr, &cbOut, &sizeOut, "=", 1);
+ switch(Desc[i].type & 0xff){
+ case typNZINT:
+ if(!(*(int*)Desc[i].ptr)) {
+ cbOut = last; break;
+ }
+ //if not zero value continue as if int
+ case typINT:
+ add_int_to_buff(&ptr, &cbOut, &sizeOut, *(int*)Desc[i].ptr, true, 0);
+ break;
+ case typNZLFLOAT:
+ if(*((double*)Desc[i].ptr) == 0.0) {
+ cbOut = last; break;
+ }
+ //if not zero or negative continue as if float
+ case typLFLOAT:
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, *(double*)Desc[i].ptr, true);
+ break;
+ case typDWORD:
+ add_hex_to_buff(&ptr, &cbOut, &sizeOut, *(DWORD *)Desc[i].ptr, true);
+ break;
+ case typFRECT:
+ fr = (fRECT*)Desc[i].ptr;
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, fr->Xmin, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, fr->Ymax, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, fr->Xmax, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, fr->Ymin, true);
+ break;
+ case typNZLFPOINT:
+ if(((lfPOINT *)Desc[i].ptr)->fx == ((lfPOINT *)Desc[i].ptr)->fy &&
+ ((lfPOINT *)Desc[i].ptr)->fx == 0.0f){
+ cbOut = last; break;
+ }
+ //if not zero continue as if fPOINT
+ case typLFPOINT:
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ((lfPOINT *)Desc[i].ptr)->fx, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ((lfPOINT *)Desc[i].ptr)->fy, true);
+ break;
+ case typPOINT3D:
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ((fPOINT3D *)Desc[i].ptr)->fx, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ((fPOINT3D *)Desc[i].ptr)->fy, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ((fPOINT3D *)Desc[i].ptr)->fz, true);
+ 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
+ add_hex_to_buff(&ptr, &cbOut, &sizeOut, ax->flags, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->min, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->max, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[0].fx, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[0].fy, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[0].fz, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[1].fx, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[1].fy, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[1].fz, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->Start, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->Step, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->Center.fx, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->Center.fy, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->Radius, true);
+ WriteTypFpLst(ax->breaks, ax->nBreaks, false);
+ break;
+ case typLINEDEF:
+ ld = (LineDEF *)Desc[i].ptr;
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ld->width, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ld->patlength, true);
+ add_hex_to_buff(&ptr, &cbOut, &sizeOut, ld->color, true);
+ add_hex_to_buff(&ptr, &cbOut, &sizeOut, ld->pattern, true);
+ break;
+ case typFILLDEF:
+ fd = (FillDEF *)Desc[i].ptr;
+ //we set the 'hatch' member to zero: reconstruct after read
+ add_int_to_buff(&ptr, &cbOut, &sizeOut, fd->type, true, 0);
+ add_hex_to_buff(&ptr, &cbOut, &sizeOut, fd->color, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, fd->scale, true);
+ add_to_buff(&ptr, &cbOut, &sizeOut, " 0x0", 4);
+ add_hex_to_buff(&ptr, &cbOut, &sizeOut, fd->color2, true);
+ break;
+ case typGOBJ:
+ if(*(GraphObj **)(Desc[i].ptr)) add_int_to_buff(&ptr, &cbOut, &sizeOut,
+ Notary->RegisterGO(*(GraphObj **)(Desc[i].ptr)), true, 0);
+ else cbOut = last;
+ break;
+ case typOBJLST:
+ if(!(*(GraphObj ***)(Desc[i].ptr)) || !(*Desc[i].count)){
+ cbOut = last; break;
+ }
+ WriteTypObjLst(*(GraphObj ***)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0);
+ break;
+ case typIPLST:
+ if(!(*(POINT**)(Desc[i].ptr)) || !(*Desc[i].count)){
+ cbOut = last; break;
+ }
+ WriteTypIpLst(*(POINT**)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0L);
+ break;
+ case typFPLST:
+ if(!(*(lfPOINT**)(Desc[i].ptr)) || !(*Desc[i].count)){
+ cbOut = last; break;
+ }
+ WriteTypFpLst(*(lfPOINT**)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0L, true);
+ break;
+ case typFPLST3D:
+ if(!(*(fPOINT3D**)(Desc[i].ptr)) || !(*Desc[i].count)){
+ cbOut = last; break;
+ }
+ WriteTypFpLst3D(*(fPOINT3D**)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0);
+ break;
+ case typTEXT:
+ if(!*(char**)(Desc[i].ptr)) cbOut = last;
+ else WriteEscString(*((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) {
+ cbOut = last; break;
+ }
+ add_hex_to_buff(&ptr, &cbOut, &sizeOut, tx->ColTxt, true);
+ add_hex_to_buff(&ptr, &cbOut, &sizeOut, tx->ColBg, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, tx->fSize, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, tx->RotBL, true);
+ add_dbl_to_buff(&ptr, &cbOut, &sizeOut, tx->RotCHAR, true);
+ add_int_to_buff(&ptr, &cbOut, &sizeOut, tx->Align, true, 0);
+ add_int_to_buff(&ptr, &cbOut, &sizeOut, tx->Mode, true, 0);
+ add_int_to_buff(&ptr, &cbOut, &sizeOut, tx->Style, true, 0);
+ add_int_to_buff(&ptr, &cbOut, &sizeOut, tx->Font, true, 0);
+ if(tx->text && tx->text[0]) {
+ add_to_buff(&ptr, &cbOut, &sizeOut, " \"", 2);
+ add_to_buff(&ptr, &cbOut, &sizeOut, tx->text, 0);
+ add_to_buff(&ptr, &cbOut, &sizeOut, "\"\n", 2);
+ }
+ break;
+ }
+ if(Desc[i].type & typLAST) break;
+ }
+ if(ptr[cbOut-1] != '\n') add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
+ return true;
+}
+
+void ReadTypIpLst(POINT *ptr, long count, unsigned char *first)
+{
+ int i, j, k, f[20];
+
+ if(!ptr || !first) return;
+#ifdef USE_WIN_SECURE
+ k = sscanf_s((char*)first, "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
+ &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]);
+#else
+ k = sscanf((char*)first, "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
+ &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]);
+#endif
+ 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;
+#ifdef USE_WIN_SECURE
+ k = sscanf_s((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]);
+#else
+ 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]);
+#endif
+ 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;
+#ifdef USE_WIN_SECURE
+ k = sscanf_s((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]);
+#else
+ 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]);
+#endif
+ 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 = (int)strlen(*txt);
+
+ do {
+ mlines = false;
+ Cache->ReadLine(tmp, sizeof(tmp));
+ for(i = (int)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 = (int)strlen(tmp+i)) && (ntxt = (char*)realloc(*txt, cb + j + 1))) {
+ rlp_strcpy(ntxt+cb, j+1, tmp+i);
+ cb += j; *(txt) = ntxt;
+ }
+ } while (mlines);
+}
+
+bool ExecInput(descIO *Desc)
+{
+ unsigned char c, tmp[1000], tmp2[20];
+ int i, j, k, l;
+ bool match, mlines;
+ int 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((char*)tmp, Desc[j].label)) {
+ Cache->ReadLine((char*)tmp, sizeof(tmp));
+ switch(Desc[j].type & 0xff){
+ case typNZINT:
+ case typINT:
+#ifdef USE_WIN_SECURE
+ sscanf_s((char*)tmp, "%d", (int*)Desc[j].ptr);
+#else
+ sscanf((char*)tmp, "%d", (int*)Desc[j].ptr);
+#endif
+ break;
+ case typNZLFLOAT: case typLFLOAT:
+#ifdef USE_WIN_SECURE
+ sscanf_s((char*)tmp, "%lf", (double*)Desc[j].ptr);
+#else
+ sscanf((char*)tmp, "%lf", (double*)Desc[j].ptr);
+#endif
+ break;
+ case typDWORD:
+#ifdef USE_WIN_SECURE
+ sscanf_s((char*)tmp, "%x", (DWORD*)Desc[j].ptr);
+#else
+ sscanf((char*)tmp, "%x", (DWORD*)Desc[j].ptr);
+#endif
+ break;
+ case typFRECT:
+ fr = (fRECT*) Desc[j].ptr;
+#ifdef USE_WIN_SECURE
+ sscanf_s((char*)tmp, "%lf%lf%lf%lf", &fr->Xmin, &fr->Ymax, &fr->Xmax, &fr->Ymin);
+#else
+ sscanf((char*)tmp, "%lf%lf%lf%lf", &fr->Xmin, &fr->Ymax, &fr->Xmax, &fr->Ymin);
+#endif
+ break;
+ case typNZLFPOINT: case typLFPOINT:
+ lfp = (lfPOINT*) Desc[j].ptr;
+#ifdef USE_WIN_SECURE
+ sscanf_s((char*)tmp, "%lf%lf", &lfp->fx, &lfp->fy);
+#else
+ sscanf((char*)tmp, "%lf%lf", &lfp->fx, &lfp->fy);
+#endif
+ break;
+ case typPOINT3D:
+ lfp3d = (fPOINT3D*) Desc[j].ptr;
+#ifdef USE_WIN_SECURE
+ sscanf_s((char*)tmp, "%lf%lf%lf", &lfp3d->fx, &lfp3d->fy, &lfp3d->fz);
+#else
+ sscanf((char*)tmp, "%lf%lf%lf", &lfp3d->fx, &lfp3d->fy, &lfp3d->fz);
+#endif
+ 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;
+#ifdef USE_WIN_SECURE
+ sscanf_s((char*)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);
+#else
+ sscanf((char*)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);
+#endif
+ 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;
+#ifdef USE_WIN_SECURE
+ sscanf_s((char*)tmp,"%lf%lf%x%x", &ld->width, &ld->patlength, &ld->color, &ld->pattern);
+#else
+ sscanf((char*)tmp,"%lf%lf%x%x", &ld->width, &ld->patlength, &ld->color, &ld->pattern);
+#endif
+ break;
+ case typFILLDEF:
+ fd = (FillDEF*) Desc[j].ptr;
+#ifdef USE_WIN_SECURE
+ sscanf_s((char*)tmp, "%d%x%lf%x%x", &fd->type, &fd->color, &fd->scale, &fd->hatch, &fd->color2);
+#else
+ sscanf((char*)tmp, "%d%x%lf%x%x", &fd->type, &fd->color, &fd->scale, &fd->hatch, &fd->color2);
+#endif
+ fd->hatch = 0L;
+ break;
+ case typGOBJ:
+ *(GraphObj**)(Desc[j].ptr) = Notary->PopGO(atol((char*)tmp));
+ break;
+ case typOBJLST:
+ for(i = 0; i < 10 && tmp[i] != '(' && tmp[i]; i++);
+ if(!tmp[i]) break;
+#ifdef USE_WIN_SECURE
+ if(sscanf_s((char*)tmp+i+1, "%ld", &il) && il) {
+#else
+ if(sscanf((char*)tmp+i+1, "%ld", &il) && il) {
+#endif
+ *Desc[j].count = il;
+ if(!*(GraphObj***)(Desc[j].ptr)){
+ *(GraphObj***)(Desc[j].ptr) = (GraphObj**)calloc(il, sizeof(GraphObj*));
+ }
+ if((gobs = *(GraphObj***)(Desc[j].ptr))){
+ i += 4;
+ while(tmp[i-1] != '{') i++; while(tmp[i-1] < 33) i++;
+#ifdef USE_WIN_SECURE
+ strcat_s((char*)tmp, 1000, " ");
+#else
+ strcat((char*)tmp, " ");
+#endif
+ 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;
+ }
+ }
+#ifdef USE_WIN_SECURE
+ sscanf_s((char*)tmp2, "%d", &jl);
+#else
+ sscanf((char*)tmp2, "%d", &jl);
+#endif
+ *gobs++ = Notary->PopGO(jl);
+ if(c == '}') break;
+ }
+ }
+ }
+ break;
+ case typIPLST:
+ for(i = 0; i < 10 && tmp[i] != '(' && tmp[i]; i++);
+ if(!tmp[i]) break;
+#ifdef USE_WIN_SECURE
+ if(sscanf_s((char*)tmp+i+1, "%d", &il) && il) {
+#else
+ if(sscanf((char*)tmp+i+1, "%d", &il) && il) {
+#endif
+ *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;
+#ifdef USE_WIN_SECURE
+ if(sscanf_s((char*)tmp+i+1, "%d", &il) && il) {
+#else
+ if(sscanf((char*)tmp+i+1, "%d", &il) && il) {
+#endif
+ *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;
+#ifdef USE_WIN_SECURE
+ if(sscanf_s((char*)tmp+i+1, "%d", &il) && il) {
+#else
+ if(sscanf((char*)tmp+i+1, "%d", &il) && il) {
+#endif
+ *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 = (int)strlen((char*)tmp); i > 0 &&(tmp[i-1] < 32 || (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((char*)tmp);
+ if(tmp[0]){
+ *(char**)(Desc[j].ptr) = (char*)memdup((char*)tmp+i, (int)strlen((char*)tmp+i)+1, 0);
+ 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
+ }
+#ifdef USE_WIN_SECURE
+ sscanf_s((char*)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);
+#else
+ sscanf((char*)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);
+#endif
+ tx->iSize = 0;
+ for(i = (int)strlen((char*)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 = (char*)memdup((char*)tmp+l+1, (int)strlen((char*)tmp+l+1)+1, 0);
+ }
+ 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((char*)tmp, sizeof(tmp)); // then continue
+ }
+ j= 0;
+ }
+ }
+ }while(!match);
+ }
+}
+
+bool SaveGraphAs(GraphObj *g)
+{
+ char *name = 0L;
+ int i;
+ bool bRet = true;
+
+ 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 = (int)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();
+ }
+ else bRet = false;
+ if(Notary) delete Notary; Notary = 0L;
+ return bRet;
+}
+
+char *GraphToMem(GraphObj *g, long *size)
+{
+ static char *ret;
+
+ if(Notary || !g) {
+ ErrorBox("Output pending or\nno graph.");
+ return false;
+ }
+ cObsW = 0; iFile = -1;
+ cbOut = sizeOut = 0; ptr = 0L;
+ 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 = -1;
+ cbOut = sizeOut = 0; ptr = 0L;
+ return ret;
+ }
+ return 0L;
+}
+
+void UpdGOfromMem(GraphObj *go, unsigned char *buff)
+{
+ int i=0;
+
+ if(!go || !buff) return;
+ iFile = -1; 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, bool bPaste)
+{
+ unsigned char c, tmp[80];
+ char debug[80];
+ int i, id, lid;
+ unsigned int hv;
+ GraphObj *go;
+ scaleINFO sc_info;
+
+ LastOpenGO = 0L;
+ 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;
+#ifdef USE_WIN_SECURE
+ sscanf_s((char*)tmp, "%d", &id);
+#else
+ sscanf((char*)tmp, "%d", &id);
+#endif
+ 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 92534: go = new Bezier(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 117848: go = new xyStat(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;
+ case 66848: go = new Func3D(FILE_READ); break;
+ case 5001225: go = new TextFrame(FILE_READ); break;
+ case 4743132: go = new NormQuant(FILE_READ); break;
+ case 64333904: go = new ContourPlot(FILE_READ); break;
+ default:
+#ifdef USE_WIN_SECURE
+ sprintf_s(debug, 80, "Object %ld in file\n(Class = \"%s\")\nhash #%d\nis unknown.", id, tmp, hv);
+#else
+ sprintf(debug, "Object %ld in file\n(Class = \"%s\")\nhash #%d\nis unknown.", id, tmp, hv);
+#endif
+ 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((LastOpenGO = go = Notary->PopGO(lid))) {
+ go->Command(CMD_SET_DATAOBJ, 0L, 0L);
+ if (name && name[0]) go->Command(CMD_FILENAME, name, 0L);
+ delete Notary; Notary = 0L;
+ if(bPaste && go->Id == GO_GRAPH) {
+ sc_info.sx.fx = -((Graph*)go)->GRect.Xmin; sc_info.sy.fx = -((Graph*)go)->GRect.Ymin;
+ sc_info.sx.fy = sc_info.sy.fy = sc_info.sz.fy = 1.0; sc_info.sz.fx = 0.0;
+ go->Command(CMD_SCALE, &sc_info, 0L);
+ sc_info.sx.fy = sc_info.sy.fy = sc_info.sz.fy = 1.0/go->GetSize(SIZE_SCALE);
+ sc_info.sx.fx = sc_info.sy.fx = sc_info.sz.fx = 0.0;
+ go->Command(CMD_SCALE, &sc_info, 0L);
+ }
+ if(bPaste && root->Command(CMD_PASTE_OBJ, (void *)go, 0L)) {
+ // object accepted
+ }
+ else if(go->Id < GO_GRAPH
+ && !(root->Command(CMD_DROP_PLOT, (void *)go, 0L))){
+ DeleteGO(go); go = 0L;
+ }
+ else if(go->Id >= GO_GRAPH
+ && !(root->Command(CMD_DROP_GRAPH, (void *)go, 0L))){
+ DeleteGO(go); go = 0L;
+ }
+ //go may not be valid any more at this stage
+ }
+ if(Notary) delete Notary; Notary = 0L;
+ delete Cache; Cache = 0L;
+ return true;
+
+ReadErr:
+ Cache->Close();
+#ifdef USE_WIN_SECURE
+ if(iFile >= 0) _close(iFile);
+#else
+ if(iFile >= 0) close(iFile);
+#endif
+ iFile = -1;
+ 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 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 && size>0) {
+ 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);
+ if(ptr) {
+ memcpy(SavVarBuf+SavVarPos, ptr, size); SavVarPos += size;
+ }
+ return true;
+ }
+ return false;
+}
+
+void *SavVarFetch()
+{
+ void *tmp;
+
+ SavVarAdd((void*)0L, sizeof(unsigned char*));
+ tmp = SavVarBuf; 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 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:
+ SavVarAdd(Desc[i].count, sizeof(long));
+ SavVarAdd(*((void **)Desc[i].ptr), sizeof(lfPOINT) * (*Desc[i].count));
+ break;
+ case typFPLST3D:
+ SavVarAdd(Desc[i].count, sizeof(long));
+ SavVarAdd(*((void **)Desc[i].ptr), sizeof(fPOINT3D) * (*Desc[i].count));
+ break;
+ case typTEXT:
+ if(*(char**)(Desc[i].ptr)) SavVarAdd(Desc[i].ptr, (int)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 = DefSize(SIZE_SYMBOL);
+ SymLine.color = parent ? parent->GetColor(COL_SYM_LINE) : defs.Color(COL_SYM_LINE);
+ SymLine.width = parent ? parent->GetSize(SIZE_SYM_LINE) : DefSize(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 = DefSize(SIZE_BUBBLE_LINE);
+ BubbleFillLine.width = DefSize(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 = DefSize(SIZE_BAR);
+ mo = 0L;
+ mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
+ 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;
+
+#ifdef USE_WIN_SECURE
+ if(fopen_s(&file, name, "r")) {
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "DataLine: open failed for file \"%s\"", name);
+#else
+ if(!(file = fopen(name, "r"))) {
+ sprintf(TmpTxt, "DataLine: open failed for file \"%s\"", name);
+#endif
+ 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 {
+#ifdef USE_WIN_SECURE
+ c = fscanf_s(file, "%lf%lf", &Values[i].fx, &Values[i].fy);
+#else
+ c = fscanf(file, "%lf%lf", &Values[i].fx, &Values[i].fy);
+#endif
+ 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 {
+#ifdef USE_WIN_SECURE
+ c = fscanf_s(file, "%lf", &Values[i].fy);
+#else
+ c = fscanf(file, "%lf", &Values[i].fy);
+#endif
+ 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)
+{
+ 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, &nPnt},
+ {"file_xy", typTEXT, &file2, 0L},
+ {"start_x", typNZLFLOAT, &Start, 0L},
+ {"step_x", typNZLFLOAT, &Step, 0L},
+ {"file_y", typTEXT, &file1, 0L},
+ {"Desc", typLAST | typTEXT, &name, 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.0;
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ nPntSet = nPnt-1;
+ if(file2)FileValues(file2, 1, 0.0, 1.0);
+ else if(file1)FileValues(file1, 2, Start, fabs(Step) > defs.min4log ? Step : 1.0);
+ if(file1) free(file1);
+ if(file2) free(file2);
+ if(nPnt && Values)return true;
+ break;
+ case FILE_WRITE:
+ return ExecOutput(Notary->RegisterGO(this), "DataLine", Desc);
+ }
+ return false;
+}
+
+bool
+DataPolygon::FileIO(int rw)
+{
+ 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, &nPnt},
+ {"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);
+ nPntSet = nPnt-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(nPnt && Values)return true;
+ break;
+ case FILE_WRITE:
+ 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", typLINEDEF, &ErrLine, 0L},
+ {"Desc", typLAST | typTEXT, &name, 0L}};
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ SizeBar = DefSize(SIZE_ERRBAR);
+ ErrLine.width = DefSize(SIZE_ERRBAR_LINE);
+ ErrLine.color = defs.Color(COL_SYM_LINE);
+ mo = 0L;
+ mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
+ 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 = DefSize(SIZE_ARROW_CAPWIDTH);
+ cl = DefSize(SIZE_ARROW_CAPLENGTH);
+ LineDef.color = parent ? parent->GetColor(COL_DATA_LINE) : defs.Color(COL_DATA_LINE);
+ LineDef.width = parent ? parent->GetSize(SIZE_ARROW_LINE) : DefSize(SIZE_ARROW_LINE);
+ type = ARROW_LINE; dh1 = dh2 = 0L; mo = 0L;
+ mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
+ 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));
+ mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
+ Fill.hatch = &Hatchline; size = DefSize(SIZE_BAR);
+ ssRef = 0L; mo = 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", typLINEDEF, &LineDef, 0L},
+ {"Desc", typLAST | typTEXT, &name, 0L}};
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ size = DefSize(SIZE_WHISKER);
+ LineDef.width = DefSize(SIZE_WHISKER_LINE);
+ LineDef.color = defs.Color(COL_WHISKER);
+ mo = 0L;
+ mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
+ 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 = DefSize(SIZE_SYMBOL);
+ Line.color = defs.Color(COL_SYM_LINE);
+ Line.width = DefSize(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 = DefSize(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 = DefSize(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 = DefSize(SIZE_ARROW_CAPWIDTH);
+ cl = DefSize(SIZE_ARROW_CAPLENGTH);
+ Line.color = defs.Color(COL_ARROW);
+ Line.width = DefSize(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},
+ {"ssRef", typIPLST, &ssRef, &cssRef},
+ {"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 = DefSize(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 = DefSize(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;
+ return true;
+ case FILE_READ:
+ return ExecInput(Desc);
+ case FILE_WRITE:
+ if(parent && parent->Id != GO_MLABEL) {
+ if(!TextDef.text || !TextDef.text[0]) return false;
+ }
+ 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},
+ {"lspc", typLFLOAT, &lspc, 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 = DefSize(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; lspc = 1.0;
+ 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
+TextFrame::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"moveable", typNZINT, &moveable, 0L},
+ {"Pos1", typNZLFPOINT, &pos1, 0L},
+ {"Pos2", typNZLFPOINT, &pos2, 0L},
+ {"lspc", typLFLOAT, &lspc, 0L},
+ {"Pad", typFRECT, &pad, 0L},
+ {"TxtDef", typTXTDEF, &TextDef, 0L},
+ {"Line", typLINEDEF, &Line, 0L},
+ {"FillLine", typLINEDEF, &FillLine, 0L},
+ {"Fill", typFILLDEF, &Fill, 0L},
+ {"Text", typLAST | typTEXT, &text, 0L}};
+ switch(rw) {
+ case SAVE_VARS:
+ return false;
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ TextDef.ColTxt = 0x0L;
+ TextDef.ColBg = 0x00ffffffL;
+ TextDef.fSize = DefSize(SIZE_TEXT);
+ TextDef.RotBL = TextDef.RotCHAR = 0.0;
+ TextDef.iSize = 0;
+ TextDef.Align = TXA_VBOTTOM | TXA_HLEFT;
+ TextDef.Mode = TXM_TRANSPARENT;
+ TextDef.Style = TXS_NORMAL;
+ TextDef.Font = FONT_HELVETICA;
+ TextDef.text = 0L;
+ lines = 0L; nlines = 0; drc = 0L;
+ cur_pos.x = cur_pos.y = tm_c = 0; tm_rec = 0L;
+ bModified = bResize = has_m1 = has_m2 = false;
+ if(Fill.hatch) memcpy(&FillLine, Fill.hatch, sizeof(LineDEF));
+ Fill.hatch = &FillLine; c_char = m1_char = m2_char = '?';
+ pad.Xmin = pad.Xmax = pad.Ymin = pad.Ymax = DefSize(SIZE_SYMBOL)/2.0;
+ Cursor.left = Cursor.right = Cursor.top = Cursor.bottom = 0;
+ pad.Xmax *= 2.0;
+ return true;
+ case FILE_READ:
+ ExecInput(Desc); Fill.hatch = &FillLine;
+ return true;
+ case FILE_WRITE:
+ if(lines)lines2text();
+ if(!text || !text[0]) return false;
+ return ExecOutput(Notary->RegisterGO(this), "TextFrame", 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 = DefSize(SIZE_SEGLINE);
+ pts = 0L; nPts = 0; mo = 0L;
+ mrc.left = mrc.right = mrc.top = mrc.bottom = 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
+Bezier::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:
+ //assume that all initialization is done by polyline::FileIO(int rw)
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ pgFill.hatch = &pgFillLine;
+ return true;
+ case FILE_WRITE:
+ return ExecOutput(Notary->RegisterGO(this), "bezier", 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 = DefSize(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 = DefSize(SIZE_DRECT_TOP); B_Rect.Xmin = DefSize(SIZE_DRECT_LEFT);
+ B_Rect.Xmax = B_Rect.Xmin + 1.5*(d = DefSize(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; hasLine = false;
+ trc.left = trc.right = trc.top = trc.bottom = 0;
+ if(!name) {
+ name = (char*)malloc(20 * sizeof(char));
+ rlp_strcpy(name, 20, "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[] = {
+ {"hide", typNZINT, &hidden, 0L},
+ {"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", typOBJLST, &Labels, &nPoints},
+ {"x_info", typTEXT, &x_info, 0L},
+ {"y_info", typTEXT, &y_info, 0L},
+ {"DataDesc", typLAST | typTEXT, &data_desc, 0L}};
+ int i;
+
+ switch(rw) {
+ case INIT_VARS:
+ x_info = y_info = z_info = 0L;
+ InitVarsGO(Desc);
+ DefSym = SYM_CIRCLE;
+ DefSel = 0x01;
+ dirty = true;
+ if(name) {
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "xy-plot (%s)", name);
+#else
+ i = sprintf(TmpTxt, "xy-plot (%s)", name);
+#endif
+ free(name); name = (char*)memdup(TmpTxt, i+1, 0);
+ }
+ 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;
+}
+
+bool
+xyStat::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"hide", typNZINT, &hidden, 0L},
+ {"Bounds", typFRECT, &Bounds, 0L},
+ {"DefSym", typNZINT, &DefSym, 0L},
+ {"baDist", typLFPOINT, &BarDist, 0L},
+ {"confi", typLFLOAT, &ci, 0L},
+ {"xRange", typTEXT, &xRange, 0L},
+ {"yRange", typTEXT, &yRange, 0L},
+ {"prefix", typTEXT, &case_prefix, 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},
+ {"Labels", typOBJLST, &Labels, &nPoints},
+ {"x_info", typTEXT, &x_info, 0L},
+ {"y_info", typLAST | typTEXT, &y_info, 0L}};
+ int i;
+
+ switch(rw) {
+ case INIT_VARS:
+ //most initialistion is done by PlotScatt::FileIO
+ curr_data = 0L;
+ case_prefix = 0L;
+ ci = 95.0;
+ 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(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), "xyStat", 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},
+ {"hide", typNZINT, &hidden, 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;
+ dmin = HUGE_VAL, dmax = -HUGE_VAL;
+ if(name) {
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "freq. dist. (%s)", name);
+#else
+ i = sprintf(TmpTxt, "freq. dist. (%s)", name);
+#endif
+ free(name); name = (char*)memdup(TmpTxt, i+1, 0);
+ }
+ 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},
+ {"hide", typNZINT, &hidden, 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) {
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "regression (%s)", name);
+#else
+ i = sprintf(TmpTxt, "regression (%s)", name);
+#endif
+ free(name); name = (char*)memdup(TmpTxt, i+1, 0);
+ }
+ 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[] = {
+ {"hide", typNZINT, &hidden, 0L},
+ {"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 = DefSize(SIZE_BUBBLE_LINE);
+ BubbleFillLine.color = defs.Color(COL_BUBBLE_FILLLINE);
+ BubbleFillLine.width = DefSize(SIZE_BUBBLE_HATCH_LINE);
+ BubbleFill.hatch = &BubbleFillLine;
+ dirty = true;
+ if(name) {
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "Bubble Plot (%s)", name);
+#else
+ i = sprintf(TmpTxt, "Bubble Plot (%s)", name);
+#endif
+ free(name); name = (char*)memdup(TmpTxt, i+1, 0);
+ }
+ 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},
+ {"hide", typNZINT, &hidden, 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) {
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "polar root (%s)", name);
+#else
+ i = sprintf(TmpTxt, "polar root (%s)", name);
+#endif
+ free(name); name = (char*)memdup(TmpTxt, i+1, 0);
+ }
+ 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(Labels) for(i = 0; i < nPoints; i++) if(Labels[i]) Labels[i]->RegGO(n);
+ if(TheLine) TheLine->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+BoxPlot::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"hide", typNZINT, &hidden, 0L},
+ {"Bounds", typFRECT, &Bounds, 0L},
+ {"xRange", typTEXT, &xRange, 0L},
+ {"yRange", typTEXT, &yRange, 0L},
+ {"prefix", typTEXT, &case_prefix, 0L},
+ {"boDist", typLFPOINT, &BoxDist, 0L},
+ {"ci_box", typNZLFLOAT, &ci_box, 0L},
+ {"ci_err", typNZLFLOAT, &ci_err, 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},
+ {"Labels", typOBJLST, &Labels, &nPoints},
+ {"Line", typLAST | typGOBJ, &TheLine, 0L}};
+ int i;
+
+ switch(rw) {
+ case INIT_VARS:
+ dirty = true; InitVarsGO(Desc);
+ if(name) {
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "boxes (%s)", name);
+#else
+ i = sprintf(TmpTxt, "boxes (%s)", name);
+#endif
+ free(name); name = (char*)memdup(TmpTxt, i+1, 0);
+ }
+ curr_data = 0L;
+ 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(Labels) for(i = 0; i < nPoints; i++)
+ if(Labels[i]) Labels[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},
+ {"hide", typNZINT, &hidden, 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},
+ {"hide", typNZINT, &hidden, 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) {
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "stack (%s)", name);
+#else
+ i = sprintf(TmpTxt, "stack (%s)", name);
+#endif
+ free(name); name = (char*)memdup(TmpTxt, i+1, 0);
+ }
+ 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},
+ {"hide", typNZINT, &hidden, 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) {
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "pie chart (%s)", name);
+#else
+ i = sprintf(TmpTxt, "pie chart (%s)", name);
+#endif
+ free(name); name = (char*)memdup(TmpTxt, i+1, 0);
+ }
+ 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},
+ {"hide", typNZINT, &hidden, 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},
+ {"DataDesc", typTEXT, &data_desc, 0L},
+ {"hide", typNZINT, &hidden, 0L},
+ {"x_axis", typNZINT, &use_xaxis, 0L},
+ {"y_axis", typNZINT, &use_yaxis, 0L},
+ {"z_axis", typNZINT, &use_zaxis, 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) {
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "xyz-plot (%s)", name);
+#else
+ i = sprintf(TmpTxt, "xyz-plot (%s)", name);
+#endif
+ free(name); name = (char*)memdup(TmpTxt, i+1, 0);
+ }
+ 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},
+ {"hide", typNZINT, &hidden, 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},
+ {"DataDesc", typTEXT, &data_desc, 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) {
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "ribbon (%s)", name);
+#else
+ i = sprintf(TmpTxt, "ribbon (%s)", name);
+#endif
+ free(name); name = (char*)memdup(TmpTxt, i+1, 0);
+ }
+ 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);
+ if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+Grid3D::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"hide", typNZINT, &hidden, 0L},
+ {"Start", typPOINT3D, &start, 0L},
+ {"Step", typPOINT3D, &step, 0L},
+ {"Line", typLINEDEF, &Line, 0L},
+ {"Fill", typFILLDEF, &Fill, 0L},
+ {"lines", typOBJLST, &lines, &nLines},
+ {"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;
+ step.fx = step.fz = 1.0;
+ if(name) {
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "grid (%s)", name);
+#else
+ i = sprintf(TmpTxt, "grid (%s)", name);
+#endif
+ free(name); name = (char*)memdup(TmpTxt, i+1, 0);
+ }
+ 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;
+ if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->parent = this;
+ return true;
+ case FILE_WRITE:
+ if(lines) for(i = 0; i < nLines; i++) if(lines[i]) lines[i]->FileIO(rw);
+ if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "Grid3D", Desc);
+ }
+ return false;
+}
+
+bool
+Limits::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Bounds", typLAST | typFRECT, &Bounds, 0L}};
+ int i;
+
+ switch(rw) {
+ case INIT_VARS:
+ if(name) {
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "limits (%s)", name);
+#else
+ i = sprintf(TmpTxt, "limits (%s)", name);
+#endif
+ free(name); name = (char*)memdup(TmpTxt, i+1, 0);
+ }
+ 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)
+{
+ descIO Desc[] = {
+ {"hide", typNZINT, &hidden, 0L},
+ {"x1", typNZLFLOAT, &x1, 0L},
+ {"x2", typNZLFLOAT, &x2, 0L},
+ {"xstep", typNZLFLOAT, &xstep, 0L},
+ {"Line", typLINEDEF, &Line, 0L},
+ {"f_xy", typTEXT, &cmdxy, 0L},
+ {"param", typTEXT, ¶m, 0L},
+ {"DataLine", typGOBJ, &dl, 0L},
+ {"Desc", typLAST | typTEXT, &name, 0L}};
+ int i;
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ cmdxy = param = 0L;
+ memcpy(&Line, defs.GetLine(), sizeof(LineDEF));
+ if(name) {
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "function (%s)", name);
+#else
+ i = sprintf(TmpTxt, "function (%s)", name);
+#endif
+ free(name); name = (char*)memdup(TmpTxt, i+1, 0);
+ }
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ if(dl) dl->parent = this;
+ return true;
+ case FILE_WRITE:
+ if(dl) dl->FileIO(rw);
+ ExecOutput(Notary->RegisterGO(this), "Function", Desc);
+ }
+ 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)
+{
+ descIO Desc[] = {
+ {"hide", typNZINT, &hidden, 0L},
+ {"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, &cmdxy, 0L},
+ {"p_xy", typTEXT, &parxy, 0L},
+ {"Symbols", typLAST | typOBJLST, &Symbols, &nPoints}};
+ int i;
+
+ 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) {
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "fit function (%s)", name);
+#else
+ i = sprintf(TmpTxt, "fit function (%s)", name);
+#endif
+ free(name); name = (char*)memdup(TmpTxt, i+1, 0);
+ }
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ if(Symbols) for(i = 0; i < nPoints; i++)
+ if(Symbols[i]) Symbols[i]->parent = this;
+ return true;
+ case FILE_WRITE:
+ 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
+NormQuant::FileIO(int rw)
+{
+ lfPOINT *dt;
+ long cnt;
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"nData", typINT, &nData, 0L},
+ {"Data", typFPLST, &dt, &cnt},
+ {"ssRef", typTEXT, &ssRef, 0L},
+ {"x_info", typTEXT, &x_info, 0L},
+ {"y_info", typLAST | typTEXT, &y_info, 0L}};
+ int i, j, l;
+
+ if(rw == FILE_WRITE) {
+ if(nData < 4) return false;
+ l = (nData >>1) +1; cnt = l;
+ if(!(dt = (lfPOINT *)calloc(l, sizeof(lfPOINT))))return false;
+ for(i = j = 0; i < nData; i += 2, j++) {
+ dt[j].fx = src_data[i]; dt[j].fy = src_data[i+1];
+ }
+ }
+ else {
+ dt = 0L; cnt = 0;
+ }
+ switch(rw) {
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ sy = new Symbol(this, data, 0.0, 0.0, SYM_CIRCLE);
+ x_vals = y_vals = src_data = 0L;
+ if(name) {
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "normal quantiles (%s)", name);
+#else
+ i = sprintf(TmpTxt, "normal quantiles (%s)", name);
+#endif
+ free(name); name = (char*)memdup(TmpTxt, i+1, 0);
+ }
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ if(dt && cnt > 1 && (src_data = (double*)malloc(nData*sizeof(double)))) {
+ for(i = j = 0, l = nData-1; i < nData; i += 2, j++) {
+ src_data[i] = dt[j].fx; if(i < l) src_data[i+1] = dt[j].fy;
+ }
+ free(dt);
+ }
+ return true;
+ case FILE_WRITE:
+ ExecOutput(Notary->RegisterGO(this), "NormQuant", Desc);
+ free(dt);
+ return true;
+ }
+ 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)
+{
+ int i;
+
+ if(n) {
+ if(Grid && (flags & AXIS_GRIDLINE)) Grid->RegGO(n);
+ if(label) label->RegGO(n);
+ if(Polygons) for(i = 0; i < numPG; i++) if(Polygons[i]) Polygons[i]->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},
+ {"Polygons", typOBJLST, &Polygons, &numPG},
+ {"Size", typLAST | typLFLOAT, &size, 0L}};
+ int i;
+
+ switch(rw) {
+ case SAVE_VARS:
+ if(Grid && (flags & AXIS_GRIDLINE)) Grid->FileIO(rw);
+ if(label) label->FileIO(rw);
+// if(Polygons) for(i = 0; i < numPG; i++) if(Polygons[i]) Polygons[i]->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;
+ n_seg = s_seg = 0; seg = 0L; bValidTick = false;
+ size = DefSize(SIZE_AXIS_TICKS);
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ Grid = (GridLine*) gl;
+ if(Grid)Grid->parent = this;
+ if(label)label->parent = this;
+ if(Polygons) for(i = 0; i < numPG; i++) if(Polygons[i]) Polygons[i]->parent = this;
+ return true;
+ case FILE_WRITE:
+ if(Grid && (flags & AXIS_GRIDLINE)) Grid->FileIO(rw);
+ else gl = 0L;
+ if(label) label->FileIO(rw);
+ if(Polygons) for(i = 0; i < numPG; i++) if(Polygons[i]) Polygons[i]->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;
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "Error open file \"%s\"\nfor axis ticks", name);
+#else
+ sprintf(TmpTxt, "Error open file \"%s\"\nfor axis ticks", name);
+#endif
+ 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 = (int)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},
+ {"moveable", typNZINT, &moveable, 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_angle", typNZLFLOAT, &tick_angle, 0L},
+ {"LbDist", typNZLFPOINT, &lbdist, 0L},
+ {"TickLbDist", typNZLFPOINT, &tlbdist, 0L},
+ {"tlbDef", typTXTDEF, &tlbdef, 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},
+ {"g_type", typINT, &grad_type, 0L},
+ {"g_col_0", typDWORD, &gCol_0, 0L},
+ {"g_col_1", typDWORD, &gCol_1, 0L},
+ {"g_col_2", typDWORD, &gCol_2, 0L},
+ {"gTrans", typLAST | typDWORD, &gTrans, 0L}};
+ int i;
+
+ switch(rw) {
+ case INIT_VARS:
+ InitVarsGO(Desc);
+ sizAxLine = DefSize(SIZE_AXIS_LINE);
+ sizAxTick = DefSize(SIZE_AXIS_TICKS);
+ sizAxTickLabel = DefSize(SIZE_TICK_LABELS);
+ colAxis = parent ? parent->GetColor(COL_AXIS) : defs.Color(COL_AXIS);
+ GridLine.color = 0x00808080L;
+ GridLine.pattern = 0xf8f8f8f8L;
+ brksymsize = DefSize(SIZE_TICK_LABELS);
+ brkgap = DefSize(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 = DefSize(SIZE_TICK_LABELS); tlbdef.Align = TXA_VCENTER | TXA_HCENTER;
+ tlbdef.Style = TXS_NORMAL; tlbdef.Mode = TXM_TRANSPARENT;
+ tlbdef.Font = FONT_HELVETICA; atv = 0L;
+ 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; grad_type = 1; gTrans = 0x00000000L;
+ gCol_0 = 0x00ffffffL; gCol_1 = 0x00ff0000L; gCol_2 = 0x000000ffL;
+ 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) 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);
+ if((type & 0x04)!=4) Desc[17].type |= typLAST;
+ return ExecOutput(Notary->RegisterGO(this), "Axis", Desc);
+ }
+ return false;
+}
+
+void
+ContourPlot::RegGO(void *n)
+{
+ int i;
+
+ if(n) {
+ if(Symbols) for(i = 0; i < nSym; i++) if(Symbols[i]) Symbols[i]->RegGO(n);
+ if(Labels) for(i = 0; i < nLab; i++) if(Labels[i]) Labels[i]->RegGO(n);
+ if(zAxis) zAxis->RegGO(n);
+ ((notary*)n)->AddRegGO(this);
+ }
+}
+
+bool
+ContourPlot::FileIO(int rw)
+{
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"hide", typNZINT, &hidden, 0L},
+ {"Bounds", typFRECT, &Bounds, 0L},
+ {"xBounds", typLFPOINT, &xBounds, 0L},
+ {"yBounds", typLFPOINT, &yBounds, 0L},
+ {"zBounds", typLFPOINT, &zBounds, 0L},
+ {"srz", typNZLFLOAT, &sr_zval, 0L},
+ {"flags", typDWORD, &flags, 0L},
+ {"zDef", typAXDEF, &z_axis, 0L},
+ {"zAxis", typGOBJ, &zAxis, 0L},
+ {"Values", typFPLST3D, &val, &nval},
+ {"Symbols", typOBJLST, &Symbols, &nSym},
+ {"Labels", typOBJLST, &Labels, &nLab},
+ {"ssRefX", typTEXT, &ssRefX, 0L},
+ {"ssRefY", typTEXT, &ssRefY, 0L},
+ {"ssRefZ", typLAST | typTEXT, &ssRefZ, 0L}};
+ 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;
+ sr_zval = 0.0; flags = 0L;
+ if(name) {
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "Contour Plot (%s)", name);
+#else
+ i = sprintf(TmpTxt, "Contour Plot (%s)", name);
+#endif
+ free(name); name = (char*)memdup(TmpTxt, i+1, 0);
+ }
+ return true;
+ case FILE_READ:
+ ExecInput(Desc);
+ if(Symbols) for(i = 0; i < nSym; i++) if(Symbols[i]) Symbols[i]->parent=this;
+ if(Labels) for(i = 0; i < nLab; i++) if(Labels[i]) Labels[i]->parent=this;
+ if(zAxis) zAxis->parent = this;
+ return true;
+ case FILE_WRITE:
+ if(Symbols) for(i = 0; i < nSym; i++) if(Symbols[i]) Symbols[i]->FileIO(rw);
+ if(Labels) for(i = 0; i < nLab; i++) if(Labels[i]) Labels[i]->FileIO(rw);
+ if(zAxis) zAxis->FileIO(rw);
+ return ExecOutput(Notary->RegisterGO(this), "ContourPlot", 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;
+ descIO Desc[] = {
+ {"hide", typNZINT, &hidden, 0L},
+ {"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},
+ {"x_axis", typNZINT, &use_xaxis, 0L},
+ {"y_axis", typNZINT, &use_yaxis, 0L},
+ {"z_axis", typNZINT, &use_zaxis, 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 = DefSize(SIZE_GRECT_LEFT) + DefSize(SIZE_DRECT_LEFT);
+ cub2.fx = DefSize(SIZE_GRECT_LEFT) + DefSize(SIZE_DRECT_RIGHT);
+ cub1.fy = DefSize(SIZE_GRECT_TOP) + DefSize(SIZE_DRECT_BOTTOM);
+ cub2.fy = DefSize(SIZE_GRECT_TOP) + DefSize(SIZE_DRECT_TOP);
+ cub1.fy += DefSize(SIZE_DRECT_TOP); cub2.fy += DefSize(SIZE_DRECT_TOP);
+ cub1.fz = 0.0;
+ cub2.fz = DefSize(SIZE_DRECT_BOTTOM) - DefSize(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;
+ Sc_Plots = 0L; nscp = 0;
+ if(name) {
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "3D-root (%s)", name);
+#else
+ i = sprintf(TmpTxt, "3D-root (%s)", name);
+#endif
+ free(name); name = (char*)memdup(TmpTxt, i+1, 0);
+ }
+ return true;
+ case FILE_READ:
+ rot_vec.fx = 0.919384; rot_vec.fy = 0.389104; rot_vec.fz = -0.057709;
+ rot_ang.fx = 0.327146; rot_ang.fy = 0.944974; rot_ang.fz = 0.055026;
+ 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
+Func3D::RegGO(void *n)
+{
+}
+
+bool
+Func3D::FileIO(int rw)
+{
+ fPOINT3D rot_vec, rot_ang;
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"hide", typNZINT, &hidden, 0L},
+ {"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},
+ {"x_axis", typNZINT, &use_xaxis, 0L},
+ {"y_axis", typNZINT, &use_yaxis, 0L},
+ {"z_axis", typNZINT, &use_zaxis, 0L},
+ {"Axes", typOBJLST, &Axes, (long*)&nAxes},
+ {"Plots", typOBJLST, &plots, (long*)&nPlots},
+ {"x1", typNZLFLOAT, &x1, 0L},
+ {"x2", typNZLFLOAT, &x2, 0L},
+ {"xstep", typNZLFLOAT, &xstep, 0L},
+ {"z1", typNZLFLOAT, &x1, 0L},
+ {"z2", typNZLFLOAT, &x2, 0L},
+ {"zstep", typNZLFLOAT, &xstep, 0L},
+ {"Line", typLINEDEF, &Line, 0L},
+ {"Fill", typFILLDEF, &Fill, 0L},
+ {"f_xz", typTEXT, &cmdxy, 0L},
+ {"param", typLAST | typTEXT, ¶m, 0L}};
+ int i;
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ x1 = -20.0; x2 = 20.0; xstep = 2.0;
+ z1 = -20.0; z2 = 20.0; zstep = 2.0;
+ gda = 0L; gob = 0L;
+ param = cmdxy = 0L;
+ Line.width = DefSize(SIZE_HAIRLINE);
+ Line.patlength = DefSize(SIZE_PATLENGTH);
+ Line.color = Line.pattern = 0x0L;
+ Fill.color = 0x00c0c0c0;
+ Fill.color2 = 0x00ffffff;
+ Fill.hatch = 0L;
+ Fill.type = FILL_LIGHT3D;
+ if(name) {
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "3D function (Plot %d)", cPlots);
+#else
+ i = sprintf(TmpTxt, "3D function (Plot %d)", cPlots);
+#endif
+ free(name); name = (char*)memdup(TmpTxt, i+1, 0);
+ }
+ return true;
+ case FILE_READ:
+ rot_vec.fx = 0.919384; rot_vec.fy = 0.389104; rot_vec.fz = -0.057709;
+ rot_ang.fx = 0.327146; rot_ang.fy = 0.944974; rot_ang.fz = 0.055026;
+ 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);
+ ExecOutput(Notary->RegisterGO(this), "Func3D", Desc);
+ }
+ return false;
+}
+
+void
+FitFunc3D::RegGO(void *n)
+{
+}
+
+bool
+FitFunc3D::FileIO(int rw)
+{
+ fPOINT3D rot_vec, rot_ang;
+ descIO Desc[] = {
+ {"Type", typNZINT, &type, 0L},
+ {"hide", typNZINT, &hidden, 0L},
+ {"ssXref", typTEXT, &ssXref, 0L},
+ {"ssYref", typTEXT, &ssYref, 0L},
+ {"ssZref", typTEXT, &ssZref, 0L},
+ {"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},
+ {"x_axis", typNZINT, &use_xaxis, 0L},
+ {"y_axis", typNZINT, &use_yaxis, 0L},
+ {"z_axis", typNZINT, &use_zaxis, 0L},
+ {"Axes", typOBJLST, &Axes, (long*)&nAxes},
+ {"Plots", typOBJLST, &plots, (long*)&nPlots},
+ {"x1", typNZLFLOAT, &x1, 0L},
+ {"x2", typNZLFLOAT, &x2, 0L},
+ {"xstep", typNZLFLOAT, &xstep, 0L},
+ {"z1", typNZLFLOAT, &x1, 0L},
+ {"z2", typNZLFLOAT, &x2, 0L},
+ {"zstep", typNZLFLOAT, &xstep, 0L},
+ {"maxiter", typNZINT, &maxiter, 0L},
+ {"Line", typLINEDEF, &Line, 0L},
+ {"Fill", typFILLDEF, &Fill, 0L},
+ {"f_xz", typTEXT, &cmdxy, 0L},
+ {"param", typLAST | typTEXT, ¶m, 0L}};
+ int i;
+
+ switch(rw) {
+ case SAVE_VARS:
+ return SaveVarGO(Desc);
+ case INIT_VARS:
+ x1 = -20.0; x2 = 20.0; xstep = 2.0;
+ z1 = -20.0; z2 = 20.0; zstep = 2.0;
+ gda = 0L; gob = 0L;
+ conv = 1.0e-15; maxiter = 100;
+ param = cmdxy = ssXref = ssYref = ssZref = 0L;
+ Line.width = DefSize(SIZE_HAIRLINE);
+ Line.patlength = DefSize(SIZE_PATLENGTH);
+ Line.color = Line.pattern = 0x0L;
+ Fill.color = 0x00c0c0c0;
+ Fill.color2 = 0x00ffffff;
+ Fill.hatch = 0L;
+ Fill.type = FILL_LIGHT3D;
+ if(name) {
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "FitFunc3D (Plot %d)", cPlots);
+#else
+ i = sprintf(TmpTxt, "FitFunc3D (Plot %d)", cPlots);
+#endif
+ free(name); name = (char*)memdup(TmpTxt, i+1, 0);
+ }
+ return true;
+ case FILE_READ:
+ rot_vec.fx = 0.919384; rot_vec.fy = 0.389104; rot_vec.fz = -0.057709;
+ rot_ang.fx = 0.327146; rot_ang.fy = 0.944974; rot_ang.fz = 0.055026;
+ 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);
+ ExecOutput(Notary->RegisterGO(this), "FitFunc3D", 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},
+ {"Scale", typNZLFLOAT, &scale, 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 = bDialogOpen = 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; bModified = false; zoom_def = 0L;
+ tl_pts = 0L; tl_nPts = 0; tickstyle = zoom_level = 0;
+ frm_g = frm_d = 0L; PasteObj = 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; if(scale == 1.0) scale = 0.0;
+ //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)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]->Id != GO_GRAPH) 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(Id == GO_PAGE)RegGO(Notary);
+ 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.cUnits, 0L},
+ {"dtHeight", typINT, &dlgtxtheight, 0L},
+ {"ss_txt", typLFLOAT, &defs.ss_txt, 0L},
+ {"fmt_date", typTEXT, &defs.fmt_date, 0L},
+ {"fmt_datetime", typTEXT, &defs.fmt_datetime, 0L},
+ {"fmt_time", typTEXT, &defs.fmt_time, 0L},
+ {"curr_path", typTEXT, &defs.currPath, 0L},
+ {"menu_height", typINT, &defs.iMenuHeight, 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);
+ //check for plausibility
+ if(defs.ss_txt < 0.3 || defs.ss_txt > 3.0) defs.ss_txt = 0.9;
+ if(defs.dUnits < 0 || defs.dUnits > 2) defs.dUnits = 0;
+ defs.cUnits = defs.dUnits;
+#ifdef _WINDOWS
+ if(dlgtxtheight < 5 || dlgtxtheight > 60) dlgtxtheight = 16;
+#else
+ if(dlgtxtheight < 5 || dlgtxtheight > 60) dlgtxtheight = 10;
+#endif
+ return true;
+ case FILE_WRITE:
+ Notary = new notary();
+#ifdef USE_WIN_SECURE
+ _unlink(defs.IniFile);
+#else
+ unlink(defs.IniFile);
+#endif
+ 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
index aacf7b2..b42c857 100755
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-# Makefile, Copyright 2002-2007 R.Lackner
+# Makefile, Copyright 2002-2008 R.Lackner
#
#
# This file is part of RLPlot.
@@ -17,28 +17,43 @@
# 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
#
CC = g++
X11LIBS = -lX11 -lm
SRCDIR = ./
+#######
+####### Declarations for Qt3
QT3DIR = /usr/lib/qt-3.3
QT3MOC = /usr/lib/qt-3.3/bin/moc
MOC3FLAGS =
QT3CFLAGS = "-I$(QT3DIR)/include -pipe -O2"
QT3H = QT3_Spec.h
QT3LIBS = "-L$(QT3DIR)/lib -L/usr/X11R6/lib -lqt-mt"
-
+#
+# If above declarations don't work for Qt3 try the following ...
+#QT3DIR = /usr/share/qt-3
+#QT3DIR = /usr/share/qt3
+#QT3MOC = /usr/share/qt-3/bin/moc
+#QT3MOC = /usr/share/qt3/bin/moc
+
+#######
+####### Declarations for Qt4
QT4DIR = /usr/lib/qt4
QT4MOC = /usr/lib/qt4/bin/moc-qt4
MOC4FLAGS = "MOCFLAGS=-DQT_VERSION=0x040000"
QT4CFLAGS = "-I/usr/include/Qt -pipe -O2"
QT4H = QT_Spec.h
-QT4LIBS = "-L$(QT4DIR)/lib -L/usr/X11R6/lib -lQtCore -lQtGui -lQtNetwork"
-
-
+QT4LIBS = "-L$(QT4DIR)/lib -L/usr/X11R6/lib -lQtCore -lQtGui"
+#
+# If above declarations don't work for Qt4 try the following ...
+#QT4DIR = /usr/share/qt4
+#QT4MOC = /usr/share/qt4/bin/moc
+#QT4MOC = /usr/lib/qt4/bin/moc
+#QT4CFLAGS = "-I/usr/include/qt4/Qt -I/usr/include/qt4 -pipe -O2"
+#QT4CFLAGS = "-I/usr/lib/qt4/include -I/usr/lib/qt4/include/Qt -pipe -O2"
+
+#######
GENOBJ = exprlp.o rlplot.o Output.o Utils.o UtilObj.o\
Fileio.o Export.o PlotObs.o Axes.o mfcalc.o rlp_math.o no_gui.o
@@ -47,6 +62,7 @@ OBJECTS = moc_QT_Spec.o QT_Spec.o Output.o Utils.o UtilObj.o\
Export.o PlotObs.o Axes.o ODbuttons.o mfcalc.o rlp_math.o use_gui.o\
reports.o
+#######
all:
make Qt4
make exprlp
@@ -65,7 +81,9 @@ exprlp: $(GENOBJ)
clean:
rm -f *.o *~
- rm moc_QT_Spec.cpp
+ rm -f moc_QT_Spec.cpp
+ rm -f rlplot
+ rm -f exprlp
####### Compile
@@ -73,7 +91,6 @@ 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-qt4 $(SRCDIR)QT_Spec.h -o moc_QT_Spec.cpp -DQT_VERSION=0x040000
$(MOC) $(SRCDIR)$(QTH) -o moc_QT_Spec.cpp $(MOCFLAGS)
mfcalc.o: $(SRCDIR)mfcalc.cpp
@@ -88,7 +105,7 @@ rlp_math.o: $(SRCDIR)rlp_math.cpp
exprlp.o: $(SRCDIR)exprlp.cpp
$(CC) $(CFLAGS) -o $@ -c $<
-QT_Spec.o: $(SRCDIR)QT_Spec.cpp $(SRCDIR)QT_Spec.h $(SRCDIR)rlplot.h
+QT_Spec.o: $(SRCDIR)QT_Spec.cpp $(SRCDIR)QT_Spec.h $(SRCDIR)rlplot.h $(SRCDIR)menu.h
$(CC) $(CFLAGS) -o $@ -c $<
Output.o: $(SRCDIR)Output.cpp $(SRCDIR)rlplot.h
@@ -133,9 +150,6 @@ no_gui.o: $(SRCDIR)no_gui.cpp $(SRCDIR)rlplot.h
use_gui.o: $(SRCDIR)use_gui.cpp $(SRCDIR)rlplot.h
$(CC) $(CFLAGS) -o $@ -c $<
-reports.o: $(SRCDIR)reports.cpp $(SRCDIR)rlplot.h
+reports.o: $(SRCDIR)reports.cpp $(SRCDIR)TheDialog.h $(SRCDIR)rlplot.h
$(CC) $(CFLAGS) -o $@ -c $<
-
-
-
diff --git a/ODbuttons.cpp b/ODbuttons.cpp
index 5d0f3d6..5146121 100755
--- a/ODbuttons.cpp
+++ b/ODbuttons.cpp
@@ -1,1508 +1,1576 @@
-//ODbuttons.cpp, Copyright (c) 2001-2007 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;
-extern Default defs;
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 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 = {0.0, 1.0, 0x0L, 0x0L};
- FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
- POINT *pts;
- int i, ix, iy, np;
-
- if(!(pts=(POINT*)malloc(sizeof(POINT)*(rec->right-rec->left)))) return;
- switch(cmd) {
- case OD_DRAWNORMAL:
- case OD_DRAWSELECTED:
- Line.color = cmd == OD_DRAWSELECTED ? 0x00000000L : 0x00e8e8e8L;
- Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00e8e8e8L;
- 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);
- if(cmd == OD_DRAWSELECTED){
- Fill.color = 0x000000ffL; o->SetFill(&Fill);
- }
- 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;
- case 210:
- pts[0].x = rec->left +9; pts[0].y = iy+4; pts[1].x = pts[0].x+1;
- for(i = 0; i < (rec->right - rec->left - 18); i++) {
- pts[1].y = 4 + iy + iround(pow(20.0, 1.0+((double)-i)/30.0) * -sin(((double)i)/4.0));
- o->oSolidLine(pts);
- pts[0].x++; pts[1].x++; pts[0].y = pts[1].y;
- }
- o->oCircle(rec->left+7, iy+4, rec->left+12, iy +9);
- o->oCircle(rec->left+12, iy-10, rec->left+17, iy -5);
- o->oCircle(rec->right-19, iy+5, rec->right-24, iy +10);
- o->oCircle(rec->right-9, iy, rec->right-14, iy+5);
- break;
- case 211:
- pts[0].y = rec->top +9; pts[0].x = ix; pts[1].y = pts[0].y+1;
- for(i = 0; i < (rec->bottom - rec->top - 18); i++) {
- pts[1].x = ix + iround(pow(20.0, 1.0+((double)-i)/50.0) * -sin(((double)i)/4.0));
- o->oSolidLine(pts);
- pts[0].y++; pts[1].y++; pts[0].x = pts[1].x;
- }
- o->oCircle(ix-3, rec->top + 9, ix+2, rec->top + 14);
- o->oCircle(rec->left+11, iy-10, rec->left+16, iy -5);
- o->oCircle(ix+3, rec->top + 27, ix+8, rec->top + 32);
- o->oCircle(ix-5, iy+12, ix, iy + 17);
- break;
- case 212:
- for(i = 2; i < (rec->bottom - rec->top - 18); i++) {
- pts[1].x = ix + iround(pow(20.0, 1.0+((double)-i)/50.0) * -sin(((double)i)/4.0));
- pts[1].y = iy + iround(pow(20.0, 1.0+((double)-i)/50.0) * -cos(((double)i)/4.0));
- if(i>2)o->oSolidLine(pts);
- pts[0].y = pts[1].y; pts[0].x = pts[1].x;
- }
- o->oCircle(ix-5, iy-4, ix, iy+1); o->oCircle(ix-10, iy-17, ix-5, iy-12);
-#ifdef _WINDOWS
- o->oCircle(ix-12, iy+9, ix-7, iy+4); o->oCircle(ix+9, iy+7, ix+4, iy+2);
-#else
- o->oCircle(ix-12, iy+9, ix-7, iy+4); o->oCircle(ix+8, iy+6, ix+4, iy+2);
-#endif
- break;
- }
- if(np) o->oPolyline(pts, np);
- switch(id) {
- case 201: case 202: case 203: case 204: case 205:
- case 206: case 207: case 208: case 209:
- o->oCircle(ix-2, iy-2, ix+3, iy+3);
-#ifdef _WINDOWS
- o->oCircle(rec->left+13, rec->bottom-13, rec->left+18, rec->bottom-18);
- o->oCircle(rec->right-13, rec->top+13, rec->right-18, rec->top+18);
-#else
- o->oCircle(rec->left+13, rec->bottom-14, rec->left+18, rec->bottom-18);
- o->oCircle(rec->right-14, rec->top+13, rec->right-18, rec->top+18);
-#endif
- break;
- case 210: case 211: case 212:
- break;
- }
- o->UpdateRect(rec, false);
- free(pts);
- 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 = {0.0, 1.0, 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 : 0x00e8e8e8L;
- Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00e8e8e8L;
- 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 = {0.0, 1.0, 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 : 0x00e8e8e8L;
- Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00e8e8e8L;
- 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 : 0x00e8e8e8L;
- Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00e8e8e8L;
- 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 = 0x00e8e8e8L;
- 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 : 0x00e8e8e8L;
- Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00e8e8e8L;
- 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 = {0.0, 1.0, 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 : 0x00e8e8e8L;
- Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00e8e8e8L;
- 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
- case 565: case 566: case 567:
- OD_AxisTempl3D(cmd, par, rec, o, data, 410+AxisTempl3D);
- break;
- default:
- Line.color = cmd == OD_DRAWSELECTED ? 0x00000000L : 0x00e8e8e8L;
- Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00e8e8e8L;
- 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: case 507:
- o->SetFill(&FillR);
- o->oRectangle(rec->left+9, rec->top+30, rec->left+13, rec->bottom-3);
- o->oRectangle(rec->right-20, id == 507 ? rec->top + 25 : 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);
- if(id == 507) {
- o->SetLine(&Line);
- pts[0].x = pts[1].x = rec->left+11; pts[0].y = rec->top+20;
- pts[1].y = rec->top+40; o->oSolidLine(pts);
- pts[0].x = pts[1].x = rec->left+15; pts[0].y = rec->top+15;
- pts[1].y = rec->top+35; o->oSolidLine(pts);
- pts[0].x = pts[1].x = rec->left+19; pts[0].y = rec->top+30;
- pts[1].y = rec->top+40; o->oSolidLine(pts);
- pts[0].x = pts[1].x = rec->right-18; pts[0].y = rec->top+15;
- pts[1].y = rec->top+35; o->oSolidLine(pts);
- pts[0].x = pts[1].x = rec->right-14; pts[0].y = rec->top+10;
- pts[1].y = rec->top+20; o->oSolidLine(pts);
- pts[0].x = pts[1].x = rec->right-10; pts[0].y = rec->top+10;
- pts[1].y = rec->top+30; o->oSolidLine(pts);
- }
- 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 506:
- 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 = pts[0].y - iround(exp(-r*r)*1.0+5.0);
- pts[1].y = rec->bottom - iround(errf(r)*16.0+26.0);
- if (i) o->oSolidLine(pts);
- pts[0].x++; pts[1].x++; pts[0].y = pts[1].y;
- }
- o->SetLine(&rLine);
- pts[0].x = ix-2; pts[1].x = pts[0].x+1;
- for(i = 0; i < (rec->right - ix-5); i++) {
- r = ((double)(i-9))/4.0;
- pts[1].y = rec->bottom - iround(exp(-r*r)*17.0+7.0);
- if (i) o->oSolidLine(pts);
- pts[0].x++; pts[1].x++; pts[0].y = pts[1].y;
- }
- o->SetFill(&FillG); o->SetLine(&Line);
- o->oCircle(ix, iy, ix+5, iy+5);
- o->oCircle(ix-5, iy+8, ix, iy+13);
- o->oCircle(ix+5, iy-10, ix+10, iy-5);
- 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 = defs.GetSize(SIZE_TEXT)*1.75; 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 532:
- pts[0].x = rec->left +13; pts[0].y = rec->top+8;
- pts[1].x = rec->left +13; pts[1].y = iy;
- o->oSolidLine(pts);
- pts[0].x -= 3; pts[1].x += 3;
- pts[0].y = pts[1].y = rec->top+8;
- o->oSolidLine(pts);
- pts[0].y = pts[1].y = iy;
- o->oSolidLine(pts);
- pts[0].x = ix; pts[0].y = iy-8;
- pts[1].x = ix; pts[1].y = rec->bottom-13;
- o->oSolidLine(pts);
- pts[0].x -= 3; pts[1].x += 3;
- pts[0].y = pts[1].y = iy-8;
- o->oSolidLine(pts);
- pts[0].y = pts[1].y = rec->bottom-13;
- o->oSolidLine(pts);
- pts[0].x = rec->right -13; pts[0].y = rec->top+10;
- pts[1].x = rec->right -13; pts[1].y = iy-6;
- o->oSolidLine(pts);
- pts[0].x -= 3; pts[1].x += 3;
- pts[0].y = pts[1].y = rec->top+10;
- o->oSolidLine(pts);
- pts[0].y = pts[1].y = iy-6;
- o->oSolidLine(pts);
- pts[0].x = rec->left+13; pts[1].x = ix; pts[2].x = rec->right-13;
- pts[0].y = (rec->top+8+iy)>>1;
- pts[1].y = (rec->bottom-13 + iy -8)>>1;
- pts[2].y = (rec->top+10+iy-6)>>1;
- o->oPolyline(pts, 3, 0L);
- o->SetFill(&FillY);
- o->oCircle(pts[0].x-3, pts[0].y-3, pts[0].x+3, pts[0].y+3);
- o->oCircle(pts[1].x-3, pts[1].y-3, pts[1].x+3, pts[1].y+3);
- o->oCircle(pts[2].x-3, pts[2].y-3, pts[2].x+3, pts[2].y+3);
- 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;
- case 565: case 566:
- o->SetLine(&rLine);
- pts[0].x = ix-16; pts[0].y = iy-2;
- pts[1].x = ix+4; pts[1].y = iy+6;
- for(i = 0; i < 4; i++) {
- o->oSolidLine(pts);
- pts[0].x += 4; pts[1].x += 4;
- pts[0].y -= 4; pts[1].y -= 4;
- }
- pts[0].x = ix+4; pts[0].y = iy+6;
- pts[1].x -= 2; pts[1].y += 4;
- for(i = 0; i < 5; i++) {
- o->oSolidLine(pts);
- pts[0].x -= 5; pts[1].x -= 5;
- pts[0].y -= 2; pts[1].y -= 2;
- }
- memcpy(&td, &o->TxtSet, sizeof(TextDEF));
- memcpy(&otd, &o->TxtSet, sizeof(TextDEF));
- td.Align = TXA_HCENTER | TXA_VTOP;
- td.Mode = TXM_TRANSPARENT;
- if(id == 565) {
- td.Style = TXS_NORMAL; td.ColTxt = 0x00c00000L;
- o->SetTextSpec(&td); o->oTextOut(ix, iy+4, "f(x,z)", 0);
- }
- else {
- td.Style = TXS_BOLD;
- td.fSize = defs.GetSize(SIZE_TEXT)*1.75; td.iSize = 0;
- td.ColTxt = cmd == OD_DRAWSELECTED ? 0x0000cb00L : 0x00cb00c0L;
- o->SetTextSpec(&td);
- o->oTextOut(ix-10, iy-6, "?", 0);
- }
- o->SetTextSpec(&otd);
- break;
- case 567:
- o->SetLine(&bLine); if(cmd == OD_DRAWSELECTED) o->SetFill(&FillG);
- pts[0].x = ix-10; pts[0].y = iy+4;
- pts[1].x = ix-6; pts[1].y = iy+10;
- pts[2].x = ix-16; pts[2].y = iy+8;
- o->oPolygon(pts, 3, 0L);
- pts[2].x = ix+2; pts[2].y = iy-10; o->oPolygon(pts, 3, 0L);
- pts[0].x = ix+10; pts[0].y = iy-12; o->oPolygon(pts, 3, 0L);
- pts[2].x = ix+2; pts[2].y = iy+14; o->oPolygon(pts, 3, 0L);
- pts[1].x = ix+12; pts[1].y = iy+4; o->oPolygon(pts, 3, 0L);
- pts[0].x = ix+16; pts[0].y = iy+12; o->oPolygon(pts, 3, 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 : 0x00e8e8e8L;
- Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00e8e8e8L;
- 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 : 0x00e8e8e8L;
- Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00e8e8e8L;
- 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);
- Line.color = cmd == OD_DRAWSELECTED ? 0x00c0c0c0L : 0x0L;
- o->SetLine(&Line); o->SetFill(&Fill);
- 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);
- Line.color = 0x00000000L; o->SetLine(&Line);
- break;
- }
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 2D Plot: 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 : 0x00e8e8e8L;
- Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00e8e8e8L;
- 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;
- }
-}
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 3D Plot: Execute axis templates for new axis as owner drawn buttons
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-void OD_NewAxisTempl3D(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 spts[24];
- int i, ix, iy, edge;
- DWORD col1, col2;
-
- switch(cmd) {
- case OD_DRAWNORMAL:
- case OD_DRAWSELECTED:
- Line.color = cmd == OD_DRAWSELECTED ? 0x00000000L : 0x00e8e8e8L;
- Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00e8e8e8L;
- col1 = cmd == OD_DRAWSELECTED ? 0x008080c0L : 0x00c8c8c8L;
- col2 = cmd == OD_DRAWSELECTED ? 0x0000ff00L : 0x0000c000L;
- o->SetLine(&Line);
- ix = (rec->right + rec->left)>>1; iy = (rec->bottom + rec->top)>>1;
- spts[0].x = spts[3].x = spts[4].x = rec->left;
- spts[0].y = spts[1].y = spts[4].y = rec->top;
- spts[1].x = spts[2].x = rec->right-1; spts[2].y = spts[3].y = rec->bottom-1;
- o->oPolyline(spts, 5); Line.color = 0x00000000L;
- o->SetLine(&Line); o->SetFill(&Fill);
- o->oRectangle(rec->left+3, rec->top+3, rec->right-3, rec->bottom-3);
- spts[0].x = spts[6].x = spts[8].x = spts[13].x = spts[18].x = spts[19].x = rec->left+20;
- spts[0].y = spts[13].y = spts[18].y = rec->bottom-14;
- spts[1].x = spts[2].x = spts[4].x = spts[5].x = spts[7].x = spts[21].x = rec->left+10;
- spts[1].y = spts[2].y = spts[4].y = rec->bottom-10;
- spts[3].x = spts[15].x = spts[16].x = spts[17].x = spts[20].x = spts[22].x = rec->right-20;
- spts[3].y = spts[15].y = spts[16].y = spts[2].y + 3;
- spts[5].y = spts[7].y = spts[21].y = rec->top+12;
- spts[6].y = spts[8].y = spts[19].y = rec->top+8;
- spts[9].x = spts[10].x = spts[11].x = spts[12].x = spts[14].x = spts[23].x = rec->right-10;
- spts[9].y = spts[10].y = spts[23].y = spts[8].y+3;
- spts[11].y = spts[12].y = spts[14].y = spts[0].y+3;
- spts[17].y = spts[20].y = spts[22].y = spts[7].y+3;
- switch(id) {
- case 201: edge = 4; break;
- case 202: edge = 16; break;
- case 203: edge = 10; break;
- case 204: edge = 18; break;
- case 205: edge = 2; break;
- case 206: edge = 14; break;
- case 207: edge = 12; break;
- case 208: edge = 0; break;
- case 209: edge = 20; break;
- case 210: edge = 22; break;
- case 211: edge = 8; break;
- case 212: edge = 6; break;
- default: edge = -1; break;
- }
- Line.color = col1; o->SetLine(&Line);
- if(true)for(i = 0; i < 24; i+= 2) {
- if(i == edge){
- Line.color = col2; o->SetLine(&Line);
- o->oSolidLine(spts+i);
- Line.color = col1; o->SetLine(&Line);
- }
- else o->oSolidLine(spts+i);
- }
- o->UpdateRect(rec, false);
- break;
- }
-}
+//ODbuttons.cpp, Copyright (c) 2001-2008 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;
+extern Default defs;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// utility draw base rectangle for OD-button
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static void OD_BaseRect(anyOutput *o, int cmd, RECT *rec)
+{
+ LineDEF Line = {0.0, 1.0, 0x0L, 0x0L};
+ FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
+ POINT pts[5];
+
+ Line.color = cmd == OD_DRAWSELECTED ? 0x00000000L : 0x00e8e8e8L;
+ Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00e8e8e8L;
+ 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);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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 polygon style as owner drawn buttons
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void OD_PolygonStyleTempl(int cmd, void *par, RECT *rec, anyOutput *o,
+ void *data, int id)
+{
+ FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
+ POINT *pts;
+ int ix= (rec->left + rec->right)>>1, iy = (rec->top +rec->bottom)>>1, np;
+ long cp;
+ POINT tmppts[] = {{rec->left+15, iy}, {rec->left+15, iy-5}, {ix-5, rec->top+14},
+ {ix, rec->top+15}, {ix+10, rec->top+17}, {rec->right-7, rec->bottom-22},
+ {rec->right-15, rec->bottom-15}, {rec->right-23, rec->bottom-8},
+ {rec->left+15, iy+5}, {rec->left+15, iy}};
+
+
+ if(!(pts=(POINT*)malloc(2*sizeof(POINT)*(rec->right-rec->left)))) return;
+ switch(cmd) {
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ OD_BaseRect(o, cmd, rec);
+ if(cmd == OD_DRAWSELECTED){
+ Fill.color = 0x0000ffffL; o->SetFill(&Fill);
+ }
+
+ np = 0;
+ switch(id) {
+ case 201:
+ pts[np].x = rec->left+15; pts[np++].y = iy;
+ pts[np].x = ix; pts[np++].y = rec->top+15;
+ pts[np].x = rec->right-15; pts[np++].y = rec->bottom-15;
+ break;
+ case 202:
+ pts[np].x = rec->left+15; 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 = rec->top+15;
+ pts[np].x = rec->right-15; pts[np++].y = rec->bottom-15;
+ pts[np].x = rec->left+15; pts[np++].y = rec->bottom-15;
+ break;
+ case 203:
+ pts[np].x = rec->left+15; pts[np++].y = iy;
+ pts[np].x = rec->left+15; pts[np++].y = rec->top+15;
+ pts[np].x = ix; pts[np++].y = rec->top+15;
+ pts[np].x = ix; pts[np++].y = rec->bottom-15;
+ pts[np].x = rec->right-15; pts[np++].y = rec->bottom-15;
+ pts[np].x = rec->right-15; pts[np++].y = iy;
+ break;
+ case 213:
+ cp = 0;
+ DrawBezier(&cp, pts, tmppts[0], tmppts[1], tmppts[2], tmppts[3], 0);
+ DrawBezier(&cp, pts, tmppts[3], tmppts[4], tmppts[5], tmppts[6], 0);
+ DrawBezier(&cp, pts, tmppts[6], tmppts[7], tmppts[8], tmppts[9], 0);
+ np = (int)cp;
+ break;
+ }
+ if(np) o->oPolygon(pts, np);
+ switch(id) {
+ case 201: case 202: case 203: case 213:
+ Fill.color = (cmd == OD_DRAWSELECTED) ? 0x000000ffL : 0x00ffffffL;
+ o->SetFill(&Fill);
+ o->oCircle(ix-2, rec->top+13, ix+3, rec->top+18);
+ o->oCircle(rec->left+13, iy-2, rec->left+18, iy+3);
+ o->oCircle(rec->right-14, rec->bottom-14, rec->right-17, rec->bottom-17);
+ break;
+ }
+ o->UpdateRect(rec, false);
+ free(pts);
+ break;
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Execute line style as owner drawn buttons
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void OD_LineStyleTempl(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;
+ int i, ix, iy, np;
+
+ if(!(pts=(POINT*)malloc(2*sizeof(POINT)*(rec->right-rec->left)))) return;
+ switch(cmd) {
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ Line.color = cmd == OD_DRAWSELECTED ? 0x00000000L : 0x00e8e8e8L;
+ Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00e8e8e8L;
+ 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);
+ if(cmd == OD_DRAWSELECTED){
+ Fill.color = 0x000000ffL; o->SetFill(&Fill);
+ }
+ 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;
+ case 210:
+ pts[0].x = rec->left +9; pts[0].y = iy+4; pts[1].x = pts[0].x+1;
+ for(i = 0; i < (rec->right - rec->left - 18); i++) {
+ pts[1].y = 4 + iy + iround(pow(20.0, 1.0+((double)-i)/30.0) * -sin(((double)i)/4.0));
+ o->oSolidLine(pts);
+ pts[0].x++; pts[1].x++; pts[0].y = pts[1].y;
+ }
+ o->oCircle(rec->left+7, iy+4, rec->left+12, iy +9);
+ o->oCircle(rec->left+12, iy-10, rec->left+17, iy -5);
+ o->oCircle(rec->right-19, iy+5, rec->right-24, iy +10);
+ o->oCircle(rec->right-9, iy, rec->right-14, iy+5);
+ break;
+ case 211:
+ pts[0].y = rec->top +9; pts[0].x = ix; pts[1].y = pts[0].y+1;
+ for(i = 0; i < (rec->bottom - rec->top - 18); i++) {
+ pts[1].x = ix + iround(pow(20.0, 1.0+((double)-i)/50.0) * -sin(((double)i)/4.0));
+ o->oSolidLine(pts);
+ pts[0].y++; pts[1].y++; pts[0].x = pts[1].x;
+ }
+ o->oCircle(ix-3, rec->top + 9, ix+2, rec->top + 14);
+ o->oCircle(rec->left+11, iy-10, rec->left+16, iy -5);
+ o->oCircle(ix+3, rec->top + 27, ix+8, rec->top + 32);
+ o->oCircle(ix-5, iy+12, ix, iy + 17);
+ break;
+ case 212:
+ for(i = 2; i < (rec->bottom - rec->top - 18); i++) {
+ pts[1].x = ix + iround(pow(20.0, 1.0+((double)-i)/50.0) * -sin(((double)i)/4.0));
+ pts[1].y = iy + iround(pow(20.0, 1.0+((double)-i)/50.0) * -cos(((double)i)/4.0));
+ if(i>2)o->oSolidLine(pts);
+ pts[0].y = pts[1].y; pts[0].x = pts[1].x;
+ }
+ o->oCircle(ix-5, iy-4, ix, iy+1); o->oCircle(ix-10, iy-17, ix-5, iy-12);
+#ifdef _WINDOWS
+ o->oCircle(ix-12, iy+9, ix-7, iy+4); o->oCircle(ix+9, iy+7, ix+4, iy+2);
+#else
+ o->oCircle(ix-12, iy+9, ix-7, iy+4); o->oCircle(ix+8, iy+6, ix+4, iy+2);
+#endif
+ break;
+ }
+ if(np) o->oPolyline(pts, np);
+ switch(id) {
+ case 201: case 202: case 203: case 204: case 205:
+ case 206: case 207: case 208: case 209:
+ o->oCircle(ix-2, iy-2, ix+3, iy+3);
+#ifdef _WINDOWS
+ o->oCircle(rec->left+13, rec->bottom-13, rec->left+18, rec->bottom-18);
+ o->oCircle(rec->right-13, rec->top+13, rec->right-18, rec->top+18);
+#else
+ o->oCircle(rec->left+13, rec->bottom-14, rec->left+18, rec->bottom-18);
+ o->oCircle(rec->right-14, rec->top+13, rec->right-18, rec->top+18);
+#endif
+ break;
+ case 210: case 211: case 212:
+ break;
+ }
+ o->UpdateRect(rec, false);
+ free(pts);
+ break;
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Execute bubble style as owner drawn buttons
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void OD_BubbleTempl(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id)
+{
+ FillDEF Fill = {FILL_NONE, 0x00c0ffffL, 1.0, 0L};
+ POINT pts[3];
+ int ix, iy;
+
+ switch(cmd) {
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ ix = (rec->left + rec->right)/2;
+ iy = (rec->top +rec->bottom)/2;
+ pts[0].x = ix-10; pts[2].x = ix+10; pts[1].x = ix;
+ OD_BaseRect(o, cmd, rec);
+ if(cmd == OD_DRAWSELECTED) o->SetFill(&Fill);
+ switch(id) {
+ case 109: case 201:
+ o->oCircle(ix-10, iy-10, ix+10, iy+10);
+ break;
+ case 110: case 202:
+ o->oRectangle(ix-10, iy-10, ix+10, iy+10);
+ break;
+ case 111: case 203:
+ pts[0].y = pts[2].y = iy + 9; pts[1].y = iy - 11;
+ o->oPolygon(pts, 3);
+ break;
+ case 112: case 204:
+ pts[0].y = pts[2].y = iy - 9; pts[1].y = iy + 11;
+ o->oPolygon(pts, 3);
+ break;
+ }
+ o->UpdateRect(rec, false);
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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)
+{
+ POINT pts[6];
+ int ix, iy;
+
+ switch(cmd) {
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ ix = (rec->left + rec->right)/2;
+ iy = (rec->top +rec->bottom)/2;
+ OD_BaseRect(o, cmd, rec);
+ 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)
+{
+ POINT pts[6];
+ int ix, iy;
+
+ switch(cmd) {
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ ix = (rec->left + rec->right)/2;
+ iy = (rec->top +rec->bottom)/2;
+ OD_BaseRect(o, cmd, rec);
+ 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 : 0x00e8e8e8L;
+ Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00e8e8e8L;
+ 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 = 0x00e8e8e8L;
+ 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 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};
+ int ix, iy;
+ double r, *ang = angels1;
+ segment *seg = 0L;
+ lfPOINT fc;
+
+ switch(cmd) {
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ ix = (rec->left + rec->right)/2;
+ iy = (rec->top +rec->bottom)/2;
+ OD_BaseRect(o, cmd, rec);
+ 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 = {0.0, 1.0, 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:
+ ix = (rec->left + rec->right)>>1;
+ iy = (rec->top +rec->bottom)>>1;
+ OD_BaseRect(o, cmd, rec);
+ 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
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static 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 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
+ case 565: case 566: case 567:
+ OD_AxisTempl3D(cmd, par, rec, o, data, 410+AxisTempl3D);
+ break;
+ default:
+ OD_BaseRect(o, cmd, rec);
+ break;
+ }
+ if(cmd != OD_DRAWSELECTED) {
+ FillR.color |= 0x00808080L; FillG.color |= 0x00808080L;
+ FillB.color |= 0x00808080L; FillY.color |= 0x00808080L;
+ }
+ 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: case 507:
+ o->SetFill(&FillR);
+ o->oRectangle(rec->left+9, rec->top+30, rec->left+13, rec->bottom-3);
+ o->oRectangle(rec->right-20, id == 507 ? rec->top + 25 : 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);
+ if(id == 507) {
+ o->SetLine(&Line);
+ pts[0].x = pts[1].x = rec->left+11; pts[0].y = rec->top+20;
+ pts[1].y = rec->top+40; o->oSolidLine(pts);
+ pts[0].x = pts[1].x = rec->left+15; pts[0].y = rec->top+15;
+ pts[1].y = rec->top+35; o->oSolidLine(pts);
+ pts[0].x = pts[1].x = rec->left+19; pts[0].y = rec->top+30;
+ pts[1].y = rec->top+40; o->oSolidLine(pts);
+ pts[0].x = pts[1].x = rec->right-18; pts[0].y = rec->top+15;
+ pts[1].y = rec->top+35; o->oSolidLine(pts);
+ pts[0].x = pts[1].x = rec->right-14; pts[0].y = rec->top+10;
+ pts[1].y = rec->top+20; o->oSolidLine(pts);
+ pts[0].x = pts[1].x = rec->right-10; pts[0].y = rec->top+10;
+ pts[1].y = rec->top+30; o->oSolidLine(pts);
+ }
+ 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 506:
+ 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 = pts[0].y - iround(exp(-r*r)*1.0+5.0);
+ pts[1].y = rec->bottom - iround(errf(r)*16.0+26.0);
+ if (i) o->oSolidLine(pts);
+ pts[0].x++; pts[1].x++; pts[0].y = pts[1].y;
+ }
+ o->SetLine(&rLine);
+ pts[0].x = ix-2; pts[1].x = pts[0].x+1;
+ for(i = 0; i < (rec->right - ix-5); i++) {
+ r = ((double)(i-9))/4.0;
+ pts[1].y = rec->bottom - iround(exp(-r*r)*17.0+7.0);
+ if (i) o->oSolidLine(pts);
+ pts[0].x++; pts[1].x++; pts[0].y = pts[1].y;
+ }
+ o->SetFill(&FillG); o->SetLine(&Line);
+ o->oCircle(ix, iy, ix+5, iy+5);
+ o->oCircle(ix-5, iy+8, ix, iy+13);
+ o->oCircle(ix+5, iy-10, ix+10, iy-5);
+ 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 = defs.GetSize(SIZE_TEXT)*1.75; 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 532:
+ pts[0].x = rec->left +13; pts[0].y = rec->top+8;
+ pts[1].x = rec->left +13; pts[1].y = iy;
+ o->oSolidLine(pts);
+ pts[0].x -= 3; pts[1].x += 3;
+ pts[0].y = pts[1].y = rec->top+8;
+ o->oSolidLine(pts);
+ pts[0].y = pts[1].y = iy;
+ o->oSolidLine(pts);
+ pts[0].x = ix; pts[0].y = iy-8;
+ pts[1].x = ix; pts[1].y = rec->bottom-13;
+ o->oSolidLine(pts);
+ pts[0].x -= 3; pts[1].x += 3;
+ pts[0].y = pts[1].y = iy-8;
+ o->oSolidLine(pts);
+ pts[0].y = pts[1].y = rec->bottom-13;
+ o->oSolidLine(pts);
+ pts[0].x = rec->right -13; pts[0].y = rec->top+10;
+ pts[1].x = rec->right -13; pts[1].y = iy-6;
+ o->oSolidLine(pts);
+ pts[0].x -= 3; pts[1].x += 3;
+ pts[0].y = pts[1].y = rec->top+10;
+ o->oSolidLine(pts);
+ pts[0].y = pts[1].y = iy-6;
+ o->oSolidLine(pts);
+ pts[0].x = rec->left+13; pts[1].x = ix; pts[2].x = rec->right-13;
+ pts[0].y = (rec->top+8+iy)>>1;
+ pts[1].y = (rec->bottom-13 + iy -8)>>1;
+ pts[2].y = (rec->top+10+iy-6)>>1;
+ o->oPolyline(pts, 3, 0L);
+ o->SetFill(&FillY);
+ o->oCircle(pts[0].x-3, pts[0].y-3, pts[0].x+3, pts[0].y+3);
+ o->oCircle(pts[1].x-3, pts[1].y-3, pts[1].x+3, pts[1].y+3);
+ o->oCircle(pts[2].x-3, pts[2].y-3, pts[2].x+3, pts[2].y+3);
+ 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;
+ case 565: case 566:
+ o->SetLine(&rLine);
+ pts[0].x = ix-16; pts[0].y = iy-2;
+ pts[1].x = ix+4; pts[1].y = iy+6;
+ for(i = 0; i < 4; i++) {
+ o->oSolidLine(pts);
+ pts[0].x += 4; pts[1].x += 4;
+ pts[0].y -= 4; pts[1].y -= 4;
+ }
+ pts[0].x = ix+4; pts[0].y = iy+6;
+ pts[1].x -= 2; pts[1].y += 4;
+ for(i = 0; i < 5; i++) {
+ o->oSolidLine(pts);
+ pts[0].x -= 5; pts[1].x -= 5;
+ pts[0].y -= 2; pts[1].y -= 2;
+ }
+ memcpy(&td, &o->TxtSet, sizeof(TextDEF));
+ memcpy(&otd, &o->TxtSet, sizeof(TextDEF));
+ td.Align = TXA_HCENTER | TXA_VTOP;
+ td.Mode = TXM_TRANSPARENT;
+ if(id == 565) {
+ td.Style = TXS_NORMAL; td.ColTxt = 0x00c00000L;
+ o->SetTextSpec(&td); o->oTextOut(ix, iy+4, "f(x,z)", 0);
+ }
+ else {
+ td.Style = TXS_BOLD;
+ td.fSize = defs.GetSize(SIZE_TEXT)*1.75; td.iSize = 0;
+ td.ColTxt = cmd == OD_DRAWSELECTED ? 0x0000cb00L : 0x00cb00c0L;
+ o->SetTextSpec(&td);
+ o->oTextOut(ix-10, iy-6, "?", 0);
+ }
+ o->SetTextSpec(&otd);
+ break;
+ case 567:
+ o->SetLine(&bLine); if(cmd == OD_DRAWSELECTED) o->SetFill(&FillG);
+ pts[0].x = ix-10; pts[0].y = iy+4;
+ pts[1].x = ix-6; pts[1].y = iy+10;
+ pts[2].x = ix-16; pts[2].y = iy+8;
+ o->oPolygon(pts, 3, 0L);
+ pts[2].x = ix+2; pts[2].y = iy-10; o->oPolygon(pts, 3, 0L);
+ pts[0].x = ix+10; pts[0].y = iy-12; o->oPolygon(pts, 3, 0L);
+ pts[2].x = ix+2; pts[2].y = iy+14; o->oPolygon(pts, 3, 0L);
+ pts[1].x = ix+12; pts[1].y = iy+4; o->oPolygon(pts, 3, 0L);
+ pts[0].x = ix+16; pts[0].y = iy+12; o->oPolygon(pts, 3, 0L);
+ break;
+ case 568:
+ if(cmd == OD_DRAWSELECTED) {
+ FillY.color |= 0x00808080L; FillG.color |= 0x00808080L;
+ FillR.color |= 0x00808080L; FillB.color |= 0x00808080L;
+ o->SetFill(&FillY);
+ pts[0].x = pts[3].x = rec->left+3; pts[0].y = pts[1].y = rec->top+3;
+ pts[1].x = pts[2].x = rec->right-3; pts[2].y = pts[3].y = rec->bottom-3;
+ o->oPolygon(pts, 4);
+ }
+ o->SetLine(cmd == OD_DRAWSELECTED ? &bLine : &Line);
+ if(cmd == OD_DRAWSELECTED) o->SetFill(&FillG);
+ pts[0].x = pts[1].x = rec->left+15; pts[0].y = rec->top+3;
+ pts[1].y = rec->top+5; pts[2].x = rec->left+12; pts[2].y = rec->top+12;
+ pts[3].x = rec->left+7; pts[3].y = pts[4].y = rec->top+15;
+ pts[4].x = rec->left+3; pts[5].x = rec->left+3; pts[5].y = rec->top+3;
+ o->oPolygon(pts, 6);
+ pts[0].x = pts[1].x = ix; pts[2].x = ix+6; pts[3].x = rec->right-7;
+ pts[4].x = rec->right-3; pts[5].x = rec->right-3; o->oPolygon(pts, 6);
+ pts[0].y = rec->bottom-3; pts[1].y = rec->bottom-9; pts[2].y = iy+3;
+ pts[3].x = rec->right-9; pts[3].y = pts[4].y = iy-3; pts[5].y = rec->bottom-3;
+ o->oPolygon(pts, 6);
+ pts[0].x = pts[1].x = rec->right-15; pts[0].y = rec->bottom-3;
+ pts[1].y = rec->bottom-5; pts[2].x = rec->right-12; pts[2].y = rec->bottom-10;
+ pts[3].x = rec->right-7; pts[3].y = pts[4].y = rec->bottom-15;
+ pts[4].x = rec->right-3; pts[5].x = rec->right-3; pts[5].y = rec->bottom-3;
+ if(cmd == OD_DRAWSELECTED) o->SetFill(&FillB); o->oPolygon(pts, 6);
+ pts[0].x = pts[1].x = rec->left+15; pts[0].y = rec->bottom-3;
+ pts[1].y = rec->bottom-5; pts[2].x = rec->left+12; pts[2].y = iy+5;
+ pts[3].x = rec->left+7; pts[3].y = pts[4].y = iy-3; pts[4].x = rec->left+3;
+ pts[5].x = rec->left+3; if(cmd == OD_DRAWSELECTED) o->SetFill(&FillG);
+ o->oPolygon(pts, 6);
+ if(cmd == OD_DRAWSELECTED) o->SetFill(&FillR); o->oCircle(ix-9, iy-9, ix+1, iy+3);
+ 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};
+ POINT pts[5];
+ int i, ty, tx, sx;
+
+ switch(cmd) {
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ OD_BaseRect(o, cmd, rec);
+ 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:
+ OD_BaseRect(o, cmd, rec);
+ Line.color = cmd == OD_DRAWSELECTED ? 0x00c0c0c0L : 0x0L;
+ o->SetLine(&Line); o->SetFill(&Fill);
+ 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);
+ Line.color = 0x00000000L; o->SetLine(&Line);
+ break;
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 2D Plot: 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)
+{
+ POINT pts[5];
+ int i, ix, iy, step, d1, d2;
+
+ switch(cmd) {
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ ix = (rec->right + rec->left)>>1;
+ iy = (rec->bottom + rec->top)>>1;
+ OD_BaseRect(o, cmd, rec);
+ 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;
+ }
+}
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 3D Plot: Execute axis templates for new axis as owner drawn buttons
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void OD_NewAxisTempl3D(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 spts[24];
+ int i, ix, iy, edge;
+ DWORD col1, col2;
+
+ switch(cmd) {
+ case OD_DRAWNORMAL:
+ case OD_DRAWSELECTED:
+ Line.color = cmd == OD_DRAWSELECTED ? 0x00000000L : 0x00e8e8e8L;
+ Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00e8e8e8L;
+ col1 = cmd == OD_DRAWSELECTED ? 0x008080c0L : 0x00c8c8c8L;
+ col2 = cmd == OD_DRAWSELECTED ? 0x0000ff00L : 0x0000c000L;
+ o->SetLine(&Line);
+ ix = (rec->right + rec->left)>>1; iy = (rec->bottom + rec->top)>>1;
+ spts[0].x = spts[3].x = spts[4].x = rec->left;
+ spts[0].y = spts[1].y = spts[4].y = rec->top;
+ spts[1].x = spts[2].x = rec->right-1; spts[2].y = spts[3].y = rec->bottom-1;
+ o->oPolyline(spts, 5); Line.color = 0x00000000L;
+ o->SetLine(&Line); o->SetFill(&Fill);
+ o->oRectangle(rec->left+3, rec->top+3, rec->right-3, rec->bottom-3);
+ spts[0].x = spts[6].x = spts[8].x = spts[13].x = spts[18].x = spts[19].x = rec->left+20;
+ spts[0].y = spts[13].y = spts[18].y = rec->bottom-14;
+ spts[1].x = spts[2].x = spts[4].x = spts[5].x = spts[7].x = spts[21].x = rec->left+10;
+ spts[1].y = spts[2].y = spts[4].y = rec->bottom-10;
+ spts[3].x = spts[15].x = spts[16].x = spts[17].x = spts[20].x = spts[22].x = rec->right-20;
+ spts[3].y = spts[15].y = spts[16].y = spts[2].y + 3;
+ spts[5].y = spts[7].y = spts[21].y = rec->top+12;
+ spts[6].y = spts[8].y = spts[19].y = rec->top+8;
+ spts[9].x = spts[10].x = spts[11].x = spts[12].x = spts[14].x = spts[23].x = rec->right-10;
+ spts[9].y = spts[10].y = spts[23].y = spts[8].y+3;
+ spts[11].y = spts[12].y = spts[14].y = spts[0].y+3;
+ spts[17].y = spts[20].y = spts[22].y = spts[7].y+3;
+ switch(id) {
+ case 201: edge = 4; break;
+ case 202: edge = 16; break;
+ case 203: edge = 10; break;
+ case 204: edge = 18; break;
+ case 205: edge = 2; break;
+ case 206: edge = 14; break;
+ case 207: edge = 12; break;
+ case 208: edge = 0; break;
+ case 209: edge = 20; break;
+ case 210: edge = 22; break;
+ case 211: edge = 8; break;
+ case 212: edge = 6; break;
+ default: edge = -1; break;
+ }
+ Line.color = col1; o->SetLine(&Line);
+ if(true)for(i = 0; i < 24; i+= 2) {
+ if(i == edge){
+ Line.color = col2; o->SetLine(&Line);
+ o->oSolidLine(spts+i);
+ Line.color = col1; o->SetLine(&Line);
+ }
+ else o->oSolidLine(spts+i);
+ }
+ o->UpdateRect(rec, false);
+ break;
+ }
+}
diff --git a/Output.cpp b/Output.cpp
index 9749dad..a8bb23d 100755
--- a/Output.cpp
+++ b/Output.cpp
@@ -1,1959 +1,1960 @@
-//Output.cpp, Copyright (c) 2000-2007 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); OC_type = OC_UNKNOWN;
- 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::UseAxis(AxisDEF *ax, int type)
-{
- AxisDEF *cax;
-
- MrkMode = MRK_NONE;
- if(!ax) return;
- switch (type) {
- case 1: //x-axis
- memcpy(cax = &xAxis, ax, sizeof(AxisDEF));
- Box1.Xmin = co2fix(ax->loc[0].fx);
- Box1.Xmax = co2fix(ax->loc[1].fx);
- ddx = GetAxisFac(&xAxis, Box1.Xmax - Box1.Xmin, 0);
- break;
- case 2: //y-axis
- memcpy(cax = &yAxis, ax, sizeof(AxisDEF));
- if(ax->flags & AXIS_3D) {
- Box1.Ymax = co2fiy(ax->loc[0].fy);
- Box1.Ymin = co2fiy(ax->loc[1].fy);
- }
- else {
- Box1.Ymin = co2fiy(ax->loc[0].fy);
- Box1.Ymax = co2fiy(ax->loc[1].fy);
- }
- ddy = GetAxisFac(&yAxis, Box1.Ymax - Box1.Ymin, 1);
- break;
- case 3: //z-axis
- memcpy(cax = &zAxis, ax, sizeof(AxisDEF));
- Box1z.fx = un2fiz(ax->loc[0].fz);
- Box1z.fy = un2fiz(ax->loc[1].fz);
- ddz = GetAxisFac(&zAxis, Box1z.fy - Box1z.fx, 2);
- break;
- default: //unnknown direction
- return;
- }
- cax->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; HideCopyMark();
- 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()
-{
- 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(CurrLabel && CurrLabel->Command(CMD_HIDEMARK, 0L, this))
- CurrGraph->Command(CMD_REDRAW, 0L, this);
- else if(MrkRect)((GraphObj*)MrkRect)->DoMark(this, false);
- else if(CurrGraph) 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 = (int)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 = (int)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 = (int)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;
- if(TxtSet.Align & TXA_VCENTER) {
- disp.top -= (TxtSet.iSize>>1);
- }
-#ifdef _WINDOWS
- disp.bottom = disp.top + TxtSet.iSize-1;
-#else
- disp.top -= 1;
- disp.bottom = disp.top + iround(TxtSet.iSize*1.25)-2;
-#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 = (int)strlen(text);
- for(i = w = 0; i < cb; i++) w += ((unsigned)text[i] < 256 ? CharWidth[(unsigned)text[i]] : 35);
- *width = iround(((double)w * (double)TxtSet.iSize)/52.0);
- *height = TxtSet.iSize;
- return true;
-}
-
-bool
-anyOutput::oGetTextExtentW(w_char *text, int cb, int *width, int *height)
-{
- if(cb < 1) for(cb = 0; text[cb]; cb++);
- *width = (TxtSet.iSize * cb)>>1;
- *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 _HatchDef{
- 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(0); 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_HASH: Hash(); break;
- case FILL_WATER: Waves2(1); 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(out->OC_type != OC_HIMETRIC && (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 -= (iy<<1); UseRect.bottom += (iy<<1);
- 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(int type) //hatch using sine waves
-{
- int i, j, level, y, ix, yinc, *pts;
- POINT Line[2];
- double dtmp;
-
- if(3>(yinc = iround(type?ybase*.8 : ybase*1.2)))yinc = 3;
- if(type == 0 && 14>(ix = iround(xbase*2.5)))ix = 14;
- else if(type == 1 && 7>(ix = iround(xbase*1.2)))ix = 7;
- if(!(pts = (int *)malloc(ix * sizeof(int))))return;
- for(i = 0; i < ix; i++) {
- dtmp = sin(6.283185307/((double)ix/(double)i));
- if(type == 1) dtmp /= 2.0;
- pts[i] = dtmp > 0.0 ? iround(0.3*ybase*dtmp) : iround(0.3*ybase*dtmp);
- }
- UseRect.bottom += yinc; UseRect.right++;
- for(y = UseRect.top, level = 0; y <= UseRect.bottom; y += yinc, level++){
- Line[0].x = UseRect.left; Line[1].x = UseRect.left+1;
- Line[0].y = y; Line[1].y = y+pts[1];
- if(type == 0) for(j = 2; Line[0].x < UseRect.right; 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];
- }
- else if(type == 1) {
- if(level & 1) {
- Line[0].x += (ix + (ix>>1)); Line[1].x = Line[0].x +1;
- }
- for(j = 2; Line[0].x < UseRect.right; j++){
- HatchLine(Line[0], Line[1]);
- Line[0].x = Line[1].x;
- Line[0].y = Line[1].y; Line[1].y = y + pts[j%ix];
- if((j-1) % ix) Line[1].x++;
- else {
- HatchLine(Line[0], Line[1]);
- Line[1].x += (ix << 1); Line[0].x = Line[1].x -1;
- }
- }
- }
- }
- 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::Hash()
-{
- int i, dh, dw, cx, cy, xinc, yinc;
- double xsize, ysize, mix, miy;
- long idum = -1;
- POINT Line[5];
-
- xsize = xbase * 0.9; ysize = ybase * 0.9;
- xinc = iround(xsize * 3.3); yinc = iround(ysize * 2.2);
- mix = xbase *.5; miy = ybase *.5;
- dw = iround(xbase > 5 ? xbase/2.0 : 2.0); dh = iround(ybase > 5 ? xbase/2.0 : 2.0);
- if(xsize < 2.0) xsize = 2.0; if(ysize < 2.0) ysize = 2.0;
- IncrementMinMaxRect(&UseRect, (int)xsize);
- for(i = 0, cy = UseRect.top; cy < UseRect.bottom; i++, cy += yinc) {
- for(cx = (i & 1) ? UseRect.left:UseRect.left+xinc/2; cx < UseRect.right; cx += xinc) {
- Line[0].x = Line[1].x = cx;
- Line[0].y = cy - iround(ran2(&idum) * ysize + miy);
- Line[1].y = cy + iround(ran2(&idum) * ysize + miy);
- HatchLine(Line[0], Line[1]);
- Line[0].x = Line[1].x = cx + dw;
- Line[0].y = cy - iround(ran2(&idum) * ysize + miy);
- Line[1].y = cy + iround(ran2(&idum) * ysize + miy);
- HatchLine(Line[0], Line[1]);
- Line[0].y = Line[1].y = cy;
- Line[0].x = cx - iround(ran2(&idum) * xsize + mix);
- Line[1].x = cx + iround(ran2(&idum) * xsize + mix);
- HatchLine(Line[0], Line[1]);
- Line[0].y = Line[1].y = cy + dh;
- Line[0].x = cx - iround(ran2(&idum) * xsize + mix);
- Line[1].x = cx + iround(ran2(&idum) * xsize + mix);
- HatchLine(Line[0], Line[1]);
- }
- }
-}
-
-void
-HatchOut::CircGrad()
-{
- int i;
- double f;
- LineDEF ld = {0.0, 1.0, 0x0, 0x0};
-
- for(i = 1; i < 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 = (char*)memdup(FileName, (int)strlen(FileName)+1, 0);
- }
- 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];
- int cb;
-
- if(name && bmo) {
-#ifdef USE_WIN_SECURE
- if(_sopen_s(&oFile, name, O_RDWR | O_BINARY | O_CREAT | O_TRUNC,
- 0x40, S_IWRITE) || oFile < 0){
- ErrorBox("Could not open output file");
- return false;
- }
-#else
- 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;
- }
-#endif
- *((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;
- cb = rlp_strcpy(prog_name, 20, "RLPlot ");
- rlp_strcpy(prog_name+cb, 20-cb, SZ_VERSION);
-#ifdef USE_WIN_SECURE
- _write(oFile, &header, sizeof(header));
- _write(oFile, &res_info, sizeof(res_info));
- _write(oFile, &prog_name, 20);
-
-#else
- write(oFile, &header, sizeof(header));
- write(oFile, &res_info, sizeof(res_info));
- write(oFile, &prog_name, 20);
-#endif
- 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) {
-#ifdef USE_WIN_SECURE
- _write(oFile, pix_data, 3072);
-#else
- write(oFile, pix_data, 3072);
-#endif
- c = 0;
- }
- }
- }
-#ifdef USE_WIN_SECURE
- _write(oFile, pix_data, c);
-#else
- write(oFile, pix_data, c);
-#endif
- free(pix_data);
- }
-#ifdef USE_WIN_SECURE
- _close(oFile);
-#else
- close(oFile);
-#endif
- oFile = -1;
- 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);
- }
-}
+//Output.cpp, Copyright (c) 2000-2008 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; minLW = 1;
+ 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); OC_type = OC_UNKNOWN;
+ 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::UseAxis(AxisDEF *ax, int type)
+{
+ AxisDEF *cax;
+
+ MrkMode = MRK_NONE;
+ if(!ax) return;
+ switch (type) {
+ case 1: //x-axis
+ memcpy(cax = &xAxis, ax, sizeof(AxisDEF));
+ Box1.Xmin = co2fix(ax->loc[0].fx);
+ Box1.Xmax = co2fix(ax->loc[1].fx);
+ ddx = GetAxisFac(&xAxis, Box1.Xmax - Box1.Xmin, 0);
+ break;
+ case 2: //y-axis
+ memcpy(cax = &yAxis, ax, sizeof(AxisDEF));
+ if(ax->flags & AXIS_3D) {
+ Box1.Ymax = co2fiy(ax->loc[0].fy);
+ Box1.Ymin = co2fiy(ax->loc[1].fy);
+ }
+ else {
+ Box1.Ymin = co2fiy(ax->loc[0].fy);
+ Box1.Ymax = co2fiy(ax->loc[1].fy);
+ }
+ ddy = GetAxisFac(&yAxis, Box1.Ymax - Box1.Ymin, 1);
+ break;
+ case 3: //z-axis
+ memcpy(cax = &zAxis, ax, sizeof(AxisDEF));
+ Box1z.fx = un2fiz(ax->loc[0].fz);
+ Box1z.fy = un2fiz(ax->loc[1].fz);
+ ddz = GetAxisFac(&zAxis, Box1z.fy - Box1z.fx, 2);
+ break;
+ default: //unnknown direction
+ return;
+ }
+ cax->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; HideCopyMark();
+ 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()
+{
+ 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(CurrLabel && CurrLabel->Command(CMD_HIDEMARK, 0L, this))
+ CurrGraph->Command(CMD_REDRAW, 0L, this);
+ else if(MrkRect)((GraphObj*)MrkRect)->DoMark(this, false);
+ else if(CurrGraph) 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 = (int)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 = (int)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 = (int)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;
+ if(TxtSet.Align & TXA_VCENTER) {
+ disp.top -= (TxtSet.iSize>>1);
+ }
+#ifdef _WINDOWS
+ disp.bottom = disp.top + TxtSet.iSize-1;
+#else
+ disp.top -= 1;
+ disp.bottom = disp.top + iround(TxtSet.iSize*1.25)-2;
+#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 = (int)strlen(text);
+ for(i = w = 0; i < cb; i++) w += ((unsigned)text[i] < 256 ? CharWidth[(unsigned)text[i]] : 35);
+ *width = iround(((double)w * (double)TxtSet.iSize)/52.0);
+ *height = TxtSet.iSize;
+ return true;
+}
+
+bool
+anyOutput::oGetTextExtentW(w_char *text, int cb, int *width, int *height)
+{
+ if(cb < 1) for(cb = 0; text[cb]; cb++);
+ *width = (TxtSet.iSize * cb)>>1;
+ *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, mlw;
+
+ 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);
+ mlw = minLW; minLW = ho->minLW = 2;
+ 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-iLine, pts, cp, 0L);
+ delete(ho); minLW = mlw;
+ 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 _HatchDef{
+ 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(0); 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_HASH: Hash(); break;
+ case FILL_WATER: Waves2(1); 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(out->OC_type != OC_HIMETRIC && (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 -= (iy<<1); UseRect.bottom += (iy<<1);
+ 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(int type) //hatch using sine waves
+{
+ int i, j, level, y, ix, yinc, *pts;
+ POINT Line[2];
+ double dtmp;
+
+ if(3>(yinc = iround(type?ybase*.8 : ybase*1.2)))yinc = 3;
+ if(type == 0 && 14>(ix = iround(xbase*2.5)))ix = 14;
+ else if(type == 1 && 7>(ix = iround(xbase*1.2)))ix = 7;
+ if(!(pts = (int *)malloc(ix * sizeof(int))))return;
+ for(i = 0; i < ix; i++) {
+ dtmp = sin(6.283185307/((double)ix/(double)i));
+ if(type == 1) dtmp /= 2.0;
+ pts[i] = dtmp > 0.0 ? iround(0.3*ybase*dtmp) : iround(0.3*ybase*dtmp);
+ }
+ UseRect.bottom += yinc; UseRect.right++;
+ for(y = UseRect.top, level = 0; y <= UseRect.bottom; y += yinc, level++){
+ Line[0].x = UseRect.left; Line[1].x = UseRect.left+1;
+ Line[0].y = y; Line[1].y = y+pts[1];
+ if(type == 0) for(j = 2; Line[0].x < UseRect.right; 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];
+ }
+ else if(type == 1) {
+ if(level & 1) {
+ Line[0].x += (ix + (ix>>1)); Line[1].x = Line[0].x +1;
+ }
+ for(j = 2; Line[0].x < UseRect.right; j++){
+ HatchLine(Line[0], Line[1]);
+ Line[0].x = Line[1].x;
+ Line[0].y = Line[1].y; Line[1].y = y + pts[j%ix];
+ if((j-1) % ix) Line[1].x++;
+ else {
+ HatchLine(Line[0], Line[1]);
+ Line[1].x += (ix << 1); Line[0].x = Line[1].x -1;
+ }
+ }
+ }
+ }
+ 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::Hash()
+{
+ int i, dh, dw, cx, cy, xinc, yinc;
+ double xsize, ysize, mix, miy;
+ long idum = -1;
+ POINT Line[5];
+
+ xsize = xbase * 0.9; ysize = ybase * 0.9;
+ xinc = iround(xsize * 3.3); yinc = iround(ysize * 2.2);
+ mix = xbase *.5; miy = ybase *.5;
+ dw = iround(xbase > 5 ? xbase/2.0 : 2.0); dh = iround(ybase > 5 ? xbase/2.0 : 2.0);
+ if(xsize < 2.0) xsize = 2.0; if(ysize < 2.0) ysize = 2.0;
+ IncrementMinMaxRect(&UseRect, (int)xsize);
+ for(i = 0, cy = UseRect.top; cy < UseRect.bottom; i++, cy += yinc) {
+ for(cx = (i & 1) ? UseRect.left:UseRect.left+xinc/2; cx < UseRect.right; cx += xinc) {
+ Line[0].x = Line[1].x = cx;
+ Line[0].y = cy - iround(ran2(&idum) * ysize + miy);
+ Line[1].y = cy + iround(ran2(&idum) * ysize + miy);
+ HatchLine(Line[0], Line[1]);
+ Line[0].x = Line[1].x = cx + dw;
+ Line[0].y = cy - iround(ran2(&idum) * ysize + miy);
+ Line[1].y = cy + iround(ran2(&idum) * ysize + miy);
+ HatchLine(Line[0], Line[1]);
+ Line[0].y = Line[1].y = cy;
+ Line[0].x = cx - iround(ran2(&idum) * xsize + mix);
+ Line[1].x = cx + iround(ran2(&idum) * xsize + mix);
+ HatchLine(Line[0], Line[1]);
+ Line[0].y = Line[1].y = cy + dh;
+ Line[0].x = cx - iround(ran2(&idum) * xsize + mix);
+ Line[1].x = cx + iround(ran2(&idum) * xsize + mix);
+ HatchLine(Line[0], Line[1]);
+ }
+ }
+}
+
+void
+HatchOut::CircGrad()
+{
+ int i;
+ double f;
+ LineDEF ld = {0.0, 1.0, 0x0, 0x0};
+
+ for(i = 1; i < 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 = (char*)memdup(FileName, (int)strlen(FileName)+1, 0);
+ }
+ 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];
+ int cb;
+
+ if(name && bmo) {
+#ifdef USE_WIN_SECURE
+ if(_sopen_s(&oFile, name, O_RDWR | O_BINARY | O_CREAT | O_TRUNC,
+ 0x40, S_IWRITE) || oFile < 0){
+ ErrorBox("Could not open output file");
+ return false;
+ }
+#else
+ 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;
+ }
+#endif
+ *((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;
+ cb = rlp_strcpy(prog_name, 20, "RLPlot ");
+ rlp_strcpy(prog_name+cb, 20-cb, SZ_VERSION);
+#ifdef USE_WIN_SECURE
+ _write(oFile, &header, sizeof(header));
+ _write(oFile, &res_info, sizeof(res_info));
+ _write(oFile, &prog_name, 20);
+
+#else
+ write(oFile, &header, sizeof(header));
+ write(oFile, &res_info, sizeof(res_info));
+ write(oFile, &prog_name, 20);
+#endif
+ 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) {
+#ifdef USE_WIN_SECURE
+ _write(oFile, pix_data, 3072);
+#else
+ write(oFile, pix_data, 3072);
+#endif
+ c = 0;
+ }
+ }
+ }
+#ifdef USE_WIN_SECURE
+ _write(oFile, pix_data, c);
+#else
+ write(oFile, pix_data, c);
+#endif
+ free(pix_data);
+ }
+#ifdef USE_WIN_SECURE
+ _close(oFile);
+#else
+ close(oFile);
+#endif
+ oFile = -1;
+ 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
index fb2f240..b3ce97a 100755
--- a/PlotObs.cpp
+++ b/PlotObs.cpp
@@ -1,5713 +1,6152 @@
-//PlotObs.cpp, Copyright (c) 2001-2007 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)
-{
- int pos, nsize;
-
- Id = GO_PLOT;
- Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
- if(name = (char*)malloc((nsize = 20)*sizeof(char))){
- pos = rlp_strcpy(name, nsize, (char*)"Plot");
- add_int_to_buff(&name, &pos, &nsize, ++cPlots, true, 0);
- }
- use_xaxis = use_yaxis = use_zaxis = 0; hidden = 0;
- x_info = y_info = z_info = data_desc = 0L;
- x_tv = y_tv = 0L; x_dtype = y_dtype = z_dtype = 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:
- return DefSize(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)
-{
- if(CurrAxes && CurrAxes[idx]) {
- switch(CurrAxes[idx]->type & 0xf) {
- case 1: // x-axis
- Undo.ValInt(parent, &use_xaxis, 0L);
- use_xaxis = idx; return true;
- case 2: // y-axis
- Undo.ValInt(parent, &use_yaxis, 0L);
- use_yaxis = idx; return true;
- case 3: // z-axis
- Undo.ValInt(parent, &use_zaxis, 0L);
- use_zaxis = idx; return true;
- }
- }
- return false;
-}
-
-void
-Plot::ApplyAxes(anyOutput *o)
-{
- if(!o || !CurrAxes || !parent) return;
- if(use_xaxis && CurrAxes[use_xaxis]) {
- o->UseAxis(CurrAxes[use_xaxis]->axis, CurrAxes[use_xaxis]->type & 0xf);
- }
- else use_xaxis = 0;
- if(use_yaxis && CurrAxes[use_yaxis]) {
- o->UseAxis(CurrAxes[use_yaxis]->axis, CurrAxes[use_yaxis]->type & 0xf);
- }
- else use_yaxis = 0;
- if(use_zaxis && CurrAxes[use_zaxis]) {
- o->UseAxis(CurrAxes[use_zaxis]->axis, CurrAxes[use_zaxis]->type & 0xf);
- }
- else use_zaxis = 0;
- return;
-}
-
-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, n, c_num, c_txt, c_datetime;
- double value, old_val;
- DataObj *CumData = 0L;
- anyResult ares;
- AccRange *ax = 0L, **ayy = 0L;
- TextValue *tv = 0L;
- bool *validRows;
-
- if(!xr || !yr || !mode || !data) return 0L;
- if(!(CumData = new DataObj()))return 0L;
- //count valid data lines
- if(!(ax = new AccRange(xr))) {
- delete CumData; CumData = 0L; return 0L;
- }
- ax->DataTypes(data, &c_num, &c_txt, &c_datetime);
- nr = ax->CountItems();
- if(!(yranges = split(yr, '&', &nc))){
- delete CumData; delete ax; return 0L;
- }
- if(x_tv) x_tv->Reset(); if(y_tv) y_tv->Reset();
- j = mode == 1 || mode == 2 ? nr : nr * 2;
- if(CumData->Init(j , nc+2) && (validRows = (bool*)calloc(j, sizeof(bool)))){
- if(!c_num && (c_txt + c_datetime) > 0 ) {
- if(x_tv) tv = x_tv;
- else if(y_tv) tv = y_tv;
- else tv = x_tv = new TextValue();
- }
- //setup all ranges
- if(!(ayy = (AccRange**)calloc(nc, sizeof(AccRange*))))return 0L;
- for(i = 0; i < nc; i++) {
- if(yranges[i] && *yranges[i] && (ayy[i] = new AccRange(yranges[i]))) {
- if(!ayy[i]->GetFirst(&ic, &ir)) return 0L;
- }
- }
- // set x values as first column
- for(i = n = 0, ax->GetFirst(&ic, &ir); ax->GetNext(&ic, &ir); i++, n++) {
- if(data->GetResult(&ares, ir, ic, false)) {
- if(tv) {
- switch(ares.type) {
- case ET_TEXT:
- value = tv->GetValue(ares.text); break;
- default:
- TranslateResult(&ares);
- value = tv->GetValue(ares.text); break;
- }
- CumData->SetValue(n, 0, value); CumData->SetValue(n, 1, base);
- }
- else if(ares.type == ET_VALUE && ares.value > -HUGE_VAL && ares.value < HUGE_VAL) {
- CumData->SetValue(n, 0, value = ares.value); CumData->SetValue(n, 1, base);
- }
- else {
- CumData->SetValue(n, 0, value = 0.0); CumData->SetValue(n, 1, base);
- }
- if(mode == 3 || mode == 4){ //complete polygon data
- CumData->SetValue((nr<<1)-i-1, 0, value);
- }
- for(j = 0; j < nc; j++) {
- if(CumData->GetValue(n, j+1, &value)) CumData->SetValue(n, j+2, value);
- if(ayy[j]->GetNext(&ic, &ir) && data->GetResult(&ares, ir, ic, false)){
- if(ares.type == ET_VALUE && ares.value > -HUGE_VAL && ares.value < HUGE_VAL){
- value = ares.value; validRows[i] = true;
- }
- else value = 0.0; old_val = 0.0;
- CumData->GetValue(n, j+2, &old_val);
- switch (mode) {
- case 1: case 3: value += old_val; break;
- case 2: case 4: value = old_val -value; break;
- }
- CumData->SetValue(n, j+2, value);
- }
- if(mode == 3 || mode == 4) //complete polygon data
- if(CumData->GetValue(n, j+1, &value)){
- if(validRows[n]) validRows[(nr<<1)-i-1] = true;
- CumData->SetValue((nr<<1)-i-1, j+2, value);
- }
- }
- }
- else {
- for(j = 0; j < nc; j++) ayy[j]->GetNext(&ic, &ir);
- }
- }
- for(i = 0; i < nc; i++) delete ayy[i]; free(ayy);
- for(i = 0; i < CumData->cRows; i++) {
- if(!validRows[i]) {
- CumData->cRows--;
- for(j = 0; j < CumData->cCols; j++) {
- if(CumData->etRows[i][j]) delete CumData->etRows[i][j];
- }
- free(CumData->etRows[i]);
- for(j = i; j < CumData->cRows; j++) {
- CumData->etRows[j] = CumData->etRows[j+1];
- validRows[j] = validRows[j+1];
- }
- if(!validRows[i] && i < CumData->cRows) i--;
- }
- }
- free(validRows);
- }
- for(i = 0; i < nc; i++) if(yranges[i]) free(yranges[i]);
- if(ax) delete ax; 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, ErrorBar **errs):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;
- }
- }
- }
- if(cBars && errs) {
- if((Errors = (ErrorBar**)calloc(cBars, sizeof(Bar*)))) {
- nPoints = cBars;
- for(i = 0; i < cBars; i++) {
- if((Errors[i] = errs[i])) Errors[i]->parent = this;
- errs[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);
- if(name) free(name); name=0L;
- if(x_info) free(x_info); x_info = 0L;
- if(y_info) free(x_info); y_info = 0L;
- if(data_desc) free(data_desc); data_desc = 0L;
- if(x_tv) delete(x_tv); x_tv = 0L;
- if(y_tv) delete(y_tv); y_tv = 0L;
- Undo.InvalidGO(this);
-}
-
-double
-PlotScatt::GetSize(int select)
-{
- int i;
- double ft1, ft2, d;
-
- switch(select){
- case SIZE_BARMINX:
- if(BarDist.fx >= 0.0001) return BarDist.fx;
- if((!Bars) || (nPoints < 2)) return BarDist.fx = 1.0;
- ft1 = -HUGE_VAL; ft2 = HUGE_VAL; BarDist.fx= HUGE_VAL;
- for(i = 0; i < nPoints; i++) {
- if(Bars[i]) {
- ft2 = Bars[i]->GetSize(SIZE_XPOS);
- d = fabs(ft2-ft1);
- if(d != 0.0 && d < BarDist.fx) BarDist.fx = d;
- }
- ft1 = ft2;
- }
- return BarDist.fx = BarDist.fx > 0.0001 && BarDist.fx != HUGE_VAL ? BarDist.fx : 1.0;
- case SIZE_BARMINY:
- if(BarDist.fy >= 0.0001) return BarDist.fy;
- if((!Bars) || (nPoints < 2)) return BarDist.fy = 1.0;
- ft1 = -HUGE_VAL; ft2 = HUGE_VAL; BarDist.fy= HUGE_VAL;
- for(i = 0; i < nPoints; i++) {
- if(Bars[i]) {
- ft2 = Bars[i]->GetSize(SIZE_YPOS);
- d = fabs(ft2-ft1);
- if(d != 0.0 && d < BarDist.fy) BarDist.fy = d;
- }
- ft1 = ft2;
- }
- return BarDist.fy = BarDist.fy > 0.0001 && BarDist.fy != HUGE_VAL ? BarDist.fy : 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_WHISKER: case SIZE_WHISKER_LINE:
- 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_LB_XDIST: case SIZE_LB_YDIST:
- if(Labels) for(i = 0; i < nPoints; i++)
- if(Labels[i]) Labels[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_WHISKER:
- 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], 0L);
- }
- else {
- for (i = 0; i < nPoints && i < 100; i++)
- if(Symbols[i]) ((Legend*)tmpl)->HasSym(0L, Symbols[i], 0L);
- }
- if(TheLine && TheLine->Id == GO_DATAPOLYGON) TheLine->Command(cmd, tmpl, o);
- }
- else if(TheLine) TheLine->Command(cmd, tmpl, o);
- if(Errors) for (i = 0; i < nPoints; i++)
- if(Errors[i]) Errors[i]->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_TEXTTHERE:
- if(Labels) for(i = 0; i < nPoints; i++) if(Labels[i] && Labels[i]->Command(cmd, tmpl, o)) return true;
- return false;
- 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){
- if (Symbols) SavVarObs((GraphObj **)Symbols, nPoints, UNDO_CONTINUE);
- if (Bars) SavVarObs((GraphObj **)Bars, nPoints, UNDO_CONTINUE);
- if (Errors) SavVarObs((GraphObj **)Errors, nPoints, UNDO_CONTINUE);
- if (Arrows) SavVarObs((GraphObj **)Arrows, nPoints, UNDO_CONTINUE);
- if (DropLines) SavVarObs((GraphObj **)DropLines, nPoints, UNDO_CONTINUE);
- if (Labels) SavVarObs((GraphObj **)Labels, nPoints, UNDO_CONTINUE);
- dirty = true;
- }
- case CMD_SET_DATAOBJ:
- if(cmd == CMD_SET_DATAOBJ) {
- Id = GO_PLOTSCATT;
- if(data && data == (DataObj *) tmpl) return true;
- data = (DataObj *)tmpl;
- }
- ForEach(cmd, tmpl, o);
- if(cmd == CMD_AUTOSCALE) {
- if(x_tv) {
- Bounds.Xmin = 0.5; Bounds.Xmax = ((double)x_tv->Count())+0.5;
- }
- if(y_tv) {
- Bounds.Ymin = 0.5; Bounds.Xmax = ((double)y_tv->Count())+0.5;
- }
- }
- 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_SCALE:
- 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_SETTEXTDEF:
- if(Labels) for(i = 0; i < nPoints; i++)
- if(Labels[i]) Labels[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: case CMD_WHISKER_STYLE: case CMD_ERRDESC:
- if(Errors) for(i = 0; i < nPoints; i++) {
- if(Errors[i]) Errors[i]->Command(cmd, tmpl, o);
- }
- 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);
- case CMD_SAVE_LABELS:
- return SavVarObs((GraphObj **)Labels, 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;
-
- 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: case CMD_SCALE:
- 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;
- 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;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// xyStat is based on scatterplot
-xyStat::xyStat(GraphObj *par, DataObj *d):PlotScatt(par, d, 0L)
-{
- FileIO(INIT_VARS);
- Id = GO_XYSTAT;
-}
-
-xyStat::xyStat(int src):PlotScatt(0)
-{
- FileIO(INIT_VARS);
- if(src == FILE_READ) {
- FileIO(FILE_READ);
- }
-}
-
-xyStat::~xyStat()
-{
- ForEach(FE_FLUSH, 0L, 0L);
- if(curr_data) delete curr_data; curr_data = 0L;
- if(case_prefix) free(case_prefix); case_prefix = 0L;
- if(yRange) free(yRange); yRange = 0L;
- if(xRange) free(xRange); xRange = 0L;
- if(name) free(name); name=0L;
- if(x_info) free(x_info); x_info = 0L;
- if(y_info) free(x_info); y_info = 0L;
- if(x_tv) delete(x_tv); x_tv = 0;
- Undo.InvalidGO(this);
-}
-
-bool
-xyStat::Command(int cmd, void *tmpl, anyOutput *o)
-{
- switch (cmd) {
- case CMD_UPDATE:
- if (Symbols) SavVarObs((GraphObj **)Symbols, nPoints, UNDO_CONTINUE);
- if (Bars) SavVarObs((GraphObj **)Bars, nPoints, UNDO_CONTINUE);
- if (Errors) SavVarObs((GraphObj **)Errors, nPoints, UNDO_CONTINUE);
- if (Labels) SavVarObs((GraphObj **)Labels, nPoints, UNDO_CONTINUE);
- CreateData();
- ForEach(CMD_SET_DATAOBJ, curr_data, o);
- ForEach(CMD_UPDATE, tmpl, o);
- return dirty = true;
- case CMD_SET_DATAOBJ:
- if(cmd == CMD_SET_DATAOBJ) {
- Id = GO_XYSTAT;
- if(data && data == (DataObj *) tmpl) return true;
- if(curr_data) delete curr_data; curr_data = 0L;
- data = (DataObj *)tmpl;
- if(data && !curr_data) CreateData();
- tmpl = curr_data;
- }
- ForEach(cmd, tmpl, o);
- return true;
- default:
- return PlotScatt::Command(cmd, tmpl, o);
- }
- return false;
-}
-
-void
-xyStat::CreateData()
-{
- int i, j, k, l, m, n, *ny, c_num, c_txt, c_dattim;
- double y, ss, d, lo, hi, **ay, *ax, *tay, *q1, *q2, *q3;
- lfPOINT *xy;
- AccRange *rX, *rY;
- anyResult x_res, y_res;
-
- if(!data || !xRange || !yRange || !xRange[0] || !yRange[0]) return;
- if(!(rX = new AccRange(xRange)) || !(rY = new AccRange(yRange))) return;
- if(!x_info) x_info = rX->RangeDesc(data, 0); if(!y_info) y_info = rY->RangeDesc(data, 0);
- m = rX->CountItems(); n = 0;
- if(m < 2 || !(xy = (lfPOINT*) malloc(m * sizeof(lfPOINT)))) {
- delete rX; delete rY;
- return;
- }
- if(x_tv) delete x_tv; x_tv = 0L;
- ny = (int*) calloc(m, sizeof(int));
- ay = (double**) calloc(m, sizeof(double*));
- ax = (double*) calloc(m, sizeof(double));
- tay = (double*)malloc(m * sizeof(double));
- if(!ny || !ay || !ax || !tay) {
- if(ny) free(ny); if(ay) free(ay);
- if(ax) free(ax); if(tay) free(tay);
- delete rX; delete rY;
- return;
- }
- rX->DataTypes(data, &c_num, &c_txt, &c_dattim);
- if(c_num < 5 && (c_txt + c_dattim) > 5) {
- x_tv = new TextValue();
- }
- rX->GetFirst(&i, &j); rY->GetFirst(&k, &l); dirty = true;
- rX->GetNext(&i, &j); rY->GetNext(&k, &l); n=0;
- do {
- if(data->GetResult(&x_res, j, i, false) && data->GetResult(&y_res, l, k, false) && y_res.type == ET_VALUE) {
- xy[n].fy = y_res.value;
- if(x_tv){
- switch(x_res.type) {
- case ET_TEXT:
- xy[n++].fx = x_tv->GetValue(x_res.text);
- break;
- case ET_VALUE: case ET_BOOL: case ET_DATE: case ET_TIME: case ET_DATETIME:
- TranslateResult(&x_res);
- xy[n++].fx = x_tv->GetValue(x_res.text);
- break;
- }
- }
- else if(x_res.type == ET_VALUE) xy[n++].fx = x_res.value;
- }
- }while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l));
- delete rX; delete rY;
- if(!n) {
- if(ny) free(ny); if(ay) free(ay);
- if(ax) free(ax); if(tay) free(tay);
- return;
- }
- SortFpArray(n, xy);
- for(i = j = 0; i < (n-1); i++, j++) {
- ax[j] = xy[i].fx; tay[0] = xy[i].fy;
- ny[j] = 1;
- for(k = 1; xy[i+1].fx == xy[i].fx; k++) {
- tay[k] = xy[i+1].fy;
- i++; ny[j]++;
- }
- ay[j] = (double*)memdup(tay, k * sizeof(double), 0);
- }
- if(xy[i].fx > xy[i-1].fx) {
- ax[j] = xy[i].fx; tay[0] = xy[i].fy;
- ny[j] = 1;
- ay[j++] = (double*)memdup(tay, sizeof(double), 0);
- }
- if(type & 0x0480) { //medians and/or percentiles required
- q1 = (double *)malloc(j * sizeof(double));
- q2 = (double *)malloc(j * sizeof(double));
- q3 = (double *)malloc(j * sizeof(double));
- if(q1 && q2 && q3) {
- for(i = 0; i < j; i++) {
- if(ny[i] > 1) d_quartile(ny[i], ay[i], q1+i, q2+i, q3+i);
- else q1[i] = q2[i] = q3[i] = *ay[i];
- }
- }
- else type &= (~0x0480);
- }
- else q1 = q2 = q3 = 0L;
- if((curr_data = curr_data ? curr_data : new DataObj()) && curr_data->Init(j, 6)) {
- for(i = 0; i < j; i++) curr_data->SetValue(i,0,ax[i]); // set x-values
- for(i = 0; i < j; i++) { // set y-values
- if(ny[i] > 1) switch(type & 0x00f0) {
- case 0x0010: default:
- curr_data->SetValue(i, 1, y=d_amean(ny[i], ay[i]));
- break;
- case 0x0020:
- curr_data->SetValue(i, 1, y=d_gmean(ny[i], ay[i]));
- break;
- case 0x0040:
- curr_data->SetValue(i, 1, y=d_hmean(ny[i], ay[i]));
- break;
- case 0x0080:
- curr_data->SetValue(i, 1, y=q2[i]);
- break;
- }
- else curr_data->SetValue(i, 1, y= *ay[i]);
- curr_data->SetValue(i, 4, y);
- }
- for(i = 0; i < j; i++) { // set errors
- switch(type & 0x1f00) {
- case 0x0100: case 0x0200: case 0x1000: //SD, SEM, conf. int.
- if(ny[i] > 1) {
- ss = d_variance(ny[i], ay[i], &y);
- switch(type & 0x1f00) {
- case 0x0100:
- curr_data->SetValue(i, 2, sqrt(ss));
- break;
- case 0x0200:
- curr_data->SetValue(i, 2, sqrt(ss)/sqrt((double)ny[i]));
- break;
- case 0x1000:
- d = distinv(t_dist, ny[i]-1, 1, 1.0-(ci/100.0), 2.0);
- curr_data->SetValue(i, 2, d * sqrt(ss)/sqrt((double)ny[i]));
- break;
- }
- }
- else curr_data->SetValue(i, 2, 0.0);
- if(curr_data->GetValue(i, 1, &y) && curr_data->GetValue(i, 2, &hi))
- curr_data->SetValue(i, 4, hi+y);
- break;
- case 0x0400: //percentiles
- curr_data->SetValue(i, 2, q1[i]); curr_data->SetValue(i, 3, q3[i]);
- curr_data->SetValue(i, 4, q3[i]);
- break;
- case 0x0800: //min-max
- lo = hi = *ay[i];
- for(k = 1; k < ny[i]; k++) {
- if(ay[i][k] < lo) lo = ay[i][k];
- if(ay[i][k] > hi) hi = ay[i][k];
- }
- curr_data->SetValue(i, 2, lo); curr_data->SetValue(i, 3, hi);
- curr_data->SetValue(i, 4, hi);
- break;
- }
- }
- if(type & 0x6000) for(i = 0; i < j; i++) { // number of cases
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "%s%d", case_prefix ? case_prefix : "", ny[i]);
-#else
- sprintf(TmpTxt, "%s%d", case_prefix ? case_prefix : "", ny[i]);
-#endif
- curr_data->SetText(i, 5, TmpTxt);
- }
- }
- if(q1) free(q1); if(q2) free(q2); if(q3) free(q3);
- for(i = 0; i < m; i++) if(ay[i]) free(ay[i]);
- free(tay); free(ay); free(ax); free(ny); free(xy);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 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(GraphObj *par, DataObj *d, char* range, bool bOnce):Plot(par, d)
-{
- FileIO(INIT_VARS);
- if(range && range[0]) {
- ssRef = (char*)memdup(range, (int)strlen(range)+1, 0);
- plots = (GraphObj**)calloc(nPlots=3, sizeof(GraphObj*));
- ProcData(-1);
- if(bOnce && ssRef) {
- free(ssRef); ssRef = 0L;
- }
- }
- Id = GO_FREQDIST;
-}
-
-FreqDist::FreqDist(GraphObj *par, DataObj *d, double *vals, int nvals, int nclasses):Plot(par, d)
-{
- int i, j;
- int *cl_data;
- Bar **bars;
-
- FileIO(INIT_VARS);
- ssRef = 0L;
- plots = (GraphObj**)calloc(nPlots=3, sizeof(GraphObj*));
- for(i = 0, dmin = HUGE_VAL, dmax = -HUGE_VAL; i < nvals; i++) {
- if(vals[i] < dmin) dmin = vals[i];
- if(vals[i] > dmax) dmax = vals[i];
- }
- start = dmin; step = 1.00001*(dmax-dmin)/((double)nclasses);
- if(!(cl_data = (int*)calloc(nclasses+1, sizeof(int)))) return;
- for(i = 0; i < nvals; i++) {
- j = (int)(floor((vals[i] - start)/step));
- if(j >= 0 && j <= nclasses) cl_data[j]++;
- }
- if(cl_data[nclasses]) nclasses++;
- if(bars = (Bar**)calloc(nclasses, sizeof(Bar*))) for(i = 0; i < nclasses; i++) {
- if(bars[i] = new Bar(this, 0L, i*step+start, (double)cl_data[i], BAR_VERTB | BAR_RELWIDTH,
- -1, -1, -1, -1, "Count")) bars[i]->SetSize(SIZE_BAR, 100.0);
- }
- //create bar chart
- if(bars && (plots[0] = new PlotScatt(this, data, nclasses, bars, 0L))){
- 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]){
- Bounds.Xmin = dmin; Bounds.Xmax = dmax;
- plots[0]->Command(CMD_AUTOSCALE, 0L, 0L);
- }
- free(cl_data);
- 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;
- }
- if(name) free(name); name=0L;
- if(x_info) free(x_info); x_info = 0L;
- if(y_info) free(y_info); y_info = 0L;
- if(x_tv) delete x_tv; x_tv = 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_SCALE:
- if(plots) for(i = 0; i < nPlots; i++) if(plots[i]) plots[i]->Command(cmd, tmpl, o);
- return true;
- 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 = HUGE_VAL; Bounds.Ymin = 0;
- Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
- if(dmax > dmin) {
- Bounds.Xmin = dmin; Bounds.Xmax = dmax;
- }
- }
- 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_PLOT: 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_f, size_fo, pos_fo, c_num, c_txt, c_dattim;
- double min, max, sum, mean, sd, tmp, *s_data, *t_data, lstep;
- double chi2, df, x, y;
- anyResult *result;
- bool bValid = false;
- Bar **bars = 0L;
- anyResult res;
- TextDEF td;
- char *fo, *fdesc = 0L, formula[500];
-
- if(!parent || !data || !ssRef || !plots) return;
- if(curr_data) delete(curr_data); curr_data = 0L;
- if(x_tv) delete x_tv; x_tv = 0L;
- if((curr_data = new DataObj()) && (ar = new AccRange(ssRef))) {
- if(!y_info && (y_info = (char*)malloc(25*sizeof(char)))) rlp_strcpy(y_info, 25, "No. of observations");
- dmin = HUGE_VAL, dmax = -HUGE_VAL;
- ar->DataTypes(data, &c_num, &c_txt, &c_dattim);
- if(c_num < 5 && (c_txt + c_dattim) > 5) {
- x_tv = new TextValue(); dmin = 0.0;
- }
- //copy spreadsheet data into array
- nv = ar->CountItems(); ar->GetFirst(&c, &r);
- if(!(s_data = (double*)malloc(nv * sizeof(double)))
- || !(t_data = (double*)malloc(nv * sizeof(double)))) {
- delete(ar); return;
- }
- for(sum = 0.0, nv = 0; ar->GetNext(&c, &r); ) if(data->GetResult(&res, r, c, false)) {
- if(x_tv){
- switch(res.type) {
- case ET_TEXT:
- if((tmp = x_tv->GetValue(res.text))> 0.0)bValid = true;
- else bValid = false; break;
- case ET_VALUE: case ET_DATE: case ET_TIME: case ET_DATETIME: case ET_BOOL:
- TranslateResult(&res);
- if((tmp = x_tv->GetValue(res.text))> 0.0)bValid = true;
- else bValid = false; break;
- default:
- bValid = false; break;
- }
- }
- else {
- if(res.type == ET_VALUE) {
- tmp = res.value; bValid = true;
- }
- else bValid = false;
- }
- if(bValid) {
- if(tmp > dmax) dmax = tmp; if(tmp < dmin) dmin = tmp;
- s_data[nv] = tmp;
- switch (type & 0xff){
- case 2:
- if(tmp > 0.0) t_data[nv] = log(tmp);
- else nv--;
- break;
- default: t_data[nv] = tmp; break;
- }
- nv++;
- }
- }
- delete(ar);
- if(!nv || dmin >= dmax) {
- free(s_data); s_data = 0L; free(t_data); t_data = 0L;
- return;
- }
- min = dmin; max = dmax;
- lstep = (max-min)/100.0;
- d_variance(nv, t_data, &mean, &sd);
- sd = sqrt(sd/((double)(nv-1)));
- step = fabs(step);
- if(x_tv) {
- start = 0.5; step = 1.0; max+= 0.5;
- }
- else 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))+1;
- 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);
- //create data object containg the counts / bin and bars
- 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) {
- if(bars[i] = new Bar(this, 0L, tmp, (double)f_data[i], BAR_VERTB | BAR_RELWIDTH,
- 0, i, 1, i, "Count")) bars[i]->SetSize(SIZE_BAR, 100.0);
- }
- }
- free(s_data); free(t_data); free(f_data);
- //create bar chart
- if(bars && (plots[0] = new PlotScatt(this, data, ncl, bars, 0L))){
- 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]){
- Bounds.Xmin = dmin; Bounds.Xmax = dmax;
- plots[0]->Command(CMD_SET_DATAOBJ, curr_data, 0L);
- plots[0]->Command(CMD_AUTOSCALE, 0L, 0L);
- }
- //create function
- if((type & 0xff) && (fo = (char*)malloc(size_fo = 1000))) {
- pos_fo = rlp_strcpy(fo, 1000, (char*) "[1=Function]\nx1=");
- add_dbl_to_buff(&fo, &pos_fo, &size_fo, min, true);
- add_to_buff(&fo, &pos_fo, &size_fo,(char*)"\nx2=", 4);
- add_dbl_to_buff(&fo, &pos_fo, &size_fo, max, true);
- add_to_buff(&fo, &pos_fo, &size_fo,(char*)"\nxstep=", 7);
- add_dbl_to_buff(&fo, &pos_fo, &size_fo, lstep, true);
- add_to_buff(&fo, &pos_fo, &size_fo,(char*)"\nLine=", 6);
- add_dbl_to_buff(&fo, &pos_fo, &size_fo, DefSize(SIZE_DATA_LINE), true);
- add_to_buff(&fo, &pos_fo, &size_fo,(char*)" 6 0x000000ff 0x0\n", 18);
- cb_f = 0;
- switch (type & 0xff){
- case 2: //lognormal
-#ifdef USE_WIN_SECURE
- cb_f = sprintf_s(formula, 500, "%g*lognormfreq(x,%g,%g)",nv*step, mean, sd);
-#else
- cb_f = sprintf(formula,"%g*lognormfreq(x,%g,%g)",nv*step, mean, sd);
-#endif
- fdesc = (char*)"Desc=\"Lognormal Dist.\"\n";
- break;
- case 3: //exponential
-#ifdef USE_WIN_SECURE
- cb_f = sprintf_s(formula, 500, "%g*expfreq(x,%g)",nv*step, 1.0/mean);
-#else
- cb_f = sprintf(formula,"%g*expfreq(x,%g)",nv*step, 1.0/mean);
-#endif
- fdesc = (char*)"Desc=\"Exponential Dist.\"\n";
- break;
- case 4: //rectangular
-#ifdef USE_WIN_SECURE
- cb_f = sprintf_s(formula, 500, "%g*%g*(x>=%g&&x<=%g)",nv*step, 1.0/(dmax-dmin), dmin, dmax);
-#else
- cb_f = sprintf(formula,"%g*%g*(x>=%g&&x<=%g)",nv*step, 1.0/(dmax-dmin), dmin, dmax);
-#endif
- fdesc = (char*)"Desc=\"Rectangular Dist.\"\n";
- break;
- case 5: //chi-square
-#ifdef USE_WIN_SECURE
- cb_f = sprintf_s(formula, 500, "%g*chifreq(x,%g)",nv*step, mean);
-#else
- cb_f = sprintf(formula,"%g*chifreq(x,%g)",nv*step, mean);
-#endif
- fdesc = (char*)"Desc=\"Chi<sup>2</sup> Dist.\"\n";
- break;
- case 10: //binomial
-#ifdef USE_WIN_SECURE
- cb_f = sprintf_s(formula, 500, "%g*binomfreq(x,%g,%g)*(x>0)",nv*step, dmax, mean/dmax);
-#else
- cb_f = sprintf(formula,"%g*binomfreq(x,%g,%g)*(x>0)",nv*step, dmax, mean/dmax);
-#endif
- fdesc = (char*)"Desc=\"Binomial Dist.\"\n";
- break;
- case 11: //poisson
-#ifdef USE_WIN_SECURE
- cb_f = sprintf_s(formula, 500, "%g*poisfreq(x,%g)*(x>0)",nv*step, mean);
-#else
- cb_f = sprintf(formula,"%g*poisfreq(x,%g)*(x>0)",nv*step, mean);
-#endif
- fdesc = (char*)"Desc=\"Poisson Dist.\"\n";
- break;
- default: //normal
-#ifdef USE_WIN_SECURE
- cb_f = sprintf_s(formula, 500, "%g*normfreq(x,%g,%g)",nv*step, mean, sd);
-#else
- cb_f = sprintf(formula,"%g*normfreq(x,%g,%g)",nv*step, mean, sd);
-#endif
- fdesc = (char*)"Desc=\"Normal Dist.\"\n";
- break;
- }
- if(cb_f) {
- add_to_buff(&fo, &pos_fo, &size_fo, "f_xy=\"y=" , 8);
- add_to_buff(&fo, &pos_fo, &size_fo, formula , cb_f);
- add_to_buff(&fo, &pos_fo, &size_fo, "\\n\"\n" , 4);
- }
- if(fdesc)add_to_buff(&fo, &pos_fo, &size_fo, fdesc, 0);
- OpenGraph(this, 0L, (unsigned char *)fo, false);
- free(fo); chi2 = df = 0.0;
- //calculate chi-square test of fit
- if(curr_data) for(i = 0; i< ncl; i++) {
- if(curr_data->GetValue(i,0, &x) && curr_data->GetValue(i,1, &y)){
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "x=%g;%s", x, formula);
-#else
- sprintf(TmpTxt, "x=%g;%s", x, formula);
-#endif
- result = do_formula(curr_data, TmpTxt);
- if(result->type == ET_VALUE && fabs(result->value) > 0.0) {
- tmp = y-result->value;
- tmp = (tmp*tmp)/result->value;
- chi2 += tmp; df += 1.0;
- }
- }
- }
- //report result of the chi-square test
- if(chi2 > 0.0 && parent && (fo = (char*)malloc(size_fo = 1000))) {
- tmp = chi_dist(chi2, df-1.0, 1.0);
- pos_fo = rlp_strcpy(fo, 1000, (char*)"chi<sup> 2</sup> =");
- add_dbl_to_buff(&fo, &pos_fo, &size_fo, chi2, true);
- add_to_buff(&fo, &pos_fo, &size_fo, (char*)", n =", 5);
- add_dbl_to_buff(&fo, &pos_fo, &size_fo, df, true);
- add_to_buff(&fo, &pos_fo, &size_fo, (char*)", df =", 6);
- add_dbl_to_buff(&fo, &pos_fo, &size_fo, df-1.0, true);
- add_to_buff(&fo, &pos_fo, &size_fo, (char*)", p =", 5);
- if(tmp < 0.0001) {
- pos_fo--; add_to_buff(&fo, &pos_fo, &size_fo, (char*)"< 0.0001", 8);
- }
- else add_dbl_to_buff(&fo, &pos_fo, &size_fo, tmp, true);
- if(!plots[2]) {
- x = (parent->GetSize(SIZE_GRECT_RIGHT) - parent->GetSize(SIZE_GRECT_LEFT))/2.0;
- y = parent->GetSize(SIZE_GRECT_BOTTOM) - DefSize(SIZE_TEXT)*5;
- y -= parent->GetSize(SIZE_DRECT_TOP);
- td.Align = TXA_VTOP | TXA_HCENTER; td.ColBg = 0x00ffffffL;
- td.ColTxt = 0x00ff0000L; td.Font = FONT_HELVETICA;
- td.fSize = DefSize(SIZE_TEXT); td.iSize = 0;
- td.Mode = TXM_TRANSPARENT; td.RotBL = td.RotCHAR = 0.0;
- td.Style = TXS_NORMAL; td.text = 0L;
- plots[2] = new Label(this, data, x, y, &td, 0x0L);
- plots[2]->moveable = 1;
- }
- plots[2]->Command(CMD_SETTEXT, fo, 0L); 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);
- if(name) free(name); name=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], "Regression");
- }
- else ((Legend*)tmpl)->HasFill(ld, 0L, "Regression");
- 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_SCALE:
- if(rLine) rLine->Command(cmd, tmpl, o);
- if(sde) sde->Command(cmd, tmpl, o);
- 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_UPDATE:
- if(Symbols) {
- SavVarObs((GraphObj**)Symbols, nPoints, 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);
- }
- if(name) free(name); name=0L;
- 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_LEGEND:
- if(((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
- if(Bubbles) for (i = 0; i < nPoints; i++)
- if(Bubbles[i]) Bubbles[i]->Command(cmd, tmpl, o);
- return true;
- case CMD_SCALE:
- if(!tmpl) return false;
- BubbleLine.width *= ((scaleINFO*)tmpl)->sy.fy;
- BubbleLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
- BubbleFillLine.width *= ((scaleINFO*)tmpl)->sy.fy;
- BubbleFillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
- BubbleFill.scale *= ((scaleINFO*)tmpl)->sy.fy;
- if(Bubbles) for(i = 0; i < nPoints; i++)
- if(Bubbles[i]) Bubbles[i]->Command(cmd, tmpl, o);
- 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:
- UseAxis(*((int*)tmpl));
- return true;
- case CMD_SET_DATAOBJ:
- Id = GO_BUBBLEPLOT;
- data = (DataObj *)tmpl;
- case CMD_UPDATE:
- if(cmd == CMD_UPDATE && Bubbles) SavVarObs((GraphObj **)Bubbles, nPoints, UNDO_CONTINUE);
- case CMD_AUTOSCALE:
- if(cmd == CMD_AUTOSCALE && Bubbles) {
- Bounds.Xmax = Bounds.Ymax = -HUGE_VAL; Bounds.Xmin = Bounds.Ymin = HUGE_VAL;
- }
- 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;
- }
- if(name) free(name); name=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 DefSize(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_SCALE:
- FillLine.width *= ((scaleINFO*)tmpl)->sy.fy;
- FillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
- Fill.scale *= ((scaleINFO*)tmpl)->sy.fy;
- if(Axes) for(i = 0; i< nAxes; i++) if(Axes[i]) Axes[i]->Command(cmd, tmpl, o);
- 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_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_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;
-}
-
-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(Labels)
- for(i = 0; i < nPoints; i++) if(Labels[i]) Labels[i]->parent = this;
- if(TheLine) TheLine->parent = this;
- }
-}
-
-BoxPlot::BoxPlot(GraphObj *par, DataObj *dt, int mode, int c1, int c2, int c3, char *box_name):Plot(par, dt)
-{
- int i, nr, cb;
- lfPOINT fp;
-
- FileIO(INIT_VARS); Id = GO_BOXPLOT; fp.fx = fp.fy = 0.0; cb = 0;
- if(data && data->GetSize(&i, &nr)) {
- nPoints = nr; if(box_name) cb = (int)strlen(box_name);
- 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, BAR_RELWIDTH, c1, i, c2, i, c1, i, c3, i);
- else Boxes[i] = new Box(this, data, fp, fp, BAR_RELWIDTH, c2, i, c1, i, c3, i, c1, i);
- if(box_name && box_name[0] && Boxes[i]) Boxes[i]->name = (char*)memdup(box_name, cb+1, 0);
- }
- }
-}
-
-BoxPlot::~BoxPlot()
-{
- int i;
-
- if(Whiskers) {
- for(i = 0; i < nPoints; i++) if(Whiskers[i]) DeleteGO(Whiskers[i]);
- free (Whiskers);
- }
- if(Boxes) {
- for(i = 0; i < nPoints; i++) if(Boxes[i]) DeleteGO(Boxes[i]);
- free (Boxes);
- }
- if(Symbols) {
- for(i = 0; i < nPoints; i++) if(Symbols[i]) DeleteGO(Symbols[i]);
- free (Symbols);
- }
- if(Labels) {
- for(i = 0; i < nPoints; i++) if(Labels[i]) DeleteGO(Labels[i]);
- free (Labels);
- }
- if(TheLine) DeleteGO(TheLine);
- if(curr_data) delete curr_data; curr_data = 0L;
- if(xRange) free(xRange); xRange = 0L;
- if(yRange) free(yRange); yRange = 0L;
- if(x_info) free(x_info); x_info = 0L;
- if(y_info) free(y_info); y_info = 0L;
- if(case_prefix) free(case_prefix); case_prefix = 0L;
- if(name) free(name); name = 0L;
- if(x_tv) delete(x_tv); x_tv = 0;
- if(y_tv) delete(y_tv); y_tv = 0;
- Undo.InvalidGO(this);
-}
-
-double
-BoxPlot::GetSize(int select)
-{
- int i;
- double ft1, ft2, d;
-
- switch(select){
- case SIZE_BOXMINX:
- if(BoxDist.fx >= 0.0001) return BoxDist.fx;
- if((!Boxes) || (nPoints < 2)) return BoxDist.fx = 1.0;
- ft1 = -HUGE_VAL; ft2 = HUGE_VAL; BoxDist.fx= HUGE_VAL;
- for(i = 0; i < nPoints; i++) {
- if(Boxes[i]) {
- ft2 = Boxes[i]->GetSize(SIZE_XPOS);
- d = fabs(ft2-ft1);
- if(d != 0.0 && d < BoxDist.fx) BoxDist.fx = d;
- }
- ft1 = ft2;
- }
- return BoxDist.fx = BoxDist.fx > 0.0001 && BoxDist.fx != HUGE_VAL ? BoxDist.fx : 1.0;
- case SIZE_BOXMINY:
- if(BoxDist.fy >= 0.0001) return BoxDist.fy;
- if((!Boxes) || (nPoints < 2)) return BoxDist.fy = 1.0;
- ft1 = -HUGE_VAL; ft2 = HUGE_VAL; BoxDist.fy= HUGE_VAL;
- for(i = 0; i < nPoints; i++) {
- if(Boxes[i]) {
- ft2 = Boxes[i]->GetSize(SIZE_YPOS);
- d = fabs(ft2-ft1);
- if(d != 0.0 && d < BoxDist.fy) BoxDist.fy = d;
- }
- ft1 = ft2;
- }
- return BoxDist.fy = BoxDist.fy > 0.0001 && BoxDist.fy != HUGE_VAL ? BoxDist.fy : 1.0;
- 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;
- case SIZE_LB_XDIST: case SIZE_LB_YDIST:
- if(Labels) for(i = 0; i < nPoints; i++)
- if(Labels[i]) Labels[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)
-{
- if(!parent || !o) return;
- parent->Command(CMD_REG_AXISPLOT, (void*)this, o);
- if(use_xaxis || use_yaxis) ApplyAxes(o);
- ForEach(FE_PLOT, 0L, 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;
-
- 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_TEXTTHERE:
- if(Labels) for(i = 0; i < nPoints; i++) if(Labels[i] && Labels[i]->Command(cmd, tmpl, o)) return true;
- return false;
- case CMD_LEGEND:
- if(((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
- 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], 0L);
- }
- else {
- for (i = 0; i < nPoints && i < 100; i++)
- if(Symbols[i]) ((Legend*)tmpl)->HasSym(0L, Symbols[i], 0L);
- }
- if(TheLine && TheLine->Id == GO_DATAPOLYGON) TheLine->Command(cmd, tmpl, o);
- }
- else if(TheLine) TheLine->Command(cmd, tmpl, o);
- if(Boxes) for (i = 0; i < nPoints; i++) if(Boxes[i]) Boxes[i]->Command(cmd, tmpl, o);
- if(Whiskers) for (i = 0; i < nPoints; i++) if(Whiskers[i]) Whiskers[i]->Command(cmd, tmpl, o);
- break;
- case CMD_SET_DATAOBJ:
- Id = GO_BOXPLOT; data = (DataObj *)tmpl; dirty = true;
- if(type && xRange && yRange && data) { //Stat. - Plot ?
- CreateData();
- return ForEach(CMD_SET_DATAOBJ, curr_data, o);
- }
- case CMD_SCALE:
- return ForEach(cmd, tmpl, o);
- 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;
- ForEach(cmd, tmpl, o);
- if(x_tv) {
- Bounds.Xmin = 0.5; Bounds.Xmax = ((double)x_tv->Count())+0.5;
- }
- 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_UPDATE:
- if(parent) {
- if(Boxes) SavVarObs((GraphObj **)Boxes, nPoints, UNDO_CONTINUE);
- if(Whiskers) SavVarObs((GraphObj **)Whiskers, nPoints, UNDO_CONTINUE);
- if(Symbols) SavVarObs((GraphObj **)Symbols, nPoints, UNDO_CONTINUE);
- if(Labels) SavVarObs((GraphObj **)Labels, nPoints, UNDO_CONTINUE);
- }
- if(type && xRange && yRange) { //Stat. - Plot ?
- CreateData();
- ForEach(CMD_SET_DATAOBJ, curr_data, o);
- }
- ForEach(cmd, tmpl, o);
- return dirty = 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_SETTEXTDEF:
- if(Labels) for(i = 0; i < nPoints; i++)
- if(Labels[i]) Labels[i]->Command(cmd, tmpl, o);
- return true;
- case CMD_DELOBJ:
- if(ForEach(FE_DELOBJ, tmpl, o)) {
- parent->Command(CMD_REDRAW, 0L, o);
- return true;
- }
- return false;
- 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_SAVE_LABELS:
- return SavVarObs((GraphObj **)Labels, 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: case CMD_ERRDESC:
- if(Whiskers) for (i = 0; i < nPoints; i++)
- if(Whiskers[i]) Whiskers[i]->Command(cmd, tmpl, o);
- return true;
- }
- return false;
-}
-
-bool
-BoxPlot::ForEach(int cmd, void *tmpl, anyOutput *o)
-{
- GraphObj ***pobs[] = {(GraphObj***)&Boxes, (GraphObj***)&Whiskers,
- (GraphObj***)&Symbols, (GraphObj***)&Labels};
- GraphObj **p;
- int i, j;
- bool bRet;
-
- switch(cmd) {
- case FE_DELOBJ:
- if(!o || !parent || !tmpl) return false;
- for(i = 0; i < 4; i++) {
- if(DeleteGOL(pobs[i], nPoints, (GraphObj*) tmpl, o)) return true;
- }
- if(TheLine && tmpl == (void *) TheLine) {
- Undo.DeleteGO((GraphObj**)(&TheLine), 0L, o);
- return true;
- }
- break;
- case FE_PLOT:
- if(TheLine) TheLine->DoPlot(o);
- for(i = 0; i < 4; i++){
- if(p= *pobs[i]) for(j = 0; j < nPoints; j++) {
- if(p[j]) p[j]->DoPlot(o);
- }
- }
- return true;
- case CMD_MOUSE_EVENT: //invers to plot order
- for(i = 3; i >= 0; i--){
- if(p= *pobs[i]) for(j = nPoints-1; j >= 0; j--) {
- if(p[j]) {
- bRet = p[j]->Command(cmd, tmpl, o);
- if(bRet && cmd == CMD_MOUSE_EVENT) return true;
- }
- }
- }
- if(TheLine) return TheLine->Command(cmd, tmpl, o);
- return false;
- default: //pass command to all objects
- for(i = 0; i < 4; i++){
- if(p= *pobs[i]) for(j = 0; j < nPoints; j++) {
- if(p[j]) {
- bRet = p[j]->Command(cmd, tmpl, o);
- }
- }
- }
- if(TheLine) return TheLine->Command(cmd, tmpl, o);
- return false;
- }
- return false;
-}
-
-void
-BoxPlot::CreateData()
-{
- int i, j, k, l, m, n, *ny, c_num, c_txt, c_dattim;
- double y, ss, d, lo, hi, **ay, *ax, *tay, *q1, *q2, *q3;
- lfPOINT *xy;
- AccRange *rX, *rY;
- anyResult x_res, y_res;
-
- if(curr_data) delete curr_data; curr_data = 0L;
- if(!data || !xRange || !yRange || !xRange[0] || !yRange[0]) return;
- if(!(rX = new AccRange(xRange)) || !(rY = new AccRange(yRange))) return;
- m = rX->CountItems(); n = 0;
- if(m < 2 || !(xy = (lfPOINT*) malloc(m * sizeof(lfPOINT)))) {
- delete rX; delete rY;
- return;
- }
- if(x_tv) delete x_tv; x_tv = 0L;
- ny = (int*) calloc(m, sizeof(int));
- ay = (double**) calloc(m, sizeof(double*));
- ax = (double*) calloc(m, sizeof(double));
- tay = (double*)malloc(m * sizeof(double));
- if(!ny || !ay || !ax || !tay) {
- if(ny) free(ny); if(ay) free(ay);
- if(ax) free(ax); if(tay) free(tay);
- delete rX; delete rY;
- return;
- }
- rX->DataTypes(data, &c_num, &c_txt, &c_dattim);
- if(c_num < 5 && (c_txt + c_dattim) > 5) {
- x_tv = new TextValue();
- }
- rX->GetFirst(&i, &j); rY->GetFirst(&k, &l);
- rX->GetNext(&i, &j); rY->GetNext(&k, &l); n=0;
- do {
- if(data->GetResult(&x_res, j, i, false) && data->GetResult(&y_res, l, k, false) && y_res.type == ET_VALUE) {
- xy[n].fy = y_res.value;
- if(x_tv){
- switch(x_res.type) {
- case ET_TEXT:
- xy[n++].fx = x_tv->GetValue(x_res.text);
- break;
- case ET_VALUE: case ET_BOOL: case ET_DATE: case ET_TIME: case ET_DATETIME:
- TranslateResult(&x_res);
- xy[n++].fx = x_tv->GetValue(x_res.text);
- break;
- }
- }
- else if(x_res.type == ET_VALUE) xy[n++].fx = x_res.value;
- }
- }while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l));
- delete rX; delete rY;
- if(!n) {
- if(ny) free(ny); if(ay) free(ay);
- if(ax) free(ax); if(tay) free(tay);
- return;
- }
- SortFpArray(n, xy);
- for(i = j = 0; i < (n-1); i++, j++) {
- ax[j] = xy[i].fx; tay[0] = xy[i].fy;
- ny[j] = 1;
- for(k = 1; xy[i+1].fx == xy[i].fx; k++) {
- tay[k] = xy[i+1].fy;
- i++; ny[j]++;
- }
- ay[j] = (double*)memdup(tay, k * sizeof(double), 0);
- }
- if(xy[i].fx > xy[i-1].fx) {
- ax[j] = xy[i].fx; tay[0] = xy[i].fy;
- ny[j] = 1;
- ay[j++] = (double*)memdup(tay, sizeof(double), 0);
- }
- if((type & 0x0004) == 0x0004 || (type & 0x0030) == 0x0030 || (type & 0x0300) == 0x0300) {
- //medians and/or percentiles required
- q1 = (double *)malloc(j * sizeof(double));
- q2 = (double *)malloc(j * sizeof(double));
- q3 = (double *)malloc(j * sizeof(double));
- if(q1 && q2 && q3) {
- for(i = 0; i < j; i++) {
- if(ny[i] > 1) d_quartile(ny[i], ay[i], q1+i, q2+i, q3+i);
- else q1[i] = q2[i] = q3[i] = *ay[i];
- }
- }
- else type = 0;
- }
- else q1 = q2 = q3 = 0L;
- if(type && (curr_data = new DataObj()) && curr_data->Init(j, 8)) {
- for(i = 0; i < j; i++) curr_data->SetValue(i,0,ax[i]); // set x-values
- for(i = 0; i < j; i++) { // set means
- if(ny[i] > 1) switch(type & 0x000f) {
- case 0x0001: default:
- curr_data->SetValue(i, 1, y=d_amean(ny[i], ay[i]));
- break;
- case 0x0002:
- curr_data->SetValue(i, 1, y=d_gmean(ny[i], ay[i]));
- break;
- case 0x0003:
- curr_data->SetValue(i, 1, y=d_hmean(ny[i], ay[i]));
- break;
- case 0x0004:
- curr_data->SetValue(i, 1, y=q2[i]);
- break;
- }
- else curr_data->SetValue(i, 1, y= *ay[i]);
- curr_data->SetValue(i, 6, y); //label's y
- }
- if((type & 0x00f0) == 0x0010 || (type & 0x00f0) == 0x0020 || (type & 0x00f0) == 0x0050
- || (type & 0x0f0f) == 0x0201 || (type & 0x0f0f) == 0x0501) for(i = 0; i < j; i++) {
- // set SD, SE, Conf. Intervall
- if(ny[i] > 1) {
- ss = sqrt(d_variance(ny[i], ay[i], &y));
- }
- else {
- y = *ay[i]; ss = 0.0;
- }
- //Box info is in cols 2 & 3
- if((type & 0x00f0) == 0x0010) {
- curr_data->SetValue(i, 2, y - ss); curr_data->SetValue(i, 3, y + ss);
- }
- else if((type & 0x00f0) == 0x0020) {
- curr_data->SetValue(i, 2, y - ss/sqrt((double)ny[i]));
- curr_data->SetValue(i, 3, y + ss/sqrt((double)ny[i]));
- }
- else if((type & 0x00f0) == 0x0050) {
- d = ny[i] > 1 ? distinv(t_dist, ny[i]-1, 1, 1.0-(ci_box/100.0), 2.0) : 0;
- curr_data->SetValue(i, 2, y - d*ss/(double)sqrt((double)ny[i]));
- curr_data->SetValue(i, 3, y + d*ss/(double)sqrt((double)ny[i]));
- }
- //Whisker info is in cols 4 & 5
- if((type & 0x0f0f) == 0x0101) {
- curr_data->SetValue(i, 4, y - ss); curr_data->SetValue(i, 5, y + ss);
- }
- else if((type & 0x0f0f) == 0x0201) {
- curr_data->SetValue(i, 4, y - ss/sqrt((double)ny[i]));
- curr_data->SetValue(i, 5, y + ss/sqrt((double)ny[i]));
- }
- else if((type & 0x0f0f) == 0x0501) {
- d = ny[i] > 1 ? distinv(t_dist, ny[i]-1, 1, 1.0-(ci_err/100.0), 2.0) : 0;
- curr_data->SetValue(i, 4, y - d*ss/sqrt((double)ny[i]));
- curr_data->SetValue(i, 5, y + d*ss/sqrt((double)ny[i]));
- }
- }
- if((type & 0x00f0) == 0x0040 || (type & 0x0f00) == 0x0400) for(i = 0; i < j; i++) {
- // set min and max
- lo = hi = *ay[i];
- if(ny[i] > 1) {
- for(k = 1; k < ny[i]; k++) {
- if(ay[i][k] < lo) lo = ay[i][k];
- if(ay[i][k] > hi) hi = ay[i][k];
- }
- }
- if((type & 0x00f0) == 0x0040) {
- curr_data->SetValue(i, 2, lo); curr_data->SetValue(i, 3, hi);
- }
- if((type & 0x0f00) == 0x0400) {
- curr_data->SetValue(i, 4, lo); curr_data->SetValue(i, 5, hi);
- }
- }
- if(q1 && q3 && ((type & 0x00f0) == 0x0030 || (type & 0x0f00) == 0x0300)) for(i = 0; i < j; i++) {
- // percentiles ....
- if((type & 0x00f0) == 0x0030) {
- curr_data->SetValue(i, 2, q1[i]); curr_data->SetValue(i, 3, q3[i]);
- }
- if((type & 0x0f00) == 0x0300) {
- curr_data->SetValue(i, 4, q1[i]); curr_data->SetValue(i, 5, q3[i]);
- }
- }
- if(type & 0xc000) for(i = 0; i < j; i++) {
- //labels ...
- if((type & 0x4000) && curr_data->GetValue(i, 5, &y)) curr_data->SetValue(i, 6, y);
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "%s%d", case_prefix ? case_prefix : "", ny[i]);
-#else
- sprintf(TmpTxt, "%s%d", case_prefix ? case_prefix : "", ny[i]);
-#endif
- curr_data->SetText(i, 7, TmpTxt);
- }
- }
- else {
- if(curr_data) delete curr_data;
- curr_data = 0L;
- }
- if(q1) free(q1); if(q2) free(q2); if(q3) free(q3);
- for(i = 0; i < m; i++) if(ay[i]) free(ay[i]);
- free(tay); free(ay); free(ax); free(ny); free(xy);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 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;
- if(name) free(name); name=0L;
- if(x_info) free(x_info); x_info = 0L;
- if(y_info) free(y_info); y_info = 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_SCALE:
- DefLine.width *= ((scaleINFO*)tmpl)->sy.fy; DefLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
- DefFillLine.width *= ((scaleINFO*)tmpl)->sy.fy; DefFillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
- DefFill.scale *= ((scaleINFO*)tmpl)->sy.fy;
- for(i = 0; i < nPoints; i++){
- if(Boxes[i]) Boxes[i]->Command(cmd, tmpl, o);
- }
- return true;
- 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;
- if(DeleteGOL((GraphObj***)&Boxes, nPoints, (GraphObj*)tmpl, o))
- return parent->Command(CMD_REDRAW, 0L, 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:
- if(Boxes) SavVarObs((GraphObj **)Boxes, nPoints, 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;
- Box **op = Boxes;
-
- if(xRange && yRange && (rX = new AccRange(xRange)) && (rY = new AccRange(yRange))) {
- if((n=rX->CountItems()) == rY->CountItems()) {
- Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
- if(!(Boxes = (Box**)realloc(Boxes, n * sizeof(Box*)))) return;
- if(op && op != Boxes) Undo.InvalidGO(this);
- for(i = nPoints; i < n; i++) {
- Boxes[i] = 0L;
- }
- nPoints = n;
- 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)){
- fp1.fx = fp2.fx; fp1.fy = fp2.fy;
- 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(op && Boxes[ic]) {
- Boxes[ic]->SetSize(SIZE_XPOS, fp1.fx); Boxes[ic]->SetSize(SIZE_XPOS+1, fp2.fx);
- Boxes[ic]->SetSize(SIZE_YPOS, fp1.fy); Boxes[ic]->SetSize(SIZE_YPOS+1, fp2.fy);
- Boxes[ic]->SetSize(SIZE_BOX, (type &0x03) ? w/2.0 : w);
- }
- else if(!op && (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));
- if(!op) {
- SetSize(SIZE_BOX_LINE, DefLine.width);
- SetColor(COL_BOX_LINE, DefLine.color);
- Command(CMD_BOX_FILL, (void*)&DefFill, 0L);
- }
- }
- 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;
- if(name) free(name); name=0L;
- if(x_tv) delete x_tv; x_tv = 0L;
- if(y_tv) delete y_tv; y_tv = 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_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_SCALE:
- dspm.fx *= ((scaleINFO*)tmpl)->sx.fy;
- dspm.fy *= ((scaleINFO*)tmpl)->sy.fy;
- 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);
- if(Lines) for (i = numPL-1; i >= 0; i--)
- if(Lines[i]) Lines[i]->Command(cmd, tmpl, o);
- if(xyPlots) for (i = 0; i < numXY; i++)
- if(xyPlots[i]) xyPlots[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_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;
- if(CumData = CreaCumData(ssXrange, ssYrange, cum_data_mode, StartVal)) {
- 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(cmd == CMD_SET_DATAOBJ) tmpl = (void*) CumData;
- 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(DeleteGOL((GraphObj***)&Polygons, numPG, (GraphObj*)tmpl, o))
- return parent->Command(CMD_REDRAW, 0L, o);
- if(DeleteGOL((GraphObj***)&Lines, numPL, (GraphObj*)tmpl, o))
- return parent->Command(CMD_REDRAW, 0L, o);
- if(DeleteGOL((GraphObj***)&xyPlots, numXY, (GraphObj*)tmpl, o))
- return parent->Command(CMD_REDRAW, 0L, o);
- if(DeleteGOL((GraphObj***)&Boxes, numPlots, (GraphObj*)tmpl, o))
- return parent->Command(CMD_REDRAW, 0L, o);
- if(xyPlots) for(i = 0; i < numXY; i++)
- if(xyPlots[i] && xyPlots[i]->Command(cmd, tmpl, o)) return true;
- if(Boxes) for(i = 0; i < numPlots; i++)
- if(Boxes[i] && Boxes[i]->Command(cmd, tmpl, o)) return true;
- return false;
- }
- 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;
- if(name) free(name); name=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_SCALE:
- if(cmd == CMD_SCALE) {
- CtDef.fx *= ((scaleINFO*)tmpl)->sx.fy; CtDef.fy *= ((scaleINFO*)tmpl)->sx.fy;
- }
- 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))) {
- SavVarObs((GraphObj **)Segments, nPts, 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);
- }
- if(name) free(name); name=0L;
- 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;
- }
- if(name) free(name); name=0L;
- if(data_desc) free(data_desc); data_desc = 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 || !parent) return;
- if(use_xaxis || use_yaxis || use_zaxis) ApplyAxes(o);
- o->GetSize(&rc);
- parent->Command(CMD_REG_AXISPLOT, (void*)this, o);
- 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);
- }
- if(use_xaxis || use_yaxis || use_zaxis)parent->Command(CMD_AXIS, 0L, o);
- dirty = false;
-}
-
-bool
-Scatt3D::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(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_USEAXIS:
- return UseAxis(*((int*)tmpl));
- 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], 0L);
- }
- else {
- for (i = 0; i < nBalls && i < 100; i++) {
- if(Balls[i]) {
- if(Balls[i]->type) Balls[i]->Command(cmd, tmpl, o);
- else ((Legend*)tmpl)->HasSym(0L, Balls[i], 0L);
- }
- }
- }
- }
- 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: case CMD_SCALE:
- if(Balls) {
- SavVarObs((GraphObj**)Balls, nBalls, UNDO_CONTINUE);
- for(i = 0; i < nBalls; i++) if(Balls[i]) Balls[i]->Command(cmd, tmpl, o);
- }
- if(Columns) {
- SavVarObs((GraphObj**)Columns, nColumns, UNDO_CONTINUE);
- for(i = 0; i < nColumns; i++) if(Columns[i]) Columns[i]->Command(cmd, tmpl, o);
- }
- if(DropLines) {
- SavVarObs((GraphObj**)DropLines, nDropLines, UNDO_CONTINUE);
- for(i = 0; i < nDropLines; i++) if(DropLines[i]) DropLines[i]->Command(cmd, tmpl, o);
- }
- if(Arrows) {
- SavVarObs((GraphObj**)Arrows, nArrows, UNDO_CONTINUE);
- 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 && xr[0]) ssRefX = (char*)memdup(xr, (int)strlen(xr)+1, 0L);
- if(yr && yr[0]) ssRefY = (char*)memdup(yr, (int)strlen(yr)+1, 0L);
- z_value = z; z_width = width;
-}
-
-Ribbon::Ribbon(GraphObj *par, DataObj *d, int which, char *xr, char *yr, char *zr)
- :Plot(par, d)
-{
- FileIO(INIT_VARS); Id = GO_RIBBON; type = which;
- if(xr && xr[0]) ssRefX = (char*)memdup(xr, (int)strlen(xr)+1, 0L);
- if(yr && yr[0]) ssRefY = (char*)memdup(yr, (int)strlen(yr)+1, 0L);
- if(zr && zr[0]) ssRefZ = (char*)memdup(zr, (int)strlen(zr)+1, 0L);
- CreateObs();
-}
-
-Ribbon::Ribbon(GraphObj *par, DataObj *d, GraphObj **go, int ngo)
- :Plot(par, d)
-{
- int i;
-
- FileIO(INIT_VARS); Id = GO_RIBBON; type = 3;
- planes = (Plane3D**)go; nPlanes = ngo;
- for(i = 0; i < ngo; i++) planes[i]->parent = this;
-}
-
-
-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;
- if(name) free(name); name=0L;
- if(data_desc) free(data_desc); data_desc = 0L;
-}
-
-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_SCALE:
- z_value *= ((scaleINFO*)tmpl)->sz.fy;
- z_width *= ((scaleINFO*)tmpl)->sz.fy;
- for(i = 0; i < nPlanes; i++) if(planes[i]) planes[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_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, j, n, rx, cx, ry, cy, rz, cz;
- double fx, fy, fz, tmp;
- fPOINT3D pg[5];
- AccRange *rX, *rY, *rZ;
- Triangle *trl, *trc, *trn;
-
- 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))) {
- if(!data_desc) data_desc = rY->RangeDesc(data, 1);
- 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 = j = 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(j) {
- 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);
- }
- j++;
- 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;
- }
- if(!data_desc) data_desc = rY->RangeDesc(data, 1);
- 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;
- case 3:
- if(!ssRefX || !ssRefY || !ssRefZ) break;
- Undo.InvalidGO(this);
- trl = Triangulate1(ssRefX, ssRefZ, ssRefY, data);
- for(i = 0, trc = trl; trc; i++) trc = trc->next;
- if((n = i) && (planes = (Plane3D**)malloc(n*sizeof(Plane3D*))))
- for(i = nPlanes = 0, trc = trl; trc && i < n; i++) {
- for(j = 0; j < 4; j++) { //swap y and z values;
- tmp = trc->pt[j].fz; trc->pt[j].fz = trc->pt[j].fy; trc->pt[j].fy = tmp;
- }
- planes[nPlanes++] = new Plane3D(this, data, trc->pt, 4);
- trn = trc->next; delete trc; trc = trn;
- }
- dirty = true; Command(CMD_AUTOSCALE, 0L, 0L);
- 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 && type < 3)) 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;
- case 3:
- if(planes) {
- for(i = 0; i < nPlanes; i++) if(planes[i]) DeleteGO(planes[i]);
- free(planes); planes = 0L; nPlanes = 0;
- }
- CreateObs();
- }
- if(rX) delete rX; if(rY) delete rY; if(rZ) delete rZ;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// draw a 3dimensional grid
-Grid3D::Grid3D(GraphObj *par, DataObj *d, int sel, double x1, double xstep, double z1, double zstep)
- :Plot(par, d)
-{
- FileIO(INIT_VARS); Id = GO_GRID3D;
- start.fx = x1; step.fx = xstep;
- start.fz = z1; step.fz = zstep;
- type = sel;
-}
-
-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;
- }
- if(planes) {
- for(i = 0; i < nPlanes; i++) if(planes[i]) DeleteGO(planes[i]);
- free(planes); planes = 0L;
- }
- nLines = nPlanes = 0;
- if(name) free(name); name=0L;
-}
-
-bool
-Grid3D::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;
- }
- return false;
-}
-
-bool
-Grid3D::SetColor(int select, DWORD col)
-{
- int i;
-
- switch (select) {
- case COL_POLYLINE:
- if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->SetColor(select, col);
- return true;
- }
- return false;
-}
-
-void
-Grid3D::DoPlot(anyOutput *o)
-{
- int i;
-
- if(!lines && !planes) CreateObs(false);
- if(lines) for(i = 0; i < nLines; i++) if(lines[i]) lines[i]->DoPlot(o);
- if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[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;
- 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_SET_LINE:
- if(tmpl) {
- memcpy(&Line, tmpl, sizeof(LineDEF));
- if(lines) {
- SavVarObs((GraphObj**)lines, nLines, 0L);
- for(i = 0; i < nLines; i++)
- if(lines[i]) lines[i]->Command(cmd, tmpl, o);
- }
- if(planes) {
- SavVarObs((GraphObj**)planes, nPlanes, 0L);
- for(i = 0; i < nPlanes; i++)
- if(planes[i]) planes[i]->Command(cmd, tmpl, o);
- }
- }
- break;
- case CMD_LEGEND:
- if(!hidden) ((Legend*)tmpl)->HasFill(&Line, planes ? &Fill : 0L, 0L);
- break;
- case CMD_CONFIG:
- return Configure();
- 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;
- if(tmpl == data) return true;
- data = (DataObj *)tmpl;
- case CMD_UPDATE:
- if(lines) for(i = 0; i < nLines; i++) if(lines[i]) lines[i]->Command(cmd, tmpl, o);
- if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->Command(cmd, tmpl, o);
- return dirty = true;
- case CMD_AUTOSCALE:
- if(!lines && !planes) CreateObs(false);
- 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(planes) for(i = 0; i < nPlanes; i++)
- if(planes[i]) planes[i]->Command(cmd, tmpl, o);
- }
- if(zBounds.fx > zBounds.fy) zBounds.fx = zBounds.fy = 0.0;
- if(parent && parent->Id > GO_PLOT && parent->Id < GO_GRAPH &&
- xBounds.fx <= xBounds.fy && yBounds.fx <= yBounds.fy){
- ((Plot*)parent)->CheckBounds3D(xBounds.fx, yBounds.fx, zBounds.fx);
- ((Plot*)parent)->CheckBounds3D(xBounds.fy, yBounds.fy, zBounds.fy);
- }
- return true;
- case CMD_SYM_FILL:
- if(!tmpl) return false;
- memcpy(&Fill, tmpl, sizeof(FillDEF));
- 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);
- case CMD_DELOBJ:
- if(!parent) return false;
- if(DeleteGOL((GraphObj***)&lines,nLines,(GraphObj*)tmpl,o)) return parent->Command(CMD_REDRAW, 0L, o);
- if(DeleteGOL((GraphObj***)&planes,nPlanes,(GraphObj*)tmpl,o)) return parent->Command(CMD_REDRAW, 0L, o);
- break;
- }
- return false;
-}
-
-void
-Grid3D::CreateObs(bool set_undo)
-{
- int i, ir, ic, idx, w, h;
- fPOINT3D *vec;
-
- if(!parent || !data || lines || planes) return;
- dirty = true;
- if(type == 0) {
- 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].fz = start.fz; data->GetValue(0, 0, &vec[0].fy);
- for(ic = 1, idx = 0; ic <= w; ic++) {
- vec[0].fx = start.fx;
- 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].fz = vec[0].fz + step.fz; vec[1].fx = vec[0].fx;
- lines[idx++] = new Line3D(this, data, vec, 2,
- -1, -1, ic-1, ir-1, -1, -1, -1, -1, ic, ir-1, -1, -1);
- }
- if(ir < h && data->GetValue(ir, ic-1, &vec[1].fy)) {
- vec[1].fz = vec[0].fz; vec[1].fx = vec[0].fx + step.fx;
- lines[idx++] = new Line3D(this, data, vec, 2,
- -1, -1, ic-1, ir-1, -1, -1, -1, -1, ic-1, ir, -1, -1);
- }
- vec[0].fx += step.fx; vec[0].fy = vec[1].fy;
- }
- vec[0].fz += step.fz;
- }
- for(i = 0; i < nLines; i++) if(lines[i]) lines[i]->Command(CMD_SET_LINE, &Line, 0L);
- free(vec);
- }
- else if(type == 1) {
- if(!(vec = (fPOINT3D*)malloc(sizeof(fPOINT3D) * 5))) return;
- vec[0].fz = vec[4].fz = start.fz;
- vec[3].fz = (start.fz +step.fz);
- data->GetSize(&w, &h);
- if(0 >= (nPlanes = w * h)) return;
- if(!(planes =(Plane3D**)calloc(nPlanes, sizeof(Plane3D*)))) return;
- for(ic = 1, idx = 0; ic <= w; ic++) {
- vec[0].fx = vec[3].fx = vec[4].fx = (start.fx+step.fx);
- vec[1].fx = vec[2].fx = start.fx;
- vec[1].fz = vec[4].fz; vec[2].fz = vec[3].fz;
- data->GetValue(0, ic-1, &vec[1].fy); data->GetValue(0, ic, &vec[2].fy);
- for(ir = 1; ir <= h; ir++){
- if(ic < w && ir < h && data->GetValue(ir, ic, &vec[3].fy)
- && data->GetValue(ir, ic-1, &vec[4].fy)) {
- vec[0].fz = vec[4].fz; vec[0].fy = vec[4].fy; vec[0].fx = vec[4].fx;
- planes[idx++] = new Plane3D(this, 0L, vec, 5);
- }
- vec[1].fz = vec[4].fz; vec[1].fy = vec[4].fy; vec[1].fx = vec[4].fx;
- vec[2].fz = vec[3].fz; vec[2].fy = vec[3].fy; vec[2].fx = vec[3].fx;
- vec[3].fx += step.fx; vec[4].fx += step.fx;
- }
- vec[3].fz += step.fz; vec[4].fz += step.fz;
- }
- nPlanes = idx;
- for(i = 0; i < nPlanes; i++) if(planes[i]){
- planes[i]->Command(CMD_SET_LINE, &Line, 0L);
- planes[i]->Command(CMD_SYM_FILL, &Fill, 0L);
- }
- SetSize(SIZE_SYM_LINE, Line.width); SetColor(COL_POLYLINE, Line.color);
- free(vec);
- }
- if(set_undo) {
- if(planes && nPlanes)Undo.StoreListGO(parent, (GraphObj***)&planes, &nPlanes, UNDO_CONTINUE);
- if(lines && nLines)Undo.StoreListGO(parent, (GraphObj***)&lines, &nLines, UNDO_CONTINUE);
- }
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 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()
-{
- if(name) free(name); name=0L;
-}
-
-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, char *desc):Plot(par, d)
-{
- FileIO(INIT_VARS); cmdxy = (char*)malloc(20*sizeof(char));
- if(parent && parent->Id == GO_POLARPLOT) {
- x1 = 0.0; x2 = 360.0; xstep = 0.5;
- if(cmdxy)rlp_strcpy(cmdxy, 20, (char*)"sin(pi*x/30)+1.1");
- }
- else {
- x1 = 0.0; x2 = 100.0; xstep = 0.5;
- if(cmdxy)rlp_strcpy(cmdxy, 20, (char*)"sin(x)/x");
- }
- if(desc) name = (char*)memdup(desc, (int)strlen(desc)+1, 0);
- 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;
- if(name) free(name); name=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 || dirty) && 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_SCALE:
- Line.patlength *= ((scaleINFO*)tmpl)->sy.fy; Line.width *= ((scaleINFO*)tmpl)->sy.fy;
- return true;
- 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 = 0L;
- if(*((char*)tmpl))param = (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1, 0);
- }
- dirty = true;
- return true;
- case CMD_SETFUNC:
- if(tmpl) {
- if(cmdxy) free(cmdxy); cmdxy = 0L;
- if(*((char*)tmpl))cmdxy = (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1, 0);
- }
- 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;
- LockData(false, false);
- do_xyfunc(data, x1, x2, xstep, cmdxy, &xydata, &ndata, param);
- LockData(false, false);
- if(xydata && ndata >1) {
- if(!dl) dl = new DataLine(this, data, xydata, ndata, name);
- else dl->LineData(xydata, ndata);
- dirty = true;
- Command(CMD_AUTOSCALE, 0L, 0L);
- return true;
- }
- return false;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Calculate and display a user defined function
-static char *lastFunc2D = 0L, *lastParam2D=0L;
-FitFunc::FitFunc(GraphObj *par, DataObj *d):Plot(par, d)
-{
- FileIO(INIT_VARS);
- x1 = 0.0; x2 = 100.0; xstep = 0.5; dl = 0L;
- if(lastFunc2D && lastFunc2D[0] && lastParam2D && lastParam2D[0]) {
- cmdxy = (char*)memdup(lastFunc2D, (int)strlen(lastFunc2D)+1, 0);
- parxy = (char*)memdup(lastParam2D, (int)strlen(lastParam2D)+1, 0);
- }
- if(!cmdxy || !parxy) {
- cmdxy = (char*)malloc(20*sizeof(char)); parxy = (char*)malloc(20*sizeof(char));
- if(cmdxy) rlp_strcpy(cmdxy, 20, "a+b*x^c");
- if(parxy) rlp_strcpy(parxy, 20, "a=1; b=1; c=0.1;");
- }
- 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;
- if(name) free(name); name=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(!dl && (dl = new Function(this, data, "Fitted function"))) {
- 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, UNDO_CONTINUE);
- }
- 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->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], "Fitted function");
- }
- else ((Legend*)tmpl)->HasFill(ld, 0L, dl->name);
- return true;
- }
- return false;
- case CMD_ENDDIALOG:
- if(!cmdxy || !parxy) return false;
- if(i = (int)strlen(cmdxy)) {
- if(lastFunc2D = (char*)realloc(lastFunc2D, i+2))
- rlp_strcpy(lastFunc2D, i+1, cmdxy);
- }
- if(i = (int)strlen(parxy)) {
- if(lastParam2D = (char*)realloc(lastParam2D, i+2))
- rlp_strcpy(lastParam2D, i+1, parxy);
- }
- return true;
- case CMD_SCALE:
- if(dl) return dl->Command(cmd, tmpl, o);
- if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->Command(cmd, tmpl, o);
- Line.patlength *= ((scaleINFO*)tmpl)->sy.fy; Line.width *= ((scaleINFO*)tmpl)->sy.fy;
- return true;
- 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 && (dl = new Function(this, data, "Fitted function"))) {
- 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, UNDO_CONTINUE);
- }
- if(dl) {
- dl->Command(cmd, tmpl, o);
- 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:
- if(Symbols) {
- SavVarObs((GraphObj**)Symbols, nPoints, UNDO_CONTINUE);
- for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->Command(cmd, tmpl, o);
- }
- Undo.String(this, &parxy, UNDO_CONTINUE);
- do_fitfunc(data, ssXref, ssYref, 0L, &parxy, cmdxy, conv, maxiter, &chi2);
- if(!dl) dl = new Function(this, data, "Fitted function");
- if(dl){
- 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, UNDO_CONTINUE);
- }
- dirty = true;
- if(parent) parent->Command(CMD_MRK_DIRTY, 0L, o);
- return true;
- case CMD_DELOBJ:
- if(!parent) return false;
- if(tmpl && tmpl == dl) return parent->Command(CMD_DELOBJ, this, o);
- else if(DeleteGOL((GraphObj***)&Symbols,nPoints,(GraphObj*)tmpl,o)) return parent->Command(CMD_REDRAW,0L,o);
- else if(dl) return dl->Command(cmd, tmpl, o);
- return false;
- case CMD_MRK_DIRTY:
- dirty = true;
- if(dl){
- dl->SetSize(SIZE_MIN_X, x1); dl->SetSize(SIZE_MAX_X, x2);
- dl->SetSize(SIZE_XSTEP, xstep);
- }
- 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;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// normal quantile plot and derivates
-NormQuant::NormQuant(GraphObj *par, DataObj *d, char* range)
- :Plot(par, d)
-{
- FileIO(INIT_VARS);
- if(range && range[0]) ssRef = (char*)memdup(range, (int)strlen(range)+1, 0);
- else ssRef = 0L;
- Id = GO_NORMQUANT;
-}
-
-NormQuant::NormQuant(GraphObj *par, DataObj *d, double *val, int nval)
- :Plot(par, d)
-{
- FileIO(INIT_VARS); ssRef = 0L;
- if(val && nval) {
- src_data = (double*)memdup(val, nval*sizeof(double), 0);
- SortArray(nData = nval, src_data); ProcessData();
- }
- Id = GO_NORMQUANT;
-}
-
-NormQuant::NormQuant(int src):Plot(0L, 0L)
-{
- FileIO(INIT_VARS);
- if(src == FILE_READ) {
- FileIO(FILE_READ);
- if(nData)SortArray(nData, src_data); ProcessData();
- }
-}
-
-NormQuant::~NormQuant()
-{
- if(ssRef) free(ssRef); ssRef = 0L;
- if(x_info) free(x_info); x_info = 0L;
- if(y_info) free(y_info); y_info = 0L;
- if(x_vals) free(x_vals); x_vals = 0L;
- if(y_vals) free(y_vals); y_vals = 0L;
- if(src_data)free(src_data); src_data = 0L;
- if(sy)delete(sy);
-}
-
-void
-NormQuant::DoPlot(anyOutput *o)
-{
- int i;
-
- //draw symbols
- if(sy && y_vals && src_data && y_vals && nValidData) {
- sy->SetSize(SIZE_SYMBOL, defs.GetSize(SIZE_SYMBOL)/10.0);
- for(i = 0; i < nValidData; i++) {
- sy->SetSize(SIZE_XPOS, x_vals[i]);
- sy->SetSize(SIZE_YPOS, y_vals[i]);
- sy->DoPlot(o);
- }
- }
-}
-
-bool
-NormQuant::Command(int cmd, void *tmpl, anyOutput *o)
-{
- switch(cmd) {
- case CMD_LEGEND:
- if(sy) ((Legend*)tmpl)->HasSym(0L, sy, x_info ? x_info : (char*)"Data");
- return true;
- case CMD_SCALE:
- return true;
- case CMD_UPDATE:
- return true;
- case CMD_REDRAW:
- if(parent) return parent->Command(cmd, tmpl, o);
- break;
- case CMD_SET_DATAOBJ:
- Id = GO_NORMQUANT;
- if(sy) sy->Command(cmd, tmpl, o);
- data = (DataObj *)tmpl;
- return true;
- }
- return false;
-}
-
-bool
-NormQuant::ProcessData()
-{
- int i, r, c, n;
- AccRange *rD;
- double y, dtmp, sum;
-
- if(data && ssRef && ssRef[0] && (rD = new AccRange(ssRef))) {
- if((n = rD->CountItems()) && (src_data = (double*)realloc(src_data, n * sizeof(double)))){
- for(nData = 0, rD->GetFirst(&c, &r); rD->GetNext(&c, &r); ) {
- if(data->GetValue(r, c, &dtmp)) src_data[nData++] = dtmp;
- }
- if(nData)SortArray(nData, src_data);
- }
- if(y_info = (char*)malloc(20)){
- rlp_strcpy(y_info, 20, "Normal quantiles");
- }
- x_info = rD->RangeDesc(data, 2);
- delete rD;
- }
- if(src_data && nData) {
- Bounds.Ymin = HUGE_VAL; Bounds.Ymax = -HUGE_VAL;
- x_vals = (double*)realloc(x_vals, nData * sizeof(double));
- y_vals = (double*)realloc(y_vals, nData * sizeof(double));
- for(n = i = 0, sum = dtmp = 1.0/((double)nData); i < (nData-1); i++ ) {
- y = distinv(norm_dist, 0.0, 1.0, sum, 0.5);
- if(y > -HUGE_VAL && y < HUGE_VAL) {
- y_vals[n] = y; x_vals[n] = src_data[i];
- if(y < Bounds.Ymin) Bounds.Ymin = y;
- if(y > Bounds.Ymax) Bounds.Ymax = y;
- n++;
- }
- sum += dtmp;
- }
- Bounds.Xmax = src_data[nData-1]; Bounds.Xmin = src_data[0];
- if(Bounds.Ymax <= Bounds.Ymin) {
- Bounds.Ymin = -5.0; Bounds.Ymax = 5.0;
- }
- nValidData = n;
- return (n > 3);
- }
- 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(nscp > 0 && nscp <= nPlots && Sc_Plots) free(Sc_Plots);
- nscp = 0; Sc_Plots = 0L;
- if(drag) DeleteGO(drag); drag = 0L;
- if(dispObs) free(dispObs); dispObs = 0L;
- free(RotDef);
- if(name) free(name); name=0L;
- 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:
- return DefSize(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;
- if(nscp > 0 && nscp <= nPlots && Sc_Plots) free(Sc_Plots);
- nscp = 0; Sc_Plots = 0L; o->MouseCursor(MC_WAIT, true);
- if(dirty) DoAutoscale();
- if(Axes && nAxes >2) { //if no axes then parent is another Plot3D ...
- o->LightSource(32.0, 16.0); CurrAxes = Axes;
- 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;
- o->SetSpace(&cu1, &cu2, defs.cUnits, RotDef, &rc, Axes[0]->GetAxis(),
- Axes[1]->GetAxis(), Axes[2]->GetAxis());
- if(nAxes >3) { //DEBUG
- nAxes = nAxes;
- }
- for(i = 0; i< nAxes; i++) if(Axes[i]) Axes[i]->DoPlot(o);
- }
- else if(IsPlot3D(parent)) {
- if (use_xaxis || use_yaxis || use_zaxis)ApplyAxes(o);
- parent->Command(CMD_REG_AXISPLOT, (void*)this, o);
- }
- else {
- CurrAxes = 0L;
- }
- 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;
- if(nObs >1 && dispObs){
- SortObj();
- 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);
- }
- if(IsPlot3D(parent) && (use_xaxis || use_yaxis || use_zaxis))parent->Command(CMD_AXIS, 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_SCALE:
- cub1.fx *= ((scaleINFO*)tmpl)->sx.fy; cub1.fy *= ((scaleINFO*)tmpl)->sy.fy;
- cub1.fz *= ((scaleINFO*)tmpl)->sz.fy; cub2.fx *= ((scaleINFO*)tmpl)->sx.fy;
- cub2.fy *= ((scaleINFO*)tmpl)->sy.fy; cub2.fz *= ((scaleINFO*)tmpl)->sz.fy;
- rotC.fx *= ((scaleINFO*)tmpl)->sx.fy; rotC.fy *= ((scaleINFO*)tmpl)->sy.fy;
- rotC.fz *= ((scaleINFO*)tmpl)->sz.fy;
- 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_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_USEAXIS:
- if(IsPlot3D(parent)) return UseAxis(*((int*)tmpl));
- break;
- case CMD_REG_AXISPLOT: //notification: plot can handle its own axes
- if(nscp > 0 && nscp <= nPlots && 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_AXIS: //one of the plots has changed scaling: reset
- CurrAxes = Axes;
- if(o) o->SetSpace(&cu1, &cu2, defs.cUnits, RotDef, &rc, Axes[0]->GetAxis(),
- Axes[1]->GetAxis(), Axes[2]->GetAxis());
- return true;
- 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);
- if(plots[i]->Id > GO_PLOT && plots[i]->Id < GO_GRAPH) plots[i]->Command(cmd, tmpl, o);
- }
- 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:
- if(IsPlot3D(parent)) return parent->Command(cmd, tmpl, o);
- return dirty = true;
- case CMD_ADDAXIS:
- if(AddAxis()){
- if(parent) return parent->Command(CMD_REDRAW, tmpl, o);
- }
- return false;
- case CMD_SET_GO3D:
- if(IsPlot3D(parent)) return parent->Command(CMD_REDRAW, 0L, o);
- 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(DeleteGOL((GraphObj***)&plots,nPlots,(GraphObj*)tmpl,o)) return parent->Command(CMD_REDRAW,0L,o);
- return false;
- 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(IsPlot3D(parent)) return parent->Command(cmd, tmpl, o);
- 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 = DefSize(SIZE_AXIS_TICKS);
- int i;
- if(Axes || !parent)return;
- TextDEF tlbdef = {parent->GetColor(COL_AXIS), 0x00ffffffL, DefSize(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+DefSize(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+DefSize(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+DefSize(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]) {
- if(plots[i]->Id >= GO_PLOT && plots[i]->Id < GO_GRAPH) {
- if(!((Plot*)plots[i])->hidden) plots[i]->Command(CMD_AUTOSCALE, 0L, 0L);
- }
- else 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);
- }
- }
- else if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
- ((Plot*)parent)->CheckBounds3D(xBounds.fx, yBounds.fx, zBounds.fx);
- ((Plot*)parent)->CheckBounds3D(xBounds.fy, yBounds.fy, zBounds.fy);
- }
- }
-}
-
-//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
- || (dispObs[j]->Zmin == dispObs[j+1]->Zmin && dispObs[j]->Zmax < dispObs[j+1]->Zmax))) ++j;
- if(rra->Zmin < dispObs[j]->Zmin || (rra->Zmin == dispObs[j]->Zmin && rra->Zmax < dispObs[j]->Zmax)) {
- 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;
-
- o->SetSpace(&cu1, &cu2, defs.cUnits, RotDef, &rc, Axes[0]->GetAxis(),
- Axes[1]->GetAxis(), Axes[2]->GetAxis());
- 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()
-{
- if(name) free(name); name=0L;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 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()
-{
- if(name) free(name); name=0L;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// use Plot3D to create a 3 dimensional bubble plot
-BubblePlot3D::BubblePlot3D(GraphObj *par, DataObj *d)
- :Plot3D(par, d, 0x0L)
-{
-}
-
-BubblePlot3D::~BubblePlot3D()
-{
- if(name) free(name); name=0L;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 3D function plotter
-Func3D::Func3D(GraphObj *par, DataObj *d)
- :Plot3D(par, d, 0x0L)
-{
- FileIO(INIT_VARS);
- if(cmdxy = (char*)malloc(40*sizeof(char)))
- rlp_strcpy(cmdxy, 40, (char*)"r=sqrt(x*x+z*z)\ny=1-exp(-8/(r+1))");
- Id = GO_FUNC3D;
-}
-
-Func3D::Func3D(int src):Plot3D(0)
-{
- int i;
-
- 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;
- }
-}
-
-Func3D::~Func3D()
-{
- if(param) free(param); param = 0L;
- if(cmdxy) free(cmdxy); cmdxy = 0L;
- if(gda) delete(gda); gda = 0L;
- if(name) free(name); name=0L;
-}
-
-bool
-Func3D::Command(int cmd, void *tmpl, anyOutput *o)
-{
- switch(cmd) {
- case CMD_SET_DATAOBJ:
- Plot3D::Command(cmd, tmpl, o);
- if(gob && gda) gob->Command(cmd, gda, o);
- Id = GO_FUNC3D;
- return true;
- case CMD_UPDATE:
- return Update();
- break;
- }
- return Plot3D::Command(cmd, tmpl, o);
-}
-
-bool
-Func3D::Update()
-{
- if(cmdxy) {
- dirty = true;
- if(xstep == 0.0) xstep = 1.0; if(zstep == 0.0) zstep = 1.0;
- if(!gda) gda = new DataObj();
- if(gda && do_func3D(gda, x1, x2, xstep, z1, z2, zstep, cmdxy, param)) {
- if(gob = new Grid3D(this, gda, type, x1, xstep, z1, zstep)) {
- gob->Command(CMD_SET_LINE, &Line, 0L);
- gob->Command(CMD_SYM_FILL, &Fill, 0L);
- if(!plots && (plots = (GraphObj**)calloc(2, sizeof(GraphObj*)))) {
- nPlots = 1; plots[0] = (Plot *)gob;
- if(parent->Id == GO_GRAPH) CreateAxes();
- return dirty = parent->Command(CMD_REDRAW, 0L, 0L);
- }
- else if(plots && nPlots && plots[0]->Id == GO_GRID3D) {
- Undo.DeleteGO(&plots[0], UNDO_CONTINUE, 0L);
- Undo.SetGO(this, &plots[0], gob, UNDO_CONTINUE);
- return true;
- }
- else {
- DeleteGO(gob); gob=0L;
- }
- }
- }
- }
- return false;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// fit 3D function to data
-static char *lastFunc3D = 0L, *lastParam3D=0L;
-FitFunc3D::FitFunc3D(GraphObj *par, DataObj *d)
- :Plot3D(par, d, 0x0L)
-{
- FileIO(INIT_VARS);
- if(lastFunc3D && lastFunc3D[0] && lastParam3D && lastParam3D[0]) {
- cmdxy = (char*)memdup(lastFunc3D, (int)strlen(lastFunc3D)+1, 0);
- param = (char*)memdup(lastParam3D, (int)strlen(lastParam3D)+1, 0);
- }
- if(!cmdxy || !param) {
- cmdxy = (char*)malloc(20*sizeof(char)); param = (char*)malloc(20*sizeof(char));
- if(cmdxy) rlp_strcpy(cmdxy, 20, (char*)"a+b*x^c");
- if(param) rlp_strcpy(param, 20, (char*)"a=1; b=1; c=0.1;");
- }
- Id = GO_FITFUNC3D;
-}
-
-FitFunc3D::FitFunc3D(int src):Plot3D(0)
-{
- int i;
-
- 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;
- }
-}
-
-FitFunc3D::~FitFunc3D()
-{
- if(param) free(param); param = 0L;
- if(cmdxy) free(cmdxy); cmdxy = 0L;
- if(gda) delete(gda); gda = 0L;
- if(name) free(name); name=0L;
-}
-
-bool
-FitFunc3D::Command(int cmd, void *tmpl, anyOutput *o)
-{
- int i;
-
- switch(cmd) {
- case CMD_ENDDIALOG:
- if(!cmdxy || !param) return false;
- if(i = (int)strlen(cmdxy)) {
- if(lastFunc3D = (char*)realloc(lastFunc3D, i+2))
- rlp_strcpy(lastFunc3D, i+1, cmdxy);
- }
- if(i = (int)strlen(param)) {
- if(lastParam3D = (char*)realloc(lastParam3D, i+2))
- rlp_strcpy(lastParam3D, i+1, param);
- }
- return true;
- case CMD_SET_DATAOBJ:
- Plot3D::Command(cmd, tmpl, o);
- if(gob && gda) gob->Command(cmd, gda, o);
- Id = GO_FITFUNC3D;
- return true;
- case CMD_UPDATE:
- return Update();
- break;
- }
- return Plot3D::Command(cmd, tmpl, o);
-}
-
-bool
-FitFunc3D::Update()
-{
- if(cmdxy) {
- dirty = true;
- if(xstep == 0.0) xstep = 1.0; if(zstep == 0.0) zstep = 1.0;
- if(!gda) gda = new DataObj();
- if(gda && do_func3D(gda, x1, x2, xstep, z1, z2, zstep, cmdxy, param)) {
- if(gob = new Grid3D(this, gda, type, x1, xstep, z1, zstep)) {
- gob->Command(CMD_SET_LINE, &Line, 0L);
- gob->Command(CMD_SYM_FILL, &Fill, 0L);
- if(!plots && (plots = (GraphObj**)calloc(3, sizeof(GraphObj*)))) {
- nPlots = 1; plots[0] = (Plot *)gob;
- if(parent->Id == GO_GRAPH) CreateAxes();
- return dirty = parent->Command(CMD_REDRAW, 0L, 0L);
- }
- else if(plots && nPlots && plots[0]->Id == GO_GRID3D) {
- Undo.DeleteGO(&plots[0], UNDO_CONTINUE, 0L);
- Undo.SetGO(this, &plots[0], gob, UNDO_CONTINUE);
- return true;
- }
- else {
- DeleteGO(gob); gob=0L;
- }
- }
- }
- }
- return false;
-}
+//PlotObs.cpp, Copyright (c) 2001-2008 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)
+{
+ int pos, nsize;
+
+ Id = GO_PLOT;
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ if(name = (char*)malloc((nsize = 20)*sizeof(char))){
+ pos = rlp_strcpy(name, nsize, (char*)"Plot");
+ add_int_to_buff(&name, &pos, &nsize, ++cPlots, true, 0);
+ }
+ use_xaxis = use_yaxis = use_zaxis = 0; hidden = 0;
+ x_info = y_info = z_info = data_desc = 0L;
+ x_tv = y_tv = 0L; x_dtype = y_dtype = z_dtype = 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:
+ return DefSize(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)
+{
+ if(CurrAxes && CurrAxes[idx]) {
+ switch(CurrAxes[idx]->type & 0xf) {
+ case 1: // x-axis
+ Undo.ValInt(parent, &use_xaxis, 0L);
+ use_xaxis = idx; return true;
+ case 2: // y-axis
+ Undo.ValInt(parent, &use_yaxis, 0L);
+ use_yaxis = idx; return true;
+ case 3: // z-axis
+ Undo.ValInt(parent, &use_zaxis, 0L);
+ use_zaxis = idx; return true;
+ }
+ }
+ return false;
+}
+
+void
+Plot::ApplyAxes(anyOutput *o)
+{
+ if(!o || !CurrAxes || !parent) return;
+ if(use_xaxis && CurrAxes[use_xaxis]) {
+ o->UseAxis(CurrAxes[use_xaxis]->axis, CurrAxes[use_xaxis]->type & 0xf);
+ }
+ else use_xaxis = 0;
+ if(use_yaxis && CurrAxes[use_yaxis]) {
+ o->UseAxis(CurrAxes[use_yaxis]->axis, CurrAxes[use_yaxis]->type & 0xf);
+ }
+ else use_yaxis = 0;
+ if(use_zaxis && CurrAxes[use_zaxis]) {
+ o->UseAxis(CurrAxes[use_zaxis]->axis, CurrAxes[use_zaxis]->type & 0xf);
+ }
+ else use_zaxis = 0;
+ return;
+}
+
+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, n, c_num, c_txt, c_datetime;
+ double value, old_val;
+ DataObj *CumData = 0L;
+ anyResult ares;
+ AccRange *ax = 0L, **ayy = 0L;
+ TextValue *tv = 0L;
+ bool *validRows;
+
+ if(!xr || !yr || !mode || !data) return 0L;
+ if(!(CumData = new DataObj()))return 0L;
+ //count valid data lines
+ if(!(ax = new AccRange(xr))) {
+ delete CumData; CumData = 0L; return 0L;
+ }
+ ax->DataTypes(data, &c_num, &c_txt, &c_datetime);
+ nr = ax->CountItems();
+ if(!(yranges = split(yr, '&', &nc))){
+ delete CumData; delete ax; return 0L;
+ }
+ if(x_tv) x_tv->Reset(); if(y_tv) y_tv->Reset();
+ j = mode == 1 || mode == 2 ? nr : nr * 2;
+ if(CumData->Init(j , nc+2) && (validRows = (bool*)calloc(j, sizeof(bool)))){
+ if(!c_num && (c_txt + c_datetime) > 0 ) {
+ if(x_tv) tv = x_tv;
+ else if(y_tv) tv = y_tv;
+ else tv = x_tv = new TextValue();
+ }
+ //setup all ranges
+ if(!(ayy = (AccRange**)calloc(nc, sizeof(AccRange*))))return 0L;
+ for(i = 0; i < nc; i++) {
+ if(yranges[i] && *yranges[i] && (ayy[i] = new AccRange(yranges[i]))) {
+ if(!ayy[i]->GetFirst(&ic, &ir)) return 0L;
+ }
+ }
+ // set x values as first column
+ for(i = n = 0, ax->GetFirst(&ic, &ir); ax->GetNext(&ic, &ir); i++, n++) {
+ if(data->GetResult(&ares, ir, ic, false)) {
+ if(tv) {
+ switch(ares.type) {
+ case ET_TEXT:
+ value = tv->GetValue(ares.text); break;
+ default:
+ TranslateResult(&ares);
+ value = tv->GetValue(ares.text); break;
+ }
+ CumData->SetValue(n, 0, value); CumData->SetValue(n, 1, base);
+ }
+ else if(ares.type == ET_VALUE && ares.value > -HUGE_VAL && ares.value < HUGE_VAL) {
+ CumData->SetValue(n, 0, value = ares.value); CumData->SetValue(n, 1, base);
+ }
+ else {
+ CumData->SetValue(n, 0, value = 0.0); CumData->SetValue(n, 1, base);
+ }
+ if(mode == 3 || mode == 4){ //complete polygon data
+ CumData->SetValue((nr<<1)-i-1, 0, value);
+ }
+ for(j = 0; j < nc; j++) {
+ if(CumData->GetValue(n, j+1, &value)) CumData->SetValue(n, j+2, value);
+ if(ayy[j]->GetNext(&ic, &ir) && data->GetResult(&ares, ir, ic, false)){
+ if(ares.type == ET_VALUE && ares.value > -HUGE_VAL && ares.value < HUGE_VAL){
+ value = ares.value; validRows[i] = true;
+ }
+ else value = 0.0; old_val = 0.0;
+ CumData->GetValue(n, j+2, &old_val);
+ switch (mode) {
+ case 1: case 3: value += old_val; break;
+ case 2: case 4: value = old_val -value; break;
+ }
+ CumData->SetValue(n, j+2, value);
+ }
+ if(mode == 3 || mode == 4) //complete polygon data
+ if(CumData->GetValue(n, j+1, &value)){
+ if(validRows[n]) validRows[(nr<<1)-i-1] = true;
+ CumData->SetValue((nr<<1)-i-1, j+2, value);
+ }
+ }
+ }
+ else {
+ for(j = 0; j < nc; j++) ayy[j]->GetNext(&ic, &ir);
+ }
+ }
+ for(i = 0; i < nc; i++) delete ayy[i]; free(ayy);
+ for(i = 0; i < CumData->cRows; i++) {
+ if(!validRows[i]) {
+ CumData->cRows--;
+ for(j = 0; j < CumData->cCols; j++) {
+ if(CumData->etRows[i][j]) delete CumData->etRows[i][j];
+ }
+ free(CumData->etRows[i]);
+ for(j = i; j < CumData->cRows; j++) {
+ CumData->etRows[j] = CumData->etRows[j+1];
+ validRows[j] = validRows[j+1];
+ }
+ if(!validRows[i] && i < CumData->cRows) i--;
+ }
+ }
+ free(validRows);
+ }
+ for(i = 0; i < nc; i++) if(yranges[i]) free(yranges[i]);
+ if(ax) delete ax; 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, ErrorBar **errs):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;
+ }
+ }
+ }
+ if(cBars && errs) {
+ if((Errors = (ErrorBar**)calloc(cBars, sizeof(Bar*)))) {
+ nPoints = cBars;
+ for(i = 0; i < cBars; i++) {
+ if((Errors[i] = errs[i])) Errors[i]->parent = this;
+ errs[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);
+ if(name) free(name); name=0L;
+ if(x_info) free(x_info); x_info = 0L;
+ if(y_info) free(x_info); y_info = 0L;
+ if(data_desc) free(data_desc); data_desc = 0L;
+ if(x_tv) delete(x_tv); x_tv = 0L;
+ if(y_tv) delete(y_tv); y_tv = 0L;
+ Undo.InvalidGO(this);
+}
+
+double
+PlotScatt::GetSize(int select)
+{
+ int i;
+ double ft1, ft2, d;
+
+ switch(select){
+ case SIZE_BARMINX:
+ if(BarDist.fx >= 0.0001) return BarDist.fx;
+ if((!Bars) || (nPoints < 2)) return BarDist.fx = 1.0;
+ ft1 = -HUGE_VAL; ft2 = HUGE_VAL; BarDist.fx= HUGE_VAL;
+ for(i = 0; i < nPoints; i++) {
+ if(Bars[i]) {
+ ft2 = Bars[i]->GetSize(SIZE_XPOS);
+ d = fabs(ft2-ft1);
+ if(d != 0.0 && d < BarDist.fx) BarDist.fx = d;
+ }
+ ft1 = ft2;
+ }
+ return BarDist.fx = BarDist.fx > 0.0001 && BarDist.fx != HUGE_VAL ? BarDist.fx : 1.0;
+ case SIZE_BARMINY:
+ if(BarDist.fy >= 0.0001) return BarDist.fy;
+ if((!Bars) || (nPoints < 2)) return BarDist.fy = 1.0;
+ ft1 = -HUGE_VAL; ft2 = HUGE_VAL; BarDist.fy= HUGE_VAL;
+ for(i = 0; i < nPoints; i++) {
+ if(Bars[i]) {
+ ft2 = Bars[i]->GetSize(SIZE_YPOS);
+ d = fabs(ft2-ft1);
+ if(d != 0.0 && d < BarDist.fy) BarDist.fy = d;
+ }
+ ft1 = ft2;
+ }
+ return BarDist.fy = BarDist.fy > 0.0001 && BarDist.fy != HUGE_VAL ? BarDist.fy : 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_WHISKER: case SIZE_WHISKER_LINE:
+ 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_LB_XDIST: case SIZE_LB_YDIST:
+ if(Labels) for(i = 0; i < nPoints; i++)
+ if(Labels[i]) Labels[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_WHISKER:
+ 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], 0L);
+ }
+ else {
+ for (i = 0; i < nPoints && i < 100; i++)
+ if(Symbols[i]) ((Legend*)tmpl)->HasSym(0L, Symbols[i], 0L);
+ }
+ if(TheLine && TheLine->Id == GO_DATAPOLYGON) TheLine->Command(cmd, tmpl, o);
+ }
+ else if(TheLine) TheLine->Command(cmd, tmpl, o);
+ if(Errors) for (i = 0; i < nPoints; i++)
+ if(Errors[i]) Errors[i]->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_TEXTTHERE:
+ if(Labels) for(i = 0; i < nPoints; i++) if(Labels[i] && Labels[i]->Command(cmd, tmpl, o)) return true;
+ return false;
+ 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){
+ if (Symbols) SavVarObs((GraphObj **)Symbols, nPoints, UNDO_CONTINUE);
+ if (Bars) SavVarObs((GraphObj **)Bars, nPoints, UNDO_CONTINUE);
+ if (Errors) SavVarObs((GraphObj **)Errors, nPoints, UNDO_CONTINUE);
+ if (Arrows) SavVarObs((GraphObj **)Arrows, nPoints, UNDO_CONTINUE);
+ if (DropLines) SavVarObs((GraphObj **)DropLines, nPoints, UNDO_CONTINUE);
+ if (Labels) SavVarObs((GraphObj **)Labels, nPoints, UNDO_CONTINUE);
+ dirty = true;
+ }
+ case CMD_SET_DATAOBJ:
+ if(cmd == CMD_SET_DATAOBJ) {
+ Id = GO_PLOTSCATT;
+ if(data && data == (DataObj *) tmpl) return true;
+ data = (DataObj *)tmpl;
+ }
+ ForEach(cmd, tmpl, o);
+ if(cmd == CMD_AUTOSCALE) {
+ if(x_tv) {
+ Bounds.Xmin = 0.5; Bounds.Xmax = ((double)x_tv->Count())+0.5;
+ }
+ if(y_tv) {
+ Bounds.Ymin = 0.5; Bounds.Xmax = ((double)y_tv->Count())+0.5;
+ }
+ }
+ 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_SCALE:
+ 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_SETTEXTDEF:
+ if(Labels) for(i = 0; i < nPoints; i++)
+ if(Labels[i]) Labels[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: case CMD_WHISKER_STYLE: case CMD_ERRDESC:
+ if(Errors) for(i = 0; i < nPoints; i++) {
+ if(Errors[i]) Errors[i]->Command(cmd, tmpl, o);
+ }
+ 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);
+ case CMD_SAVE_LABELS:
+ return SavVarObs((GraphObj **)Labels, 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;
+
+ 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: case CMD_SCALE:
+ 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;
+ 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;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// xyStat is based on scatterplot
+xyStat::xyStat(GraphObj *par, DataObj *d):PlotScatt(par, d, 0L)
+{
+ FileIO(INIT_VARS);
+ Id = GO_XYSTAT;
+}
+
+xyStat::xyStat(int src):PlotScatt(0)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+xyStat::~xyStat()
+{
+ ForEach(FE_FLUSH, 0L, 0L);
+ if(curr_data) delete curr_data; curr_data = 0L;
+ if(case_prefix) free(case_prefix); case_prefix = 0L;
+ if(yRange) free(yRange); yRange = 0L;
+ if(xRange) free(xRange); xRange = 0L;
+ if(name) free(name); name=0L;
+ if(x_info) free(x_info); x_info = 0L;
+ if(y_info) free(x_info); y_info = 0L;
+ if(x_tv) delete(x_tv); x_tv = 0;
+ Undo.InvalidGO(this);
+}
+
+bool
+xyStat::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ switch (cmd) {
+ case CMD_UPDATE:
+ if (Symbols) SavVarObs((GraphObj **)Symbols, nPoints, UNDO_CONTINUE);
+ if (Bars) SavVarObs((GraphObj **)Bars, nPoints, UNDO_CONTINUE);
+ if (Errors) SavVarObs((GraphObj **)Errors, nPoints, UNDO_CONTINUE);
+ if (Labels) SavVarObs((GraphObj **)Labels, nPoints, UNDO_CONTINUE);
+ CreateData();
+ ForEach(CMD_SET_DATAOBJ, curr_data, o);
+ ForEach(CMD_UPDATE, tmpl, o);
+ return dirty = true;
+ case CMD_SET_DATAOBJ:
+ if(cmd == CMD_SET_DATAOBJ) {
+ Id = GO_XYSTAT;
+ if(data && data == (DataObj *) tmpl) return true;
+ if(curr_data) delete curr_data; curr_data = 0L;
+ data = (DataObj *)tmpl;
+ if(data && !curr_data) CreateData();
+ tmpl = curr_data;
+ }
+ ForEach(cmd, tmpl, o);
+ return true;
+ default:
+ return PlotScatt::Command(cmd, tmpl, o);
+ }
+ return false;
+}
+
+void
+xyStat::CreateData()
+{
+ int i, j, k, l, m, n, *ny, c_num, c_txt, c_dattim;
+ double y, ss, d, lo, hi, **ay, *ax, *tay, *q1, *q2, *q3;
+ lfPOINT *xy;
+ AccRange *rX, *rY;
+ anyResult x_res, y_res;
+
+ if(!data || !xRange || !yRange || !xRange[0] || !yRange[0]) return;
+ if(!(rX = new AccRange(xRange)) || !(rY = new AccRange(yRange))) return;
+ if(!x_info) x_info = rX->RangeDesc(data, 0); if(!y_info) y_info = rY->RangeDesc(data, 0);
+ m = rX->CountItems(); n = 0;
+ if(m < 2 || !(xy = (lfPOINT*) malloc(m * sizeof(lfPOINT)))) {
+ delete rX; delete rY;
+ return;
+ }
+ if(x_tv) delete x_tv; x_tv = 0L;
+ ny = (int*) calloc(m, sizeof(int));
+ ay = (double**) calloc(m, sizeof(double*));
+ ax = (double*) calloc(m, sizeof(double));
+ tay = (double*)malloc(m * sizeof(double));
+ if(!ny || !ay || !ax || !tay) {
+ if(ny) free(ny); if(ay) free(ay);
+ if(ax) free(ax); if(tay) free(tay);
+ delete rX; delete rY;
+ return;
+ }
+ rX->DataTypes(data, &c_num, &c_txt, &c_dattim);
+ if(c_num < 5 && (c_txt + c_dattim) > 5) {
+ x_tv = new TextValue();
+ }
+ rX->GetFirst(&i, &j); rY->GetFirst(&k, &l); dirty = true;
+ rX->GetNext(&i, &j); rY->GetNext(&k, &l); n=0;
+ do {
+ if(data->GetResult(&x_res, j, i, false) && data->GetResult(&y_res, l, k, false) && y_res.type == ET_VALUE) {
+ xy[n].fy = y_res.value;
+ if(x_tv){
+ switch(x_res.type) {
+ case ET_TEXT:
+ xy[n++].fx = x_tv->GetValue(x_res.text);
+ break;
+ case ET_VALUE: case ET_BOOL: case ET_DATE: case ET_TIME: case ET_DATETIME:
+ TranslateResult(&x_res);
+ xy[n++].fx = x_tv->GetValue(x_res.text);
+ break;
+ }
+ }
+ else if(x_res.type == ET_VALUE) xy[n++].fx = x_res.value;
+ }
+ }while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l));
+ delete rX; delete rY;
+ if(!n) {
+ if(ny) free(ny); if(ay) free(ay);
+ if(ax) free(ax); if(tay) free(tay);
+ return;
+ }
+ SortFpArray(n, xy);
+ for(i = j = 0; i < (n-1); i++, j++) {
+ ax[j] = xy[i].fx; tay[0] = xy[i].fy;
+ ny[j] = 1;
+ for(k = 1; xy[i+1].fx == xy[i].fx; k++) {
+ tay[k] = xy[i+1].fy;
+ i++; ny[j]++;
+ }
+ ay[j] = (double*)memdup(tay, k * sizeof(double), 0);
+ }
+ if(xy[i].fx > xy[i-1].fx) {
+ ax[j] = xy[i].fx; tay[0] = xy[i].fy;
+ ny[j] = 1;
+ ay[j++] = (double*)memdup(tay, sizeof(double), 0);
+ }
+ if(type & 0x0480) { //medians and/or percentiles required
+ q1 = (double *)malloc(j * sizeof(double));
+ q2 = (double *)malloc(j * sizeof(double));
+ q3 = (double *)malloc(j * sizeof(double));
+ if(q1 && q2 && q3) {
+ for(i = 0; i < j; i++) {
+ if(ny[i] > 1) d_quartile(ny[i], ay[i], q1+i, q2+i, q3+i);
+ else q1[i] = q2[i] = q3[i] = *ay[i];
+ }
+ }
+ else type &= (~0x0480);
+ }
+ else q1 = q2 = q3 = 0L;
+ if((curr_data = curr_data ? curr_data : new DataObj()) && curr_data->Init(j, 6)) {
+ for(i = 0; i < j; i++) curr_data->SetValue(i,0,ax[i]); // set x-values
+ for(i = 0; i < j; i++) { // set y-values
+ if(ny[i] > 1) switch(type & 0x00f0) {
+ case 0x0010: default:
+ curr_data->SetValue(i, 1, y=d_amean(ny[i], ay[i]));
+ break;
+ case 0x0020:
+ curr_data->SetValue(i, 1, y=d_gmean(ny[i], ay[i]));
+ break;
+ case 0x0040:
+ curr_data->SetValue(i, 1, y=d_hmean(ny[i], ay[i]));
+ break;
+ case 0x0080:
+ curr_data->SetValue(i, 1, y=q2[i]);
+ break;
+ }
+ else curr_data->SetValue(i, 1, y= *ay[i]);
+ curr_data->SetValue(i, 4, y);
+ }
+ for(i = 0; i < j; i++) { // set errors
+ switch(type & 0x1f00) {
+ case 0x0100: case 0x0200: case 0x1000: //SD, SEM, conf. int.
+ if(ny[i] > 1) {
+ ss = d_variance(ny[i], ay[i], &y);
+ switch(type & 0x1f00) {
+ case 0x0100:
+ curr_data->SetValue(i, 2, sqrt(ss));
+ break;
+ case 0x0200:
+ curr_data->SetValue(i, 2, sqrt(ss)/sqrt((double)ny[i]));
+ break;
+ case 0x1000:
+ d = distinv(t_dist, ny[i]-1, 1, 1.0-(ci/100.0), 2.0);
+ curr_data->SetValue(i, 2, d * sqrt(ss)/sqrt((double)ny[i]));
+ break;
+ }
+ }
+ else curr_data->SetValue(i, 2, 0.0);
+ if(curr_data->GetValue(i, 1, &y) && curr_data->GetValue(i, 2, &hi))
+ curr_data->SetValue(i, 4, hi+y);
+ break;
+ case 0x0400: //percentiles
+ curr_data->SetValue(i, 2, q1[i]); curr_data->SetValue(i, 3, q3[i]);
+ curr_data->SetValue(i, 4, q3[i]);
+ break;
+ case 0x0800: //min-max
+ lo = hi = *ay[i];
+ for(k = 1; k < ny[i]; k++) {
+ if(ay[i][k] < lo) lo = ay[i][k];
+ if(ay[i][k] > hi) hi = ay[i][k];
+ }
+ curr_data->SetValue(i, 2, lo); curr_data->SetValue(i, 3, hi);
+ curr_data->SetValue(i, 4, hi);
+ break;
+ }
+ }
+ if(type & 0x6000) for(i = 0; i < j; i++) { // number of cases
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "%s%d", case_prefix ? case_prefix : "", ny[i]);
+#else
+ sprintf(TmpTxt, "%s%d", case_prefix ? case_prefix : "", ny[i]);
+#endif
+ curr_data->SetText(i, 5, TmpTxt);
+ }
+ }
+ if(q1) free(q1); if(q2) free(q2); if(q3) free(q3);
+ for(i = 0; i < m; i++) if(ay[i]) free(ay[i]);
+ free(tay); free(ay); free(ax); free(ny); free(xy);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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(GraphObj *par, DataObj *d, char* range, bool bOnce):Plot(par, d)
+{
+ FileIO(INIT_VARS);
+ if(range && range[0]) {
+ ssRef = (char*)memdup(range, (int)strlen(range)+1, 0);
+ plots = (GraphObj**)calloc(nPlots=3, sizeof(GraphObj*));
+ ProcData(-1);
+ if(bOnce && ssRef) {
+ free(ssRef); ssRef = 0L;
+ }
+ }
+ Id = GO_FREQDIST;
+}
+
+FreqDist::FreqDist(GraphObj *par, DataObj *d, double *vals, int nvals, int nclasses):Plot(par, d)
+{
+ int i, j;
+ int *cl_data;
+ Bar **bars;
+
+ FileIO(INIT_VARS);
+ ssRef = 0L;
+ plots = (GraphObj**)calloc(nPlots=3, sizeof(GraphObj*));
+ for(i = 0, dmin = HUGE_VAL, dmax = -HUGE_VAL; i < nvals; i++) {
+ if(vals[i] < dmin) dmin = vals[i];
+ if(vals[i] > dmax) dmax = vals[i];
+ }
+ start = dmin; step = 1.00001*(dmax-dmin)/((double)nclasses);
+ if(!(cl_data = (int*)calloc(nclasses+1, sizeof(int)))) return;
+ for(i = 0; i < nvals; i++) {
+ j = (int)(floor((vals[i] - start)/step));
+ if(j >= 0 && j <= nclasses) cl_data[j]++;
+ }
+ if(cl_data[nclasses]) nclasses++;
+ if(bars = (Bar**)calloc(nclasses, sizeof(Bar*))) for(i = 0; i < nclasses; i++) {
+ if(bars[i] = new Bar(this, 0L, i*step+start, (double)cl_data[i], BAR_VERTB | BAR_RELWIDTH,
+ -1, -1, -1, -1, "Count")) bars[i]->SetSize(SIZE_BAR, 100.0);
+ }
+ //create bar chart
+ if(bars && (plots[0] = new PlotScatt(this, data, nclasses, bars, 0L))){
+ 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]){
+ Bounds.Xmin = dmin; Bounds.Xmax = dmax;
+ plots[0]->Command(CMD_AUTOSCALE, 0L, 0L);
+ }
+ free(cl_data);
+ 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;
+ }
+ if(name) free(name); name=0L;
+ if(x_info) free(x_info); x_info = 0L;
+ if(y_info) free(y_info); y_info = 0L;
+ if(x_tv) delete x_tv; x_tv = 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_SCALE:
+ if(plots) for(i = 0; i < nPlots; i++) if(plots[i]) plots[i]->Command(cmd, tmpl, o);
+ return true;
+ 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 = HUGE_VAL; Bounds.Ymin = 0;
+ Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ if(dmax > dmin) {
+ Bounds.Xmin = dmin; Bounds.Xmax = dmax;
+ }
+ }
+ 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_PLOT: 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_f, size_fo, pos_fo, c_num, c_txt, c_dattim;
+ double min, max, sum, mean, sd, tmp, *s_data, *t_data, lstep;
+ double chi2, df, x, y;
+ anyResult *result;
+ bool bValid = false;
+ Bar **bars = 0L;
+ anyResult res;
+ TextDEF td;
+ char *fo, *fdesc = 0L, formula[500];
+
+ if(!parent || !data || !ssRef || !plots) return;
+ if(curr_data) delete(curr_data); curr_data = 0L;
+ if(x_tv) delete x_tv; x_tv = 0L;
+ if((curr_data = new DataObj()) && (ar = new AccRange(ssRef))) {
+ if(!y_info && (y_info = (char*)malloc(25*sizeof(char)))) rlp_strcpy(y_info, 25, "No. of observations");
+ dmin = HUGE_VAL, dmax = -HUGE_VAL;
+ ar->DataTypes(data, &c_num, &c_txt, &c_dattim);
+ if(c_num < 5 && (c_txt + c_dattim) > 5) {
+ x_tv = new TextValue(); dmin = 0.0;
+ }
+ //copy spreadsheet data into array
+ nv = ar->CountItems(); ar->GetFirst(&c, &r);
+ if(!(s_data = (double*)malloc(nv * sizeof(double)))
+ || !(t_data = (double*)malloc(nv * sizeof(double)))) {
+ delete(ar); return;
+ }
+ for(sum = 0.0, nv = 0; ar->GetNext(&c, &r); ) if(data->GetResult(&res, r, c, false)) {
+ if(x_tv){
+ switch(res.type) {
+ case ET_TEXT:
+ if((tmp = x_tv->GetValue(res.text))> 0.0)bValid = true;
+ else bValid = false; break;
+ case ET_VALUE: case ET_DATE: case ET_TIME: case ET_DATETIME: case ET_BOOL:
+ TranslateResult(&res);
+ if((tmp = x_tv->GetValue(res.text))> 0.0)bValid = true;
+ else bValid = false; break;
+ default:
+ bValid = false; break;
+ }
+ }
+ else {
+ if(res.type == ET_VALUE) {
+ tmp = res.value; bValid = true;
+ }
+ else bValid = false;
+ }
+ if(bValid) {
+ if(tmp > dmax) dmax = tmp; if(tmp < dmin) dmin = tmp;
+ s_data[nv] = tmp;
+ switch (type & 0xff){
+ case 2:
+ if(tmp > 0.0) t_data[nv] = log(tmp);
+ else nv--;
+ break;
+ default: t_data[nv] = tmp; break;
+ }
+ nv++;
+ }
+ }
+ delete(ar);
+ if(!nv || dmin >= dmax) {
+ free(s_data); s_data = 0L; free(t_data); t_data = 0L;
+ return;
+ }
+ min = dmin; max = dmax;
+ lstep = (max-min)/100.0;
+ d_variance(nv, t_data, &mean, &sd);
+ sd = sqrt(sd/((double)(nv-1)));
+ step = fabs(step);
+ if(x_tv) {
+ start = 0.5; step = 1.0; max+= 0.5;
+ }
+ else 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))+1;
+ 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);
+ //create data object containg the counts / bin and bars
+ 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) {
+ if(bars[i] = new Bar(this, 0L, tmp, (double)f_data[i], BAR_VERTB | BAR_RELWIDTH,
+ 0, i, 1, i, "Count")) bars[i]->SetSize(SIZE_BAR, 100.0);
+ }
+ }
+ free(s_data); free(t_data); free(f_data);
+ //create bar chart
+ if(bars && (plots[0] = new PlotScatt(this, data, ncl, bars, 0L))){
+ 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]){
+ Bounds.Xmin = dmin; Bounds.Xmax = dmax;
+ plots[0]->Command(CMD_SET_DATAOBJ, curr_data, 0L);
+ plots[0]->Command(CMD_AUTOSCALE, 0L, 0L);
+ }
+ //create function
+ if((type & 0xff) && (fo = (char*)malloc(size_fo = 1000))) {
+ pos_fo = rlp_strcpy(fo, 1000, (char*) "[1=Function]\nx1=");
+ add_dbl_to_buff(&fo, &pos_fo, &size_fo, min, true);
+ add_to_buff(&fo, &pos_fo, &size_fo,(char*)"\nx2=", 4);
+ add_dbl_to_buff(&fo, &pos_fo, &size_fo, max, true);
+ add_to_buff(&fo, &pos_fo, &size_fo,(char*)"\nxstep=", 7);
+ add_dbl_to_buff(&fo, &pos_fo, &size_fo, lstep, true);
+ add_to_buff(&fo, &pos_fo, &size_fo,(char*)"\nLine=", 6);
+ add_dbl_to_buff(&fo, &pos_fo, &size_fo, DefSize(SIZE_DATA_LINE), true);
+ add_to_buff(&fo, &pos_fo, &size_fo,(char*)" 6 0x000000ff 0x0\n", 18);
+ cb_f = 0;
+ switch (type & 0xff){
+ case 2: //lognormal
+#ifdef USE_WIN_SECURE
+ cb_f = sprintf_s(formula, 500, "%g*lognormfreq(x,%g,%g)",nv*step, mean, sd);
+#else
+ cb_f = sprintf(formula,"%g*lognormfreq(x,%g,%g)",nv*step, mean, sd);
+#endif
+ fdesc = (char*)"Desc=\"Lognormal Dist.\"\n";
+ break;
+ case 3: //exponential
+#ifdef USE_WIN_SECURE
+ cb_f = sprintf_s(formula, 500, "%g*expfreq(x,%g)",nv*step, 1.0/mean);
+#else
+ cb_f = sprintf(formula,"%g*expfreq(x,%g)",nv*step, 1.0/mean);
+#endif
+ fdesc = (char*)"Desc=\"Exponential Dist.\"\n";
+ break;
+ case 4: //rectangular
+#ifdef USE_WIN_SECURE
+ cb_f = sprintf_s(formula, 500, "%g*%g*(x>=%g&&x<=%g)",nv*step, 1.0/(dmax-dmin), dmin, dmax);
+#else
+ cb_f = sprintf(formula,"%g*%g*(x>=%g&&x<=%g)",nv*step, 1.0/(dmax-dmin), dmin, dmax);
+#endif
+ fdesc = (char*)"Desc=\"Rectangular Dist.\"\n";
+ break;
+ case 5: //chi-square
+#ifdef USE_WIN_SECURE
+ cb_f = sprintf_s(formula, 500, "%g*chifreq(x,%g)",nv*step, mean);
+#else
+ cb_f = sprintf(formula,"%g*chifreq(x,%g)",nv*step, mean);
+#endif
+ fdesc = (char*)"Desc=\"Chi<sup>2</sup> Dist.\"\n";
+ break;
+ case 10: //binomial
+#ifdef USE_WIN_SECURE
+ cb_f = sprintf_s(formula, 500, "%g*binomfreq(x,%g,%g)*(x>0)",nv*step, dmax, mean/dmax);
+#else
+ cb_f = sprintf(formula,"%g*binomfreq(x,%g,%g)*(x>0)",nv*step, dmax, mean/dmax);
+#endif
+ fdesc = (char*)"Desc=\"Binomial Dist.\"\n";
+ break;
+ case 11: //poisson
+#ifdef USE_WIN_SECURE
+ cb_f = sprintf_s(formula, 500, "%g*poisfreq(x,%g)*(x>0)",nv*step, mean);
+#else
+ cb_f = sprintf(formula,"%g*poisfreq(x,%g)*(x>0)",nv*step, mean);
+#endif
+ fdesc = (char*)"Desc=\"Poisson Dist.\"\n";
+ break;
+ default: //normal
+#ifdef USE_WIN_SECURE
+ cb_f = sprintf_s(formula, 500, "%g*normfreq(x,%g,%g)",nv*step, mean, sd);
+#else
+ cb_f = sprintf(formula,"%g*normfreq(x,%g,%g)",nv*step, mean, sd);
+#endif
+ fdesc = (char*)"Desc=\"Normal Dist.\"\n";
+ break;
+ }
+ if(cb_f) {
+ add_to_buff(&fo, &pos_fo, &size_fo, "f_xy=\"y=" , 8);
+ add_to_buff(&fo, &pos_fo, &size_fo, formula , cb_f);
+ add_to_buff(&fo, &pos_fo, &size_fo, "\\n\"\n" , 4);
+ }
+ if(fdesc)add_to_buff(&fo, &pos_fo, &size_fo, fdesc, 0);
+ OpenGraph(this, 0L, (unsigned char *)fo, false);
+ free(fo); chi2 = df = 0.0;
+ //calculate chi-square test of fit
+ if(curr_data) for(i = 0; i< ncl; i++) {
+ if(curr_data->GetValue(i,0, &x) && curr_data->GetValue(i,1, &y)){
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "x=%g;%s", x, formula);
+#else
+ sprintf(TmpTxt, "x=%g;%s", x, formula);
+#endif
+ result = do_formula(curr_data, TmpTxt);
+ if(result->type == ET_VALUE && fabs(result->value) > 0.0) {
+ tmp = y-result->value;
+ tmp = (tmp*tmp)/result->value;
+ chi2 += tmp; df += 1.0;
+ }
+ }
+ }
+ //report result of the chi-square test
+ if(chi2 > 0.0 && parent && (fo = (char*)malloc(size_fo = 1000))) {
+ tmp = chi_dist(chi2, df-1.0, 1.0);
+ pos_fo = rlp_strcpy(fo, 1000, (char*)"chi<sup> 2</sup> =");
+ add_dbl_to_buff(&fo, &pos_fo, &size_fo, chi2, true);
+ add_to_buff(&fo, &pos_fo, &size_fo, (char*)", n =", 5);
+ add_dbl_to_buff(&fo, &pos_fo, &size_fo, df, true);
+ add_to_buff(&fo, &pos_fo, &size_fo, (char*)", df =", 6);
+ add_dbl_to_buff(&fo, &pos_fo, &size_fo, df-1.0, true);
+ add_to_buff(&fo, &pos_fo, &size_fo, (char*)", p =", 5);
+ if(tmp < 0.0001) {
+ pos_fo--; add_to_buff(&fo, &pos_fo, &size_fo, (char*)"< 0.0001", 8);
+ }
+ else add_dbl_to_buff(&fo, &pos_fo, &size_fo, tmp, true);
+ if(!plots[2]) {
+ x = (parent->GetSize(SIZE_GRECT_RIGHT) - parent->GetSize(SIZE_GRECT_LEFT))/2.0;
+ y = parent->GetSize(SIZE_GRECT_BOTTOM) - DefSize(SIZE_TEXT)*5;
+ y -= parent->GetSize(SIZE_DRECT_TOP);
+ td.Align = TXA_VTOP | TXA_HCENTER; td.ColBg = 0x00ffffffL;
+ td.ColTxt = 0x00ff0000L; td.Font = FONT_HELVETICA;
+ td.fSize = DefSize(SIZE_TEXT); td.iSize = 0;
+ td.Mode = TXM_TRANSPARENT; td.RotBL = td.RotCHAR = 0.0;
+ td.Style = TXS_NORMAL; td.text = 0L;
+ plots[2] = new Label(this, data, x, y, &td, 0x0L);
+ plots[2]->moveable = 1;
+ }
+ plots[2]->Command(CMD_SETTEXT, fo, 0L); 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);
+ if(name) free(name); name=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], "Regression");
+ }
+ else ((Legend*)tmpl)->HasFill(ld, 0L, "Regression");
+ 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_SCALE:
+ if(rLine) rLine->Command(cmd, tmpl, o);
+ if(sde) sde->Command(cmd, tmpl, o);
+ 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_UPDATE:
+ if(Symbols) {
+ SavVarObs((GraphObj**)Symbols, nPoints, 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);
+ }
+ if(name) free(name); name=0L;
+ 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_LEGEND:
+ if(((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+ if(Bubbles) for (i = 0; i < nPoints; i++)
+ if(Bubbles[i]) Bubbles[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_SCALE:
+ if(!tmpl) return false;
+ BubbleLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+ BubbleLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+ BubbleFillLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+ BubbleFillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+ BubbleFill.scale *= ((scaleINFO*)tmpl)->sy.fy;
+ if(Bubbles) for(i = 0; i < nPoints; i++)
+ if(Bubbles[i]) Bubbles[i]->Command(cmd, tmpl, o);
+ 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:
+ UseAxis(*((int*)tmpl));
+ return true;
+ case CMD_SET_DATAOBJ:
+ Id = GO_BUBBLEPLOT;
+ data = (DataObj *)tmpl;
+ case CMD_UPDATE:
+ if(cmd == CMD_UPDATE && Bubbles) SavVarObs((GraphObj **)Bubbles, nPoints, UNDO_CONTINUE);
+ case CMD_AUTOSCALE:
+ if(cmd == CMD_AUTOSCALE && Bubbles) {
+ Bounds.Xmax = Bounds.Ymax = -HUGE_VAL; Bounds.Xmin = Bounds.Ymin = HUGE_VAL;
+ }
+ 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;
+ }
+ if(name) free(name); name=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 DefSize(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_SCALE:
+ FillLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+ FillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+ Fill.scale *= ((scaleINFO*)tmpl)->sy.fy;
+ if(Axes) for(i = 0; i< nAxes; i++) if(Axes[i]) Axes[i]->Command(cmd, tmpl, o);
+ 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_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_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;
+}
+
+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(Labels)
+ for(i = 0; i < nPoints; i++) if(Labels[i]) Labels[i]->parent = this;
+ if(TheLine) TheLine->parent = this;
+ }
+}
+
+BoxPlot::BoxPlot(GraphObj *par, DataObj *dt, int mode, int c1, int c2, int c3, char *box_name):Plot(par, dt)
+{
+ int i, nr, cb;
+ lfPOINT fp;
+
+ FileIO(INIT_VARS); Id = GO_BOXPLOT; fp.fx = fp.fy = 0.0; cb = 0;
+ if(data && data->GetSize(&i, &nr)) {
+ nPoints = nr; if(box_name) cb = (int)strlen(box_name);
+ 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, BAR_RELWIDTH, c1, i, c2, i, c1, i, c3, i);
+ else Boxes[i] = new Box(this, data, fp, fp, BAR_RELWIDTH, c2, i, c1, i, c3, i, c1, i);
+ if(box_name && box_name[0] && Boxes[i]) Boxes[i]->name = (char*)memdup(box_name, cb+1, 0);
+ }
+ }
+}
+
+BoxPlot::~BoxPlot()
+{
+ int i;
+
+ if(Whiskers) {
+ for(i = 0; i < nPoints; i++) if(Whiskers[i]) DeleteGO(Whiskers[i]);
+ free (Whiskers);
+ }
+ if(Boxes) {
+ for(i = 0; i < nPoints; i++) if(Boxes[i]) DeleteGO(Boxes[i]);
+ free (Boxes);
+ }
+ if(Symbols) {
+ for(i = 0; i < nPoints; i++) if(Symbols[i]) DeleteGO(Symbols[i]);
+ free (Symbols);
+ }
+ if(Labels) {
+ for(i = 0; i < nPoints; i++) if(Labels[i]) DeleteGO(Labels[i]);
+ free (Labels);
+ }
+ if(TheLine) DeleteGO(TheLine);
+ if(curr_data) delete curr_data; curr_data = 0L;
+ if(xRange) free(xRange); xRange = 0L;
+ if(yRange) free(yRange); yRange = 0L;
+ if(x_info) free(x_info); x_info = 0L;
+ if(y_info) free(y_info); y_info = 0L;
+ if(case_prefix) free(case_prefix); case_prefix = 0L;
+ if(name) free(name); name = 0L;
+ if(x_tv) delete(x_tv); x_tv = 0;
+ if(y_tv) delete(y_tv); y_tv = 0;
+ Undo.InvalidGO(this);
+}
+
+double
+BoxPlot::GetSize(int select)
+{
+ int i;
+ double ft1, ft2, d;
+
+ switch(select){
+ case SIZE_BOXMINX:
+ if(BoxDist.fx >= 0.0001) return BoxDist.fx;
+ if((!Boxes) || (nPoints < 2)) return BoxDist.fx = 1.0;
+ ft1 = -HUGE_VAL; ft2 = HUGE_VAL; BoxDist.fx= HUGE_VAL;
+ for(i = 0; i < nPoints; i++) {
+ if(Boxes[i]) {
+ ft2 = Boxes[i]->GetSize(SIZE_XPOS);
+ d = fabs(ft2-ft1);
+ if(d != 0.0 && d < BoxDist.fx) BoxDist.fx = d;
+ }
+ ft1 = ft2;
+ }
+ return BoxDist.fx = BoxDist.fx > 0.0001 && BoxDist.fx != HUGE_VAL ? BoxDist.fx : 1.0;
+ case SIZE_BOXMINY:
+ if(BoxDist.fy >= 0.0001) return BoxDist.fy;
+ if((!Boxes) || (nPoints < 2)) return BoxDist.fy = 1.0;
+ ft1 = -HUGE_VAL; ft2 = HUGE_VAL; BoxDist.fy= HUGE_VAL;
+ for(i = 0; i < nPoints; i++) {
+ if(Boxes[i]) {
+ ft2 = Boxes[i]->GetSize(SIZE_YPOS);
+ d = fabs(ft2-ft1);
+ if(d != 0.0 && d < BoxDist.fy) BoxDist.fy = d;
+ }
+ ft1 = ft2;
+ }
+ return BoxDist.fy = BoxDist.fy > 0.0001 && BoxDist.fy != HUGE_VAL ? BoxDist.fy : 1.0;
+ 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;
+ case SIZE_LB_XDIST: case SIZE_LB_YDIST:
+ if(Labels) for(i = 0; i < nPoints; i++)
+ if(Labels[i]) Labels[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)
+{
+ if(!parent || !o) return;
+ parent->Command(CMD_REG_AXISPLOT, (void*)this, o);
+ if(use_xaxis || use_yaxis) ApplyAxes(o);
+ ForEach(FE_PLOT, 0L, 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;
+
+ 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_TEXTTHERE:
+ if(Labels) for(i = 0; i < nPoints; i++) if(Labels[i] && Labels[i]->Command(cmd, tmpl, o)) return true;
+ return false;
+ case CMD_LEGEND:
+ if(((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+ 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], 0L);
+ }
+ else {
+ for (i = 0; i < nPoints && i < 100; i++)
+ if(Symbols[i]) ((Legend*)tmpl)->HasSym(0L, Symbols[i], 0L);
+ }
+ if(TheLine && TheLine->Id == GO_DATAPOLYGON) TheLine->Command(cmd, tmpl, o);
+ }
+ else if(TheLine) TheLine->Command(cmd, tmpl, o);
+ if(Boxes) for (i = 0; i < nPoints; i++) if(Boxes[i]) Boxes[i]->Command(cmd, tmpl, o);
+ if(Whiskers) for (i = 0; i < nPoints; i++) if(Whiskers[i]) Whiskers[i]->Command(cmd, tmpl, o);
+ break;
+ case CMD_SET_DATAOBJ:
+ Id = GO_BOXPLOT; data = (DataObj *)tmpl; dirty = true;
+ if(type && xRange && yRange && data) { //Stat. - Plot ?
+ CreateData();
+ return ForEach(CMD_SET_DATAOBJ, curr_data, o);
+ }
+ case CMD_SCALE:
+ return ForEach(cmd, tmpl, o);
+ 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;
+ ForEach(cmd, tmpl, o);
+ if(x_tv) {
+ Bounds.Xmin = 0.5; Bounds.Xmax = ((double)x_tv->Count())+0.5;
+ }
+ 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_UPDATE:
+ if(parent) {
+ if(Boxes) SavVarObs((GraphObj **)Boxes, nPoints, UNDO_CONTINUE);
+ if(Whiskers) SavVarObs((GraphObj **)Whiskers, nPoints, UNDO_CONTINUE);
+ if(Symbols) SavVarObs((GraphObj **)Symbols, nPoints, UNDO_CONTINUE);
+ if(Labels) SavVarObs((GraphObj **)Labels, nPoints, UNDO_CONTINUE);
+ }
+ if(type && xRange && yRange) { //Stat. - Plot ?
+ CreateData();
+ ForEach(CMD_SET_DATAOBJ, curr_data, o);
+ }
+ ForEach(cmd, tmpl, o);
+ return dirty = 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_SETTEXTDEF:
+ if(Labels) for(i = 0; i < nPoints; i++)
+ if(Labels[i]) Labels[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_DELOBJ:
+ if(ForEach(FE_DELOBJ, tmpl, o)) {
+ parent->Command(CMD_REDRAW, 0L, o);
+ return true;
+ }
+ return false;
+ 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_SAVE_LABELS:
+ return SavVarObs((GraphObj **)Labels, 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: case CMD_ERRDESC:
+ if(Whiskers) for (i = 0; i < nPoints; i++)
+ if(Whiskers[i]) Whiskers[i]->Command(cmd, tmpl, o);
+ return true;
+ }
+ return false;
+}
+
+bool
+BoxPlot::ForEach(int cmd, void *tmpl, anyOutput *o)
+{
+ GraphObj ***pobs[] = {(GraphObj***)&Boxes, (GraphObj***)&Whiskers,
+ (GraphObj***)&Symbols, (GraphObj***)&Labels};
+ GraphObj **p;
+ int i, j;
+ bool bRet;
+
+ switch(cmd) {
+ case FE_DELOBJ:
+ if(!o || !parent || !tmpl) return false;
+ for(i = 0; i < 4; i++) {
+ if(DeleteGOL(pobs[i], nPoints, (GraphObj*) tmpl, o)) return true;
+ }
+ if(TheLine && tmpl == (void *) TheLine) {
+ Undo.DeleteGO((GraphObj**)(&TheLine), 0L, o);
+ return true;
+ }
+ break;
+ case FE_PLOT:
+ if(TheLine) TheLine->DoPlot(o);
+ for(i = 0; i < 4; i++){
+ if(p= *pobs[i]) for(j = 0; j < nPoints; j++) {
+ if(p[j]) p[j]->DoPlot(o);
+ }
+ }
+ return true;
+ case CMD_MOUSE_EVENT: //invers to plot order
+ for(i = 3; i >= 0; i--){
+ if(p= *pobs[i]) for(j = nPoints-1; j >= 0; j--) {
+ if(p[j]) {
+ bRet = p[j]->Command(cmd, tmpl, o);
+ if(bRet && cmd == CMD_MOUSE_EVENT) return true;
+ }
+ }
+ }
+ if(TheLine) return TheLine->Command(cmd, tmpl, o);
+ return false;
+ default: //pass command to all objects
+ for(i = 0; i < 4; i++){
+ if(p= *pobs[i]) for(j = 0; j < nPoints; j++) {
+ if(p[j]) {
+ bRet = p[j]->Command(cmd, tmpl, o);
+ }
+ }
+ }
+ if(TheLine) return TheLine->Command(cmd, tmpl, o);
+ return false;
+ }
+ return false;
+}
+
+void
+BoxPlot::CreateData()
+{
+ int i, j, k, l, m, n, *ny, c_num, c_txt, c_dattim;
+ double y, ss, d, lo, hi, **ay, *ax, *tay, *q1, *q2, *q3;
+ lfPOINT *xy;
+ AccRange *rX, *rY;
+ anyResult x_res, y_res;
+
+ if(curr_data) delete curr_data; curr_data = 0L;
+ if(!data || !xRange || !yRange || !xRange[0] || !yRange[0]) return;
+ if(!(rX = new AccRange(xRange)) || !(rY = new AccRange(yRange))) return;
+ m = rX->CountItems(); n = 0;
+ if(m < 2 || !(xy = (lfPOINT*) malloc(m * sizeof(lfPOINT)))) {
+ delete rX; delete rY;
+ return;
+ }
+ if(x_tv) delete x_tv; x_tv = 0L;
+ ny = (int*) calloc(m, sizeof(int));
+ ay = (double**) calloc(m, sizeof(double*));
+ ax = (double*) calloc(m, sizeof(double));
+ tay = (double*)malloc(m * sizeof(double));
+ if(!ny || !ay || !ax || !tay) {
+ if(ny) free(ny); if(ay) free(ay);
+ if(ax) free(ax); if(tay) free(tay);
+ delete rX; delete rY;
+ return;
+ }
+ rX->DataTypes(data, &c_num, &c_txt, &c_dattim);
+ if(c_num < 5 && (c_txt + c_dattim) > 5) {
+ x_tv = new TextValue();
+ }
+ rX->GetFirst(&i, &j); rY->GetFirst(&k, &l);
+ rX->GetNext(&i, &j); rY->GetNext(&k, &l); n=0;
+ do {
+ if(data->GetResult(&x_res, j, i, false) && data->GetResult(&y_res, l, k, false) && y_res.type == ET_VALUE) {
+ xy[n].fy = y_res.value;
+ if(x_tv){
+ switch(x_res.type) {
+ case ET_TEXT:
+ xy[n++].fx = x_tv->GetValue(x_res.text);
+ break;
+ case ET_VALUE: case ET_BOOL: case ET_DATE: case ET_TIME: case ET_DATETIME:
+ TranslateResult(&x_res);
+ xy[n++].fx = x_tv->GetValue(x_res.text);
+ break;
+ }
+ }
+ else if(x_res.type == ET_VALUE) xy[n++].fx = x_res.value;
+ }
+ }while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l));
+ delete rX; delete rY;
+ if(!n) {
+ if(ny) free(ny); if(ay) free(ay);
+ if(ax) free(ax); if(tay) free(tay);
+ return;
+ }
+ SortFpArray(n, xy);
+ for(i = j = 0; i < (n-1); i++, j++) {
+ ax[j] = xy[i].fx; tay[0] = xy[i].fy;
+ ny[j] = 1;
+ for(k = 1; xy[i+1].fx == xy[i].fx; k++) {
+ tay[k] = xy[i+1].fy;
+ i++; ny[j]++;
+ }
+ ay[j] = (double*)memdup(tay, k * sizeof(double), 0);
+ }
+ if(xy[i].fx > xy[i-1].fx) {
+ ax[j] = xy[i].fx; tay[0] = xy[i].fy;
+ ny[j] = 1;
+ ay[j++] = (double*)memdup(tay, sizeof(double), 0);
+ }
+ if((type & 0x0004) == 0x0004 || (type & 0x0030) == 0x0030 || (type & 0x0300) == 0x0300) {
+ //medians and/or percentiles required
+ q1 = (double *)malloc(j * sizeof(double));
+ q2 = (double *)malloc(j * sizeof(double));
+ q3 = (double *)malloc(j * sizeof(double));
+ if(q1 && q2 && q3) {
+ for(i = 0; i < j; i++) {
+ if(ny[i] > 1) d_quartile(ny[i], ay[i], q1+i, q2+i, q3+i);
+ else q1[i] = q2[i] = q3[i] = *ay[i];
+ }
+ }
+ else type = 0;
+ }
+ else q1 = q2 = q3 = 0L;
+ if(type && (curr_data = new DataObj()) && curr_data->Init(j, 8)) {
+ for(i = 0; i < j; i++) curr_data->SetValue(i,0,ax[i]); // set x-values
+ for(i = 0; i < j; i++) { // set means
+ if(ny[i] > 1) switch(type & 0x000f) {
+ case 0x0001: default:
+ curr_data->SetValue(i, 1, y=d_amean(ny[i], ay[i]));
+ break;
+ case 0x0002:
+ curr_data->SetValue(i, 1, y=d_gmean(ny[i], ay[i]));
+ break;
+ case 0x0003:
+ curr_data->SetValue(i, 1, y=d_hmean(ny[i], ay[i]));
+ break;
+ case 0x0004:
+ curr_data->SetValue(i, 1, y=q2[i]);
+ break;
+ }
+ else curr_data->SetValue(i, 1, y= *ay[i]);
+ curr_data->SetValue(i, 6, y); //label's y
+ }
+ if((type & 0x00f0) == 0x0010 || (type & 0x00f0) == 0x0020 || (type & 0x00f0) == 0x0050
+ || (type & 0x0f0f) == 0x0201 || (type & 0x0f0f) == 0x0501) for(i = 0; i < j; i++) {
+ // set SD, SE, Conf. Intervall
+ if(ny[i] > 1) {
+ ss = sqrt(d_variance(ny[i], ay[i], &y));
+ }
+ else {
+ y = *ay[i]; ss = 0.0;
+ }
+ //Box info is in cols 2 & 3
+ if((type & 0x00f0) == 0x0010) {
+ curr_data->SetValue(i, 2, y - ss); curr_data->SetValue(i, 3, y + ss);
+ }
+ else if((type & 0x00f0) == 0x0020) {
+ curr_data->SetValue(i, 2, y - ss/sqrt((double)ny[i]));
+ curr_data->SetValue(i, 3, y + ss/sqrt((double)ny[i]));
+ }
+ else if((type & 0x00f0) == 0x0050) {
+ d = ny[i] > 1 ? distinv(t_dist, ny[i]-1, 1, 1.0-(ci_box/100.0), 2.0) : 0;
+ curr_data->SetValue(i, 2, y - d*ss/(double)sqrt((double)ny[i]));
+ curr_data->SetValue(i, 3, y + d*ss/(double)sqrt((double)ny[i]));
+ }
+ //Whisker info is in cols 4 & 5
+ if((type & 0x0f0f) == 0x0101) {
+ curr_data->SetValue(i, 4, y - ss); curr_data->SetValue(i, 5, y + ss);
+ }
+ else if((type & 0x0f0f) == 0x0201) {
+ curr_data->SetValue(i, 4, y - ss/sqrt((double)ny[i]));
+ curr_data->SetValue(i, 5, y + ss/sqrt((double)ny[i]));
+ }
+ else if((type & 0x0f0f) == 0x0501) {
+ d = ny[i] > 1 ? distinv(t_dist, ny[i]-1, 1, 1.0-(ci_err/100.0), 2.0) : 0;
+ curr_data->SetValue(i, 4, y - d*ss/sqrt((double)ny[i]));
+ curr_data->SetValue(i, 5, y + d*ss/sqrt((double)ny[i]));
+ }
+ }
+ if((type & 0x00f0) == 0x0040 || (type & 0x0f00) == 0x0400) for(i = 0; i < j; i++) {
+ // set min and max
+ lo = hi = *ay[i];
+ if(ny[i] > 1) {
+ for(k = 1; k < ny[i]; k++) {
+ if(ay[i][k] < lo) lo = ay[i][k];
+ if(ay[i][k] > hi) hi = ay[i][k];
+ }
+ }
+ if((type & 0x00f0) == 0x0040) {
+ curr_data->SetValue(i, 2, lo); curr_data->SetValue(i, 3, hi);
+ }
+ if((type & 0x0f00) == 0x0400) {
+ curr_data->SetValue(i, 4, lo); curr_data->SetValue(i, 5, hi);
+ }
+ }
+ if(q1 && q3 && ((type & 0x00f0) == 0x0030 || (type & 0x0f00) == 0x0300)) for(i = 0; i < j; i++) {
+ // percentiles ....
+ if((type & 0x00f0) == 0x0030) {
+ curr_data->SetValue(i, 2, q1[i]); curr_data->SetValue(i, 3, q3[i]);
+ }
+ if((type & 0x0f00) == 0x0300) {
+ curr_data->SetValue(i, 4, q1[i]); curr_data->SetValue(i, 5, q3[i]);
+ }
+ }
+ if(type & 0xc000) for(i = 0; i < j; i++) {
+ //labels ...
+ if((type & 0x4000) && curr_data->GetValue(i, 5, &y)) curr_data->SetValue(i, 6, y);
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "%s%d", case_prefix ? case_prefix : "", ny[i]);
+#else
+ sprintf(TmpTxt, "%s%d", case_prefix ? case_prefix : "", ny[i]);
+#endif
+ curr_data->SetText(i, 7, TmpTxt);
+ }
+ }
+ else {
+ if(curr_data) delete curr_data;
+ curr_data = 0L;
+ }
+ if(q1) free(q1); if(q2) free(q2); if(q3) free(q3);
+ for(i = 0; i < m; i++) if(ay[i]) free(ay[i]);
+ free(tay); free(ay); free(ax); free(ny); free(xy);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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;
+ if(name) free(name); name=0L;
+ if(x_info) free(x_info); x_info = 0L;
+ if(y_info) free(y_info); y_info = 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_SCALE:
+ DefLine.width *= ((scaleINFO*)tmpl)->sy.fy; DefLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+ DefFillLine.width *= ((scaleINFO*)tmpl)->sy.fy; DefFillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+ DefFill.scale *= ((scaleINFO*)tmpl)->sy.fy;
+ for(i = 0; i < nPoints; i++){
+ if(Boxes[i]) Boxes[i]->Command(cmd, tmpl, o);
+ }
+ return true;
+ 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;
+ if(DeleteGOL((GraphObj***)&Boxes, nPoints, (GraphObj*)tmpl, o))
+ return parent->Command(CMD_REDRAW, 0L, 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:
+ if(Boxes) SavVarObs((GraphObj **)Boxes, nPoints, 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;
+ Box **op = Boxes;
+
+ if(xRange && yRange && (rX = new AccRange(xRange)) && (rY = new AccRange(yRange))) {
+ if((n=rX->CountItems()) == rY->CountItems()) {
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ if(!(Boxes = (Box**)realloc(Boxes, n * sizeof(Box*)))) return;
+ if(op && op != Boxes) Undo.InvalidGO(this);
+ for(i = nPoints; i < n; i++) {
+ Boxes[i] = 0L;
+ }
+ nPoints = n;
+ 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)){
+ fp1.fx = fp2.fx; fp1.fy = fp2.fy;
+ 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(op && Boxes[ic]) {
+ Boxes[ic]->SetSize(SIZE_XPOS, fp1.fx); Boxes[ic]->SetSize(SIZE_XPOS+1, fp2.fx);
+ Boxes[ic]->SetSize(SIZE_YPOS, fp1.fy); Boxes[ic]->SetSize(SIZE_YPOS+1, fp2.fy);
+ Boxes[ic]->SetSize(SIZE_BOX, (type &0x03) ? w/2.0 : w);
+ }
+ else if(!op && (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));
+ if(!op) {
+ SetSize(SIZE_BOX_LINE, DefLine.width);
+ SetColor(COL_BOX_LINE, DefLine.color);
+ Command(CMD_BOX_FILL, (void*)&DefFill, 0L);
+ }
+ }
+ 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;
+ if(name) free(name); name=0L;
+ if(x_tv) delete x_tv; x_tv = 0L;
+ if(y_tv) delete y_tv; y_tv = 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_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_SCALE:
+ dspm.fx *= ((scaleINFO*)tmpl)->sx.fy;
+ dspm.fy *= ((scaleINFO*)tmpl)->sy.fy;
+ 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);
+ if(Lines) for (i = numPL-1; i >= 0; i--)
+ if(Lines[i]) Lines[i]->Command(cmd, tmpl, o);
+ if(xyPlots) for (i = 0; i < numXY; i++)
+ if(xyPlots[i]) xyPlots[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_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;
+ if(CumData = CreaCumData(ssXrange, ssYrange, cum_data_mode, StartVal)) {
+ 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(cmd == CMD_SET_DATAOBJ) tmpl = (void*) CumData;
+ 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(DeleteGOL((GraphObj***)&Polygons, numPG, (GraphObj*)tmpl, o))
+ return parent->Command(CMD_REDRAW, 0L, o);
+ if(DeleteGOL((GraphObj***)&Lines, numPL, (GraphObj*)tmpl, o))
+ return parent->Command(CMD_REDRAW, 0L, o);
+ if(DeleteGOL((GraphObj***)&xyPlots, numXY, (GraphObj*)tmpl, o))
+ return parent->Command(CMD_REDRAW, 0L, o);
+ if(DeleteGOL((GraphObj***)&Boxes, numPlots, (GraphObj*)tmpl, o))
+ return parent->Command(CMD_REDRAW, 0L, o);
+ if(xyPlots) for(i = 0; i < numXY; i++)
+ if(xyPlots[i] && xyPlots[i]->Command(cmd, tmpl, o)) return true;
+ if(Boxes) for(i = 0; i < numPlots; i++)
+ if(Boxes[i] && Boxes[i]->Command(cmd, tmpl, o)) return true;
+ return false;
+ }
+ 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;
+ if(name) free(name); name=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_SCALE:
+ if(cmd == CMD_SCALE) {
+ CtDef.fx *= ((scaleINFO*)tmpl)->sx.fy; CtDef.fy *= ((scaleINFO*)tmpl)->sx.fy;
+ }
+ 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))) {
+ SavVarObs((GraphObj **)Segments, nPts, 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);
+ }
+ if(name) free(name); name=0L;
+ 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;
+ }
+ if(name) free(name); name=0L;
+ if(data_desc) free(data_desc); data_desc = 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 || !parent) return;
+ if(use_xaxis || use_yaxis || use_zaxis) ApplyAxes(o);
+ o->GetSize(&rc);
+ parent->Command(CMD_REG_AXISPLOT, (void*)this, o);
+ 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);
+ }
+ if(use_xaxis || use_yaxis || use_zaxis)parent->Command(CMD_AXIS, 0L, o);
+ dirty = false;
+}
+
+bool
+Scatt3D::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(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_USEAXIS:
+ return UseAxis(*((int*)tmpl));
+ 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], 0L);
+ }
+ else {
+ for (i = 0; i < nBalls && i < 100; i++) {
+ if(Balls[i]) {
+ if(Balls[i]->type) Balls[i]->Command(cmd, tmpl, o);
+ else ((Legend*)tmpl)->HasSym(0L, Balls[i], 0L);
+ }
+ }
+ }
+ }
+ 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: case CMD_SCALE:
+ if(Balls) {
+ SavVarObs((GraphObj**)Balls, nBalls, UNDO_CONTINUE);
+ for(i = 0; i < nBalls; i++) if(Balls[i]) Balls[i]->Command(cmd, tmpl, o);
+ }
+ if(Columns) {
+ SavVarObs((GraphObj**)Columns, nColumns, UNDO_CONTINUE);
+ for(i = 0; i < nColumns; i++) if(Columns[i]) Columns[i]->Command(cmd, tmpl, o);
+ }
+ if(DropLines) {
+ SavVarObs((GraphObj**)DropLines, nDropLines, UNDO_CONTINUE);
+ for(i = 0; i < nDropLines; i++) if(DropLines[i]) DropLines[i]->Command(cmd, tmpl, o);
+ }
+ if(Arrows) {
+ SavVarObs((GraphObj**)Arrows, nArrows, UNDO_CONTINUE);
+ 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 && xr[0]) ssRefX = (char*)memdup(xr, (int)strlen(xr)+1, 0L);
+ if(yr && yr[0]) ssRefY = (char*)memdup(yr, (int)strlen(yr)+1, 0L);
+ z_value = z; z_width = width;
+}
+
+Ribbon::Ribbon(GraphObj *par, DataObj *d, int which, char *xr, char *yr, char *zr)
+ :Plot(par, d)
+{
+ FileIO(INIT_VARS); Id = GO_RIBBON; type = which;
+ if(xr && xr[0]) ssRefX = (char*)memdup(xr, (int)strlen(xr)+1, 0L);
+ if(yr && yr[0]) ssRefY = (char*)memdup(yr, (int)strlen(yr)+1, 0L);
+ if(zr && zr[0]) ssRefZ = (char*)memdup(zr, (int)strlen(zr)+1, 0L);
+ CreateObs();
+}
+
+Ribbon::Ribbon(GraphObj *par, DataObj *d, GraphObj **go, int ngo)
+ :Plot(par, d)
+{
+ int i;
+
+ FileIO(INIT_VARS); Id = GO_RIBBON; type = 3;
+ planes = (Plane3D**)go; nPlanes = ngo;
+ for(i = 0; i < ngo; i++) planes[i]->parent = this;
+}
+
+
+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;
+ if(name) free(name); name=0L;
+ if(data_desc) free(data_desc); data_desc = 0L;
+}
+
+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_SCALE:
+ z_value *= ((scaleINFO*)tmpl)->sz.fy;
+ z_width *= ((scaleINFO*)tmpl)->sz.fy;
+ for(i = 0; i < nPlanes; i++) if(planes[i]) planes[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_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, j, n, rx, cx, ry, cy, rz, cz;
+ double fx, fy, fz, tmp;
+ fPOINT3D pg[5];
+ AccRange *rX, *rY, *rZ;
+ Triangle *trl, *trc, *trn;
+
+ 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))) {
+ if(!data_desc) data_desc = rY->RangeDesc(data, 1);
+ 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 = j = 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(j) {
+ 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);
+ }
+ j++;
+ 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;
+ }
+ if(!data_desc) data_desc = rY->RangeDesc(data, 1);
+ 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;
+ case 3:
+ if(!ssRefX || !ssRefY || !ssRefZ) break;
+ Undo.InvalidGO(this);
+ trl = Triangulate1(ssRefX, ssRefZ, ssRefY, data);
+ for(i = 0, trc = trl; trc; i++) trc = trc->next;
+ if((n = i) && (planes = (Plane3D**)malloc(n*sizeof(Plane3D*))))
+ for(i = nPlanes = 0, trc = trl; trc && i < n; i++) {
+ for(j = 0; j < 4; j++) { //swap y and z values;
+ tmp = trc->pt[j].fz; trc->pt[j].fz = trc->pt[j].fy; trc->pt[j].fy = tmp;
+ }
+ planes[nPlanes++] = new Plane3D(this, data, trc->pt, 4);
+ trn = trc->next; delete trc; trc = trn;
+ }
+ dirty = true; Command(CMD_AUTOSCALE, 0L, 0L);
+ 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 && type < 3)) 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;
+ case 3:
+ if(planes) {
+ for(i = 0; i < nPlanes; i++) if(planes[i]) DeleteGO(planes[i]);
+ free(planes); planes = 0L; nPlanes = 0;
+ }
+ CreateObs();
+ }
+ if(rX) delete rX; if(rY) delete rY; if(rZ) delete rZ;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// draw a 3dimensional grid
+Grid3D::Grid3D(GraphObj *par, DataObj *d, int sel, double x1, double xstep, double z1, double zstep)
+ :Plot(par, d)
+{
+ FileIO(INIT_VARS); Id = GO_GRID3D;
+ start.fx = x1; step.fx = xstep;
+ start.fz = z1; step.fz = zstep;
+ type = sel;
+}
+
+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;
+ }
+ if(planes) {
+ for(i = 0; i < nPlanes; i++) if(planes[i]) DeleteGO(planes[i]);
+ free(planes); planes = 0L;
+ }
+ nLines = nPlanes = 0;
+ if(name) free(name); name=0L;
+}
+
+bool
+Grid3D::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;
+ }
+ return false;
+}
+
+bool
+Grid3D::SetColor(int select, DWORD col)
+{
+ int i;
+
+ switch (select) {
+ case COL_POLYLINE:
+ if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->SetColor(select, col);
+ return true;
+ }
+ return false;
+}
+
+void
+Grid3D::DoPlot(anyOutput *o)
+{
+ int i;
+
+ if(!lines && !planes) CreateObs(false);
+ if(lines) for(i = 0; i < nLines; i++) if(lines[i]) lines[i]->DoPlot(o);
+ if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[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;
+ 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_SET_LINE:
+ if(tmpl) {
+ memcpy(&Line, tmpl, sizeof(LineDEF));
+ if(lines) {
+ SavVarObs((GraphObj**)lines, nLines, 0L);
+ for(i = 0; i < nLines; i++)
+ if(lines[i]) lines[i]->Command(cmd, tmpl, o);
+ }
+ if(planes) {
+ SavVarObs((GraphObj**)planes, nPlanes, 0L);
+ for(i = 0; i < nPlanes; i++)
+ if(planes[i]) planes[i]->Command(cmd, tmpl, o);
+ }
+ }
+ break;
+ case CMD_LEGEND:
+ if(!hidden) ((Legend*)tmpl)->HasFill(&Line, planes ? &Fill : 0L, 0L);
+ break;
+ case CMD_CONFIG:
+ return Configure();
+ 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;
+ if(tmpl == data) return true;
+ data = (DataObj *)tmpl;
+ case CMD_UPDATE:
+ if(lines) for(i = 0; i < nLines; i++) if(lines[i]) lines[i]->Command(cmd, tmpl, o);
+ if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->Command(cmd, tmpl, o);
+ return dirty = true;
+ case CMD_AUTOSCALE:
+ if(!lines && !planes) CreateObs(false);
+ 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(planes) for(i = 0; i < nPlanes; i++)
+ if(planes[i]) planes[i]->Command(cmd, tmpl, o);
+ }
+ if(zBounds.fx > zBounds.fy) zBounds.fx = zBounds.fy = 0.0;
+ if(parent && parent->Id > GO_PLOT && parent->Id < GO_GRAPH &&
+ xBounds.fx <= xBounds.fy && yBounds.fx <= yBounds.fy){
+ ((Plot*)parent)->CheckBounds3D(xBounds.fx, yBounds.fx, zBounds.fx);
+ ((Plot*)parent)->CheckBounds3D(xBounds.fy, yBounds.fy, zBounds.fy);
+ }
+ return true;
+ case CMD_SYM_FILL:
+ if(!tmpl) return false;
+ memcpy(&Fill, tmpl, sizeof(FillDEF));
+ 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);
+ case CMD_DELOBJ:
+ if(!parent) return false;
+ if(DeleteGOL((GraphObj***)&lines,nLines,(GraphObj*)tmpl,o)) return parent->Command(CMD_REDRAW, 0L, o);
+ if(DeleteGOL((GraphObj***)&planes,nPlanes,(GraphObj*)tmpl,o)) return parent->Command(CMD_REDRAW, 0L, o);
+ break;
+ }
+ return false;
+}
+
+void
+Grid3D::CreateObs(bool set_undo)
+{
+ int i, ir, ic, idx, w, h;
+ fPOINT3D *vec;
+
+ if(!parent || !data || lines || planes) return;
+ dirty = true;
+ if(type == 0) {
+ 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].fz = start.fz; data->GetValue(0, 0, &vec[0].fy);
+ for(ic = 1, idx = 0; ic <= w; ic++) {
+ vec[0].fx = start.fx;
+ 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].fz = vec[0].fz + step.fz; vec[1].fx = vec[0].fx;
+ lines[idx++] = new Line3D(this, data, vec, 2,
+ -1, -1, ic-1, ir-1, -1, -1, -1, -1, ic, ir-1, -1, -1);
+ }
+ if(ir < h && data->GetValue(ir, ic-1, &vec[1].fy)) {
+ vec[1].fz = vec[0].fz; vec[1].fx = vec[0].fx + step.fx;
+ lines[idx++] = new Line3D(this, data, vec, 2,
+ -1, -1, ic-1, ir-1, -1, -1, -1, -1, ic-1, ir, -1, -1);
+ }
+ vec[0].fx += step.fx; vec[0].fy = vec[1].fy;
+ }
+ vec[0].fz += step.fz;
+ }
+ for(i = 0; i < nLines; i++) if(lines[i]) lines[i]->Command(CMD_SET_LINE, &Line, 0L);
+ free(vec);
+ }
+ else if(type == 1) {
+ if(!(vec = (fPOINT3D*)malloc(sizeof(fPOINT3D) * 5))) return;
+ vec[0].fz = vec[4].fz = start.fz;
+ vec[3].fz = (start.fz +step.fz);
+ data->GetSize(&w, &h);
+ if(0 >= (nPlanes = w * h)) return;
+ if(!(planes =(Plane3D**)calloc(nPlanes, sizeof(Plane3D*)))) return;
+ for(ic = 1, idx = 0; ic <= w; ic++) {
+ vec[0].fx = vec[3].fx = vec[4].fx = (start.fx+step.fx);
+ vec[1].fx = vec[2].fx = start.fx;
+ vec[1].fz = vec[4].fz; vec[2].fz = vec[3].fz;
+ data->GetValue(0, ic-1, &vec[1].fy); data->GetValue(0, ic, &vec[2].fy);
+ for(ir = 1; ir <= h; ir++){
+ if(ic < w && ir < h && data->GetValue(ir, ic, &vec[3].fy)
+ && data->GetValue(ir, ic-1, &vec[4].fy)) {
+ vec[0].fz = vec[4].fz; vec[0].fy = vec[4].fy; vec[0].fx = vec[4].fx;
+ planes[idx++] = new Plane3D(this, 0L, vec, 5);
+ }
+ vec[1].fz = vec[4].fz; vec[1].fy = vec[4].fy; vec[1].fx = vec[4].fx;
+ vec[2].fz = vec[3].fz; vec[2].fy = vec[3].fy; vec[2].fx = vec[3].fx;
+ vec[3].fx += step.fx; vec[4].fx += step.fx;
+ }
+ vec[3].fz += step.fz; vec[4].fz += step.fz;
+ }
+ nPlanes = idx;
+ for(i = 0; i < nPlanes; i++) if(planes[i]){
+ planes[i]->Command(CMD_SET_LINE, &Line, 0L);
+ planes[i]->Command(CMD_SYM_FILL, &Fill, 0L);
+ }
+ SetSize(SIZE_SYM_LINE, Line.width); SetColor(COL_POLYLINE, Line.color);
+ free(vec);
+ }
+ if(set_undo) {
+ if(planes && nPlanes)Undo.StoreListGO(parent, (GraphObj***)&planes, &nPlanes, UNDO_CONTINUE);
+ if(lines && nLines)Undo.StoreListGO(parent, (GraphObj***)&lines, &nLines, UNDO_CONTINUE);
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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()
+{
+ if(name) free(name); name=0L;
+}
+
+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, char *desc):Plot(par, d)
+{
+ FileIO(INIT_VARS); cmdxy = (char*)malloc(20*sizeof(char));
+ if(parent && parent->Id == GO_POLARPLOT) {
+ x1 = 0.0; x2 = 360.0; xstep = 0.5;
+ if(cmdxy)rlp_strcpy(cmdxy, 20, (char*)"sin(pi*x/30)+1.1");
+ }
+ else {
+ x1 = 0.0; x2 = 100.0; xstep = 0.5;
+ if(cmdxy)rlp_strcpy(cmdxy, 20, (char*)"sin(x)/x");
+ }
+ if(desc) name = (char*)memdup(desc, (int)strlen(desc)+1, 0);
+ 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;
+ if(name) free(name); name=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 || dirty) && 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_SCALE:
+ Line.patlength *= ((scaleINFO*)tmpl)->sy.fy; Line.width *= ((scaleINFO*)tmpl)->sy.fy;
+ return true;
+ 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 = 0L;
+ if(*((char*)tmpl))param = (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1, 0);
+ }
+ dirty = true;
+ return true;
+ case CMD_SETFUNC:
+ if(tmpl) {
+ if(cmdxy) free(cmdxy); cmdxy = 0L;
+ if(*((char*)tmpl))cmdxy = (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1, 0);
+ }
+ 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;
+ LockData(false, false);
+ do_xyfunc(data, x1, x2, xstep, cmdxy, &xydata, &ndata, param);
+ LockData(false, false);
+ if(xydata && ndata >1) {
+ if(!dl) dl = new DataLine(this, data, xydata, ndata, name);
+ else dl->LineData(xydata, ndata);
+ dirty = true;
+ Command(CMD_AUTOSCALE, 0L, 0L);
+ return true;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Calculate and display a user defined function
+static char *lastFunc2D = 0L, *lastParam2D=0L;
+FitFunc::FitFunc(GraphObj *par, DataObj *d):Plot(par, d)
+{
+ FileIO(INIT_VARS);
+ x1 = 0.0; x2 = 100.0; xstep = 0.5; dl = 0L;
+ if(lastFunc2D && lastFunc2D[0] && lastParam2D && lastParam2D[0]) {
+ cmdxy = (char*)memdup(lastFunc2D, (int)strlen(lastFunc2D)+1, 0);
+ parxy = (char*)memdup(lastParam2D, (int)strlen(lastParam2D)+1, 0);
+ }
+ if(!cmdxy || !parxy) {
+ cmdxy = (char*)malloc(20*sizeof(char)); parxy = (char*)malloc(20*sizeof(char));
+ if(cmdxy) rlp_strcpy(cmdxy, 20, "a+b*x^c");
+ if(parxy) rlp_strcpy(parxy, 20, "a=1; b=1; c=0.1;");
+ }
+ 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;
+ if(name) free(name); name=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(!dl && (dl = new Function(this, data, "Fitted function"))) {
+ 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, UNDO_CONTINUE);
+ }
+ 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->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], "Fitted function");
+ }
+ else ((Legend*)tmpl)->HasFill(ld, 0L, dl->name);
+ return true;
+ }
+ return false;
+ case CMD_ENDDIALOG:
+ if(!cmdxy || !parxy) return false;
+ if(i = (int)strlen(cmdxy)) {
+ if(lastFunc2D = (char*)realloc(lastFunc2D, i+2))
+ rlp_strcpy(lastFunc2D, i+1, cmdxy);
+ }
+ if(i = (int)strlen(parxy)) {
+ if(lastParam2D = (char*)realloc(lastParam2D, i+2))
+ rlp_strcpy(lastParam2D, i+1, parxy);
+ }
+ return true;
+ case CMD_SCALE:
+ if(dl) return dl->Command(cmd, tmpl, o);
+ if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->Command(cmd, tmpl, o);
+ Line.patlength *= ((scaleINFO*)tmpl)->sy.fy; Line.width *= ((scaleINFO*)tmpl)->sy.fy;
+ return true;
+ 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 && (dl = new Function(this, data, "Fitted function"))) {
+ 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, UNDO_CONTINUE);
+ }
+ if(dl) {
+ dl->Command(cmd, tmpl, o);
+ 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:
+ if(Symbols) {
+ SavVarObs((GraphObj**)Symbols, nPoints, UNDO_CONTINUE);
+ for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->Command(cmd, tmpl, o);
+ }
+ Undo.String(this, &parxy, UNDO_CONTINUE);
+ do_fitfunc(data, ssXref, ssYref, 0L, &parxy, cmdxy, conv, maxiter, &chi2);
+ if(!dl) dl = new Function(this, data, "Fitted function");
+ if(dl){
+ 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, UNDO_CONTINUE);
+ }
+ dirty = true;
+ if(parent) parent->Command(CMD_MRK_DIRTY, 0L, o);
+ return true;
+ case CMD_DELOBJ:
+ if(!parent) return false;
+ if(tmpl && tmpl == dl) return parent->Command(CMD_DELOBJ, this, o);
+ else if(DeleteGOL((GraphObj***)&Symbols,nPoints,(GraphObj*)tmpl,o)) return parent->Command(CMD_REDRAW,0L,o);
+ else if(dl) return dl->Command(cmd, tmpl, o);
+ return false;
+ case CMD_MRK_DIRTY:
+ dirty = true;
+ if(dl){
+ dl->SetSize(SIZE_MIN_X, x1); dl->SetSize(SIZE_MAX_X, x2);
+ dl->SetSize(SIZE_XSTEP, xstep);
+ }
+ 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;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// normal quantile plot and derivates
+NormQuant::NormQuant(GraphObj *par, DataObj *d, char* range)
+ :Plot(par, d)
+{
+ FileIO(INIT_VARS);
+ if(range && range[0]) ssRef = (char*)memdup(range, (int)strlen(range)+1, 0);
+ else ssRef = 0L;
+ Id = GO_NORMQUANT;
+}
+
+NormQuant::NormQuant(GraphObj *par, DataObj *d, double *val, int nval)
+ :Plot(par, d)
+{
+ FileIO(INIT_VARS); ssRef = 0L;
+ if(val && nval) {
+ src_data = (double*)memdup(val, nval*sizeof(double), 0);
+ SortArray(nData = nval, src_data); ProcessData();
+ }
+ Id = GO_NORMQUANT;
+}
+
+NormQuant::NormQuant(int src):Plot(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ if(nData)SortArray(nData, src_data); ProcessData();
+ }
+}
+
+NormQuant::~NormQuant()
+{
+ if(ssRef) free(ssRef); ssRef = 0L;
+ if(x_info) free(x_info); x_info = 0L;
+ if(y_info) free(y_info); y_info = 0L;
+ if(x_vals) free(x_vals); x_vals = 0L;
+ if(y_vals) free(y_vals); y_vals = 0L;
+ if(src_data)free(src_data); src_data = 0L;
+ if(sy)delete(sy);
+}
+
+void
+NormQuant::DoPlot(anyOutput *o)
+{
+ int i;
+
+ //draw symbols
+ if(sy && y_vals && src_data && y_vals && nValidData) {
+ sy->SetSize(SIZE_SYMBOL, defs.GetSize(SIZE_SYMBOL)/10.0);
+ for(i = 0; i < nValidData; i++) {
+ sy->SetSize(SIZE_XPOS, x_vals[i]);
+ sy->SetSize(SIZE_YPOS, y_vals[i]);
+ sy->DoPlot(o);
+ }
+ }
+}
+
+bool
+NormQuant::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ switch(cmd) {
+ case CMD_LEGEND:
+ if(sy) ((Legend*)tmpl)->HasSym(0L, sy, x_info ? x_info : (char*)"Data");
+ return true;
+ case CMD_SCALE:
+ return true;
+ case CMD_UPDATE:
+ return true;
+ case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ break;
+ case CMD_SET_DATAOBJ:
+ Id = GO_NORMQUANT;
+ if(sy) sy->Command(cmd, tmpl, o);
+ data = (DataObj *)tmpl;
+ return true;
+ }
+ return false;
+}
+
+bool
+NormQuant::ProcessData()
+{
+ int i, r, c, n;
+ AccRange *rD;
+ double y, dtmp, sum;
+
+ if(data && ssRef && ssRef[0] && (rD = new AccRange(ssRef))) {
+ if((n = rD->CountItems()) && (src_data = (double*)realloc(src_data, n * sizeof(double)))){
+ for(nData = 0, rD->GetFirst(&c, &r); rD->GetNext(&c, &r); ) {
+ if(data->GetValue(r, c, &dtmp)) src_data[nData++] = dtmp;
+ }
+ if(nData)SortArray(nData, src_data);
+ }
+ if(y_info = (char*)malloc(20)){
+ rlp_strcpy(y_info, 20, "Normal quantiles");
+ }
+ x_info = rD->RangeDesc(data, 2);
+ delete rD;
+ }
+ if(src_data && nData) {
+ Bounds.Ymin = HUGE_VAL; Bounds.Ymax = -HUGE_VAL;
+ x_vals = (double*)realloc(x_vals, nData * sizeof(double));
+ y_vals = (double*)realloc(y_vals, nData * sizeof(double));
+ for(n = i = 0, sum = dtmp = 1.0/((double)nData); i < (nData-1); i++ ) {
+ y = distinv(norm_dist, 0.0, 1.0, sum, 0.5);
+ if(y > -HUGE_VAL && y < HUGE_VAL) {
+ y_vals[n] = y; x_vals[n] = src_data[i];
+ if(y < Bounds.Ymin) Bounds.Ymin = y;
+ if(y > Bounds.Ymax) Bounds.Ymax = y;
+ n++;
+ }
+ sum += dtmp;
+ }
+ Bounds.Xmax = src_data[nData-1]; Bounds.Xmin = src_data[0];
+ if(Bounds.Ymax <= Bounds.Ymin) {
+ Bounds.Ymin = -5.0; Bounds.Ymax = 5.0;
+ }
+ nValidData = n;
+ return (n > 3);
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Contour Plot
+ContourPlot::ContourPlot(GraphObj *par, DataObj *d)
+ :Plot(par, d)
+{
+ FileIO(INIT_VARS); Id = GO_CONTOUR;
+}
+
+ContourPlot::ContourPlot(int src):Plot(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+ContourPlot::~ContourPlot()
+{
+ int i;
+
+ if(Symbols) {
+ for(i = 0; i < nSym; i++) if(Symbols[i]) DeleteGO(Symbols[i]);
+ free(Symbols);
+ Symbols = 0L; nSym = 0;
+ }
+ if(Labels) {
+ for(i = 0; i < nLab; i++) if(Labels[i]) DeleteGO(Labels[i]);
+ free(Labels);
+ Labels = 0L; nLab = 0;
+ }
+ if(zAxis) DeleteGO(zAxis);
+ if(ssRefX) free(ssRefX); if(ssRefY) free(ssRefY);
+ if(ssRefZ) free(ssRefZ); ssRefX = ssRefY = ssRefZ = 0L;
+ Undo.InvalidGO(this);
+ if(name) free(name); name=0L;
+ if(val) free(val); val = 0L;
+}
+
+bool
+ContourPlot::SetSize(int select, double value)
+{
+ int i;
+
+ switch(select & 0xfff){
+ case SIZE_SYMBOL: case SIZE_SYM_LINE:
+ if(Symbols) for(i = 0; i < nSym; i++)
+ if(Symbols[i]) Symbols[i]->SetSize(select, value);
+ return true;
+ case SIZE_LB_XDIST: case SIZE_LB_YDIST:
+ if(Labels) for(i = 0; i < nLab; i++)
+ if(Labels[i]) Labels[i]->SetSize(select, value);
+ return true;
+ }
+ return false;
+}
+
+bool
+ContourPlot::SetColor(int select, DWORD col)
+{
+ int i;
+
+ switch(select) {
+ case COL_SYM_LINE: case COL_SYM_FILL:
+ if(Symbols) for(i = 0; i < nSym; i++)
+ if(Symbols[i]) Symbols[i]->SetColor(select, col);
+ return true;
+ }
+ return false;
+}
+
+void
+ContourPlot::DoPlot(anyOutput *o)
+{
+ FillDEF bg_fill={0, 0x0L, 1.0, 0L, 0x0L};
+ LineDEF bg_line = {0.0, 1.0, 0x0L, 0x0L};
+ POINT clp[4];
+ int i;
+
+ if(!zAxis){
+ DoAxis(o);
+ DoTriangulate();
+ }
+ if(zAxis) {
+ clp[0].x = clp[3].x = iround(o->Box1.Xmin); clp[0].y = clp[1].y = iround(o->Box1.Ymin);
+ clp[1].x = clp[2].x = iround(o->Box1.Xmax); clp[2].y = clp[3].y = iround(o->Box1.Ymax);
+ ClipBezier(0L, 0L, clp[0], clp[0], clp[0], clp[0], &clp[0], &clp[2]); //set clipping rectangle
+ bg_fill.color = bg_fill.color2 = bg_line.color = zAxis->GradColor(z_axis.min);
+ o->SetFill(&bg_fill); o->SetLine(&bg_line);
+ o->oPolygon(clp, 4, 0L);
+ zAxis->Command(CMD_DRAWPG, 0L, o);
+ if(Symbols) {
+ for(i = 0; i < nSym; i++) if(Symbols[i]) Symbols[i]->DoPlot(o);
+ }
+ if(Labels) {
+ for(i = 0; i < nLab; i++) if(Labels[i]) Labels[i]->DoPlot(o);
+ }
+ zAxis->DoPlot(o);
+ }
+}
+
+bool
+ContourPlot::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ int i;
+
+ switch (cmd) {
+ case CMD_MOUSE_EVENT:
+ if(hidden) return false;
+ mev = (MouseEvent *) tmpl;
+ switch(mev->Action) {
+ case MOUSE_LBUP:
+ if(Symbols) for (i = nSym-1; i >= 0; i--)
+ if(Symbols[i] && Symbols[i]->Command(cmd, tmpl, o)) return true;
+ if(Labels) for (i = nLab-1; i >= 0; i--)
+ if(Labels[i] && Labels[i]->Command(cmd, tmpl, o)) return true;
+ if(zAxis && zAxis->Command(cmd, tmpl, o)) return true;
+ break;
+ }
+ break;
+ case CMD_SETTEXTDEF:
+ if(Labels) for (i = nLab-1; i >= 0; i--)
+ if(Labels[i]) Labels[i]->Command(cmd, tmpl, o);
+ return true;
+ case CMD_SCALE:
+ if(Symbols) for (i = nSym-1; i >= 0; i--)
+ if(Symbols[i]) Symbols[i]->Command(cmd, tmpl, o);
+ if(Labels) for (i = nLab-1; i >= 0; i--)
+ if(Labels[i]) Labels[i]->Command(cmd, tmpl, o);
+ if(zAxis) zAxis->Command(cmd, tmpl, o);
+ return true;
+ case CMD_DELOBJ:
+ if(parent && DeleteGOL((GraphObj***)&Symbols, nSym, (GraphObj*) tmpl, o))
+ return parent->Command(CMD_REDRAW,0L,o);
+ if(parent && DeleteGOL((GraphObj***)&Labels, nLab, (GraphObj*) tmpl, o))
+ return parent->Command(CMD_REDRAW,0L,o);
+ return false;
+ case CMD_UPDATE:
+ if(Symbols) Undo.DropListGO(this, (GraphObj***)&Symbols, &nSym, UNDO_CONTINUE);
+ if(Labels) Undo.DropListGO(this, (GraphObj***)&Labels, &nLab, UNDO_CONTINUE);
+ LoadData(ssRefX, ssRefY, ssRefZ);
+// if(zAxis) zAxis->Command(CMD_RECALC, tmpl, o);
+// else DoAxis(o);
+ DoAxis(o);
+ if(zAxis) DoTriangulate();
+ return true;
+ case CMD_RECALC:
+ if(zAxis) zAxis->Command(cmd, tmpl, o);
+ else DoAxis(o);
+ if(zAxis) DoTriangulate();
+ return true;
+ case CMD_SET_DATAOBJ:
+ Id = GO_CONTOUR;
+ if(Symbols) for (i = nSym-1; i >= 0; i--)
+ if(Symbols[i]) Symbols[i]->Command(cmd, tmpl, o);
+ if(Labels) for (i = nLab-1; i >= 0; i--)
+ if(Labels[i]) Labels[i]->Command(cmd, tmpl, o);
+ if(zAxis) zAxis->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_SAVE_SYMBOLS:
+ return SavVarObs((GraphObj **)Symbols, nSym, 0L);
+ case CMD_SAVE_LABELS:
+ return SavVarObs((GraphObj **)Labels, nLab, 0L);
+ case CMD_SYMTEXT: case CMD_SYMTEXT_UNDO: case CMD_SYM_RANGETEXT:
+ case CMD_SYMTEXTDEF: case CMD_SYM_TYPE:
+ if(Symbols) for(i = 0; i < nSym; i++)
+ if(Symbols[i]) Symbols[i]->Command(cmd, tmpl, o);
+ return true;
+ }
+ return false;
+}
+
+bool
+ContourPlot::LoadData(char *xref, char *yref, char *zref)
+{
+ AccRange *rX, *rY, *rZ;
+ int i, n, cx, cy, cz, rx, ry, rz;
+ int nVals, nTxt, nTime;
+ bool bValid;
+ anyResult arx, ary, arz;
+
+ if(!data || !xref || !xref[0] || !yref || !yref[0] || !zref || !zref[0]) return false;
+ if(!(rX = new AccRange(xref)) || !(rY = new AccRange(yref)) || !(rZ = new AccRange(zref))) return false;
+ if(val) free(val); val = 0L; nval = 0;
+ if(3 < (n = rX->CountItems())) val = (fPOINT3D*) malloc((n+1)*sizeof(fPOINT3D));
+ 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(rX->DataTypes(data, &nVals, &nTxt, &nTime)){
+ if(!nVals && nTime > 1 && nTime > nTxt) x_dtype = ET_DATETIME;
+ else x_dtype = 0;
+ }
+ if(val && rX->GetFirst(&cx, &rx) && rY->GetFirst(&cy, &ry) && rZ->GetFirst(&cz, &rz)) {
+ i = 0;
+ while(rX->GetNext(&cx, &rx) && rY->GetNext(&cy, &ry) && rZ->GetNext(&cz, &rz)) {
+ if(data->GetResult(&arx, rx, cx) && data->GetResult(&ary, ry, cy) && data->GetResult(&arz, rz, cz)
+ && ary.type == ET_VALUE && arz.type == ET_VALUE) {
+ bValid = false;
+ if(x_dtype == ET_DATETIME && (arx.type == ET_DATE || arx.type == ET_TIME || arx.type == ET_DATETIME))
+ bValid = true;
+ else if(!x_dtype && arx.type == ET_VALUE) bValid = true;
+ if(bValid) {
+ val[i].fx = arx.value; val[i].fy = ary.value;
+ val[i].fz = arz.value; i++;
+ if(arx.value < Bounds.Xmin) Bounds.Xmin = arx.value;
+ if(arx.value > Bounds.Xmax) Bounds.Xmax = arx.value;
+ if(ary.value < Bounds.Ymin) Bounds.Ymin = ary.value;
+ if(ary.value > Bounds.Ymax) Bounds.Ymax = ary.value;
+ if(arz.value < zBounds.fx) zBounds.fx = arz.value;
+ if(arz.value > zBounds.fy) zBounds.fy = arz.value;
+ }
+ }
+ }
+ xBounds.fx = Bounds.Xmin; xBounds.fy = Bounds.Xmax;
+ yBounds.fx = Bounds.Ymin; yBounds.fy = Bounds.Ymax;
+ nval = i;
+ }
+ delete rX; delete rY; delete rZ;
+ return (nval >3);
+}
+
+bool
+ContourPlot::DoTriangulate()
+{
+ int i;
+ double srz, zsum;
+ Triangle *trl, *trn, *trc;
+ Triangulate *tria;
+
+ //check minima and maxima
+ if(!val || nval < 4) return false;
+ if((flags & 0x03) == 0x02 || Bounds.Xmax <= Bounds.Xmin || Bounds.Ymax <= Bounds.Ymin || zBounds.fy <= zBounds.fx) {
+ 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, zsum = 0.0; i < nval; i++) {
+ if(val[i].fx < Bounds.Xmin) Bounds.Xmin = val[i].fx;
+ if(val[i].fx > Bounds.Xmax) Bounds.Xmax = val[i].fx;
+ if(val[i].fy < Bounds.Ymin) Bounds.Ymin = val[i].fy;
+ if(val[i].fy > Bounds.Ymax) Bounds.Ymax = val[i].fy;
+ if(val[i].fz < zBounds.fx) zBounds.fx = val[i].fz;
+ if(val[i].fz > zBounds.fy) zBounds.fy = val[i].fz;
+ zsum += val[i].fz;
+ }
+ xBounds.fx = Bounds.Xmin; xBounds.fy = Bounds.Xmax;
+ yBounds.fx = Bounds.Ymin; yBounds.fy = Bounds.Ymax;
+ }
+ if(Bounds.Xmax <= Bounds.Xmin || Bounds.Ymax <= Bounds.Ymin || zBounds.fy <= zBounds.fx) return false;
+ //setup two super triangles
+ switch (flags & 0x03) {
+ case 0: default:
+ srz = zBounds.fx; break;
+ case 1:
+ srz = zBounds.fy; break;
+ case 2:
+ srz = (zsum/((double)nval)); break;
+ case 3:
+ srz = sr_zval; break;
+ }
+ if(!(trl = new Triangle()) || !(trn = new Triangle())) return false;
+ trl->pt[0].fz = trl->pt[1].fz = trl->pt[2].fz = srz;
+ trn->pt[0].fz = trn->pt[1].fz = trn->pt[2].fz = srz;
+ trl->pt[0].fx = trn->pt[0].fx = trl->pt[2].fx = Bounds.Xmin-(Bounds.Xmax-Bounds.Xmin)*1.0E-8;
+ trl->pt[0].fy = trn->pt[0].fy = trn->pt[1].fy = Bounds.Ymin-(Bounds.Ymax-Bounds.Ymin)*1.0E-8;
+ trl->pt[1].fx = trn->pt[2].fx = trn->pt[1].fx = Bounds.Xmax+(Bounds.Xmax-Bounds.Xmin)*1.0E-8;
+ trl->pt[1].fy = trn->pt[2].fy = trl->pt[2].fy = Bounds.Ymax+(Bounds.Ymax-Bounds.Ymin)*1.0E-8;
+ trl->SetRect(); trn->SetRect();
+ trl->next = trn; trn->next = 0L;
+ //do triangulation
+ if(!(tria = new Triangulate(trl))) {
+ delete tria; delete trl;
+ return false;
+ }
+ for(i = 0; i < nval; i++) {
+ tria->AddVertex(&val[i]);
+ }
+ trl = tria->trl; delete tria; tria = 0L;
+ //cut surface: create isopleths
+ if(!zAxis) DoAxis(0L);
+ if(zAxis && !zAxis->NumTicks) zAxis->CreateTicks();
+ if(zAxis) for(i = 0; i < zAxis->NumTicks; i++) {
+ trc = trl;
+ while(trc) {
+ trn = trc->next;
+ if(zAxis->Ticks[i]) trc->IsoLine(zAxis->Ticks[i]->GetSize(SIZE_MINE), zAxis->Ticks[i]);
+ trc = trn;
+ }
+ if(zAxis->Ticks[i]) zAxis->Ticks[i]->ProcSeg();
+ }
+ //create symbols
+ if(flags & 0x30) DoSymbols(trl);
+ //free triangle list
+ trc = trl;
+ while(trc) {
+ trn = trc->next; delete trc; trc = trn;
+ }
+ return false;
+}
+
+bool
+ContourPlot::DoAxis(anyOutput *o)
+{
+ TextDEF tlbdef;
+
+ if(!zAxis) {
+ z_axis.min = zBounds.fx; z_axis.max = zBounds.fy;
+ NiceAxis(&z_axis, 5);
+ z_axis.flags = AXIS_AUTOSCALE | AXIS_POSTICKS;
+ z_axis.loc[0].fx = z_axis.loc[1].fx = defs.GetSize(SIZE_DRECT_LEFT) + defs.GetSize(SIZE_TEXT);
+ z_axis.loc[0].fy = defs.GetSize(SIZE_DRECT_TOP) + defs.GetSize(SIZE_TEXT);
+ z_axis.loc[1].fy = defs.GetSize(SIZE_DRECT_TOP) + defs.GetSize(SIZE_TEXT)*10.0;
+ if(!(zAxis = new Axis(this, data, &z_axis, AXIS_AUTOTICK | AXIS_AUTOSCALE | AXIS_POSTICKS)))return false;
+ zAxis->SetSize(SIZE_LB_XDIST, -NiceValue(DefSize(SIZE_AXIS_TICKS)*3.0));
+ zAxis->SetSize(SIZE_TLB_XDIST, NiceValue(DefSize(SIZE_AXIS_TICKS)*2.0));
+ tlbdef.ColTxt = defs.Color(COL_AXIS); tlbdef.ColBg = 0x00ffffffL;
+ tlbdef.RotBL = tlbdef.RotCHAR = 0.0; tlbdef.iSize = 0;
+ tlbdef.fSize = DefSize(SIZE_TICK_LABELS); tlbdef.Align = TXA_VCENTER | TXA_HLEFT;
+ tlbdef.Style = TXS_NORMAL; tlbdef.Mode = TXM_TRANSPARENT;
+ tlbdef.Font = FONT_HELVETICA; tlbdef.text = 0L;
+ zAxis->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L); zAxis->type = 4;
+ zAxis->CreateTicks(); zAxis->moveable = 1;
+ }
+ else if(z_axis.flags & AXIS_AUTOSCALE) {
+ z_axis.min = zBounds.fx; z_axis.max = zBounds.fy;
+ NiceAxis(&z_axis, 4);
+ if(zAxis) {
+ zAxis->Command(CMD_AUTOSCALE, &z_axis, o);
+ zAxis->Command(CMD_RECALC, 0L, o);
+ }
+ }
+ return true;
+}
+
+void
+ContourPlot::DoSymbols(Triangle *trl)
+{
+ int i;
+ Triangle *trc;
+ fPOINT3D *vx;
+ bool isValid;
+ char lb_buff[20];
+ TextDEF td = {0x0L, 0x00ffffffL, defs.GetSize(SIZE_SYMBOL), 0.0, 0.0, 0, TXA_HLEFT | TXA_VCENTER, TXM_TRANSPARENT,
+ TXS_NORMAL, FONT_HELVETICA, lb_buff+1};
+
+ if(!val || nval < 4 || !trl || Symbols || Labels || !(flags & 0x30)) return;
+ if(!(vx = (fPOINT3D*)malloc(nval * sizeof(fPOINT3D)))) return;
+ switch(flags & 0x30) {
+ case 0x10: // at minima
+ for(i = 0; i < nval; i++) {
+ trc = trl; isValid = true;
+ do {
+ if((trc->pt[trc->order[1]].fx == val[i].fx && trc->pt[trc->order[1]].fy == val[i].fy
+ && trc->pt[trc->order[1]].fz == val[i].fz) || (trc->pt[trc->order[2]].fx == val[i].fx
+ && trc->pt[trc->order[2]].fy == val[i].fy && trc->pt[trc->order[2]].fz == val[i].fz))
+ isValid = false;
+ trc = trc->next;
+ } while(trc && isValid);
+ if(isValid) {
+ vx[nSym].fx = val[i].fx; vx[nSym].fy = val[i].fy;
+ vx[nSym].fz = val[i].fz; nSym++;
+ }
+ }
+ break;
+ case 0x20: // at maxima
+ for(i = 0; i < nval; i++) {
+ trc = trl; isValid = true;
+ do {
+ if((trc->pt[trc->order[0]].fx == val[i].fx && trc->pt[trc->order[0]].fy == val[i].fy
+ && trc->pt[trc->order[0]].fz == val[i].fz) || (trc->pt[trc->order[1]].fx == val[i].fx
+ && trc->pt[trc->order[1]].fy == val[i].fy && trc->pt[trc->order[1]].fz == val[i].fz))
+ isValid = false;
+ trc = trc->next;
+ } while(trc && isValid);
+ if(isValid) {
+ vx[nSym].fx = val[i].fx; vx[nSym].fy = val[i].fy;
+ vx[nSym].fz = val[i].fz; nSym++;
+ }
+ }
+ break;
+ case 0x30: // all values
+ for(nSym = 0; nSym < nval; nSym++) {
+ vx[nSym].fx = val[nSym].fx; vx[nSym].fy = val[nSym].fy;
+ vx[nSym].fz = val[nSym].fz;
+ }
+ break;
+ }
+ // create symbols
+ if(nSym && (flags & 0x40) && (Symbols = (Symbol**)malloc(nSym * sizeof(Symbol*)))) {
+ for(i =0; i < nSym; i++) {
+ Symbols[i] = new Symbol(this, data, vx[i].fx, vx[i].fy, 0);
+ }
+ }
+ // add labels to symbols?
+ if(nSym && (flags & 0x40) && (Labels = (Label**)malloc(nSym * sizeof(Label*)))) {
+ for(nLab = 0; nLab < nSym; nLab++) {
+ WriteNatFloatToBuff(lb_buff, vx[nLab].fz);
+ if(Labels[nLab] = new Label(this, data, vx[nLab].fx, vx[nLab].fy, &td, LB_X_DATA | LB_Y_DATA)){
+ Labels[nLab]->SetSize(SIZE_LB_XDIST, defs.GetSize(SIZE_SYMBOL));
+ }
+ }
+ }
+ free(vx);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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(nscp > 0 && nscp <= nPlots && Sc_Plots) free(Sc_Plots);
+ nscp = 0; Sc_Plots = 0L;
+ if(drag) DeleteGO(drag); drag = 0L;
+ if(dispObs) free(dispObs); dispObs = 0L;
+ free(RotDef);
+ if(name) free(name); name=0L;
+ 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:
+ return DefSize(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;
+
+ nObs = 0;
+ if(!parent || !o) return;
+ if(nscp > 0 && nscp <= nPlots && Sc_Plots) free(Sc_Plots);
+ nscp = 0; Sc_Plots = 0L; o->MouseCursor(MC_WAIT, true);
+ if(dirty) DoAutoscale();
+ if(Axes && nAxes >2) { //if no axes then parent is another Plot3D ...
+ o->LightSource(32.0, 16.0); CurrAxes = Axes;
+ 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;
+ o->SetSpace(&cu1, &cu2, defs.cUnits, RotDef, &rc, Axes[0]->GetAxis(),
+ Axes[1]->GetAxis(), Axes[2]->GetAxis());
+ if(nAxes >3) { //DEBUG
+ nAxes = nAxes;
+ }
+ for(i = 0; i< nAxes; i++) if(Axes[i]) Axes[i]->DoPlot(o);
+ }
+ else if(IsPlot3D(parent)) {
+ if (use_xaxis || use_yaxis || use_zaxis)ApplyAxes(o);
+ parent->Command(CMD_REG_AXISPLOT, (void*)this, o);
+ }
+ else CurrAxes = 0L;
+ 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;
+ if(nObs >1 && dispObs){
+ SortObj();
+ for (i = 1; i <= nObs; i++){
+ for(j = 1; 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);
+ }
+ if(IsPlot3D(parent) && (use_xaxis || use_yaxis || use_zaxis))parent->Command(CMD_AXIS, 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_SCALE:
+ cub1.fx *= ((scaleINFO*)tmpl)->sx.fy; cub1.fy *= ((scaleINFO*)tmpl)->sy.fy;
+ cub1.fz *= ((scaleINFO*)tmpl)->sz.fy; cub2.fx *= ((scaleINFO*)tmpl)->sx.fy;
+ cub2.fy *= ((scaleINFO*)tmpl)->sy.fy; cub2.fz *= ((scaleINFO*)tmpl)->sz.fy;
+ rotC.fx *= ((scaleINFO*)tmpl)->sx.fy; rotC.fy *= ((scaleINFO*)tmpl)->sy.fy;
+ rotC.fz *= ((scaleINFO*)tmpl)->sz.fy;
+ 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_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_USEAXIS:
+ if(IsPlot3D(parent)) return UseAxis(*((int*)tmpl));
+ break;
+ case CMD_REG_AXISPLOT: //notification: plot can handle its own axes
+ if(nscp > 0 && nscp <= nPlots && 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_AXIS: //one of the plots has changed scaling: reset
+ CurrAxes = Axes;
+ if(o) o->SetSpace(&cu1, &cu2, defs.cUnits, RotDef, &rc, Axes[0]->GetAxis(),
+ Axes[1]->GetAxis(), Axes[2]->GetAxis());
+ return true;
+ 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);
+ if(plots[i]->Id > GO_PLOT && plots[i]->Id < GO_GRAPH) plots[i]->Command(cmd, tmpl, o);
+ }
+ 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:
+ if(IsPlot3D(parent)) return parent->Command(cmd, tmpl, o);
+ return dirty = true;
+ case CMD_ADDAXIS:
+ if(AddAxis()){
+ if(parent) return parent->Command(CMD_REDRAW, tmpl, o);
+ }
+ return false;
+ case CMD_SET_GO3D:
+ if(IsPlot3D(parent)) return parent->Command(CMD_REDRAW, 0L, o);
+ 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(DeleteGOL((GraphObj***)&plots,nPlots,(GraphObj*)tmpl,o)) return parent->Command(CMD_REDRAW,0L,o);
+ return false;
+ 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(IsPlot3D(parent)) return parent->Command(cmd, tmpl, o);
+ 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 = DefSize(SIZE_AXIS_TICKS);
+ int i;
+ if(Axes || !parent)return;
+ TextDEF tlbdef = {parent->GetColor(COL_AXIS), 0x00ffffffL, DefSize(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+DefSize(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+DefSize(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+DefSize(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]) {
+ if(plots[i]->Id >= GO_PLOT && plots[i]->Id < GO_GRAPH) {
+ if(!((Plot*)plots[i])->hidden) plots[i]->Command(CMD_AUTOSCALE, 0L, 0L);
+ }
+ else 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);
+ }
+ }
+ else if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH) {
+ ((Plot*)parent)->CheckBounds3D(xBounds.fx, yBounds.fx, zBounds.fx);
+ ((Plot*)parent)->CheckBounds3D(xBounds.fy, yBounds.fy, zBounds.fy);
+ }
+ }
+}
+
+//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
+int
+Plot3D::cmp_obj_desc(obj_desc *obj1, obj_desc *obj2)
+{
+ double *v1, *v2, tmp1, tmp2;
+
+ if(obj1->go->Id == GO_PLANE && obj2->go->Id == GO_PLANE) {
+ if(obj1->Zmax < obj2->Zmin) return -1;
+ if(obj2->Zmax < obj1->Zmin) return 1;
+ if(obj1->Zmax == obj2->Zmax) {
+ if(obj1->Zmin < obj2->Zmin) return -1;
+ else if(obj1->Zmin > obj2->Zmin) return 1;
+ else return 0;
+ }
+ if((v1=((plane*)(obj1->go))->GetVec()) && (v2=((plane*)(obj2->go))->GetVec()) ) {
+ if(v1[0] == v2[0] && v1[1] == v2[1] && v1[2] == v2[2]){
+ if(obj1->Zmax < obj2->Zmax) return -1;
+ else if(obj2->Zmax < obj1->Zmax) return 1;
+ else return 0;
+ }
+ }
+ tmp1 = obj1->Zmax + obj1->Zmin; tmp2 = obj2->Zmax + obj2->Zmin;
+ if(tmp1 < tmp2) return -1;
+ else if(tmp1 > tmp2) return 1;
+ else return 0;
+ }
+ else {
+ if(obj1->Zmin < obj2->Zmin) return -1;
+ if(obj1->Zmin > obj2->Zmin) return 1;
+ }
+ return 0;
+}
+
+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 && cmp_obj_desc(dispObs[j], dispObs[j+1]) < 0) ++j;
+ if(cmp_obj_desc(rra, dispObs[j])) {
+ 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;
+
+ o->SetSpace(&cu1, &cu2, defs.cUnits, RotDef, &rc, Axes[0]->GetAxis(),
+ Axes[1]->GetAxis(), Axes[2]->GetAxis());
+ 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()
+{
+ if(name) free(name); name=0L;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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()
+{
+ if(name) free(name); name=0L;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// use Plot3D to create a 3 dimensional bubble plot
+BubblePlot3D::BubblePlot3D(GraphObj *par, DataObj *d)
+ :Plot3D(par, d, 0x0L)
+{
+}
+
+BubblePlot3D::~BubblePlot3D()
+{
+ if(name) free(name); name=0L;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 3D function plotter
+Func3D::Func3D(GraphObj *par, DataObj *d)
+ :Plot3D(par, d, 0x0L)
+{
+ FileIO(INIT_VARS);
+ if(cmdxy = (char*)malloc(40*sizeof(char)))
+ rlp_strcpy(cmdxy, 40, (char*)"r=sqrt(x*x+z*z)\ny=1-exp(-8/(r+1))");
+ Id = GO_FUNC3D;
+}
+
+Func3D::Func3D(int src):Plot3D(0)
+{
+ int i;
+
+ 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;
+ }
+}
+
+Func3D::~Func3D()
+{
+ if(param) free(param); param = 0L;
+ if(cmdxy) free(cmdxy); cmdxy = 0L;
+ if(gda) delete(gda); gda = 0L;
+ if(name) free(name); name=0L;
+}
+
+bool
+Func3D::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ switch(cmd) {
+ case CMD_SET_DATAOBJ:
+ Plot3D::Command(cmd, tmpl, o);
+ if(gob && gda) gob->Command(cmd, gda, o);
+ Id = GO_FUNC3D;
+ return true;
+ case CMD_UPDATE:
+ return Update();
+ break;
+ }
+ return Plot3D::Command(cmd, tmpl, o);
+}
+
+bool
+Func3D::Update()
+{
+ if(cmdxy) {
+ dirty = true;
+ if(xstep == 0.0) xstep = 1.0; if(zstep == 0.0) zstep = 1.0;
+ if(!gda) gda = new DataObj();
+ if(gda && do_func3D(gda, x1, x2, xstep, z1, z2, zstep, cmdxy, param)) {
+ if(gob = new Grid3D(this, gda, type, x1, xstep, z1, zstep)) {
+ gob->Command(CMD_SET_LINE, &Line, 0L);
+ gob->Command(CMD_SYM_FILL, &Fill, 0L);
+ if(!plots && (plots = (GraphObj**)calloc(2, sizeof(GraphObj*)))) {
+ nPlots = 1; plots[0] = (Plot *)gob;
+ if(parent->Id == GO_GRAPH) CreateAxes();
+ return dirty = parent->Command(CMD_REDRAW, 0L, 0L);
+ }
+ else if(plots && nPlots && plots[0]->Id == GO_GRID3D) {
+ Undo.DeleteGO(&plots[0], UNDO_CONTINUE, 0L);
+ Undo.SetGO(this, &plots[0], gob, UNDO_CONTINUE);
+ return true;
+ }
+ else {
+ DeleteGO(gob); gob=0L;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// fit 3D function to data
+static char *lastFunc3D = 0L, *lastParam3D=0L;
+FitFunc3D::FitFunc3D(GraphObj *par, DataObj *d)
+ :Plot3D(par, d, 0x0L)
+{
+ FileIO(INIT_VARS);
+ if(lastFunc3D && lastFunc3D[0] && lastParam3D && lastParam3D[0]) {
+ cmdxy = (char*)memdup(lastFunc3D, (int)strlen(lastFunc3D)+1, 0);
+ param = (char*)memdup(lastParam3D, (int)strlen(lastParam3D)+1, 0);
+ }
+ if(!cmdxy || !param) {
+ cmdxy = (char*)malloc(20*sizeof(char)); param = (char*)malloc(20*sizeof(char));
+ if(cmdxy) rlp_strcpy(cmdxy, 20, (char*)"a+b*x^c");
+ if(param) rlp_strcpy(param, 20, (char*)"a=1; b=1; c=0.1;");
+ }
+ Id = GO_FITFUNC3D;
+}
+
+FitFunc3D::FitFunc3D(int src):Plot3D(0)
+{
+ int i;
+
+ 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;
+ }
+}
+
+FitFunc3D::~FitFunc3D()
+{
+ if(param) free(param); param = 0L;
+ if(cmdxy) free(cmdxy); cmdxy = 0L;
+ if(gda) delete(gda); gda = 0L;
+ if(name) free(name); name=0L;
+}
+
+bool
+FitFunc3D::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i;
+
+ switch(cmd) {
+ case CMD_ENDDIALOG:
+ if(!cmdxy || !param) return false;
+ if(i = (int)strlen(cmdxy)) {
+ if(lastFunc3D = (char*)realloc(lastFunc3D, i+2))
+ rlp_strcpy(lastFunc3D, i+1, cmdxy);
+ }
+ if(i = (int)strlen(param)) {
+ if(lastParam3D = (char*)realloc(lastParam3D, i+2))
+ rlp_strcpy(lastParam3D, i+1, param);
+ }
+ return true;
+ case CMD_SET_DATAOBJ:
+ Plot3D::Command(cmd, tmpl, o);
+ if(gob && gda) gob->Command(cmd, gda, o);
+ Id = GO_FITFUNC3D;
+ return true;
+ case CMD_UPDATE:
+ return Update();
+ break;
+ }
+ return Plot3D::Command(cmd, tmpl, o);
+}
+
+bool
+FitFunc3D::Update()
+{
+ if(cmdxy) {
+ dirty = true;
+ if(xstep == 0.0) xstep = 1.0; if(zstep == 0.0) zstep = 1.0;
+ if(!gda) gda = new DataObj();
+ if(gda && do_func3D(gda, x1, x2, xstep, z1, z2, zstep, cmdxy, param)) {
+ if(gob = new Grid3D(this, gda, type, x1, xstep, z1, zstep)) {
+ gob->Command(CMD_SET_LINE, &Line, 0L);
+ gob->Command(CMD_SYM_FILL, &Fill, 0L);
+ if(!plots && (plots = (GraphObj**)calloc(3, sizeof(GraphObj*)))) {
+ nPlots = 1; plots[0] = (Plot *)gob;
+ if(parent->Id == GO_GRAPH) CreateAxes();
+ return dirty = parent->Command(CMD_REDRAW, 0L, 0L);
+ }
+ else if(plots && nPlots && plots[0]->Id == GO_GRID3D) {
+ Undo.DeleteGO(&plots[0], UNDO_CONTINUE, 0L);
+ Undo.SetGO(this, &plots[0], gob, UNDO_CONTINUE);
+ return true;
+ }
+ else {
+ DeleteGO(gob); gob=0L;
+ }
+ }
+ }
+ }
+ return false;
+}
diff --git a/PropertyDlg.cpp b/PropertyDlg.cpp
index 4a6230d..979d340 100755
--- a/PropertyDlg.cpp
+++ b/PropertyDlg.cpp
@@ -1,9867 +1,10124 @@
-//PropertyDlg.cpp, Copyright (c) 2001-2007 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 <time.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
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *SymDlg_DlgTmpl =
- "1,+,,DEFAULT,PUSHBUTTON,-1,145,10,60,12\n"
- ".,.,,,PUSHBUTTON,2,145,25,60,12\n"
- ".,.,,,PUSHBUTTON,-2,145,40,60,12\n"
- ".,50,5,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
- ".,+,100,ISPARENT | CHECKED,SHEET,3,5,10,130,113\n"
- ".,.,200,TOUCHEXIT | ISPARENT,SHEET,4,5,10,130,113\n"
- ".,,300,ISPARENT,SHEET,5,5,10,130,113\n"
- "50,,,TOUCHEXIT,SYMBUTT,0,155,75,40,40\n"
- "100,+,,,RTEXT,6,5,25,45,8\n"
- ".,.,,TOUCHEXIT,INCDECVAL1,9,55,25,32,10\n"
- ".,.,,,LTEXT,-3,89,25,20,8\n"
- ".,.,,,RTEXT,10,5,37,45,8\n"
- ".,.,,TOUCHEXIT,INCDECVAL1,11,55,37,32,10\n"
- ".,.,,,LTEXT,-3,89,37,20,8\n"
- ".,.,,,RTEXT,12,5,49,45,8\n"
- ".,.,,TOUCHEXIT | OWNDIALOG, COLBUTT,13,55,49,25,10\n"
- ".,.,,,RTEXT,14,5,61,45,8\n"
- ".,401,,TOUCHEXIT | OWNDIALOG,COLBUTT,15,55,61,25,10\n"
- "200,204,201,CHECKED | ISPARENT, GROUPBOX,16,12,28,50,39\n"
- ".,+,,TOUCHEXIT, RADIO1,17,15,33,45,8\n"
- ".,.,,TOUCHEXIT, RADIO1,18,15,43,45,8\n"
- ".,,,TOUCHEXIT, RADIO1,19,15,53,43,8\n"
- ".,250,205,CHECKED | ISPARENT, GROUPBOX,20,72,28,57,39\n"
- "205,+,,TOUCHEXIT, CHECKBOX,21,75,33,25,8\n"
- ".,.,,TOUCHEXIT, CHECKBOX,22,75,43,25,8\n"
- ".,,,TOUCHEXIT, CHECKBOX,23,75,53,25,8\n"
- "250,+,,TOUCHEXIT | CHECKED, RADIO1,24,10,75,45,8\n"
- ".,.,,,EDTEXT,25,60,75,68,10\n"
- ".,.,,TOUCHEXIT,RADIO1,26,10,92,60,8\n"
- ".,,,,EDTEXT,27,20,102,100,10\n"
- "300,+,,,RTEXT,-12,5,30,45,8\n"
- ".,.,,,EDVAL1,7,55,30,45,10\n"
- ".,.,,,RTEXT,-13,5,50,45,8\n"
- ".,,,LASTOBJ,EDVAL1,8,55,50,45,10";
-
-bool
-Symbol::PropertyDlg()
-{
- TabSHEET tab1 = {0, 47, 10, "Size & Color"};
- TabSHEET tab2 = {47, 70, 10, "Text"};
- TabSHEET tab3 = {70, 92, 10, "Edit"};
- Symbol *PrevSym = 0L;
- char text1[40], text2[100];
- void *dyndata[] = {(void*)"Apply to Symbol", (void*)"Apply to PLOT", (void*)&tab1,
- (void*)&tab2, (void*)&tab3, (void*)"size", (void*)&fPos.fx, (void*)&fPos.fy,
- (void*)&size, (void*)"line width", (void*)&SymLine.width, (void*)"line color",
- (void *)&SymLine.color, (void*)"fill color", (void *)&SymFill.color, (void*)" font ",
- (void*)"Helvetica", (void*)"Times", (void*)"Courier", (void*)" style ", (void*)"bold",
- (void*)"italic", (void*)"underlined", (void*)"fixed text:", (void*)text1,
- (void*)"from spreadsheet range:", (void*)text2};
- DlgInfo *SymDlg;
- DlgRoot *Dlg;
- void *hDlg;
- int i, k, ix, iy, tmpType, res, width, height, n_syms;
- DWORD tmpCol, undo_flags = 0L;
- double tmpVal, o_size, n_size, o_lwidth, n_lwidth;
- TextDEF textdef;
- anyOutput *cdisp = Undo.cdisp;
- lfPOINT o_pos, n_pos;
- static const int syms[] = {SYM_CIRCLE, SYM_CIRCLEF, SYM_CIRCLEC, SYM_RECT, SYM_RECTF, SYM_RECTC,
- SYM_TRIAU, SYM_TRIAUF, SYM_TRIAUC, SYM_TRIAUL, SYM_TRIAUR, SYM_TRIAD, SYM_TRIADF, SYM_TRIADC,
- SYM_TRIADL, SYM_TRIADR, SYM_DIAMOND, SYM_DIAMONDF, SYM_DIAMONDC, SYM_5GON, SYM_5GONF, SYM_5GONC,
- SYM_4STAR, SYM_4STARF, SYM_5STAR, SYM_5STARF, SYM_6STAR, SYM_6STARF, SYM_1QUAD, SYM_2QUAD,
- SYM_3QUAD, SYM_PLUS, SYM_CROSS, SYM_STAR, SYM_HLINE, SYM_VLINE, SYM_TEXT};
-
- if(!(SymDlg = CompileDialog(SymDlg_DlgTmpl, dyndata)))return false;
- if(!Command(CMD_GETTEXT, (void*)text1, 0L)) rlp_strcpy(text1, 40, "text");
-#ifdef USE_WIN_SECURE
- if(parent && data && data->GetSize(&width, &height)) sprintf_s(text2, 100, "b1:b%d", height);
-#else
- if(parent && data && data->GetSize(&width, &height)) sprintf(text2, "b1:b%d", height);
-#endif
- else rlp_strcpy(text2, 100, "(not available)");
- n_syms = sizeof(syms)/sizeof(int);
- for(k = 1; !(SymDlg[k-1].flags & LASTOBJ); k++);
- if(!parent) n_syms--;
- if(!(SymDlg = (DlgInfo *)realloc(SymDlg, (k+n_syms)*sizeof(DlgInfo)))) return false;
- SymDlg[k-1].flags &= (~LASTOBJ);
- for(i = 1, iy = 66; i <= n_syms; i++, ix += 10) {
- if((i%11) == 1) {
- iy += 10; ix = 15;
- }
- SymDlg[k].id = 400 + i; SymDlg[k].next = 400 + i + 1;
- SymDlg[k].first = 0; SymDlg[k].flags = TOUCHEXIT;
- SymDlg[k].type = SYMRADIO; SymDlg[k].ptype = (void*)&syms[i-1];
- SymDlg[k].x = ix; SymDlg[k].y = iy;
- if(type == syms[i-1]) SymDlg[k].flags |= CHECKED;
- SymDlg[k].w = SymDlg[k].h = 10; k++;
- }
- SymDlg[k-1].flags |= LASTOBJ; if(parent) SymDlg[k-1].w = 30;
- if(parent) {
- SymDlg[0].ptype = dyndata[0];
- }
- else {
- SymDlg[5].flags |= HIDDEN; SymDlg[6].flags |= HIDDEN;
- SymDlg[1].flags |= HIDDEN; SymDlg[2].y = 25;
- SymDlg[0].w = SymDlg[2].w = 45; SymDlg[7].x = 145;
- }
- 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;
- SymDlg[7].ptype = (void*)&PrevSym;
- }
- if(PrevSym && (Dlg = new DlgRoot(SymDlg, data))) {
- 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);
- 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 && parent->name) {
- width = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Symbol of ");
- rlp_strcpy(TmpTxt+width, TMP_TXT_SIZE-width, parent->name);
- width =10;
- }
- else {
- rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Symbol properties");
- }
- if(!(hDlg = CreateDlgWnd(TmpTxt, 50, 50, parent ? 430 : 400, 292, 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 1: case 2:
- Undo.SetDisp(cdisp);
- if(parent && PrevSym->type == SYM_TEXT && Dlg->GetCheck(250)){
- Dlg->GetText(251, text1, 40);
- 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(parent && PrevSym->type == SYM_TEXT && Dlg->GetCheck(252)) {
- if(Dlg->GetCheck(252) && Dlg->GetText(253, text2, 100))
- PrevSym->Command(CMD_RANGETEXT, &text2, 0L);
- }
- Dlg->GetValue(101, &n_size); Dlg->GetValue(104, &n_lwidth);
- break;
- case 6: //the text sheets
- if(parent)Dlg->SetCheck(400+n_syms, 0L, true);
- if(PrevSym->type != SYM_TEXT) {
- PrevSym->type = SYM_TEXT; Dlg->DoPlot(0L);
- }
- 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(0L);
- }
- res = -1;
- break;
- default: //symbol selection ?
- if(res > 400 && res <= (400+n_syms)) tmpType = syms[res-401];
- else break;
- 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 50: //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,40))PrevSym->Command(CMD_SETTEXT, text1, 0L);
- else if(Dlg->GetCheck(252) && Dlg->GetText(253, text2,100))
- PrevSym->Command(CMD_RANGETEXT, text2, 0L);
- }
- Dlg->DoPlot(0L);
- 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,40))PrevSym->Command(CMD_SETTEXT, text1, 0L);
- else if(Dlg->GetCheck(252) && Dlg->GetText(253, text2, 100))
- 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);
- undo_flags |= UNDO_CONTINUE;
- 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, 100))
- 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; free(SymDlg);
- delete PrevSym; return undo_flags != 0;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Bubble properties dialog
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *BubDlg_DlgTmpl =
- "1,2,,DEFAULT,PUSHBUTTON,1,130,10,60,12\n"
- "2,3,,,PUSHBUTTON,2,130,25,60,12\n"
- "3,4,,,PUSHBUTTON,-2,130,40,60,12\n"
- "4,,5,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
- "5,6,100,ISPARENT | CHECKED,SHEET,3,5,10,120,100\n"
- "6,7,200,ISPARENT,SHEET,4,5,10,120,100\n"
- "7,,300,ISPARENT,SHEET,5,5,10,120,100\n"
- "100,109,,NOSELECT,ODBUTTON,6,18,57,90,50\n"
- "109,110,,,SYMRADIO,7,30,30,20,20\n"
- "110,111,,,SYMRADIO,8,50,30,20,20\n"
- "111,112,,,SYMRADIO,9,70,30,20,20\n"
- "112,,,,SYMRADIO,10,90,30,20,20\n"
- "200,201,,,LTEXT,11,10,30,110,8\n"
- "201,202,210, ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "202,203,,,LTEXT,12,10,64,110,8\n"
- "203,, 220,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "210,211,,,RADIO1,-3,40,38,45,8\n"
- "211,212,,,RADIO1,13,40,46,45,8\n"
- "212,,,,RADIO1,14,40,54,45,8\n"
- "220,221,,,RADIO1,15,40,72,45,8\n"
- "221,222,,,RADIO1,16,40,80,45,8\n"
- "222,0,,,RADIO1,17,40,88,45,8\n"
- "300,301,,,RTEXT,-12,10,40,45,8\n"
- "301,302,,,EDVAL1,18,60,40,35,10\n"
- "302,303,,,RTEXT,-13,10,60,45,8\n"
- "303,304,,,EDVAL1,19,60,60,35,10\n"
- "304,305,,,RTEXT,20,10,80,45,8\n"
- "305,,,LASTOBJ, EDVAL1,21,60,80,35,10";
-
-bool
-Bubble::PropertyDlg()
-{
- TabSHEET tab1 = {0, 52, 10, "Shape & Color"};
- TabSHEET tab2 = {52, 84, 10, "Scaling"};
- TabSHEET tab3 = {84, 106, 10, "Edit"};
- int syms[] = {SYM_CIRCLE, SYM_RECT, SYM_TRIAU, SYM_TRIAD};
- void *dyndata[] = {(void*)"Apply to BUBBLE", (void*)"Apply to PLOT", (void*)&tab1, (void*)&tab2,
- (void*)&tab3, (void*)&OD_filldef, (void *)&syms[0], (void *)&syms[1], (void *)&syms[2], (void *)&syms[3],
- (void*)"Sizes are given as", (void*)"Proportionality (relative to circle)", (void*)"scaling with X axis",
- (void*)"scaling with Y axis", (void*)"diameter", (void*)"circumference", (void*)"area", (void*)&fPos.fx,
- (void*)&fPos.fy, (void*)"size", (void*)&fs};
- DlgInfo *BubDlg = CompileDialog(BubDlg_DlgTmpl, dyndata);
- DlgRoot *Dlg;
- void *hDlg;
- int cb, res, tmpType;
- lfPOINT o_pos, n_pos;
- LineDEF newLine, newFillLine;
- FillDEF newFill;
- DWORD undo_flags = 0L;
- anyOutput *cdisp = Undo.cdisp;
- 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, data);
- 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) {
- cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Bubble of ");
- rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
- }
- else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Bubble properties");
- hDlg = CreateDlgWnd(TmpTxt, 50, 50, 396, 260, Dlg, 0x0L);
- do {
- LoopDlgWnd();
- res = Dlg->GetResult();
- switch(res) {
- case 1: //accept for current bubble only
- case 2: //accept for plot
- Undo.SetDisp(cdisp);
- 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; free(BubDlg); return bRet;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Bar properties dialog
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *BarDlg_DlgTmpl =
- "1,+,,DEFAULT,PUSHBUTTON,1,130,10,55,12\n"
- ".,.,,,PUSHBUTTON,2,130,25,55,12\n"
- ".,.,,,PUSHBUTTON,-2,130,40,55,12\n"
- ".,,5,CHECKED | ISPARENT,GROUP,0,138,40,55,12\n"
- "5,+,100,ISPARENT | CHECKED,SHEET,3,5,10,120,120\n"
- ".,.,200,ISPARENT,SHEET,4,5,10,120,120\n"
- ".,,300,ISPARENT,SHEET,5,5,10,120,120\n"
- "100,109,,NOSELECT,ODBUTTON,6,18,30,90,50\n"
- "109,+,,,LTEXT,7,10,80,45,8\n"
- ".,.,,,RADIO1,8,20,92,25,8\n"
- ".,.,,,EDTEXT,9,60,92,25,10\n"
- ".,.,,,LTEXT,-3,87,92,20,8\n"
- ".,.,,,RADIO1,10,20,104,25,8\n"
- ".,.,,,EDTEXT,11,60,104,25,10\n"
- ".,,,,LTEXT,-10,87,104,10,8\n"
- "200,+,,TOUCHEXIT,RADIO2,12,20,30,45,8\n"
- ".,205,202,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
- ".,+,,TOUCHEXIT,RADIO1,13,30,40,35,8\n"
- ".,.,,TOUCHEXIT,RADIO1,14,30,48,35,8\n"
- ".,,,TOUCHEXIT,RADIO1,15,30,56,35,8\n"
- "205,+,,,EDVAL1,16,65,56,35,10\n"
- ".,.,,TOUCHEXIT,RADIO2,17,20,70,45,8\n"
- ".,211,208,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
- "208,+,,TOUCHEXIT,RADIO1,18,30,80,35,8\n"
- ".,.,,TOUCHEXIT,RADIO1,19,30,88,35,8\n"
- ".,,,TOUCHEXIT,RADIO1,20,30,96,35,8\n"
- "211,+,,,EDVAL1,21,65,96,35,10\n"
- ".,,,,CHECKBOX,22,20,113,50,8\n"
- "300,+,,,RTEXT,-12,10,50,45,8\n"
- ".,.,,,EDVAL1,23,60,50,40,10\n"
- ".,.,,,RTEXT,-13,10,75,45,8\n"
- ".,,,LASTOBJ,EDVAL1,24,60,75,40,10";
-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];
- void *dyndata[] = {(void*)"Apply to BAR", (void*)"Apply to PLOT", (void*)&tab1,
- (void*)&tab2, (void*)&tab3, (void*)OD_filldef, (void*)"bar width:", (void*)" fixed",
- (void*)&sTxt1[1], (void*)" relative", (void*)&sTxt2[1], (void*)"vertical bars",
- (void*)"bottom baseline", (void*)"top", (void*)"user y =", (void*)&BarBase.fy,
- (void*)"horizontal bars", (void*)"left baseline", (void*)"right", (void*)"user x =",
- (void*)&BarBase.fx, (void*)"bars centered across baseline", (void*)&fPos.fx, (void*)&fPos.fy};
- DlgInfo *BarDlg = CompileDialog(BarDlg_DlgTmpl, dyndata);
- DlgRoot *Dlg;
- void *hDlg;
- double n_size;
- int cb, res, tmpType = type;
- bool bRet = false;
- LineDEF newLine, newFillLine;
- FillDEF newFill;
- DWORD undo_flags = 0L;
- anyOutput *cdisp = Undo.cdisp;
- 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, DefSize(SIZE_BAR));
- }
- else {
- WriteNatFloatToBuff(sTxt1, size);
- rlp_strcpy(sTxt2, 20, " 50");
- }
- Dlg = new DlgRoot(BarDlg, data);
- 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->name) {
- cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Bar of ");
- rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
- }
- else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "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, 300, 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:
- Undo.SetDisp(cdisp);
- 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; free(BarDlg);
- return bRet;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Data line properties dialog
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *LineDlg_DlgTmpl =
- "1,2,,DEFAULT,PUSHBUTTON,-1,150,10,45,12\n"
- "2,3,,,PUSHBUTTON,-2,150,25,45,12\n"
- "3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "4,5,100,ISPARENT | CHECKED,SHEET,1,5,10,139,120\n"
- "5,6,200,ISPARENT,SHEET,2,5,10,139,120\n"
- "6,,300,ISPARENT | HIDDEN,SHEET,3,5,10,139,120\n"
- "100,,,NOSELECT,ODBUTTON,9,10,38,130,100\n"
- "200,201,,,LTEXT,4,10,32,130,100\n"
- "201,202,,EXRADIO,ODBUTTON,10,12,45,25,25\n"
- "202,203,,EXRADIO,ODBUTTON,10,37,45,25,25\n"
- "203,204,,EXRADIO,ODBUTTON,10,62,45,25,25\n"
- "204,205,,EXRADIO,ODBUTTON,10,87,45,25,25\n"
- "205,206,,EXRADIO,ODBUTTON,10,112,45,25,25\n"
- "206,207,,EXRADIO,ODBUTTON,10,37,70,25,25\n"
- "207,208,,EXRADIO,ODBUTTON,10,62,70,25,25\n"
- "208,209,,EXRADIO,ODBUTTON,10,87,70,25,25\n"
- "209,210,,EXRADIO,ODBUTTON,10,112,70,25,25\n"
- "210,211,,EXRADIO,ODBUTTON,10,37,95,25,25\n"
- "211,212,,EXRADIO,ODBUTTON,10,62,95,25,25\n"
- "212,,,EXRADIO,ODBUTTON,10,87,95,25,25\n"
- "300,301,,,LTEXT,5,15,30,80,9\n"
- "301,302,,,EDTEXT,7,15,40,119,10\n"
- "302,303,,,LTEXT,6,15,55,80,9\n"
- "303,,,LASTOBJ,EDTEXT,8,15,65,119,10";
-
-bool
-DataLine::PropertyDlg()
-{
- TabSHEET tab1 = {0, 40, 10, "Line"};
- TabSHEET tab2 = {40, 80, 10, "Style"};
- TabSHEET tab3 = {80, 120, 10, "Edit"};
- void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"select style:",
- (void*)"range for x-values", (void*)"range for y-values", (void*)ssXref, (void*)ssYref,
- (void*)OD_linedef, (void*)(OD_LineStyleTempl)};
- DlgInfo *LineDlg = CompileDialog(LineDlg_DlgTmpl, dyndata);
- DlgRoot *Dlg;
- void *hDlg;
- int cb, res, tmpType = type;
- DWORD undo_flags = 0L;
- LineDEF newLine;
- bool bRet = false;
- anyOutput *cdisp = Undo.cdisp;
-
- 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, data)))return false;
- Dlg->SetCheck(201 + (type & 0x0f), 0L, true);
- if(ssXref && ssYref) Dlg->ShowItem(6, true);
- if(parent->name) {
- cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Line of ");
- rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
- }
- else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "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: case 210: case 211: case 212:
- if((tmpType & 0x0f) == (res-201)) res = 1;
- else {
- tmpType &= ~0x0f; tmpType |= (res-201);
- res = -1;
- }
- break;
- }
- }while (res < 0);
- if(res == 1){ //OK pressed
- Undo.SetDisp(cdisp);
- if(ssXref && ssYref) {
- TmpTxt[0] = 0; Dlg->GetText(301, TmpTxt, TMP_TXT_SIZE);
- undo_flags = CheckNewString(&ssXref, ssXref, TmpTxt, this, undo_flags);
- TmpTxt[0] = 0; Dlg->GetText(303, TmpTxt, TMP_TXT_SIZE);
- undo_flags = CheckNewString(&ssYref, ssYref, TmpTxt, this, undo_flags);
- if(undo_flags & UNDO_CONTINUE) {
- Command(CMD_UPDATE, 0L, cdisp); parent->Command(CMD_MRK_DIRTY, 0L, cdisp);
- }
- }
- 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; free(LineDlg); 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;
- anyOutput *cdisp = Undo.cdisp;
- int cb, 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, data);
- if(parent->name) {
- cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Polygon of ");
- rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
- }
- else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Polygon properties");
- hDlg = CreateDlgWnd(TmpTxt, 50, 50, 310, 210, Dlg, 0x0L);
- do{
- LoopDlgWnd();
- res = Dlg->GetResult();
- }while (res < 0);
- if(res == 1){ //OK pressed
- Undo.SetDisp(cdisp);
- 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[60], text2[60], text3[60], text4[60], text5[60];
- 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 cb, res, tmpType;
- bool bRet = false;
- LineDEF newLine;
- DWORD undo_flags = 0L;
- anyOutput *cdisp = Undo.cdisp;
- 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;
- }
-#ifdef USE_WIN_SECURE
- sprintf_s(text1, 60, "%s = %.3lf + %.3lf * %s (n = %ld)", ty, l1.fx, l1.fy, tx, nPoints);
- sprintf_s(text2, 60, "%s = %.3lf + %.3lf * %s", ty, l2.fx, l2.fy, tx);
- sprintf_s(text3, 60, "%s = %.3lf + %.3lf * %s", ty, l3.fx, l3.fy, tx);
- sprintf_s(text4, 60, "%s = %.3lf + %.3lf * %s", ty, l4.fx, l4.fy, tx);
- sprintf_s(text5, 60, "%s = a + b * %s", ty, tx);
-#else
- 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);
-#endif
- if(!(Dlg = new DlgRoot(LineDlg, data))) 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->name) {
- cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Regression line of ");
- rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
- }
- else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "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
- Undo.SetDisp(cdisp);
- 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
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char* SdEllipseDlg_Tmpl =
- "1,+,,DEFAULT,PUSHBUTTON,-1,150,10,45,12\n"
- ".,.,,,PUSHBUTTON,-2,150,25,45,12\n"
- ".,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "4,+,100,ISPARENT | CHECKED,SHEET,1,5,10,139,140\n"
- ".,,200,ISPARENT,SHEET,2,5,10,139,140\n"
- "100,,,NOSELECT,ODBUTTON,3,10,48,130,100\n"
- "200,+,,,CHECKBOX,4,20,26,80,9\n"
- ".,.,250,CHECKED, GROUPBOX,5,10,45,129,100\n"
- "250,+,,,LTEXT,6,25,82,60,8\n"
- ".,.,,,RTEXT,7,20,92,60,8\n"
- ".,.,,,LTEXT,0,82,92,30,8\n"
- ".,.,,,RTEXT,8,20,100,60,8\n"
- ".,.,,,LTEXT,0,82,100,30,8\n"
- ".,.,,,LTEXT,9,25,112,60,8\n"
- ".,.,,,RTEXT,10,20,122,60,8\n"
- ".,.,,,LTEXT,0,82,122,30,8\n"
- ".,.,,,RTEXT,11,20,130,60,8\n"
- ".,.,,,LTEXT,0,82,130,30,8\n"
- ".,.,,,LTEXT,12,25,52,30,8\n"
- ".,.,,,RADIO1,13,50,52,30,8\n"
- ".,.,,,RADIO1,14,50,61,30,8\n"
- ".,,,LASTOBJ,RADIO1,15,50,70,30,8";
-bool
-SDellipse::PropertyDlg()
-{
- TabSHEET tab1 = {0, 40, 10, "Line"};
- TabSHEET tab2 = {40, 80, 10, "Details"};
- void *dyndata[] = {(void*)&tab1, (void*) &tab2, (void*)OD_linedef, (void*)" show regression line",
- (void*)" ellipse ", (void*)"center (means of data)", (void*)"x =", (void*)"y =",
- (void*)"standard deviation (S.D.)", (void*)"major axis", (void*)"minor axis", (void*)"size:",
- (void*)" 1 x S.D.", (void*)" 2 x S.D.", (void*)" 3 x S.D."};
- DlgInfo *ellDlg;
- DlgRoot *Dlg;
- void *hDlg;
- int cb, res, tmpType;
- LineDEF newLine;
- bool bRet = false;
- DWORD undo_flags = 0L;
- anyOutput *cdisp = Undo.cdisp;
-
- if(!parent) return false;
- if(!(ellDlg = CompileDialog(SdEllipseDlg_Tmpl, dyndata))) return false;
- OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
- if(!(Dlg = new DlgRoot(ellDlg, data))) 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);
- rlp_strcpy(TmpTxt, 4, "+/-");
- WriteNatFloatToBuff(TmpTxt+3, sd1); Dlg->SetText(259, TmpTxt);
- WriteNatFloatToBuff(TmpTxt+3, sd2); Dlg->SetText(257, TmpTxt);
- switch(type & 0x60000) {
- case 0x20000: Dlg->SetCheck(262, 0L, true); break;
- case 0x40000: Dlg->SetCheck(263, 0L, true); break;
- default: Dlg->SetCheck(261, 0L, true); break;
- }
- tmpType = type;
- if(parent->name) {
- cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "SD ellipse of ");
- rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
- }
- else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "SD ellipse properties");
- hDlg = CreateDlgWnd(TmpTxt, 50, 50, 410, 340, Dlg, 0x0L);
- do{
- LoopDlgWnd();
- res = Dlg->GetResult();
- }while (res < 0);
- if(res == 1){ //OK pressed
- Undo.SetDisp(cdisp);
- 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;
- tmpType &= ~0x60000;
- if(Dlg->GetCheck(262)) tmpType |= 0x20000;
- else if(Dlg->GetCheck(263)) tmpType |= 0x40000;
- undo_flags = CheckNewInt(&type, type, tmpType, parent, undo_flags);
- if(undo_flags & UNDO_CONTINUE) bRet = true;
- }
- CloseDlgWnd(hDlg); delete Dlg; free(ellDlg);
- 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, TOUCHEXIT | 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, COLBUTT, (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, 30, 28, 8},
- {301, 302, 0, 0x0L, EDVAL1, &fPos.fx, 46, 30, 35, 10},
- {302, 303, 0, 0x0L, RTEXT, (void*)"y-value", 15, 45, 28, 8},
- {303, 304, 0, 0x0L, EDVAL1, &fPos.fy, 46, 45, 35, 10},
- {304, 305, 0, 0x0L, RTEXT, (void*)"error", 15, 60, 28, 8},
- {305, 306, 0, 0x0L, EDVAL1, &ferr, 46, 60, 35, 10},
- {306, 307, 0, 0x0L, LTEXT, (void*)"description:", 10, 80, 70, 8},
- {307, 0, 0, 0x0L, EDTEXT, (void*)name, 10, 90, 80, 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 cb, 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;
- anyOutput *cdisp = Undo.cdisp;
- bool bRet = false;
- char desc[80];
-
- if(!parent) return false;
- desc[0] = 0;
- if(!(Dlg = new DlgRoot(ErrDlg, data)))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->name) {
- cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Error bar of ");
- rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
- }
- else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Error bar 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 7: //edit tab
- Dlg->Activate(307, true); res = -1; break;
- case 1: //accept for this object
- case 2: // or all objects of plot
- desc[0] = 0;
- Undo.SetDisp(cdisp); Dlg->GetText(307, desc, 80);
- 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(&ferr, o_err, n_err, 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 = CheckNewString(&name, name, desc, this, undo_flags);
- 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);
- 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);
- if(desc[0] || name) parent->Command(CMD_ERRDESC, desc, 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, COLBUTT, (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 cb, res, tmptype = type, undo_level = *Undo.pcb;
- bool bRet = false;
- DWORD o_col, n_col, undo_flags = 0L;
- anyOutput *cdisp = Undo.cdisp;
-
- if(!parent) return false;
- if(!(Dlg = new DlgRoot(ArrowDlg, data))) 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->name) {
- cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Arrow of ");
- rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
- }
- else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Arrow properties");
- hDlg = CreateDlgWnd(TmpTxt, 50, 50, 328, 260, Dlg, 0x0L);
- do {
- LoopDlgWnd(); res = Dlg->GetResult();
- switch (res) {
- case 600: case 601: case 602: case 603:
- Undo.SetDisp(cdisp);
- res = ExecDrawOrderButt(parent, this, res);
- }
- 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:
- Undo.SetDisp(cdisp);
- 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
- Undo.SetDisp(cdisp);
- 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 cb, res, tmpType = type;
- FillDEF newFill;
- LineDEF newLine, newHatchLine;
- DWORD undo_flags = 0L;
- anyOutput *cdisp = Undo.cdisp;
- 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, DefSize(SIZE_BAR));
- }
- else {
- WriteNatFloatToBuff(sTxt1, size);
- rlp_strcpy(sTxt2, 20, " 50");
- }
- Dlg = new DlgRoot(BoxDlg, data);
- 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->name) {
- cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Box of ");
- rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
- }
- else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "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
- Undo.SetDisp(cdisp);
- 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, &n_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
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *WhiskerDlgTmpl =
- "1,2,,DEFAULT,PUSHBUTTON,1,100,10,64,12\n"
- "2,3,,,PUSHBUTTON,2,100,25,64,12\n"
- "3,4,,,PUSHBUTTON,-2, 100, 40, 64, 12\n"
- "4,,5,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "5,6,100,ISPARENT | CHECKED,SHEET,3, 5, 10, 90, 100\n"
- "6,7,500,ISPARENT,SHEET,4,5,10,90,100\n"
- "7,,300,ISPARENT,SHEET,5,5,10,90,100\n"
- "100,101,,,RTEXT,6,15,40,28,8\n"
- "101,102,,,EDVAL1,7,46,40,25,10\n"
- "102,103,,,LTEXT,-3,73,40,20,8\n"
- "103,104,,,RTEXT,8,15,55,28,8\n"
- "104,105,,,EDVAL1,9,46,55,25,10\n"
- "105,106,,,LTEXT,-3,73,55,20,8\n"
- "106,107,,,RTEXT,10,15,70,28,8\n"
- "107,,,OWNDIALOG,COLBUTT,11,46,70,25,10\n"
- "300,301,,,RTEXT,12,15,30,28,8\n"
- "301,302,,,EDVAL1,13,46,30,35,10\n"
- "302,303,,,RTEXT,-5,15,42,28,8\n"
- "303,304,,,EDVAL1,14,46,42,35,10\n"
- "304,305,,,RTEXT,15,15,55,28,8\n"
- "305,306,,,EDVAL1,16,46,55,35,10\n"
- "306,307,,,RTEXT,-5,15,67,28,8\n"
- "307,308,,,EDVAL1,17,46,67,35,10\n"
- "308,309,,,LTEXT,18,10,85,70,8\n"
- "309,,,,EDTEXT,19,10,95,80,10\n"
- "500,501,,EXRADIO,ODBUTTON,20,32,40,18,18\n"
- "501,502,,EXRADIO,ODBUTTON,20,14,40,18,18\n"
- "502,503,,EXRADIO,ODBUTTON,20,50,40,18,18\n"
- "503,504,,EXRADIO,ODBUTTON,20,68,40,18,18\n"
- "504,,,LASTOBJ,LTEXT,21,14,30,30,9";
-bool
-Whisker::PropertyDlg()
-{
- TabSHEET tab1 = {0, 38, 10, "Whisker"};
- TabSHEET tab2 = {65, 90, 10, "Edit"};
- TabSHEET tab3 = {38, 65, 10, "Style"};
- void *dyndata[] = {(void*)"Apply to WHISKER", (void*)"Apply to PLOT", (void*)&tab1,
- (void*)&tab3, (void*)&tab2, (void*)"cap width", (void*)&size, (void*)"line width",
- (void*)&LineDef.width, (void*)"line color", (void *)&LineDef.color, (void*)"point 1 x",
- (void*)&pos1.fx, (void*)&pos1.fy, (void*)"point 2 x", (void*)&pos2.fx, (void*)&pos2.fy,
- (void*)"description:", (void*)name, (void*)(OD_WhiskerTempl), (void*)"select style:"};
- DlgInfo *ErrDlg = CompileDialog(WhiskerDlgTmpl, dyndata);
- DlgRoot *Dlg;
- void *hDlg;
- int cb, res, tmp_type;
- DWORD undo_flags = 0L, n_col = LineDef.color;
- anyOutput *cdisp = Undo.cdisp;
- lfPOINT n_pos;
- double tmpVal, o_size, n_size, o_lw, n_lw;
- bool bRet = false;
- char desc[80];
-
- if(!parent) return false;
- desc[0] = 0; tmp_type = type;
- Dlg = new DlgRoot(ErrDlg, data);
- Dlg->SetCheck(500 + (tmp_type & 0x03), 0L, true);
- Dlg->GetValue(101, &o_size); Dlg->GetValue(104, &o_lw);
- if(parent->name) {
- cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Whisker of ");
- rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
- }
- else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "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
- Undo.SetDisp(cdisp); Dlg->GetValue(101, &n_size);
- Dlg->GetValue(104, &n_lw); Dlg->GetColor(107, &n_col);
- desc[0] = 0; Dlg->GetText(309, desc, 80);
- break;
- }
- }while (res <0);
- switch (res) {
- case 1: //new setting for current whisker
- undo_flags = CheckNewString(&name, name, desc, this, undo_flags);
- 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 && !desc[0] && !name) break;
- parent->Command(CMD_SAVE_ERRS, 0L, 0L);
- if(desc[0] || name) parent->Command(CMD_ERRDESC, desc, 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; free(ErrDlg);
- 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 cb, res, tmptype;
- bool bRet = false;
- LineDEF newLine;
- DWORD undo_flags = 0L;
- anyOutput * cdisp = Undo.cdisp;
- lfPOINT o_pos, n_pos;
-
- if(!parent) return false;
- OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
- Dlg = new DlgRoot(LineDlg, data);
- 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) {
- cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Dropline of ");
- rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
- }
- else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "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
- Undo.SetDisp(cdisp); 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 cb, res, tmptype, i;
- bool bRet = false;
- LineDEF newLine;
- DWORD undo_flags = 0L;
- anyOutput *cdisp = Undo.cdisp;
- fPOINT3D o_pos, n_pos;
-
- if(!parent) return false;
- OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
- Dlg = new DlgRoot(LineDlg, data);
- 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) {
- cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Dropline of ");
- rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
- }
- else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "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
- Undo.SetDisp(cdisp);
- 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 < 4 ? type : 0], 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, COLBUTT, (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 cb, res;
- bool bRet = false, bContinue = false;
- fPOINT3D n_pos, o_pos;
- DWORD new_lcolor = Line.color, undo_flags = 0L;
- anyOutput *cdisp = Undo.cdisp;
- double o_size, n_size, o_lsize, n_lsize;
-
- if(!parent) return false;
- memcpy(&newFill, &Fill, sizeof(FillDEF));
- Dlg = new DlgRoot(BallDlg, data);
- 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) {
- cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Ball of ");
- rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
- }
- else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Ball properties");
- hDlg = CreateDlgWnd(TmpTxt, 50, 50, 335, 220, Dlg, 0x0L);
- do{
- LoopDlgWnd();
- res = Dlg->GetResult();
- switch (res) {
- case 0:
- if(bContinue) res = -1;
- bContinue = false;
- break;
- case 1: case 2:
- Undo.SetDisp(cdisp); 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
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *Plane3D_DlgTmpl =
- "1,2,,DEFAULT, PUSHBUTTON,1,115,10,55,12\n"
- "2,3,,,PUSHBUTTON,2,115,25,55,12\n"
- "3,4,,,PUSHBUTTON,-2,115,40,55,12\n"
- "4,,10,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "10,,100,ISPARENT | CHECKED,SHEET,3,5,10,105,85\n"
- "100,101,,,RTEXT,4,15,30,36,8\n"
- "101,102,,,EDVAL1,5,53,30,25,10\n"
- "102,103,,,LTEXT,-3,80,30,15,8\n"
- "103,104,,,RTEXT,6,15,42,36,8\n"
- "104,105,,OWNDIALOG,COLBUTT,7,53,42,25,10\n"
- "105,106,,,RTEXT,8,15,54,36,8\n"
- "106,200,,OWNDIALOG,SHADE3D,9,53,54,25,10\n"
- "200,,201,CHECKED,GROUP,0,0,0,0,0\n"
- "201,202,,,RTEXT,10,15,66,36,8\n"
- "202,203,,,INCDECVAL1,11,53,66,25,10\n"
- "203,204,,,LTEXT,-10,80,66,5,8\n"
- "204,205,,,RTEXT,12,15,78,36,8\n"
- "205,206,,,EDVAL1,13,53,78,25,10\n"
- "206,,,LASTOBJ,LTEXT,14,80,78,40,8";
-
-bool
-Plane3D::PropertyDlg()
-{
- TabSHEET tab1 = {0, 27, 10, "Plane"};
- double rb_width = 0.0, rb_z = 0.0;
- FillDEF newFill;
- void *dyndata[] = {(void*)"Apply to PLANE", (void*)"Apply to PLOT", (void*)&tab1,
- (void*)"line width", (void*)&Line.width, (void*)"line color", (void *)&Line.color,
- (void*)"fill color", (void*)&newFill, (void*)"ribbon width", (void*)&rb_width,
- (void*)"ribbon pos.", (void*)&rb_z, (void*)"[z-data]"};
- DlgInfo *PlaneDlg = CompileDialog(Plane3D_DlgTmpl, dyndata);
- DlgRoot *Dlg;
- void *hDlg;
- int cb, res;
- bool bRet = false;
- DWORD new_lcolor = Line.color, undo_flags = 0L;
- anyOutput *cdisp = Undo.cdisp;
- double o_lsize, n_lsize, o_rbw, n_rbw, o_rbz, n_rbz;
-
- if(!parent) return false;
- if(parent->Id == GO_GRID3D) return parent->PropertyDlg();
- 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, data);
- Dlg->GetValue(101, &o_lsize); Dlg->GetValue(202, &o_rbw);
- Dlg->GetValue(205, &o_rbz);
- if(parent && ((parent->Id==GO_RIBBON && parent->type > 1) || parent->Id==GO_GRID3D))
- Dlg->ShowItem(200, false); //paravent plot
- if(parent->Id == GO_RIBBON && parent->type >2) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "3D Surface Properties");
- else if(parent->name) {
- cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Plane of ");
- rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
- }
- else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Plane properties");
- hDlg = CreateDlgWnd(TmpTxt, 50, 50, 355, 226, Dlg, 0x0L);
- do{
- LoopDlgWnd();
- res = Dlg->GetResult();
- switch (res) {
- case 1: case 2:
- Undo.SetDisp(cdisp); 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, COLBUTT, (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 cb, res;
- bool bRet = false;
- DWORD col1 = Line.color, undo_flags = 0L;
- anyOutput *cdisp = Undo.cdisp;
- 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, data);
- 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) {
- cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Column of ");
- rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
- }
- else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Column properties");
- hDlg = CreateDlgWnd(TmpTxt, 50, 50, 405, 296, Dlg, 0x0L);
- do {
- LoopDlgWnd();
- res = Dlg->GetResult();
- switch (res) {
- case 1: case 2:
- Undo.SetDisp(cdisp); 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
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *Arrow3D_DlgTmpl =
- "1,2,,DEFAULT, PUSHBUTTON,1,100,10,57,12\n"
- "2,3,,,PUSHBUTTON,2,100,25,57,12\n"
- "3,4,,,PUSHBUTTON,-2,100,40,57,12\n"
- "4,,5,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "5,6,100,ISPARENT | CHECKED,SHEET,3,5,10,90,100\n"
- "6,7,200,ISPARENT,SHEET,4,5,10,90,100\n"
- "7,,300,ISPARENT,SHEET,5,5,10,90,100\n"
- "100,101,,,RTEXT,6,15,40,28,8\n"
- "101,102,,,EDVAL1,7,46,40,25,10\n"
- "102,103,,,LTEXT,-3,73,40,20,8\n"
- "103,104,,,RTEXT,8,15,52,28,8\n"
- "104,105,,,EDVAL1,9,46,52,25,10\n"
- "105,106,,,LTEXT,-3,73,52,20,8\n"
- "106,107,,,RTEXT,10,15,70,28,8\n"
- "107,108,,,EDVAL1,11,46,70,25,10\n"
- "108,109,,,LTEXT,-3,73,70,20,8\n"
- "109,110,,,RTEXT,-11,15,82,28,8\n"
- "110,,,OWNDIALOG,COLBUTT,12,46,82,25,10\n"
- "200,201,,TOUCHEXIT,RADIO1,13,15,40,60,8\n"
- "201,202,,TOUCHEXIT,RADIO1,14,15,55,60,8\n"
- "202,,,TOUCHEXIT,RADIO1,15,15,70,60,8\n"
- "300,301,,,RTEXT,-12,10,25,28,8\n"
- "301,302,,,EDVAL1,16,46,25,35,10\n"
- "302,303,,,RTEXT,-13,10,36,28,8\n"
- "303,304,,,EDVAL1,17,46,36,35,10\n"
- "304,305,,,RTEXT,-14,10,47,28,8\n"
- "305,306,,,EDVAL1,18,46,47,35,10\n"
- "306,307,,,RTEXT,19,10,60,28,8\n"
- "307,308,,,EDVAL1,20,46,60,35,10\n"
- "308,309,,,RTEXT,-5,10,71,28,8\n"
- "309,310,,,EDVAL1,21,46,71,35,10\n"
- "310,311,,,RTEXT,-6,10,82,28,8\n"
- "311,312,,,EDVAL1,22,46,82,35,10\n"
- "312,,,LASTOBJ,CHECKBOX,23,16,95,70,8";
-
-bool
-Arrow3D::PropertyDlg()
-{
- TabSHEET tab1 = {0, 29, 10, "Arrow"};
- TabSHEET tab2 = {29, 59, 10, "Type"};
- TabSHEET tab3 = {59, 90, 10, "Edit"};
- void *dyndata[] = {(void*)"Apply to ARROW", (void*)"Apply to PLOT", (void*)&tab1,
- (void*)&tab2, (void*)&tab3, (void*)"cap width", (void*)&cw, (void*)"length",
- (void*)&cl, (void*)"line width", (void*)&Line.width, (void *)&Line.color,
- (void*)"line only", (void*)"arrow with lines", (void*)"filled arrow",
- (void*)&fPos2.fx, (void*)&fPos2.fy, (void*)&fPos2.fz, (void*)"origin x",
- (void*)&fPos1.fx, (void*)&fPos1.fy, (void*)&fPos1.fz, (void*)"set common origin"};
- DlgInfo *ArrowDlg = CompileDialog(Arrow3D_DlgTmpl, dyndata);
- 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 cb, res, tmptype = type, undo_level = *Undo.pcb;
- bool bRet = false;
- DWORD o_col, n_col, undo_flags = 0L;
- anyOutput *cdisp = Undo.cdisp;
-
- if(!parent) return false;
- if(!(Dlg = new DlgRoot(ArrowDlg, data))) 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) {
- cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Arrow of ");
- rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
- }
- else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "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:
- Undo.SetDisp(cdisp);
- 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; free(ArrowDlg); 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 cb, res;
- bool bRet = false;
- LineDEF newLine;
- anyOutput *cdisp = Undo.cdisp;
-
- if(!parent) return false;
- if(parent->Id == GO_GRID3D) return parent->PropertyDlg();
- OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
- if(!(Dlg = new DlgRoot(LineDlg, data)))return false;
- if(parent->name) {
- cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Line of ");
- rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
- }
- else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Line properties");
- hDlg = CreateDlgWnd(TmpTxt, 50, 50, 410, 314, Dlg, 0x0L);
- do{
- LoopDlgWnd();
- res = Dlg->GetResult();
- }while (res < 0);
- switch(res) {
- case 1: //OK pressed
- Undo.SetDisp(cdisp);
- 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"};
- bool isDataLabel = ((parent) && (parent->Id == GO_PLOTSCATT || parent->Id == GO_XYSTAT || parent->Id == GO_BOXPLOT));
- int bwidth = isDataLabel ? 55 : 45;
- double lspc = 100.0;
- DlgInfo LabelDlg[] = {
- {1, 2, 0, DEFAULT, PUSHBUTTON, isDataLabel ? (void*)"Apply to LABEL" : (void*)"OK", 170, 10, bwidth, 12},
- {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 170, isDataLabel ? 40 : 25, bwidth, 12},
- {3, isDataLabel ? 10 : 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},
- {10, 50, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 170, 25, bwidth, 12},
- {50, 0, 600, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
- {100, 101, 0, 0x0L, RTEXT, (void*)"size", 30, 33, 45, 8},
- {101, 102, 0, 0x0L, INCDECVAL1, &TextDef.fSize, 80, 33, 33, 10},
- {102, 103, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 115, 33, 20, 8},
- {103, 104, 0, 0x0L, RTEXT, (void*)"color", 30, 45, 45, 8},
- {104, 107, 0, OWNDIALOG, COLBUTT, (void *)&TextDef.ColTxt, 80, 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", 30, 57, 45, 8},
- {108, 109, 0, 0x0L, EDVAL1, &TextDef.RotBL, 80, 57, 25, 10},
- {109, 150, 0, 0x0L, LTEXT, (void *)"deg.", 107, 57, 20, 8},
- {150, 154, 151, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
- {151, 152, 0, 0x0L, RTEXT, (void *)"line spacing", 30, 69, 45, 8},
- {152, 153, 0, 0x0L, INCDECVAL1, &lspc, 80, 69, 33, 10},
- {153, 0, 0, 0x0L, LTEXT, (void *)"%", 115, 69, 20, 8},
- {154, 105, 0, 0x0L, CHECKBOX, (void*) " moveable", 80, 83, 60, 9},
- {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, 185, 45, 15, 15},
- {601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 185, 60, 15, 15},
- {602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 185, 75, 15, 15},
- {603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 185, 90, 15, 15}};
- DlgRoot *Dlg;
- void *hDlg;
- int res, i, c_style, c_font;
- bool RetVal = false, check;
- double tmp;
- DWORD undo_flags = 0x0;
- anyOutput *cdisp = Undo.cdisp;
- lfPOINT o_pos, o_dist, n_pos, n_dist;
- TextDEF OldTxtDef, NewTxtDef;
- Axis *pa;
- fmtText *fmt = 0L;
-
- if(!parent) return false;
- if(parent->Id == GO_MLABEL) {
- lspc = 100.0 * parent->GetSize(SIZE_LSPC);
- }
- if (lspc < 50.0) lspc = 100.0;
- if(Dlg = new DlgRoot(LabelDlg, data)) {
- if(parent->Id == GO_MLABEL) Dlg->ShowItem(150, true);
- 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);
- if(moveable){
- Dlg->SetCheck(154, 0L, true);
- }
- 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) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(axis)");
- else if(parent->parent->Id == GO_TICK) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(tick)");
- }
- else {
- if(parent->Id == GO_AXIS) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(axis)");
- else if(parent->Id == GO_TICK) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(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) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(axis)");
- if(parent->parent->Id == GO_TICK) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(tick)");
- }
- else {
- if(parent->Id == GO_AXIS) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(axis)");
- if(parent->Id == GO_TICK) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(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, isDataLabel ? 470 : 450, 258, Dlg, 0x0L);
- do{
- LoopDlgWnd(); res = Dlg->GetResult();
- switch (res) {
- case 600: case 601: case 602: case 603:
- Undo.SetDisp(cdisp);
- res = ExecDrawOrderButt(parent, this, res);
- }
- switch (res) {
- case 10:
- Undo.SetDisp(cdisp);
- parent->Command(CMD_SAVE_LABELS, 0L, 0L);
- undo_flags |= UNDO_CONTINUE;
- 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, TMP_TXT_SIZE))) 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 || res == 10) {
- Undo.SetDisp(cdisp);
- 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;
- }
- i = Dlg->GetCheck(154) ? 1 : 0;
- if(i != moveable) {
- Undo.ValInt(parent, &moveable, undo_flags);
- moveable = i; undo_flags |= UNDO_CONTINUE;
- }
- TmpTxt[0] = 0; Dlg->GetText(106, TmpTxt, TMP_TXT_SIZE);
- if(res == 1) undo_flags = CheckNewString(&TextDef.text, TextDef.text, TmpTxt, this, undo_flags);
- if(cmpTextDEF(&OldTxtDef, &NewTxtDef)){
- if(NewTxtDef.ColTxt != TextDef.ColTxt) bBGvalid = false;
- if (pa) pa->Command(CMD_TLB_TXTDEF, &NewTxtDef, 0L);
- else if(res == 10 || 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(res == 10 || parent->Id == GO_MLABEL) {
- if(n_dist.fx != o_dist.fx && parent->SetSize(SIZE_LB_XDIST, n_dist.fx)) RetVal = true;
- if(n_dist.fy != o_dist.fy && 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(parent->Id == GO_MLABEL && Dlg->GetValue(152, &tmp) && tmp != lspc) {
- parent->SetSize(SIZE_LSPC, tmp/100.0); RetVal = true;
- }
- if(undo_flags & UNDO_CONTINUE) RetVal = true;
- }
- CloseDlgWnd(hDlg);
- if(fmt) delete(fmt);
- delete Dlg;
- return RetVal;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Text frame properties dialog
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-bool
-TextFrame::PropertyDlg()
-{
- TabSHEET tab1 = {0, 27, 10, "Text"};
- TabSHEET tab2 = {27, 57, 10, "Frame"};
- double lspc2, lspc1 = lspc2 = lspc * 100.0;
- DlgInfo TextFrmDlg[] = {
- {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 130, 10, 45, 12},
- {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 25, 45, 12},
- {3, 50, 4, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
- {4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 119, 100},
- {5, 0, 200, ISPARENT, SHEET, &tab2, 5, 10, 119, 100},
- {50, 0, 600, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
- {100, 101, 0, 0x0L, RTEXT, (void*)"size", 10, 33, 45, 8},
- {101, 102, 0, 0x0L, INCDECVAL1, &TextDef.fSize, 60, 33, 33, 10},
- {102, 103, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 95, 33, 20, 8},
- {103, 104, 0, 0x0L, RTEXT, (void*)"color", 10, 45, 45, 8},
- {104, 150, 0, OWNDIALOG, COLBUTT, (void *)&TextDef.ColTxt, 60, 45, 25, 10},
- {150, 0, 151, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
- {151, 152, 0, 0x0L, RTEXT, (void *)"line spacing", 10, 57, 45, 8},
- {152, 153, 0, 0x0L, INCDECVAL1, &lspc1, 60, 57, 33, 10},
- {153, 0, 0, 0x0L, LTEXT, (void *)"%", 95, 57, 20, 8},
- {200, 0, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 20, 30, 90, 50},
- {600, 601, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 145, 45, 15, 15},
- {601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 145, 60, 15, 15},
- {602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 145, 75, 15, 15},
- {603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 145, 90, 15, 15}};
- DlgRoot *Dlg;
- void *hDlg;
- anyOutput *cdisp = Undo.cdisp;
- int i, res;
- bool bRet = false;
- LineDEF newLine, newFillLine;
- FillDEF newFill;
- DWORD undo_flags = 0L;
- TextDEF OldTxtDef, NewTxtDef;
-
- if(!parent || !data) return 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(TextFrmDlg, data)))return false;
- memcpy(&OldTxtDef, &TextDef, sizeof(TextDEF)); OldTxtDef.text = 0L;
- Dlg->GetValue(101, &OldTxtDef.fSize); memcpy(&NewTxtDef, &OldTxtDef, sizeof(TextDEF));
- Dlg->GetValue(152, &lspc1);
- hDlg = CreateDlgWnd("Text Frame", 50, 50, 370, 258, Dlg, 0x0L);
- do{
- LoopDlgWnd(); res = Dlg->GetResult();
- switch (res) {
- case 1:
- Dlg->GetValue(101, &NewTxtDef.fSize); Dlg->GetColor(104, &NewTxtDef.ColTxt);
- Dlg->GetValue(152, &lspc2); lspc1 /= 100.0; lspc2 /= 100.0;
- break;
- case 600: case 601: case 602: case 603:
- Undo.SetDisp(cdisp);
- res = ExecDrawOrderButt(parent, this, res);
- break;
- }
- }while (res < 0);
- if(res == 1){ //OK pressed
- Undo.SetDisp(cdisp);
- OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
- OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&newFill, 0);
- memcpy(&newFillLine, &FillLine, sizeof(LineDEF));
- if(newFill.hatch) memcpy(&newFillLine, newFill.hatch, sizeof(LineDEF));
- if(cmpTextDEF(&OldTxtDef, &NewTxtDef)){
- Undo.TextDef(this, &TextDef, undo_flags);
- memcpy(&TextDef, &NewTxtDef, sizeof(TextDEF));
- undo_flags |= UNDO_CONTINUE; TextDef.text = 0L;
- }
- undo_flags = CheckNewFloat(&lspc, lspc1, lspc2, parent, undo_flags);
- if(cmpLineDEF(&Line, &newLine)) {
- Undo.Line(parent, &Line, undo_flags); undo_flags |= UNDO_CONTINUE;
- memcpy(&Line, &newLine, sizeof(LineDEF));
- }
- if(newFill.type && cmpLineDEF(&FillLine, &newFillLine)) {
- Undo.Line(parent, &FillLine, undo_flags); undo_flags |= UNDO_CONTINUE;
- memcpy(&FillLine, &newFillLine, sizeof(LineDEF));
- }
- if(cmpFillDEF(&Fill, &newFill)) {
- Undo.Fill(parent, &Fill, undo_flags); undo_flags |= UNDO_CONTINUE;
- memcpy(&Fill, &newFill, sizeof(FillDEF));
- }
- Fill.hatch = &FillLine;
- if(undo_flags & UNDO_CONTINUE){
- bRet = bModified = true; lines2text();
- Undo.TextBuffer(this, &csize, &cpos, &text, undo_flags, cdisp);
- if(lines) {
- for(i = 0; i < nlines; i++) if(lines[i]) free(lines[i]);
- free(lines); lines = 0L;
- }
- HideTextCursor(); cur_pos.x = cur_pos.y = 0;
- }
- }
- CloseDlgWnd(hDlg); delete Dlg;
- return bRet;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 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;
- anyOutput *cdisp = Undo.cdisp;
-
- 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, data);
- 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:
- Undo.SetDisp(cdisp);
- 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;
- anyOutput *cdisp = Undo.cdisp;
- bool bRet = false;
- LineDEF newLine;
-
- if(!parent) return false;
- OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&pgLine, 0);
- if(!(Dlg = new DlgRoot(LineDlg, data)))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 = Dlg->GetResult();
- switch (res) {
- case 600: case 601: case 602: case 603:
- Undo.SetDisp(cdisp);
- res = ExecDrawOrderButt(parent, this, res); break;
- case 1: case 2:
- Undo.SetDisp(cdisp); break;
- }
- }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;
- anyOutput *cdisp = Undo.cdisp;
- 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, data);
- 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 = Dlg->GetResult();
- switch(res) {
- case 600: case 601: case 602: case 603:
- Undo.SetDisp(cdisp);
- res = ExecDrawOrderButt(parent, this, res); break;
- case 1: case 2:
- Undo.SetDisp(cdisp); break;
- }
- }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;
- anyOutput *cdisp = Undo.cdisp;
- 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, data)))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 = Dlg->GetResult();
- switch(res) {
- case 600: case 601: case 602: case 603:
- Undo.SetDisp(cdisp);
- res = ExecDrawOrderButt(parent, this, res); break;
- case 1: case 2:
- Undo.SetDisp(cdisp); break;
- }
- }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, CHECKED, 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, RANGEINPUT, 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;
- double x, y;
- AccRange *rY = 0L;
- LineDEF Line;
- FillDEF Fill;
-
- if(!parent || !data) return false;
- 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);
- UseRangeMark(data, 1, TmpTxt);
- if(!(Dlg = new DlgRoot(BarDlg, data)))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, TMP_TXT_SIZE)){
- rY = new AccRange(TmpTxt);
- yRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
- }
- else {
- rY = 0L; yRange = 0L;
- }
- 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, TOUCHEXIT | ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 131, 100},
- {5, 6, 200, TOUCHEXIT | ISPARENT, SHEET, &tab2, 5, 10, 131, 100},
- {6, 7, 300, TOUCHEXIT | ISPARENT, SHEET, &tab3, 5, 10, 131, 100},
- {7, 10, 400, TOUCHEXIT | ISPARENT, SHEET, &tab4, 5, 10, 131, 100},
- {10, 0, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
- {100, 101, 0, 0x0L, LTEXT, (void*)"range for X Data", 10, 30, 60, 8},
- {101, 102, 0, 0x0L, RANGEINPUT, text1, 20, 40, 100, 10},
- {102, 103, 0, 0x0L, LTEXT, (void*)"range for Y Data", 10, 55, 60, 8},
- {103, 104, 0, 0x0L, RANGEINPUT, 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, RANGEINPUT, 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, RANGEINPUT, 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, BarType, nVals, nTxt, nTime;
- double x, y, e;
- lfPOINT fp1, fp2;
- bool bRet = false, bLayout = false, bContinue = false, bValid;
- anyResult xRes, yRes;
- TextDEF lbdef = {defs.Color(COL_TEXT), defs.Color(COL_BG), DefSize(SIZE_TEXT), 0.0f, 0.0f, 0,
- TXA_HLEFT | TXA_VBOTTOM, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, TmpTxt};
- AccRange *rX, *rY, *rE, *rL;
-
- if(!parent || !data) return false;
- if(Id == GO_BARCHART) return CreateBarChart();
- UseRangeMark(data, 1, text1, text2, text3, text4);
- rX = rY = rE = rL = 0L;
- if(!(Dlg = new DlgRoot(XYDlg, data)))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 4: // the data tab sheet
- Dlg->Activate(101, true); res = -1; break;
- case 5: // the layout tab sheet
- bLayout = true; res = -1; break;
- case 6: // the error tab sheet
- Dlg->Activate(304, true); res = -1; break;
- case 7: // the label tab sheet
- Dlg->Activate(402, 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, TMP_TXT_SIZE)) 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, TMP_TXT_SIZE)) 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, TMP_TXT_SIZE)) 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, TMP_TXT_SIZE)) 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, TMP_TXT_SIZE)) xRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
- if(Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE)) yRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
- Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
- data_desc = rY->RangeDesc(data, 1);
- //analyse data types
- if(rX->DataTypes(data, &nVals, &nTxt, &nTime)){
- if(!nVals && nTxt > 1 && nTxt > nTime) x_tv = new TextValue();
- else if(!nVals && nTime > 1 && nTime > nTxt) x_dtype = ET_DATETIME;
- }
- if(rY->DataTypes(data, &nVals, &nTxt, &nTime)){
- if(!nVals && nTxt > 1 && nTxt > nTime) y_tv = new TextValue();
- else if(!nVals && nTime > 1 && nTime > nTxt) y_dtype = ET_DATETIME;
- }
- //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, TMP_TXT_SIZE)){
- ErrRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
- rE->GetFirst(&m, &n); rE->GetNext(&m, &n);
- }
- else {
- rE = 0L; ErrRange = 0L;
- }
- }
- if(Dlg->GetCheck(400) && rL) { //labels ?
- Labels = (Label**)calloc(nPoints, sizeof(Label*));
- if(Dlg->GetText(402, TmpTxt, TMP_TXT_SIZE)) LbRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
- 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 {
- bValid = false;
- if(data->GetResult(&xRes, j, i, false) && data->GetResult(&yRes, l, k, false)) {
- bValid = true;
- if(x_tv) {
- if(xRes.type == ET_TEXT) x = x_tv->GetValue(xRes.text);
- else bValid = false;
- }
- else if(x_dtype == ET_DATETIME) {
- if(xRes.type == ET_DATE || xRes.type == ET_TIME || xRes.type == ET_DATETIME) x = xRes.value;
- else bValid = false;
- }
- else {
- if(xRes.type == ET_VALUE) x = xRes.value;
- else bValid = false;
- }
- if(y_tv) {
- if(yRes.type == ET_TEXT) y = y_tv->GetValue(yRes.text);
- else bValid = false;
- }
- else if(y_dtype == ET_DATETIME) {
- if(yRes.type == ET_DATE || yRes.type == ET_TIME || yRes.type == ET_DATETIME) y = yRes.value;
- else bValid = false;
- }
- else {
- if(yRes.type == ET_VALUE) y = yRes.value;
- else bValid = false;
- }
- }
- if(bValid){
- 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);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// calculate means and error to create a xy-plot
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-bool
-xyStat::PropertyDlg()
-{
- char text1[100], text2[100];
- DlgInfo StatDlg[] = {
- {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 130, 10, 45, 12},
- {2, 10, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 25, 45, 12},
- {10, 100, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
- {100, 101, 0, 0x0L, LTEXT, (void*)"range for grouping variable", 10, 10, 90, 9},
- {101, 102, 0, 0x0L, LTEXT, (void*)"(X data)", 10, 20, 60, 9},
- {102, 103, 0, 0x0L, RANGEINPUT, text1, 10, 30, 100, 10},
- {103, 104, 0, 0x0L, LTEXT, (void*)"range for Y data", 10, 45, 90, 9},
- {104, 200, 0, 0x0L, RANGEINPUT, text2, 10, 55, 100, 10},
- {200, 300, 201, ISPARENT | CHECKED, GROUPBOX, (void*) " draw means ", 10, 75, 165, 50},
- {201, 202, 0, CHECKED, CHECKBOX, (void*)" line", 15, 80, 50, 9},
- {202, 203, 0, CHECKED, CHECKBOX, (void*)" symbols", 15, 90, 50, 9},
- {203, 204, 0, 0x0L, CHECKBOX, (void*)" bars", 15, 100, 50, 9},
- {204, 205, 0, 0x0L, LTEXT, (void*)"using", 65, 90, 30, 9},
- {205, 206, 0, CHECKED, RADIO1, (void*)" arithmetic mean", 95, 80, 50, 9},
- {206, 207, 0, 0x0L, RADIO1, (void*)" geometric mean", 95, 90, 50, 9},
- {207, 208, 0, 0x0L, RADIO1, (void*)" harmonic mean", 95, 100, 50, 9},
- {208, 0, 0, 0x0L, RADIO1, (void*)" median", 95, 110, 50, 9},
- {300, 400, 301, ISPARENT | CHECKED, GROUPBOX, (void*) " draw error bars ", 10, 130, 165, 40},
- {301, 302, 0, ISRADIO | CHECKED, CHECKBOX, (void*)" std. deviation (SD)", 15, 135, 70, 9},
- {302, 303, 0, ISRADIO, CHECKBOX, (void*)" std. error (SEM)", 15, 145, 70, 9},
- {303, 304, 0, ISRADIO, CHECKBOX, (void*)" 25, 75% percentiles", 95, 135, 70, 9},
- {304, 305, 0, ISRADIO, CHECKBOX, (void*)" min and max", 95, 145, 70, 9},
- {305, 306, 0, ISRADIO, CHECKBOX, (void*)" ", 15, 155, 70, 9},
- {306, 307, 0, 0x0L, EDVAL1, &ci, 28, 154, 15, 10},
- {307, 0, 0, 0x0L, LTEXT, (void*) "% conf. interval", 45, 155, 70, 9},
- {400, 0, 401, ISPARENT | CHECKED, GROUPBOX, (void*) " number of cases ", 10, 175, 165, 30},
- {401, 402, 0, ISRADIO | CHECKED, CHECKBOX, (void*)" on top of error", 15, 180, 70, 9},
- {402, 403, 0, ISRADIO, CHECKBOX, (void*)" on top of mean", 95, 180, 70, 9},
- {403, 404, 0, 0x0L, LTEXT, (void*)"prefix:", 15, 190, 24, 9},
- {404, 0, 0, LASTOBJ, EDTEXT, (void*)"n = ", 40, 189, 30, 10}};
- DlgRoot *Dlg;
- void *hDlg;
- bool bRet = false;
- int i, res, width, height, cb_mdesc;
- double x, y, e, f, dx, dy;
- lfPOINT fp1, fp2;
- char errdesc[40], *mdesc;
- TextDEF lbdef = {defs.Color(COL_TEXT), defs.Color(COL_BG), DefSize(SIZE_TEXT), 0.0f, 0.0f, 0,
- TXA_HLEFT | TXA_VBOTTOM, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, TmpTxt};
-
- if(!parent || !data) return false;
- UseRangeMark(data, 1, text1, text2);
- if(!(Dlg = new DlgRoot(StatDlg, data)))return false;
- text1[0] = text2[0] = 0;
- hDlg = CreateDlgWnd("Mean and Error Plot", 50, 50, 370, 450, Dlg, 0x0L);
- do {
- LoopDlgWnd();
- res = Dlg->GetResult();
- switch(res) {
- case 0:
- if(Dlg->GetCheck(10)) res=-1;
- break;
- case 1:
- if(!(Dlg->GetText(102, text1, 100) && Dlg->GetText(104, text2, 100) && text1[0] && text2[0])) res = 2;
- break;
- }
- }while (res <0);
- if(res == 1) {
- xRange = (char*)memdup(text1, ((int)strlen(text1))+2, 0);
- yRange = (char*)memdup(text2, ((int)strlen(text2))+2, 0);
- type = 0;
- if(Dlg->GetCheck(201)) type |= 0x0001; if(Dlg->GetCheck(202)) type |= 0x0002;
- if(Dlg->GetCheck(203)) type |= 0x0004;
- if(Dlg->GetCheck(205)) type |= 0x0010; if(Dlg->GetCheck(206)) type |= 0x0020;
- if(Dlg->GetCheck(207)) type |= 0x0040; if(Dlg->GetCheck(208)) type |= 0x0080;
- if(Dlg->GetCheck(301)) type |= 0x0100; if(Dlg->GetCheck(302)) type |= 0x0200;
- if(Dlg->GetCheck(303)) type |= 0x0400; if(Dlg->GetCheck(304)) type |= 0x0800;
- if(Dlg->GetCheck(305)) type |= 0x1000;
- if(Dlg->GetCheck(401)) type |= 0x2000; if(Dlg->GetCheck(402)) type |= 0x4000;
- Dlg->GetValue(306, &ci); TmpTxt[0] = 0;
- if(Dlg->GetText(404, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0]) case_prefix = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
- CreateData();
- if(type && curr_data) {
- switch (type & 0x00f0) {
- case 0x0010: mdesc = "Mean"; break;
- case 0x0020: mdesc = "Geometric mean"; break;
- case 0x0040: mdesc = "Harmonic mean"; break;
- case 0x0080: mdesc = "Median"; break;
- default: mdesc = "n.a."; break;
- }
- cb_mdesc = (int)strlen(mdesc);
- curr_data->GetSize(&width, &height); nPoints = height;
-#ifdef USE_WIN_SECURE
- sprintf_s(text1, 100, "a1:a%d", height); sprintf_s(text2, 100, "b1:b%d", height);
-#else
- sprintf(text1, "a1:a%d", height); sprintf(text2, "b1:b%d", height);
-#endif
- Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
- if(type & 0x0001) {
- if(nPoints >1 && (TheLine = new DataLine(this, curr_data, text1, text2)) &&
- (TheLine->name = (char*)malloc(cb_mdesc+2))) rlp_strcpy(TheLine->name, cb_mdesc+2, mdesc);
- }
- if((type & 0x0002) && (Symbols = (Symbol**)calloc(nPoints, sizeof(Symbol*)))) {
- for(i = 0; i < height; i++) {
- if(curr_data->GetValue(i, 0, &x) && curr_data->GetValue(i, 1, &y)
- && (Symbols[i] = new Symbol(this, curr_data, x, y, DefSym, 0, i, 1, i))){
- Symbols[i]->idx = i;
- if(Symbols[i]->name = (char*)malloc(cb_mdesc+2))
- rlp_strcpy(Symbols[i]->name, cb_mdesc+2, mdesc);
- }
- }
- }
- if((type & 0x0004) && (Bars = (Bar**)calloc(nPoints, sizeof(Bar*)))) {
- for(i = 0; i < height; i++) {
- if(curr_data->GetValue(i, 0, &x) && curr_data->GetValue(i, 1, &y)
- && (Bars[i] = new Bar(this, curr_data, x, y, BAR_VERTB | BAR_RELWIDTH, 0, i, 1, i))){
- if(Bars[i]->name = (char*)malloc(cb_mdesc+2))
- rlp_strcpy(Bars[i]->name, cb_mdesc+2, mdesc);
- }
- }
- }
- if(type & 0x1f00) {
- Errors = (ErrorBar**)calloc(nPoints, sizeof(ErrorBar*));
- switch(type & 0x1f00) {
- case 0x0100: rlp_strcpy(errdesc, 40, "Std. Dev."); break;
- case 0x0200: rlp_strcpy(errdesc, 40, "Std. Err."); break;
- case 0x0400: rlp_strcpy(errdesc, 40, "25, 75% Perc."); break;
- case 0x0800: rlp_strcpy(errdesc, 40, "Min./Max."); break;
-#ifdef USE_WIN_SECURE
- case 0x1000: sprintf_s(errdesc, 40, "'%g%% CI", ci); break;
-#else
- case 0x1000: sprintf(errdesc, "'%g%% CI", ci); break;
-#endif
- default: rlp_strcpy(errdesc, 40, "error");
- }
- }
- if((type & 0x1300) && Errors) {
- for(i = 0; i < height; i++) {
- if(curr_data->GetValue(i, 0, &x) && curr_data->GetValue(i, 1, &y)
- && curr_data->GetValue(i, 2, &e)) {
- Errors[i]= new ErrorBar(this, curr_data, x, y, e, 0, 0, i, 1, i, 2, i);
- if(Errors[i]) Errors[i]->Command(CMD_ERRDESC, errdesc, 0L);
- }
- }
- }
- if((type & 0x0c00) && Errors) {
- for(i = 0; i < height; i++) {
- if(curr_data->GetValue(i, 0, &x) && curr_data->GetValue(i, 2, &e) && curr_data->GetValue(i, 3, &f)){
- fp1.fx = fp2.fx = x; fp1.fy = e; fp2.fy = f;
- Errors[i]= (ErrorBar*)new Whisker(this, curr_data, fp1, fp2, 0, 0, i, 2, i, 0, i, 3, i);
- if(Errors[i]) Errors[i]->Command(CMD_ERRDESC, errdesc, 0L);
- }
- }
- }
- if((type & 0x6000) && (Labels = (Label**)calloc(nPoints, sizeof(Label*)))) {
- dy = -0.4 * DefSize(SIZE_SYMBOL);
- if(type & 0x2000){
- lbdef.Align = TXA_HCENTER | TXA_VBOTTOM;
- dx = 0.0;
- }
- else {
- lbdef.Align = TXA_HLEFT | TXA_VBOTTOM;
- dx = -dy;
- }
- for(i = 0; i < height; i++) {
- if(curr_data->GetValue(i, 0, &x) && curr_data->GetText(i, 5, TmpTxt, TMP_TXT_SIZE, false)){
- if((type & 0x2000) && curr_data->GetValue(i, 4, &y))
- Labels[i] = new Label(this, curr_data, x, y, &lbdef,
- LB_X_DATA | LB_Y_DATA, 0, i, 4, i, 5, i);
- else if((type & 0x4000) && curr_data->GetValue(i, 1, &y))
- Labels[i] = new Label(this, curr_data, x, y, &lbdef,
- LB_X_DATA | LB_Y_DATA, 0, i, 1, i, 5, i);
- if(Labels[i]){
- Labels[i]->SetSize(SIZE_LB_YDIST, dy);
- Labels[i]->SetSize(SIZE_LB_XDIST, dx);
- }
- }
- }
- }
- Command(CMD_AUTOSCALE, 0L, 0L);
- bRet = true;
- }
- }
- CloseDlgWnd(hDlg);
- delete Dlg;
- return bRet;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Frequency distribution
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *FreqDlg_Tmpl =
- "1,2,,DEFAULT,PUSHBUTTON,-1,130,10,45,12\n"
- "2,3,,,PUSHBUTTON,-2,130,25,45,12\n"
- "3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "4,5,100,ISPARENT | CHECKED,SHEET,1,5,10,120,153\n"
- "5,10,200,ISPARENT,SHEET,2,5,10,120,153\n"
- "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
- "100,101,,,LTEXT,3,10,25,60,8\n"
- "101,102,,,RANGEINPUT,-15,10,38,110,10\n"
- "102,103,120,ISPARENT | CHECKED,GROUPBOX,4,10,55,110,42\n"
- "103,,150,ISPARENT | CHECKED,GROUPBOX,5,10,102,110,57\n"
- "120,121,,CHECKED,RADIO1,6,15,60,30,9\n"
- "121,122,,, EDVAL1,7,47,60,15,10\n"
- "122,123,,, LTEXT,8,64,60,35,8\n"
- "123,124,,, RADIO1,9, 15, 72, 45, 9\n"
- "124,125,,, EDTEXT,-16,65,72,50,10\n"
- "125,126,,, RTEXT,10,15,84, 47,8\n"
- "126,,,,EDTEXT,-16,65,84,50,10\n"
- "150,151,,ISRADIO,CHECKBOX,13,15,107,30, 8\n"
- "151,152,,ISRADIO,CHECKBOX,14,15,117,30, 8\n"
- "152,153,,ISRADIO,CHECKBOX,15,65,107,30, 8\n"
- "153,154,,ISRADIO,CHECKBOX,16,65,117,30,8\n"
- "154,155,,ISRADIO,CHECKBOX,17,15,127,30,8\n"
- "155,156,,ISRADIO,CHECKBOX,18,15,137,30,8\n"
- "156,,,ISRADIO,CHECKBOX,19,15,147,30,8\n"
- "200,, 210,ISPARENT | CHECKED,GROUPBOX,11,10,27,110,61\n"
- "210,,,LASTOBJ | NOSELECT,ODBUTTON,12,25,34,90,50";
-
-bool
-FreqDist::PropertyDlg()
-{
- TabSHEET tab1 = {0, 25, 10, "Data"};
- TabSHEET tab2 = {25, 52, 10, "Style"};
- void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)"spread sheet range for values",
- (void*)" classes ", (void*)" plot distribution ", (void*)"create", (void*)&step,
- (void*)"classes and bars", (void*)"class size is", (void*)"starting at",
- (void*)" bar style ", (void*)OD_filldef, (void*)" normal", (void*)" log-normal",
- (void*)" binomial", (void*)" poisson", (void*)" exponential", (void*)" rectangular",
- (void*)" chi-square"};
- DlgInfo *FreqDlg;
- DlgRoot *Dlg;
- void *hDlg;
- bool bRet = false;
- int res, r, c;
- double tmp;
- char *mrk;
- AccRange *aR;
-
- if(!parent || !data) return false;
- if(!(FreqDlg = CompileDialog(FreqDlg_Tmpl, dyndata))) return false;
- step = 7; TmpTxt[100] = 0;
- OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&BarLine, 0);
- OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&BarFill, 0);
- if(data->Command(CMD_GETMARK, &mrk, 0L)) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, mrk);
- else TmpTxt[0] = 0;
- if(!(Dlg = new DlgRoot(FreqDlg, data)))return false;
- hDlg = CreateDlgWnd("Frequency Distribution", 50, 50, 370, 370, 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, TMP_TXT_SIZE)) ssRef = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
- if(Dlg->GetCheck(150)) type = 1;
- else if(Dlg->GetCheck(151)) type = 2;
- else if(Dlg->GetCheck(154)) type = 3;
- else if(Dlg->GetCheck(155)) type = 4;
- else if(Dlg->GetCheck(156)) type = 5;
- else if(Dlg->GetCheck(152)) type = 10;
- else if(Dlg->GetCheck(153)) type = 11;
- else type = 0;
- break;
- }
- }while (res <0);
- if(res==1 && (plots = (GraphObj**)calloc(nPlots=3, 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(y_info = (char*)malloc(25*sizeof(char))) rlp_strcpy(y_info, 25, "No. of observations");
- if(x_info = (char*)malloc(25*sizeof(char))){
- rlp_strcpy(x_info, 25, "Categories");
- if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE) && (aR = new AccRange(TmpTxt))) {
- if(aR->GetFirst(&c, &r) && !data->GetValue(r, c, &tmp) && data->GetText(r, c, TmpTxt, 150, false))
- rlp_strcpy(x_info, 25, TmpTxt);
- delete aR;
- }
- }
- if(plots[0]) bRet = true;
- }
- CloseDlgWnd(hDlg); delete Dlg; free(FreqDlg);
- return bRet;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Regression properties dialog
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char* RegDlg_Tmpl =
- "1,+,,DEFAULT,PUSHBUTTON,-1,140,10,45,12\n"
- ".,.,,,PUSHBUTTON,-2,140,25,45,12\n"
- ".,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "4,+,100,ISPARENT | CHECKED,SHEET,1,5,10,130,85\n"
- ".,10,200,ISPARENT,SHEET,2,5,10,130,85\n"
- "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
- "100,+,,,LTEXT,3,10,22,60,8\n"
- ".,.,,,RANGEINPUT,-16,20,32,100,10\n"
- ".,.,,,LTEXT,4,10,45,60,8\n"
- ".,.,,,RANGEINPUT,-17,20,55,100,10\n"
- ".,.,,CHECKED,CHECKBOX,5,10,70,100,8\n"
- ".,,,,CHECKBOX,6,10,80,100,8\n"
- "200,210,201,CHECKED | ISPARENT, GROUPBOX,7,10,30,58,56\n"
- "201,+,,CHECKED, RADIO1,8,20,40,30,8\n"
- ".,.,,,RADIO1,9,20,50,30,8\n"
- ".,.,,,RADIO1,10,20,60,30,8\n"
- ".,,,,RADIO1,11,20,70,30,8\n"
- "210,,211,CHECKED | ISPARENT,GROUPBOX,12,72,30,58,56\n"
- ".,+,,CHECKED,RADIO1,13,82,40,30,8\n"
- ".,.,,,RADIO1,14,82,50,30,8\n"
- ".,.,,,RADIO1,15,82,60,30,8\n"
- ".,,,LASTOBJ,RADIO1,16,82,70,30,8";
-
-bool
-Regression::PropertyDlg()
-{
- TabSHEET tab1 = {0, 28, 10, "Data"};
- TabSHEET tab2 = {28, 70, 10, "Transform"};
- void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)"range for X Data",
- (void*)"range for Y Data", (void*)" include symbols in plot", (void*) " draw SD ellipse",
- (void*)" x-values ", (void*)"x = x", (void*)"x = log(x)", (void*)"x = 1/x",
- (void*)"x = sqrt(x)", (void*)" y-values ", (void*)"y = y", (void*)"y = log(y)",
- (void*)"y = 1/y",(void*)"y = sqrt(y)"};
- DlgInfo *RegDlg;
- DlgRoot *Dlg;
- void *hDlg;
- int c, i, j, k, l, ic, res, n;
- double x, y;
- AccRange *rX, *rY;
- bool bRet = false, bContinue = false, dValid;
- lfPOINT *values = 0L;
-
- if(!parent || !data) return false;
- if(!(RegDlg = CompileDialog(RegDlg_Tmpl, dyndata))) return false;
- rX = rY = 0L;
- UseRangeMark(data, 1, TmpTxt+100, TmpTxt+200);
- if(!(Dlg = new DlgRoot(RegDlg, data)))return false;
- hDlg = CreateDlgWnd("Linear regression analysis step 1/2", 50, 50, 380, 230, 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, TMP_TXT_SIZE)) 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, TMP_TXT_SIZE)) 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, TMP_TXT_SIZE)) xRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
- if(Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE)) yRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 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);
- 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 | 0x20002))&&
- (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;
- free(RegDlg); 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, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
- {100, 101, 0, 0x0L, LTEXT, (void*)"range for X Data", 10, 40, 60, 8},
- {101, 102, 0, 0x0L, RANGEINPUT, text1, 20, 50, 100, 10},
- {102, 103, 0, 0x0L, LTEXT, (void*)"range for Y Data", 10, 65, 60, 8},
- {103, 104, 0, 0x0L, RANGEINPUT, text2, 20, 75, 100, 10},
- {104, 105, 0, 0x0L, LTEXT, (void*)"range for sizes", 10, 90, 60, 8},
- {105, 0, 0, 0x0L, RANGEINPUT, 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, COLBUTT, (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, COLBUTT, (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, 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};
-
- if(!parent || !data) return false;
- UseRangeMark(data, 1, text1, text2, text3);
- memcpy(&ShowFill, &BubbleFill, sizeof(FillDEF));
- if(BubbleFill.hatch) memcpy(&ShowFillLine, BubbleFill.hatch, sizeof(LineDEF));
- ShowFill.hatch = &ShowFillLine;
- if(!(Dlg = new DlgRoot(PlotDlg, data)))return false;
- 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, 100) && Dlg->GetText(103, text2, 100) &&
- Dlg->GetText(105, text3, 100) && (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
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *AddPolDlg_Tmpl =
- "1,2,,DEFAULT,PUSHBUTTON,-1,140,14,45,12\n"
- "2,3,,,PUSHBUTTON,-2,140,29,45,12\n"
- "3,10,200,ISPARENT | CHECKED,GROUPBOX,1,5,14,131,96\n"
- "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
- "200,201,,CHECKED | EXRADIO,ODBUTTON,2,10,24,20,20\n"
- "201,202,,EXRADIO,ODBUTTON,2,30,24,20,20\n"
- "202,203,,EXRADIO,ODBUTTON,2,50,24,20,20\n"
- "203,204,,EXRADIO,ODBUTTON,2,70,24,20,20\n"
- "204,210,,EXRADIO,ODBUTTON,2,90,24,20,20\n"
- "210,211,,,LTEXT,3,10,50,50,8\n"
- "211,212,,,RANGEINPUT,-15,20,62,100,10\n"
- "212,213,,,LTEXT,4,10,75,50,8\n"
- "213,,,LASTOBJ,RANGEINPUT,-16,20,87,100,10";
-
-bool
-PolarPlot::AddPlot()
-{
- void *dyndata[] = {(void*)" select template and data range ", (void*)OD_PolarTempl,
- (void*)"range for x-data (circular or angular data)",
- (void*)"range for y-data (radial data)"};
- DlgInfo *PolDlg;
- DlgRoot *Dlg;
- void *hDlg;
- int i, j, k, l, ic, n, res, cType = 200;
- bool bRet = false, bContinue = false;
- double x, y;
- AccRange *rX = 0L, *rY = 0L;
- Symbol **Symbols = 0L;
- DataLine *TheLine = 0L;
- Plot **tmpPlots;
- Function *func;
- anyOutput *cdisp = Undo.cdisp;
-
- if(!parent || !data) return false;
- if(!(PolDlg = CompileDialog(AddPolDlg_Tmpl, dyndata))) return false;
- UseRangeMark(data, 1, TmpTxt, TmpTxt+100);
- if(!(Dlg = new DlgRoot(PolDlg, data)))return false;
- hDlg = CreateDlgWnd("Add Polar Plot", 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 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, TmpTxt, 100) && Dlg->GetText(213, TmpTxt+100, 100) &&
- (rX = new AccRange(TmpTxt)) && (rY = new AccRange(TmpTxt+100)) &&
- (n = rX ? rX->CountItems() : 0) &&
- (tmpPlots = (Plot**)realloc(Plots, (nPlots+2)*sizeof(Plot*)))) {
- Undo.SetDisp(cdisp);
- 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, TmpTxt, TmpTxt+100);
- else if(Dlg->GetCheck(203))
- TheLine = new DataPolygon(this, data, TmpTxt, TmpTxt+100);
- else if(Dlg->GetCheck(204)) {
- if(func = new Function(this, data, "Function")){
- 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; free(PolDlg);
- 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, data);
- 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 | TOUCHEXIT, SHEET, &tab1, 5, 10, 131, 100},
- {5, 10, 200, ISPARENT | TOUCHEXIT | CHECKED, SHEET, &tab2, 5, 10, 131, 100},
- {10, 0, 0, CHECKED, 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, RANGEINPUT, (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, RANGEINPUT, (void*)text2, 20, 92, 100, 10}};
- DlgRoot *Dlg;
- void *hDlg;
- int res, 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(!parent || !data) return false;
- if(Plots) return Config();
- 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;
- UseRangeMark(data, 1, text1, text2);
- tlbdef.ColTxt = defs.Color(COL_AXIS);
- tlbdef.ColBg = 0x00ffffffL;
- tlbdef.RotBL = tlbdef.RotCHAR = 0.0f;
- tlbdef.fSize = DefSize(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, data)))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: case 4:
- bType = true;
- res = -1;
- break;
- case 1:
- if(!bType) { //the 'Coordinates' sheet must have been visited
- bType = true;
- Dlg->SetCheck(4, 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, 100) && Dlg->GetText(213, text2, 100) &&
- (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, "Function")){
- 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(-DefSize(SIZE_AXIS_TICKS)*6.0));
- Axes[1]->SetSize(SIZE_TLB_XDIST,
- NiceValue(-DefSize(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
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static int boxplot_mode_sel = 52;
-bool
-BoxPlot::PropertyDlg()
-{
- DlgInfo PlotDlg[] = {
- {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 130, 10, 45, 12},
- {2, 10, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 25, 45, 12},
- {10, 50, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
- {50, 60, 51, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
- {51, 52, 0, 0x0L, LTEXT, (void*)"Data Source:", 10, 12, 40, 9},
- {52, 53, 0, TOUCHEXIT, RADIO2, (void*)" user values", 60, 12, 50, 9},
- {53, 0, 0, TOUCHEXIT, RADIO2, (void*)" statistical data", 60, 22, 60, 9},
- {60, 61, 100, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
- {61, 0, 200, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
- {100, 102, 0, 0x0L, LTEXT, (void*)"range for grouping variable (X data)", 10, 39, 140, 9},
- {102, 103, 0, 0x0L, RANGEINPUT, TmpTxt+100, 10, 49, 165, 10},
- {103, 104, 0, 0x0L, LTEXT, (void*)"range for Y data", 10, 60, 90, 9},
- {104, 150, 0, 0x0L, RANGEINPUT, TmpTxt+200, 10, 70, 165, 10},
- {150, 160, 151, ISPARENT | CHECKED, GROUPBOX, (void*) " draw means ", 10, 87, 165, 45},
- {151, 152, 0, 0x0L, CHECKBOX, (void*)" line", 15, 92, 50, 9},
- {152, 153, 0, CHECKED, CHECKBOX, (void*)" symbols", 15, 101, 50, 9},
- {153, 154, 0, 0x0L, LTEXT, (void*)"using", 65, 101, 30, 9},
- {154, 155, 0, 0x0L, RADIO1, (void*)" arithmetic mean", 95, 90, 50, 9},
- {155, 156, 0, 0x0L, RADIO1, (void*)" geometric mean", 95, 99, 50, 9},
- {156, 157, 0, 0x0L, RADIO1, (void*)" harmonic mean", 95, 108, 50, 9},
- {157, 0, 0, CHECKED, RADIO1, (void*)" median", 95, 117, 50, 9},
- {160, 170, 161, ISPARENT | CHECKED, GROUPBOX, (void*) " draw boxes ", 10, 137, 165, 38},
- {161, 162, 0, ISRADIO, CHECKBOX, (void*)" std. deviation (SD)", 15, 142, 70, 9},
- {162, 163, 0, ISRADIO, CHECKBOX, (void*)" std. error (SEM)", 15, 151, 70, 9},
- {163, 164, 0, ISRADIO | CHECKED, CHECKBOX, (void*)" 25, 75% percentiles", 95, 142, 70, 9},
- {164, 165, 0, ISRADIO, CHECKBOX, (void*)" min and max", 95, 151, 70, 9},
- {165, 166, 0, ISRADIO, CHECKBOX, (void*)" ", 15, 161, 70, 9},
- {166, 167, 0, 0x0L, EDVAL1, &ci_box, 28, 160, 15, 10},
- {167, 0, 0, 0x0L, LTEXT, (void*) "% conf. interval", 45, 161, 70, 9},
- {170, 400, 171, ISPARENT | CHECKED, GROUPBOX, (void*) " draw whiskers ", 10, 180, 165, 38},
- {171, 172, 0, ISRADIO, CHECKBOX, (void*)" std. deviation (SD)", 15, 185, 70, 9},
- {172, 173, 0, ISRADIO, CHECKBOX, (void*)" std. error (SEM)", 15, 194, 70, 9},
- {173, 174, 0, ISRADIO, CHECKBOX, (void*)" 25, 75% percentiles", 95, 185, 70, 9},
- {174, 175, 0, ISRADIO | CHECKED, CHECKBOX, (void*)" min and max", 95, 194, 70, 9},
- {175, 176, 0, ISRADIO, CHECKBOX, (void*)" ", 15, 204, 70, 9},
- {176, 177, 0, 0x0L, EDVAL1, &ci_err, 28, 203, 15, 10},
- {177, 0, 0, 0x0L, LTEXT, (void*) "% conf. interval", 45, 203, 70, 9},
- {200, 202, 0, 0x0L, LTEXT, (void*)"range for common X values", 10, 39, 140, 9},
- {202, 250, 0, 0x0L, RANGEINPUT, TmpTxt+100, 10, 49, 165, 10},
- {250, 260, 251, ISPARENT | CHECKED, GROUPBOX, (void*) " ", 10, 68, 165, 30},
- {251, 252, 0, 0x0L, CHECKBOX, (void*)" draw line", 15, 63, 50, 9},
- {252, 253, 0, 0x0L, LTEXT, (void*)"range for line values", 15, 73, 80, 9},
- {253, 0, 0, 0x0L, RANGEINPUT, TmpTxt+200, 15, 83, 155, 10},
- {260, 270, 261, ISPARENT | CHECKED, GROUPBOX, (void*) " ", 10, 106, 165, 30},
- {261, 262, 0, CHECKED, CHECKBOX, (void*)" draw symbols", 15, 101, 50, 9},
- {262, 263, 0, 0x0L, LTEXT, (void*)"range for symbol values", 15, 111, 80, 9},
- {263, 0, 0, 0x0L, RANGEINPUT, TmpTxt+200, 15, 121, 155, 10},
- {270, 280, 271, ISPARENT | CHECKED, GROUPBOX, (void*) " ", 10, 144, 165, 50},
- {271, 272, 0, CHECKED, CHECKBOX, (void*)" draw boxes", 15, 139, 50, 9},
- {272, 273, 0, 0x0L, LTEXT, (void*)"range for HI values", 15, 149, 80, 9},
- {273, 274, 0, 0x0L, RANGEINPUT, TmpTxt+300, 15, 159, 155, 10},
- {274, 275, 0, 0x0L, LTEXT, (void*)"range for LO values", 15, 169, 80, 9},
- {275, 0, 0, 0x0L, RANGEINPUT, TmpTxt+400, 15, 179, 155, 10},
- {280, 0, 281, ISPARENT | CHECKED, GROUPBOX, (void*) " ", 10, 202, 165, 50},
- {281, 282, 0, CHECKED, CHECKBOX, (void*)" draw whiskers", 15, 197, 50, 9},
- {282, 283, 0, 0x0L, LTEXT, (void*)"range for HI values", 15, 207, 80, 9},
- {283, 284, 0, 0x0L, RANGEINPUT, TmpTxt+500, 15, 217, 155, 10},
- {284, 285, 0, 0x0L, LTEXT, (void*)"range for LO values", 15, 227, 80, 9},
- {285, 0, 0, 0x0L, RANGEINPUT, TmpTxt+600, 15, 237, 155, 10},
- {400, 0, 401, ISPARENT | CHECKED, GROUPBOX, (void*) " number of cases ", 10, 223, 165, 30},
- {401, 402, 0, ISRADIO | CHECKED, CHECKBOX, (void*)" on top of error", 15, 228, 70, 9},
- {402, 403, 0, ISRADIO, CHECKBOX, (void*)" on top of mean", 95, 228, 70, 9},
- {403, 404, 0, 0x0L, LTEXT, (void*)"prefix:", 15, 238, 24, 9},
- {404, 0, 0, LASTOBJ, EDTEXT, (void*)"n = ", 40, 237, 30, 10}};
- DlgRoot *Dlg;
- void *hDlg;
- bool bRet = false;
- int i, j, k, k1, l, l1, n, ic, c, res, cb, width, height;
- double x, y1, y2, dx, dy;
- char errdesc[40], boxdesc[40], symdesc[40];
- lfPOINT fp1, fp2;
- TextDEF lbdef = {defs.Color(COL_TEXT), defs.Color(COL_BG), DefSize(SIZE_TEXT), 0.0f, 0.0f, 0,
- TXA_HLEFT | TXA_VBOTTOM, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, TmpTxt};
- AccRange *rX = 0L, *rY1 = 0L, *rY2 = 0L;
-
- if(!parent || !data) return false;
- UseRangeMark(data, 1, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400, TmpTxt+500, TmpTxt+600);
- ci_box = ci_err = 95.0;
- if(!(Dlg = new DlgRoot(PlotDlg, data)))return false;
- TmpTxt[0] = TmpTxt[100] = 0;
- //restore previous style
- if(boxplot_mode_sel == 53) {
- Dlg->ShowItem(61, false); Dlg->SetCheck(53, 0L, true);
- }
- else {
- Dlg->SetCheck(52, 0L, true); Dlg->ShowItem(60, false);
- }
- hDlg = CreateDlgWnd("Box and Whisker Plot", 50, 50, 370, 550, Dlg, 0x0L);
- do {
- LoopDlgWnd();
- res = Dlg->GetResult();
- switch(res) {
- case 0:
- if(Dlg->GetCheck(10)) res=-1;
- break;
- case 52: case 53:
- boxplot_mode_sel = res;
- if(res == 53) {
- Dlg->ShowItem(60, true); Dlg->ShowItem(61, false);
- }
- else {
- Dlg->ShowItem(60, false); Dlg->ShowItem(61, true);
- }
- Dlg->Command(CMD_REDRAW, 0L, 0L); res=-1;
- break;
- }
- }while (res <0);
- if(res == 1) {
- type = 0; dirty = true;
- if(Dlg->GetCheck(52) && Dlg->GetText(202, TmpTxt+100, 50) && TmpTxt[100] &&(rX = new AccRange(TmpTxt+100))) {
- xRange = (char*)memdup(TmpTxt+100, ((int)strlen(TmpTxt+100))+2, 0);
- n = rX->CountItems(); nPoints = n;
- // data line
- if(n > 1 && Dlg->GetCheck(251) && Dlg->GetText(253, TmpTxt, TMP_TXT_SIZE)) {
- TheLine = new DataLine(this, data, TmpTxt+100, TmpTxt);
- bRet = true;
- }
- // symbols
- if(n > 0 && Dlg->GetCheck(261) && Dlg->GetText(263, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0]
- && (Symbols = (Symbol**)calloc(n, sizeof(Symbol*)))
- && (rY1 = new AccRange(TmpTxt))) {
- yRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
- rX->GetFirst(&i, &j); rY1->GetFirst(&k, &l);
- rX->GetNext(&i, &j); rY1->GetNext(&k, &l);
- ic = c = 0;
- do {
- if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y1)) {
- if(Symbols[ic] = new Symbol(this, data, x, y1, SYM_PLUS, i, j, k, l))
- Symbols[ic++]->idx = c;
- }
- c++;
- }while(rX->GetNext(&i, &j) && rY1->GetNext(&k, &l));
- delete rY1; rY1 = 0L;
- if(ic) bRet = true;
- }
- // boxes
- if(n > 0 && Dlg->GetCheck(271) && Dlg->GetText(273, TmpTxt+300, 50) && Dlg->GetText(275, TmpTxt+400, 50)
- && (Boxes = (Box**)calloc(n, sizeof(Box*)))
- && (rY1 = new AccRange(TmpTxt+300)) && (rY2 = new AccRange(TmpTxt+400))) {
- rX->GetFirst(&i, &j); rY1->GetFirst(&k, &l); rY2->GetFirst(&k1, &l1);
- rX->GetNext(&i, &j); rY1->GetNext(&k, &l); rY2->GetNext(&k1, &l1);
- ic = 0;
- do {
- if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y1) && data->GetValue(l1, k1, &y2)) {
- fp1.fy = y1; fp2.fy = y2; fp1.fx = fp2.fx = x;
- Boxes[ic] = new Box(this, data, fp1, fp2, BAR_RELWIDTH, i, j, k, l, i, j, k1, l1);
- if(Boxes[ic]) Boxes[ic++]->SetSize(SIZE_BOX, 60.0);
- }
- }while(rX->GetNext(&i, &j) && rY1->GetNext(&k, &l) && rY2->GetNext(&k1, &l1));
- delete rY1; rY1 = 0L; delete rY2; rY2 = 0L;
- if(ic) bRet = true;
- }
- // whiskers
- if(n > 0 && Dlg->GetCheck(281) && Dlg->GetText(283, TmpTxt+300, 50) && Dlg->GetText(285, TmpTxt+400, 50)
- && (Whiskers = (Whisker**)calloc(n, sizeof(Whisker*)))
- && (rY1 = new AccRange(TmpTxt+300)) && (rY2 = new AccRange(TmpTxt+400))) {
- rX->GetFirst(&i, &j); rY1->GetFirst(&k, &l); rY2->GetFirst(&k1, &l1);
- rX->GetNext(&i, &j); rY1->GetNext(&k, &l); rY2->GetNext(&k1, &l1);
- ic = 0;
- do {
- if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y1) && data->GetValue(l1, k1, &y2)) {
- fp1.fy = y1; fp2.fy = y2; fp1.fx = fp2.fx = x;
- Whiskers[ic++] = new Whisker(this, data, fp1, fp2, 0, i, j, k, l, i, j, k1, l1);
- }
- }while(rX->GetNext(&i, &j) && rY1->GetNext(&k, &l) && rY2->GetNext(&k1, &l1));
- delete rY1; rY1 = 0L; delete rY2; rY2 = 0L;
- if(ic) bRet = true;
- }
- if (bRet) Command(CMD_AUTOSCALE, 0L, 0L);
- }
- else if(Dlg->GetText(102, TmpTxt+100, 50) && TmpTxt[100] && Dlg->GetText(104, TmpTxt+200, 50) && TmpTxt[200]){
- xRange = (char*)memdup(TmpTxt+100, ((int)strlen(TmpTxt+100))+2, 0);
- yRange = (char*)memdup(TmpTxt+200, ((int)strlen(TmpTxt+200))+2, 0);
- if((rX = new AccRange(xRange)) && (rY1 = new AccRange(yRange))) {
- x_info = rX->RangeDesc(data, 2); y_info = rY1->RangeDesc(data, 2);
- delete rX; delete rY1; rX = rY1 = 0L;
- }
- if(Dlg->GetCheck(154)) type |= 0x0001; if(Dlg->GetCheck(155)) type |= 0x0002;
- if(Dlg->GetCheck(156)) type |= 0x0003; if(Dlg->GetCheck(157)) type |= 0x0004;
- if(Dlg->GetCheck(161)) type |= 0x0010; if(Dlg->GetCheck(162)) type |= 0x0020;
- if(Dlg->GetCheck(163)) type |= 0x0030; if(Dlg->GetCheck(164)) type |= 0x0040;
- if(Dlg->GetCheck(165)) type |= 0x0050;
- if(Dlg->GetCheck(171)) type |= 0x0100; if(Dlg->GetCheck(172)) type |= 0x0200;
- if(Dlg->GetCheck(173)) type |= 0x0300; if(Dlg->GetCheck(174)) type |= 0x0400;
- if(Dlg->GetCheck(175)) type |= 0x0500;
- if(Dlg->GetCheck(151)) type |= 0x1000; if(Dlg->GetCheck(152)) type |= 0x2000;
- if(Dlg->GetCheck(401)) type |= 0x4000; if(Dlg->GetCheck(402)) type |= 0x8000;
- Dlg->GetValue(166, &ci_box); Dlg->GetValue(176, &ci_err);
- if(Dlg->GetText(404, TmpTxt, TMP_TXT_SIZE)) case_prefix = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
- CreateData();
- if(curr_data && type) {
- curr_data->GetSize(&width, &height);
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt+100, 50, "a1:a%d", height); sprintf_s(TmpTxt+200, 50, "b1:b%d", height);
-#else
- sprintf(TmpTxt+100, "a1:a%d", height); sprintf(TmpTxt+200, "b1:b%d", height);
-#endif
- nPoints = height;
- if(nPoints > 1 && (type & 0x1000)) {
- TheLine = new DataLine(this, curr_data, TmpTxt+100, TmpTxt+200);
- bRet = true;
- }
- if(nPoints > 0 && (type & 0x2000) && (Symbols = (Symbol**)calloc(nPoints, sizeof(Symbol*)))) {
- switch(type & 0x000f) {
- case 0x0001: cb = rlp_strcpy(symdesc, 40, "Mean"); break;
- case 0x0002: cb = rlp_strcpy(symdesc, 40, "Geometric mean"); break;
- case 0x0003: cb = rlp_strcpy(symdesc, 40, "Harmonic mean"); break;
- case 0x0004: cb = rlp_strcpy(symdesc, 40, "Median"); break;
- default: cb = rlp_strcpy(symdesc, 40, "n.a."); break;
- }
- for(i = 0; i < height; i++) {
- if(curr_data->GetValue(i, 0, &x) && curr_data->GetValue(i, 1, &y1)
- && (Symbols[i] = new Symbol(this, curr_data, x, y1, SYM_PLUS, 0, i, 1, i))){
- Symbols[i]->idx = i;
- Symbols[i]->name = (char*)memdup(symdesc, cb+1, 0);
- }
- }
- bRet = true;
- }
- if(nPoints > 0 && (type & 0x00f0) && (Boxes = (Box**)calloc(nPoints, sizeof(Box*)))) {
- switch(type & 0x00f0) {
- case 0x0010: cb = rlp_strcpy(boxdesc, 40, "Std. Dev."); break;
- case 0x0020: cb = rlp_strcpy(boxdesc, 40, "Std. Err."); break;
- case 0x0030: cb = rlp_strcpy(boxdesc, 40, "25, 75% Perc."); break;
- case 0x0040: cb = rlp_strcpy(boxdesc, 40, "Min./Max."); break;
-#ifdef USE_WIN_SECURE
- case 0x0500: cb = sprintf_s(boxdesc, 40, "'%g%% CI", ci_err); break;
-#else
- case 0x0500: cb = sprintf(boxdesc, "'%g%% CI", ci_err); break;
-#endif
- default: cb = rlp_strcpy(boxdesc, 40, "n.a.");
- }
- for(i = 0; i < height; i++) {
- if(curr_data->GetValue(i, 0, &x) && curr_data->GetValue(i, 2, &y1)
- && curr_data->GetValue(i, 3, &y2)) {
- fp1.fy = y1; fp2.fy = y2; fp1.fx = fp2.fx = x;
- Boxes[i] = new Box(this, curr_data, fp1, fp2, BAR_RELWIDTH, 0, i, 2, i, 0, i, 3, i);
- if(Boxes[i]){
- Boxes[i]->SetSize(SIZE_BOX, 60.0);
- Boxes[i]->name = (char*)memdup(boxdesc, cb+1, 0);
- }
- }
- }
- bRet = true;
- }
- if(nPoints > 0 && (type & 0x0f00) && (Whiskers = (Whisker**)calloc(nPoints, sizeof(Whisker*)))) {
- switch(type & 0x0f00) {
- case 0x0100: rlp_strcpy(errdesc, 40, "Std. Dev."); break;
- case 0x0200: rlp_strcpy(errdesc, 40, "Std. Err."); break;
- case 0x0300: rlp_strcpy(errdesc, 40, "25, 75% Perc."); break;
- case 0x0400: rlp_strcpy(errdesc, 40, "Min./Max."); break;
-#ifdef USE_WIN_SECURE
- case 0x0500: sprintf_s(errdesc, 40, "'%g%% CI", ci_err); break;
-#else
- case 0x0500: sprintf(errdesc, "'%g%% CI", ci_err); break;
-#endif
- default: rlp_strcpy(errdesc, 40, "error");
- }
- for(i = 0; i < height; i++) {
- if(curr_data->GetValue(i, 0, &x) && curr_data->GetValue(i, 4, &y1)
- && curr_data->GetValue(i, 5, &y2)) {
- fp1.fy = y1; fp2.fy = y2; fp1.fx = fp2.fx = x;
- Whiskers[i] = new Whisker(this, curr_data, fp1, fp2, 0, 0, i, 4, i, 0, i, 5, i);
- if(Whiskers[i]) Whiskers[i]->Command(CMD_ERRDESC, errdesc, 0L);
- }
- }
- bRet = true;
- }
- if(nPoints > 0 && (type & 0xc000) && (Labels = (Label**)calloc(nPoints, sizeof(Label*)))) {
- dy = -0.4 * DefSize(SIZE_SYMBOL);
- if(type & 0x4000){
- lbdef.Align = TXA_HCENTER | TXA_VBOTTOM;
- dx = 0.0;
- }
- else {
- lbdef.Align = TXA_HLEFT | TXA_VBOTTOM;
- dx = -dy;
- }
- for(i = 0; i < height; i++) {
- if(curr_data->GetValue(i, 0, &x) && curr_data->GetText(i, 7, TmpTxt, TMP_TXT_SIZE)){
- if(curr_data->GetValue(i, 6, &y1))Labels[i] = new Label(this, curr_data, x, y1, &lbdef,
- LB_X_DATA | LB_Y_DATA, 0, i, 6, i, 7, i);
- if(Labels[i]){
- Labels[i]->SetSize(SIZE_LB_YDIST, dy); Labels[i]->SetSize(SIZE_LB_XDIST, dx);
- }
- }
- }
- bRet = true;
- }
- }
- }
- }
- if(bRet) {
- dirty = true;
- Command(CMD_AUTOSCALE, 0L, 0L);
- }
- CloseDlgWnd(hDlg);
- delete Dlg;
- if(rX) delete rX;
- 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, CHECKED, 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, RANGEINPUT, text1, 20, 40, 100, 10},
- {102, 103, 0, 0x0L, LTEXT, (void*)"range for width (density) data", 10, 55, 60, 8},
- {103, 104, 0, 0x0L, RANGEINPUT, 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, align = 0;
- bool bRet = false, bContinue = false, bVert;
- AccRange *rX = 0L, *rY = 0L;
-
- if(!parent || !data) return false;
- OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)defs.GetOutLine(), 0);
- OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)defs.GetFill(), 0);
- UseRangeMark(data, 1, text1, text2);
- if(!(Dlg = new DlgRoot(PlotDlg, data)))return false;
- 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, TMP_TXT_SIZE)) 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, TMP_TXT_SIZE) && (rY = new AccRange(TmpTxt))){
- if(n != rY->CountItems()) {
- ErrorBox("both ranges must be given\nand must have the same size");
- bContinue = true;
- res = -1;
- }
- }
- }
- }while (res < 0);
- if(res == 1 && n && rX && rY) {
- if(Dlg->GetCheck(104)) {
- y_info = rX->RangeDesc(data, 0); x_info = rY->RangeDesc(data, 0);
- }
- else {
- x_info = rX->RangeDesc(data, 0); y_info = rY->RangeDesc(data, 0);
- }
- type = (bVert = Dlg->GetCheck(104)) ? align | 0x10 : align;
- if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) xRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
- if(Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE)) yRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
- 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
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-static char *StackBar_DlgTmpl =
- "1,2,,DEFAULT,PUSHBUTTON,-1,158,10,45,12\n"
- "2,3,,,PUSHBUTTON,-2,158,25,45,12\n"
- "3,,10,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "10,11,100,ISPARENT | CHECKED, SHEET,1,5,10,140,100\n"
- "11,12,200,ISPARENT,SHEET,2,5,10,140,100\n"
- "12,20,300,ISPARENT,SHEET,3,5,10,140,100\n"
- "20,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
- "100,101,,,LTEXT,4,15,30,60,8\n"
- "101,152,,,RANGEINPUT,5,25,40,100,10\n"
- "152,153,,ISPARENT | CHECKED,GROUPBOX,6, 12, 60, 128, 45\n"
- "153,154,,,LTEXT,0,25,65,60,8\n"
- "154,155,,,RANGEINPUT,5,25,75,100,10\n"
- "155,156,0,,PUSHBUTTON,-8,95,87,30,12\n"
- "156,,,,PUSHBUTTON,-9,60,87,35,12\n"
- "200,201,,CHECKED,RADIO1,7,25,35,60,8\n"
- "201,202,,,RADIO1,8,25,50,60,8\n"
- "202,203,,,RTEXT,9,31,65,38,8\n"
- "203,204,,,EDVAL1,10,70,65,30,10\n"
- "204,,,,CHECKBOX,11,25,90,60,8\n"
- "300,,,LASTOBJ | NOSELECT, ODBUTTON,12,20,35,80,60";
-
-bool
-StackBar::PropertyDlg()
-{
- TabSHEET tab1 = {0, 25, 10, "Data"};
- TabSHEET tab2 = {25, 55, 10, "Details"};
- TabSHEET tab3 = {55, 90, 10, "Scheme"};
- void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"range for common x values",
- (void*)TmpTxt, (void*)" ranges for y values ", (void*)" add each y to start value",
- (void*)" subtract each y from start value", (void*)"start value:", (void*)&StartVal,
- (void*)" horizontal plot", (void*)(OD_scheme)};
- DlgInfo *StackBarDlg;
- DlgRoot *Dlg;
- void *hDlg;
- int i, sc, j, res, currYR = 0, maxYR = 0, nx = 0, ny, c_num, c_txt, c_datetime;
- bool updateYR = true, bContinue = false, bSub, bRet = false, bHor;
- char **rd = 0L, *rname;
- AccRange *rX = 0L, *rY = 0L;
- TextValue *tv = 0L;
-
- if(!parent || !data) return false;
- if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
- TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return false;
- if(!(StackBarDlg = CompileDialog(StackBar_DlgTmpl, dyndata))) return false;
- if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
- for(i=100, j= 0; i <= 1000; i +=100) if(TmpTxt[i])
- rd[j++] = (char*)memdup(TmpTxt+i, ((int)strlen(TmpTxt+i))+2, 0); maxYR = j-1;
- }
- if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
- if(!(Dlg = new DlgRoot(StackBarDlg, data))) return false;
- if(rd && rd[currYR] && *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
- 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);
- }
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "y-values # %d/%d", currYR+1, maxYR+1);
-#else
- sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
-#endif
- //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) TmpTxt[j++] = '&';
- j+= rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, rd[i]);
- }
- rX->DataTypes(data, &c_num, &c_txt, &c_datetime);
- if(!c_num && (c_txt + c_datetime) > 0 ) tv = new TextValue();
- if(Dlg->GetCheck(204)) {
- y_info = rX->RangeDesc(data, 3); y_tv = tv;
- }
- else {
- x_info = rX->RangeDesc(data, 3); x_tv = tv;
- }
- ssYrange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+1, 0);
- if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) ssXrange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+1, 0);;
- 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(rY)delete rY; rY = 0L;
- if(Id == GO_STACKBAR){
- numPlots = maxYR;
- if(Boxes = (BoxPlot**)calloc(numPlots, sizeof(BoxPlot*)))
- for(i = sc = 0; i < (maxYR) && rd[i] && *rd[i]; i++) {
- rY = new AccRange(rd[i]); rname = rY->RangeDesc(data, 3);
- if(Boxes[i]= new BoxPlot(0L, CumData, Dlg->GetCheck(204)? 2:1, 0, i+1, i+2, rname)){
- Boxes[i]->Command(CMD_UPDATE, 0L, 0L); Boxes[i]->parent = this;
- Boxes[i]->Command(CMD_AUTOSCALE, 0L, 0L);
- Boxes[i]->Command(CMD_BOX_FILL, GetSchemeFill(&sc), 0L);
- Boxes[i]->SetSize(SIZE_BOX, 60.0);
- if(rname) free(rname); delete rY; rY = 0L;
- }
- }
- }
- //do stacked polygon
- else if(Id == GO_STACKPG){
- numPG = maxYR;
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, 20, "a1:a%d", nx*2);
-#else
- sprintf(TmpTxt, "a1:a%d", nx*2);
-#endif
- if(Polygons=(DataPolygon**)calloc(numPG,sizeof(DataPolygon*)))
- for(i=sc=0; i < maxYR && rd[i] && *rd[i];i++){
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt+20, 20, "%c1:%c%d", 'c'+i, 'c'+i, nx*2);
-#else
- sprintf(TmpTxt+20, "%c1:%c%d", 'c'+i, 'c'+i, nx*2);
-#endif
- rY = new AccRange(rd[i]); rname = rY->RangeDesc(data, 3);
- if(Dlg->GetCheck(204)) Polygons[i]=new DataPolygon(this,CumData,TmpTxt+20,TmpTxt, rname);
- else Polygons[i] = new DataPolygon(this, CumData, TmpTxt, TmpTxt+20, rname);
- if(Polygons[i]) {
- Polygons[i]->Command(CMD_AUTOSCALE, 0L, 0L);
- Polygons[i]->Command(CMD_PG_FILL, GetSchemeFill(&sc), 0L);
- }
- if(rname) free(rname); delete rY; rY = 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; free(StackBarDlg);
- return bRet;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// create grouped bars chart
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *GBDlg_Tmpl =
- "1,+,,DEFAULT,PUSHBUTTON,-1,140,10,45,12\n"
- ".,.,,,PUSHBUTTON,-2,140,25,45,12\n"
- ".,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "4,+,99,ISPARENT | CHECKED | TOUCHEXIT,SHEET,1,5,10,128,100\n"
- ".,.,200,ISPARENT,SHEET,2,5,10,128,100\n"
- ".,.,300,ISPARENT,SHEET,3,5,10,128,100\n"
- ".,10,250,ISPARENT | TOUCHEXIT,SHEET,16,5,10,128,100\n"
- "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
- "99,100,110,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "100,,160,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "101,+,,,LTEXT,0,25,39,60,8\n"
- ".,.,,,RANGEINPUT,-15,25,49,100,10\n"
- ".,.,,,LTEXT,0,25,61,60,8\n"
- ".,.,,,RANGEINPUT,-16,25,71,100,10\n"
- ".,.,,,PUSHBUTTON,-8,95,87,30,12\n"
- ".,,,,PUSHBUTTON,-9,60,87,35,12\n"
- "110,+,,,LTEXT,4,10,25,60,8\n"
- ".,150,,,LTEXT,5,10,33,60,8\n"
- "150,,153,ISPARENT | CHECKED,GROUPBOX,6,10,50,118,55\n"
- "160,101,,ISPARENT | CHECKED,GROUPBOX,19,10,30,118,75\n"
- "153,+,,,LTEXT,0,15,60,60,8\n"
- ".,.,,,RANGEINPUT,-1,15,70,108,10\n"
- ".,.,,,PUSHBUTTON,-8,93,87,30,12\n"
- ".,,,,PUSHBUTTON,-9,58,87,35,12\n"
- "200,+,,,RTEXT,7,10,35,38,8\n"
- ".,.,,,EDVAL1,8,58,35,35,10\n"
- ".,.,,,RTEXT,9,10,50,38,8\n"
- ".,.,,,EDVAL1,10,58,50,35,10\n"
- ".,.,,,RTEXT,11,10,65,38,8\n"
- ".,.,,,EDVAL1,12,58,65,35,10\n"
- ".,.,,,LTEXT,-10,95,65,8,8\n"
- ".,.,,,RTEXT,13,10,80,38,8\n"
- ".,.,,,EDVAL1,14,58,80,35,10\n"
- ".,,,,LTEXT,-10,95,80,8,8\n"
- "250,+,TOUCHEXIT,CHECKED,RADIO1,17,20,35,70,8\n"
- ".,.,,TOUCHEXIT,RADIO1,18,20,50,70,8\n"
- ".,,,,RANGEINPUT,0,15,65,108,10\n"
- "300,,,LASTOBJ | NOSELECT,ODBUTTON,15,24,30,90,60";
-
-bool
-GroupBars::PropertyDlg()
-{
- TabSHEET tab1 = {0, 27, 10, "Data"};
- TabSHEET tab2 = {27, 59, 10, "Details"};
- TabSHEET tab3 = {59, 96, 10, "Scheme"};
- TabSHEET tab4 = {96, 128, 10, "Labels"};
- double start = 1.0, step = 1.0, bw = 100.0, gg = 100.0;
- void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"Get values from spreadsheet:",
- (void*)"All ranges should have equal size!", (void*)" ranges for y values ", (void*)"start value",
- (void*)&start, (void*)"group step", (void*)&step, (void*)"bar width", (void*)&bw,
- (void*)"group gap", (void*)&gg, (void*)(OD_scheme), (void*)&tab4, (void*)" no group labels",
- (void*)"from spreadsheet range:", (void*)" ranges for y- and error- data "};
- DlgInfo *GBDlg;
- DlgRoot *Dlg;
- void *hDlg;
- bool bRet = false, updateYR = true, bContinue = false, bError;
- char **rd=0L, **rdx=0L, **rdy=0L, *desc;
- Bar **bars = 0L;
- ErrorBar **errs = 0L;
- AccRange *rX = 0L, *rY = 0L;
- anyResult ares;
- int i, j, ic, res, ix, iy, ex, ey, ny, s1, s2, sc = 0, currYR = 0, maxYR = 0;
- double x, y, xinc, e, ebw;
-
- if(!parent || !data) return false;
- if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
- TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return false;
- if(!(GBDlg = CompileDialog(GBDlg_Tmpl, dyndata)))return false;
- if(mode == 0 && TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
- for(i=0, j= 0; i <= 1000; i +=100)
- if(TmpTxt[i]) rd[j++] = (char*)memdup(TmpTxt+i, ((int)strlen(TmpTxt+i))+2, 0);
- maxYR = j-1;
- }
- else if(mode == 1 && TmpTxt[0] && TmpTxt[100] && (rdx = (char**)calloc(12, sizeof(char*)))
- && (rdy = (char**)calloc(12, sizeof(char*)))) {
- for(i=j=0; i <= 1000; i +=200) if(TmpTxt[i]) {
- rdx[j] = (char*)memdup(TmpTxt+i, (int)strlen(TmpTxt)+1, 0);
- rdy[j] = (char*)memdup(TmpTxt+i+100, (int)strlen(TmpTxt+i+100)+1, 0); maxYR = j++;
- }
- }
- Id = GO_STACKBAR;
- if(mode == 0 && !rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
- if(mode == 1 && !rdx && !rdy && !(rdx = (char**)calloc(1, sizeof(char*)))
- && !(rdy = (char**)calloc(1, sizeof(char*))))return false;
- if(!(Dlg = new DlgRoot(GBDlg, data)))return false;
- if(mode == 1) {
- Dlg->ShowItem(99, false); Dlg->ShowItem(100, true);
- }
- else {
- Dlg->ShowItem(99, true); Dlg->ShowItem(100, false);
- }
- if(rd && rd[currYR] && *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
- else Dlg->SetText(154, "");
- hDlg = CreateDlgWnd(mode == 0 ? (char*)"Grouped Bar Chart" : (char*)"Grouped Bar Chart with Error Bars", 50, 50, 390, 260, Dlg, 0x0L);
- do {
- if(updateYR) {
- if(currYR >0) {
- Dlg->ShowItem(156, true); Dlg->ShowItem(106, true);
- }
- else {
- Dlg->ShowItem(156, false); Dlg->ShowItem(106, false);
- }
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, 20, "y-values # %d/%d", currYR+1, maxYR+1);
- sprintf_s(TmpTxt+100, 20, "errors # %d/%d", currYR+1, maxYR+1);
-#else
- sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
- sprintf(TmpTxt+100,"errors # %d/%d", currYR+1, maxYR+1);
-#endif
- //SetText will also cause a redraw of the whole dialog
- if(mode == 0) Dlg->SetText(153, TmpTxt);
- else {
- Dlg->SetText(101, TmpTxt); Dlg->SetText(103, TmpTxt+100);
- }
- updateYR = false;
- }
- LoopDlgWnd();
- res = Dlg->GetResult();
- switch (res) {
- case 0:
- if(bContinue || Dlg->GetCheck(10)) res = -1;
- break;
- case -1:
- bContinue = false;
- break;
- case 250: case 251:
- case 7:
- Dlg->Activate(252, true);
- res = -1; break;
- case 4:
- Dlg->Activate(mode ? 102:154, true);
- res = -1; break;
- case 1:
- Dlg->GetValue(201, &start); Dlg->GetValue(203, &step);
- Dlg->GetValue(205, &bw); Dlg->GetValue(208, &gg);
- res = com_StackDlg(res, Dlg, 0L, 0L, &rd, &currYR,
- &rY, &bContinue, &ny, &maxYR, &updateYR);
- if(!mode) break;
- case 105: //next button
- bError=false; s1 = s2 = 0;
- if(Dlg->GetText(102, TmpTxt, 100)) {
- if(rX = new AccRange(TmpTxt)) {
- s1 = rX->CountItems();
- if(s1 < 2) {
- ErrorBox("y-range not valid");
- bContinue=bError=true;
- Dlg->Activate(102, true);
- }
- delete rX;
- }
- else bError = true;
- }
- else bError = true;
- if(Dlg->GetText(104, TmpTxt+100, 100) && !bError) {
- if(rY = new AccRange(TmpTxt+100)) {
- s2 = rY->CountItems();
- if(s2 < 2) {
- ErrorBox("error-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("Y-range and error-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));
- rdx[currYR] = rdx[currYR+1] = rdy[currYR] = rdy[currYR+1] = 0L;
- maxYR = currYR+1;
- }
- if(rdx[currYR]) free(rdx[currYR]); //store x-range
- rdx[currYR] = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
- if(rdy[currYR]) free(rdy[currYR]); //store y range
- rdy[currYR] = (char*)memdup(TmpTxt+100, (int)strlen(TmpTxt+100)+1, 0);
- updateYR = true; 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, TmpTxt, 100) && Dlg->GetText(104, TmpTxt+100, 100)){
- if(rdx[currYR]) free(rdx[currYR]); if(rdy[currYR]) free(rdy[currYR]);
- rdx[currYR] = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
- rdy[currYR] = (char*)memdup(TmpTxt+100, (int)strlen(TmpTxt+100)+1, 0);
- }
- else if(currYR == maxYR) maxYR--;
- currYR--;
- Dlg->SetText(102, rdx[currYR]);
- Dlg->SetText(104, rdy[currYR]); Dlg->Activate(102, true);
- updateYR = true;
- res = -1;
- break;
- 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])||(rdx && rdy && rdx[0] && rdy[0] && rdx[0][0] && rdy[0][0]))){
- //accept settings and create plots
- if((mode == 0 && rd[maxYR]) || (mode == 1 && rdx[maxYR])) maxYR++;
- ebw = defs.GetSize(SIZE_ERRBAR)*9.0/((double)(s1*maxYR));
- if(Dlg->GetCheck(251) && Dlg->GetText(252, TmpTxt, 100) && (rX = new AccRange(TmpTxt))
- && rX->GetFirst(&ix, &iy)){
- x_tv = new TextValue(); rX->GetNext(&ix, &iy);
- i = 1; start = step = 1.0;
- do {
- if(data->GetResult(&ares, iy, ix, false)) switch(ares.type) {
- case ET_TEXT:
- x_tv->GetValue(ares.text); break;
- case ET_VALUE: case ET_DATE: case ET_TIME:
- case ET_DATETIME: case ET_BOOL:
- TranslateResult(&ares);
- x_tv->GetValue(ares.text); break;
- }
- i++;
- }while(rX->GetNext(&ix, &iy));
- }
- if(rX) delete rX; rX = 0L;
- 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, desc = 0L; i < maxYR; i++) {
- x = start + xinc * (double)i;
- if(mode == 0 && rd) {
- if(rd[i] && (rY = new AccRange(rd[i]))) ny = rY->CountItems();
- else {
- rY = 0L; ny = 0;
- }
- }
- else if(mode == 1 && rdx && rdy) {
- if(rdx[i] && (rY = new AccRange(rdx[i]))) ny = rY->CountItems();
- else {
- rY = 0L; ny = 0;
- }
- }
- if(rY) {
- desc = rY->RangeDesc(data, 1);
- rY->GetFirst(&ix, &iy);
- if(mode == 1 && (rX = new AccRange(rdy[i]))) {
- errs = (ErrorBar**)calloc(ny, sizeof(ErrorBar*));
- rX->GetFirst(&ex, &ey);
- }
- rY->GetNext(&ix, &iy);
- if(ny && rY && (bars = (Bar **)calloc(ny, sizeof(Bar*)))){
- for(ic = 0; ic < ny; ic++) {
- if(bContinue = data->GetValue(iy, ix, &y)){
- bars[ic] = new Bar(0L, data, x, y, BAR_VERTB | BAR_RELWIDTH,
- -1, -1, ix, iy, desc);
- CheckBounds(x, y);
- }
- if(errs && rX && rX->GetNext(&ex, &ey) && data->GetValue(ey, ex, &e)) {
- if(bContinue && (errs[ic] = new ErrorBar(0L, data, x, y, e, 0, -1, -1, ix, iy, ex, ey)))
- errs[ic]->SetSize(SIZE_ERRBAR, ebw);
- CheckBounds(x, y+e); CheckBounds(x, y-e);
- }
- x += step;
- rY->GetNext(&ix, &iy);
- }
- xyPlots[numXY++] = new PlotScatt(this, data, ic, bars, errs);
- 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]);
- if(errs) for(ic = 0; ic < ny; ic++) if(errs[ic]) delete(errs[ic]);
- free(bars); if(errs) free(errs); bRet = true;
- }
- delete(rY); if(desc) free(desc); rY = 0L;
- }
- }
- }
- CloseDlgWnd(hDlg);
- delete Dlg;
- if(rd) {
- for (i = 0; i < maxYR; i++) if(rd[i]) free(rd[i]);
- free(rd);
- }
- 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(rY) delete rY; if(rX) delete rX; free(GBDlg);
- 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, CHECKED, 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, RANGEINPUT, 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, RANGEINPUT, TmpTxt, 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, COLBUTT, (void*)&defcol, 105, 35, 20, 10},
- {302, 303, 0, 0x0L, RADIO1, (void*)" increment color scheme:", 20, 55, 80, 9},
- {303, 304, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[0], 25, 70, 10, 10},
- {304, 305, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[1], 37, 70, 10, 10},
- {305, 306, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[2], 49, 70, 10, 10},
- {306, 307, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[3], 61, 70, 10, 10},
- {307, 308, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[4], 73, 70, 10, 10},
- {308, 309, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[5], 85, 70, 10, 10},
- {309, 310, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[6], 97, 70, 10, 10},
- {310, 0, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[7], 109, 70, 10, 10},
- {500, 0, 0, LASTOBJ, NONE, 0L, 0, 0, 0, 0}};
- DlgRoot *Dlg;
- void *hDlg;
- int i, j, res, currYR=0, maxYR=0, nx=0, ny;
- char **rd = 0L;
- bool updateYR = true, bContinue = false, bRet = false, bUseSch;
- AccRange *rX = 0L, *rY = 0L;
-
- if(!parent || !data) return false;
- if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
- TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return false;
- if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
- for(i=100, j= 0; i <= 1000; i +=100) if(TmpTxt[i])
- rd[j++] = (char*)memdup(TmpTxt+i, ((int)strlen(TmpTxt+i))+2, 0);
- maxYR = j-1;
- }
- if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
- if(!(Dlg = new DlgRoot(StackBarDlg, data))) return false;
- if(rd && rd[currYR] && *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
- 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);
- }
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, 20, "y-values # %d/%d", currYR+1, maxYR+1);
-#else
- sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
-#endif
- //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, 100);
- 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
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *MultiLineDlg_Tmpl =
- "1,2,,DEFAULT,PUSHBUTTON,-1,158,10,45,12\n"
- "2,3,,,PUSHBUTTON,-2,158,25,45,12\n"
- "3,,10,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "10,11,100,ISPARENT | CHECKED,SHEET,1,5,10,140,100\n"
- "11,12,300,ISPARENT,SHEET,2,5,10,140,100\n"
- "12,20,200,ISPARENT,SHEET,15,5,10,140,100\n"
- "20,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
- "100,101,,ISPARENT | CHECKED,GROUPBOX,3,12,30,128,75\n"
- "101,102,,,LTEXT,0,25,39,60,8\n"
- "102,103,,,RANGEINPUT,-15,25,49,100,10\n"
- "103,104,,,LTEXT,0,25,61,60,8\n"
- "104,105,,,RANGEINPUT,-16,25,71,100,10\n"
- "105,106,,,PUSHBUTTON,-8,95,87,30,12\n"
- "106,107,,,PUSHBUTTON,-9,60,87,35,12\n"
- "107,108,,OWNDIALOG,COLBUTT,4,25,87,20,12\n"
- "108,,,,LTEXT,12,47,90,30,9\n"
- "200,201,,CHECKED,CHECKBOX,16,25,35,80,9\n"
- "201,202,,ODEXIT,SYMBUTT,17,25,70,10,10\n"
- "202,203,,ODEXIT,SYMBUTT,18,37,70,10,10\n"
- "203,204,,ODEXIT,SYMBUTT,19,49,70,10,10\n"
- "204,205,,ODEXIT,SYMBUTT,20,61,70,10,10\n"
- "205,206,,ODEXIT,SYMBUTT,21,73,70,10,10\n"
- "206,207,,ODEXIT,SYMBUTT,22,85,70,10,10\n"
- "207,208,,ODEXIT,SYMBUTT,23,97,70,10,10\n"
- "208,209,,ODEXIT,SYMBUTT,24,109,70,10,10\n"
- "209,,,CHECKED,CHECKBOX,25,25,50,80,9\n"
- "300,301,,TOUCHEXIT,RADIO1,13,20,35,80,9\n"
- "301,302,,ODEXIT,COLBUTT,4,105,35,20,10\n"
- "302,303,,CHECKED | TOUCHEXIT, RADIO1,14,20,55,80,9\n"
- "303,304,,ODEXIT,COLBUTT,4,25,70,10,10\n"
- "304,305,,ODEXIT,COLBUTT,5,37,70,10,10\n"
- "305,306,,ODEXIT,COLBUTT,6,49,70,10,10\n"
- "306,307,,ODEXIT,COLBUTT,7,61,70,10,10\n"
- "307,308,,ODEXIT,COLBUTT,8,73,70,10,10\n"
- "308,309,,ODEXIT,COLBUTT,9,85,70,10,10\n"
- "309,310,,ODEXIT,COLBUTT,10,97,70,10,10\n"
- "310,,,LASTOBJ | ODEXIT,COLBUTT,11,109,70,10,10\n";
-
-bool
-MultiLines::PropertyDlg()
-{
- TabSHEET tab1 = {0, 25, 10, "Data"};
- TabSHEET tab2 = {25, 60, 10, "Scheme"};
- TabSHEET tab3 = {60, 97, 10, "Symbols"};
- static DWORD colarr[] = {0x00000000L, 0x00ff0000L, 0x0000ff00L, 0x000000ffL,
- 0x00ff00ff, 0x00ffff00L, 0x0000ffff, 0x00c0c0c0};
- Symbol *syms[8], **lsyms;
- static DWORD defcol = 0x0L;
- char x_txt[100], y_txt[100];
- DlgInfo *StackBarDlg;
- void *dyndata[] = {(void*) &tab1, (void*)&tab2, (void*)" ranges for x- and y- values ",
- (void*)&colarr[0], (void*)&colarr[1], (void*)&colarr[2], (void*)&colarr[3],
- (void*)&colarr[4], (void*)&colarr[5], (void*)&colarr[6], (void*)&colarr[7],
- (void*)"line color", (void*)" common color for lines:", (void*)" increment color scheme:",
- (void*) &tab3, (void*)" draw symbols", (void*)&syms[0], (void*)&syms[1], (void*)&syms[2],
- (void*)&syms[3], (void*)&syms[4], (void*)&syms[5], (void*)&syms[6], (void*)&syms[7],
- (void*) " use line color for symbols"};
- DlgRoot *Dlg;
- void *hDlg;
- char **rdx=0L, **rdy=0L;
- DWORD *rdc = 0L, curr_col;
- int i, j, nd, res, currYR=0, maxYR=0, s1, s2, rx, ry, cx, cy;
- double symsize, x, y;
- bool updateYR = true, bContinue = false, bError, bRet = false;
- AccRange *rX = 0L, *rY = 0L;
- DataLine *dl;
-
- if(!parent || !data) return false;
- symsize = NiceValue(defs.GetSize(SIZE_SYMBOL)*.8);
- for(i = 0; i < 8; i++) if(syms[i] = new Symbol(0L, data, 0.0, 0.0, i)) {
- if(i != 2 && i != 3)syms[i]->SetSize(SIZE_SYMBOL, symsize);
- }
- if(!(StackBarDlg = CompileDialog(MultiLineDlg_Tmpl, dyndata)))return false;
- if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
- TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return false;
- if(TmpTxt[0] && TmpTxt[100] && (rdx = (char**)calloc(12, sizeof(char*)))
- && (rdy = (char**)calloc(12, sizeof(char*))) && (rdc = (DWORD*)malloc(12*sizeof(DWORD)))) {
- for(i=100, j= 0; i <= 1000; i +=100) if(TmpTxt[i]) {
- rdx[j] = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0); rdc[j] = colarr[j%8];
- rdy[j] = (char*)memdup(TmpTxt+i, (int)strlen(TmpTxt+i)+1, 0); maxYR = j++;
- }
- }
- if(!(Dlg = new DlgRoot(StackBarDlg, data))) return false;
- hDlg = CreateDlgWnd("Create Multi Line Plot", 50, 50, 420, 260, Dlg, 0x0L);
- do {
- if(updateYR) {
- if(currYR >0) {
- Dlg->ShowItem(106, true); Dlg->ShowItem(108, false);
- }
- else {
- Dlg->ShowItem(106, false); Dlg->ShowItem(108, true);
- }
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "x-range # %d/%d", currYR+1, maxYR+1);
-#else
- sprintf(TmpTxt,"x-range # %d/%d", currYR+1, maxYR+1);
-#endif
- //SetText will also cause a redraw of the whole dialog
- Dlg->SetText(101, TmpTxt);
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "y-range # %d/%d", currYR+1, maxYR+1);
-#else
- sprintf(TmpTxt,"y-range # %d/%d", currYR+1, maxYR+1);
-#endif
- 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, 100)) {
- 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, 100) && !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]); //store x-range
- rdx[currYR] = (char*)memdup(x_txt, (int)strlen(x_txt)+1, 0);
- if(rdy[currYR]) free(rdy[currYR]); //store y range
- rdy[currYR] = (char*)memdup(y_txt, (int)strlen(y_txt)+1, 0);
- 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, 100) && Dlg->GetText(104, y_txt, 100)){
- if(rdx[currYR]) free(rdx[currYR]); if(rdy[currYR]) free(rdy[currYR]);
- rdx[currYR] = (char*)memdup(x_txt, (int)strlen(x_txt)+1, 0);
- rdy[currYR] = (char*)memdup(y_txt, (int)strlen(y_txt)+1, 0);
- 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 201: case 202: case 203: case 204:
- case 205: case 206: case 207: case 208:
- res = -1;
- 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);
- i = res-303;
- if(rdx && rdy && i <= maxYR && rdc[i] == colarr[i]) {
- Dlg->GetColor(res, &colarr[i]); rdc[i] = colarr[i];
- Dlg->SetColor(107, rdc[currYR]);
- }
- else {
- Dlg->GetColor(res, &colarr[i]);
- }
- res = -1; break;
- }
- }while (res < 0);
- if(res == 1 && rdx && rdy && maxYR) {
- maxYR++; rX = rY = 0L;
- 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(Dlg->GetCheck(200) && (rX = new AccRange(rdx[i])) && (rY = new AccRange(rdy[i]))) {
- lsyms = (Symbol**)calloc(rX->CountItems()+1, sizeof(Symbol*));
- symsize = syms[i &0x07]->GetSize(SIZE_SYMBOL);
- for(nd = 0, rX->GetFirst(&cx, &rx), rY->GetFirst(&cy, &ry); rX->GetNext(&cx, &rx), rY->GetNext(&cy, &ry); ) {
- if(data->GetValue(rx, cx, &x) && data->GetValue(ry, cy, &y)) {
- lsyms[nd] = new Symbol(0L, data, x, y, syms[i &0x07]->type, cx, rx, cy, ry);
- if(Dlg->GetCheck(209)) lsyms[nd]->SetColor(COL_SYM_LINE, Dlg->GetCheck(300) ? defcol : rdc[i & 0x07]);
- else {
- lsyms[nd]->SetColor(COL_SYM_LINE, syms[i &0x07]->GetColor(COL_SYM_LINE));
- lsyms[nd]->SetColor(COL_SYM_FILL, syms[i &0x07]->GetColor(COL_SYM_FILL));
- }
- lsyms[nd]->SetSize(SIZE_SYMBOL, symsize);
- nd++;
- }
- }
- }
- else {
- nd = 0; lsyms = 0L;
- }
- if(dl = new DataLine(this, data, rdx[i], rdy[i])) {
- dl->SetColor(COL_DATA_LINE, Dlg->GetCheck(300) ? defcol : rdc[i & 0xf]);
- if(xyPlots[numXY] = new PlotScatt(this, data, nd, lsyms, dl)) {
- if(rY) xyPlots[numXY]->data_desc = rY->RangeDesc(data, 1);
- numXY++;
- }
- else delete dl;
- }
- if(rX)delete rX; if(rY)delete rY; rX = rY = 0L;
- }
- }
- 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);
- }
- for(i = 0; i < 8; i++) if(syms[i]) delete syms[i];
- free(StackBarDlg); if(rdc) free(rdc);
- if(bRet) {
- Bounds.Xmax = Bounds.Ymax = -HUGE_VAL; Bounds.Xmin = Bounds.Ymin = HUGE_VAL;
- Command(CMD_AUTOSCALE, 0L, 0L);
- }
- return bRet;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Pie and ring chart properties
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *PieDlgTmpl =
- "1,2,,DEFAULT,PUSHBUTTON,-1,130,10,45,12\n"
- "2,3,,,PUSHBUTTON,-2,130,25,45,12\n"
- "3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "4,5,100,ISPARENT | CHECKED,SHEET,1,5,10,120,103\n"
- "5,6,200,ISPARENT,SHEET,2,5,10,120,103\n"
- "6,10,300,ISPARENT,SHEET,3,5,10,120,103\n"
- "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
- "100,101,,,LTEXT,4,10,25,60,8\n"
- "101,105,,,RANGEINPUT,-15,15,35,100,10\n"
- "105,106,500,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "106,107,600,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "107,108,,,EDVAL1,6,58,59,30,10\n"
- "108,,,,LTEXT,-3,89,59,15,8\n"
- "200,201,,,LTEXT,7,15,30,60,8\n"
- "201,202,,,RTEXT,-4,2,42,20,8\n"
- "202,204,,,EDVAL1,8,23,42,30,10\n"
- "204,205,,,RTEXT,-5,47,42,20,8\n"
- "205,206,,,EDVAL1,9,68,42,30,10\n"
- "206,207,,,LTEXT,-3,99,42,15,8\n"
- "207,208,,,RTEXT,10,27,58,20,8\n"
- "208,209,,,EDVAL1,11,48,58,30,10\n"
- "209,210,,,LTEXT,12,79,58,15,8\n"
- "210,211,400,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "211,212,410,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "212,,,,LTEXT,13,15,80,30,8\n"
- "300,,,NOSELECT,ODBUTTON,14,20,35,80,60\n"
- "400,401,,EXRADIO | CHECKED,ODBUTTON,15,40,75,30,30\n"
- "401,,,EXRADIO,ODBUTTON,15,70,75,30,30\n"
- "410,411,,EXRADIO | CHECKED,ODBUTTON,15,40,75,30,30\n"
- "411,,,EXRADIO,ODBUTTON,15,70,75,30,30\n"
- "500,501,,CHECKED,RADIO1,16,10,59,20,8\n"
- "501,502,,,RADIO1,17,10,71,40,8\n"
- "502,503,,,RANGEINPUT,-16,15,82,100,10\n"
- "503,504,,,LTEXT,19,15,94,10,8\n"
- "504,505,,,EDVAL1,20,42,94,25,10\n"
- "505,,,,LTEXT,21,70,94,15,8\n"
- "600,601,,,RTEXT,22,8,59,45,8\n"
- "601,602,,,RTEXT,23,8,74,45,8\n"
- "602,603,,,EDVAL1,24,58,74,30,10\n"
- "603,,,LASTOBJ,LTEXT,-3,89,74,15,8";
-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];
- void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"spread sheet range for values",
- 0L, (void*)&frad, (void*)"position of center:", (void*)&fcx, (void*)&fcy,
- (void*)"start angle", (void*)&CtDef.fx, (void*)"degree", (void*)"style:", (void*)(OD_scheme),
- (void*)(OD_PieTempl), (void*)"fixed radius", (void*)"pick radii from spreadsheet range",
- 0L, (void*)"x factor", (void*)&FacRad, (void*)&txt2, (void*)"outer radius",
- (void*)"inner radius", (void*)&firad};
- DlgInfo *PieDlg = CompileDialog(PieDlgTmpl, dyndata);
- DlgRoot *Dlg;
- void *hDlg;
- int i, ix, iy, rix, riy, ny, res, cf, cb;
- bool bRet = false, bContinue = false;
- double sum = 0.0, dang1, dang2;
- double fv;
- lfPOINT fpCent;
- AccRange *rY = 0L, *rR = 0L;
-
- if(!parent || !data) return false;
- UseRangeMark(data, 1, TmpTxt, TmpTxt+100);
- cb = rlp_strcpy(txt2, 80, "= ["); cb += rlp_strcpy(txt2+cb, 80-cb, Units[defs.cUnits].display);
- rlp_strcpy(txt2+cb, 80-cb, "]");
- 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;
- if(!(Dlg = new DlgRoot(PieDlg, data)))return false;
- 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, 266, 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, TMP_TXT_SIZE) && 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, TMP_TXT_SIZE) &&
- (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, TMP_TXT_SIZE)) ssRefA = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
- if(rR && Dlg->GetText(502, TmpTxt, TMP_TXT_SIZE)) ssRefR = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
- 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; free(PieDlg);
- 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(DefSize(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, CHECKED, 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, RANGEINPUT, 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, RANGEINPUT, (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, DefSize(SIZE_TEXT), 0.0, 0.0, 0,
- TXA_HCENTER | TXA_VCENTER, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, 0L};
-
- if(!parent || !data) return false;
- data->GetSize(&width, &height);
-#ifdef USE_WIN_SECURE
- sprintf_s(txt1, 80,"a1:a%d", height); sprintf_s(txt2, 80, "= [%s]", Units[defs.cUnits].display);
-#else
- sprintf(txt1, "a1:a%d", height); sprintf(txt2, "= [%s]", Units[defs.cUnits].display);
-#endif
- 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, data)))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, TMP_TXT_SIZE) && 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, TMP_TXT_SIZE) && 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;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Grid3D represents a surface in space
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-bool
-Grid3D::PropertyDlg()
-{
- return Configure();
-}
-
-bool
-Grid3D::Configure()
-{
- TabSHEET tab1 = {0, 37, 10, "Function"};
- TabSHEET tab2 = {37, 65, 10, "Style"};
- FillDEF newFill;
- DlgInfo GridDlg[] = {
- {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 155, 10, 50, 12},
- {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 155, 25, 50, 12},
- {3, 0, 300, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
- {300, 301, 500, HIDDEN | CHECKED, GROUPBOX, (void*)" grid lines ", 10, 10, 140, 100},
- {301, 305, 400, HIDDEN | CHECKED, GROUPBOX, (void*)" surface ", 10, 10, 140, 100},
- {305, 306, 0, TOUCHEXIT, RADIO1, (void*) " grid lines", 155, 45, 50, 10},
- {306, 0, 0, TOUCHEXIT, RADIO1, (void*) " surface", 155, 57, 50, 10},
- {400, 401, 0, 0x0L, RTEXT, (void*)"grid line width", 38, 20, 40, 8},
- {401, 402, 0, 0x0L, EDVAL1, &Line.width, 80, 20, 25, 10},
- {402, 403, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 107, 20, 20, 8},
- {403, 404, 0, 0x0L, RTEXT, (void*)"grid line color", 38, 32, 40, 8},
- {404, 405, 0, OWNDIALOG, COLBUTT, (void *)&Line.color, 80, 32, 25, 10},
- {405, 406, 0, 0x0L, RTEXT,(void*)"plane color" , 38, 44, 40, 8},
- {406, 0, 0, OWNDIALOG, SHADE3D, &newFill, 80, 44, 25, 10},
- {500, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)OD_linedef, 15, 15, 130, 100}};
- DlgRoot *Dlg;
- void *hDlg;
- int res, cb, new_type, undo_level = *Undo.pcb;
- bool bRet = false;
- double tmp;
- DWORD new_col;
- LineDEF newLine;
- anyOutput *cdisp = Undo.cdisp;
-
- if(!parent) return false;
- memcpy(&newFill, &Fill, sizeof(FillDEF));
- OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
- if(!(Dlg = new DlgRoot(GridDlg, data))) return false;
- if(!type) {
- Dlg->ShowItem(300, true); Dlg->SetCheck(305, 0L, true);
- }
- else {
- Dlg->ShowItem(301, true); Dlg->SetCheck(306, 0L, true);
- }
- if(parent->name) {
- cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Grid of ");
- rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
- }
- else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "3D Grid");
- hDlg = CreateDlgWnd(TmpTxt, 50, 50, 426, 260, Dlg, 0x0L);
- do{
- LoopDlgWnd();
- res = Dlg->GetResult();
- switch (res) {
- case 305: case 306:
- if(Dlg->GetCheck(305)) {
- Dlg->ShowItem(300, true); Dlg->ShowItem(301, false);
- }
- else {
- Dlg->ShowItem(300, false); Dlg->ShowItem(301, true);
- }
- Dlg->Command(CMD_REDRAW, 0L, 0L);
- res = -1;
- break;
- }
- }while (res < 0);
- Undo.SetDisp(cdisp);
- while(*Undo.pcb > undo_level) Undo.Pop(cdisp);
- if(res == 1) {
- if(Dlg->GetCheck(305) && type == 0) {
- OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
- if(cmpLineDEF(&Line, &newLine)) {
- Command(CMD_SET_LINE, &newLine, 0L);
- bRet = true;
- }
- }
- else if(Dlg->GetCheck(306) && type == 1) {
- Dlg->GetValue(401, &tmp); Dlg->GetColor(404, &new_col);
- if(planes && (cmpFillDEF(&Fill, &newFill) || tmp != Line.width || new_col != Line.color)) {
- Command(CMD_SAVE_SYMBOLS, 0L, 0L);
- Command(CMD_SYM_FILL, &newFill, 0L);
- if(tmp != Line.width) SetSize(SIZE_SYM_LINE, tmp);
- if(new_col != Line.color) SetColor(COL_POLYLINE, new_col);
- bRet = true;
- }
- }
- else {
- Undo.ValInt(parent, &type, 0L);
- Undo.Line(this, &Line, UNDO_CONTINUE); Undo.Fill(this, &Fill, UNDO_CONTINUE);
- if(Dlg->GetCheck(305)) {
- new_type = 0;
- OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&Line, 0);
- }
- else {
- new_type = 1;
- memcpy(&Fill, &newFill, sizeof(FillDEF));
- Dlg->GetValue(401, &Line.width);
- Dlg->GetColor(404, &Line.color);
- Line.pattern = 0L;
- Line.patlength = 1;
- }
- if(planes && nPlanes) Undo.DropListGO(parent, (GraphObj***)&planes, &nPlanes, UNDO_CONTINUE);
- if(lines && nLines) Undo.DropListGO(parent, (GraphObj***)&lines, &nLines, UNDO_CONTINUE);
- Undo.VoidPtr(parent, (void**)&planes, 0L, 0L, UNDO_CONTINUE);
- Undo.VoidPtr(parent, (void**)&lines, 0L, 0L, UNDO_CONTINUE);
- type = new_type;
- CreateObs(true);
- bRet = true;
- }
- }
- CloseDlgWnd(hDlg);
- delete Dlg;
- return bRet;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Scatt3D is a layer representing most simple 3D plots
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *Dlg3DTmpl =
- "1,2,,DEFAULT,PUSHBUTTON,-1,142,10,45,12\n"
- "2,3,,,PUSHBUTTON,-2,142,25,45,12\n"
- "3,50,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "4,5,100,TOUCHEXIT | ISPARENT | CHECKED, SHEET,1,5,10,131,100\n"
- "5,6,200,TOUCHEXIT | ISPARENT, SHEET,2,5,10,131,100\n"
- "6,10,400, TOUCHEXIT | ISPARENT, SHEET,3,5,10,131,100\n"
- "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
- "50,60,,NOSELECT, ODBUTTON,4,142,65,45,45\n"
- "60,61,,,ICON,5,10,114,20,20\n"
- "61,62,,,LTEXT,6,30,116,100,6\n"
- "62,,,,LTEXT,7,30,122,100,6\n"
- "100,101,,,LTEXT,8,10,30,60,8\n"
- "101,102,,,RANGEINPUT,9,20,40,100,10\n"
- "102,103,,,LTEXT,10,10,55,60,8\n"
- "103,104,,,RANGEINPUT,11,20,65,100,10\n"
- "104,105,,,LTEXT,12,10,80,60,8\n"
- "105,,,,RANGEINPUT,13,20,90,100,10\n"
- "200,201,,,LTEXT,14,25,30,60,8\n"
- "201,202,,,CHECKBOX,15,30,55,60,8\n"
- "202,203,,TOUCHEXIT,CHECKBOX,16,30,65,60,8\n"
- "203,204,,TOUCHEXIT,CHECKBOX,17,30,45,60,8\n"
- "204,205,,TOUCHEXIT,CHECKBOX,18,30,75,60,8\n"
- "205,,,TOUCHEXIT,CHECKBOX,19,30,85,60,8\n"
- "400,410,,,LTEXT,20,20,30,60,8\n"
- "410,411,,EXRADIO,ODBUTTON,21,20,42,25,25\n"
- "411,412,,EXRADIO,ODBUTTON,21,45,42,25,25\n"
- "412,,,LASTOBJ | EXRADIO,ODBUTTON,21,70,42,25,25";
-
-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;
- void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)(OD_AxisDesc3D), (void*)&icon,
- (void*)"Use [arrow keys], [shift]+[arrow key],", (void*)"and [r], [R], [l] or [L] to rotate graph.",
- (void*)"range for X Data", (void*)text1, (void*)"range for Y Data", (void*)text2,
- (void*)"range for Z Data", (void*)text3, (void*)"select style:", (void*)" balls", (void*)" columns",
- (void*)" line", (void*)" drop lines", (void*)" arrows", (void*)"select template:",
- (void*)(OD_AxisTempl3D)};
- DlgInfo *Dlg3D = CompileDialog(Dlg3DTmpl, dyndata);
- DlgRoot *Dlg;
- void *hDlg;
- int res, n1, n2, n3, ic = 0;
- int i, j, k, l, m, n, i2, j2, k2, l2, m2, cb;
- double x, y, z, bar_w, bar_d, rad;
- bool bRet = false, bContinue = false;
- AccRange *rX, *rY, *rZ;
- fPOINT3D pos1, pos2;
-
- if(!data || !parent)return false;
- UseRangeMark(data, 1, text1, text2, text3);
- if(!(Dlg = new DlgRoot(Dlg3D, data)))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 || c_flags == 0x4000) {
- Dlg->ShowItem(5, false); Dlg->ShowItem(6, false);
- }
- else Dlg->ShowItem(6, (c_flags & 0x1000) == 0x1000);
- rX = rY = rZ = 0L; rad = DefSize(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 Paravent Plot":
- c_flags == 0x4000 ? (char*)"Delauney Surface" : (char*)"Create 3D 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, 100) && (rX = new AccRange(text1))) n1 = rX->CountItems();
- if(Dlg->GetText(103, text2, 100) && (rY = new AccRange(text2))) n2 = rY->CountItems();
- if(Dlg->GetText(105, text3, 100) && (rZ = new AccRange(text3))) n3 = rZ->CountItems();
- if(n1 && n2 && n3){
- if(c_flags == 0x2000 || c_flags == 0x4000) {
- //no more but a ribbon or surface
- }
- 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 {
- cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Ranges for ");
- if(!n1) cb += rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, "\n- X Data");
- if(!n2) cb += rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, "\n- Y Data");
- if(!n3) cb += rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, "\n- Z Data");
- rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, "\nnot given or not valid.");
- 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 = (DefSize(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, 2, text1, text2, text3);
- }
- else if(c_flags == 0x4000){
- rib = new Ribbon(this, data, 3, 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; free(Dlg3D);
- 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, 600, 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, NOSELECT, ODBUTTON, (void*)OD_linedef, 15, 25, 130, 100},
- {600, 601, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 170, 45, 15, 15},
- {601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 170, 60, 15, 15},
- {602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 170, 75, 15, 15},
- {603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 170, 90, 15, 15}};
- 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;
- anyOutput *cdisp = Undo.cdisp;
-
- 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, data))) 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;
- case 600: case 601: case 602: case 603:
- Undo.SetDisp(cdisp);
- res = ExecDrawOrderButt(parent, this, res);
- }
- }while (res < 0);
- Undo.SetDisp(cdisp);
- if(res == 2) while(*Undo.pcb > undo_level) Undo.Restore(true, cdisp);
- else 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, TMP_TXT_SIZE);
- cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
- ReshapeFormula(&cmdxy); 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);
- if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE))
- undo_flags = CheckNewString(&cmdxy, cmdxy, TmpTxt, this, undo_flags);
- if(undo_flags & UNDO_CONTINUE){
- Update(0L, UNDO_CONTINUE); Command(CMD_MRK_DIRTY, 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;
- 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, CHECKED, 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, RANGEINPUT, (void*)text1, 20, 40, 100, 10},
- {402, 403, 0, 0x0L, LTEXT, (void*)"range for Y Data", 10, 55, 60, 8},
- {403, 404, 0, 0x0L, RANGEINPUT, (void*)text2, 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;
- size_t cb;
- 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;
- anyOutput *cdisp = Undo.cdisp;
- anyResult *ares;
-
- if(!parent || !data) return false;
- if(!(o_cmdxy = (char*)memdup(cmdxy, (int)strlen(cmdxy)+1, 0))) return false;;
- if(!(o_parxy = (char*)memdup(parxy, (int)strlen(parxy)+1, 0))) return false;;
- UseRangeMark(data, 1, text1, text2);
- iter = (double)maxiter;
- OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
- if(!(Dlg = new DlgRoot(FuncDlg, data))) 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) {
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "Chi 2 = %g", chi2);
-#else
- sprintf(TmpTxt, "Chi 2 = %g", chi2);
-#endif
- 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, TMP_TXT_SIZE)) {
- if(parxy = (char*)realloc(parxy, (cb = strlen(TmpTxt)+2)))
- rlp_strcpy(parxy, (int)cb, TmpTxt);
- }
- if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
- if(cmdxy = (char*)realloc(cmdxy, (cb = strlen(TmpTxt)+2)))
- rlp_strcpy(cmdxy, (int)cb, TmpTxt);
- }
- ReshapeFormula(&parxy); ReshapeFormula(&cmdxy);
- dirty = true;
- break;
- }
- case 7: //Start: do nonlinear regression
- Undo.SetDisp(cdisp);
- if(Dlg->GetCheck(5)) { // the function tab must be shown
- if(Dlg->CurrDisp) Dlg->CurrDisp->MouseCursor(MC_WAIT, true);
- Dlg->GetText(401, text1, 100); Dlg->GetText(403, text2, 100);
- if(Dlg->GetText(102, TmpTxt, TMP_TXT_SIZE)) {
- if(parxy = (char*)realloc(parxy, (cb = strlen(TmpTxt)+2)))
- rlp_strcpy(parxy, (int)cb, TmpTxt);
- }
- if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
- if(cmdxy = (char*)realloc(cmdxy, (cb = strlen(TmpTxt)+2)))
- rlp_strcpy(cmdxy, (int)cb, TmpTxt);
- }
- Dlg->GetValue(153, &conv); Dlg->GetValue(155, &iter);
- ReshapeFormula(&parxy); ReshapeFormula(&cmdxy);
- do_formula(data, 0L); //clear any error condition
- ares = do_formula(data, parxy);
- if(ares->type != ET_VALUE) {
- ErrorBox("Syntax Error in parameters.");
- bContinue = true; res = -1;
- break;
- }
- ares = do_formula(data, cmdxy);
- if(ares->type != ET_VALUE) {
- ErrorBox("Syntax Error in formula.");
- bContinue = true; res = -1;
- break;
- }
- i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE-2, parxy); i += rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, ";x=1;");
- rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, cmdxy); yywarn(0L, true);
- ares = do_formula(data, TmpTxt);
- if(tmp_char = yywarn(0L, false)) {
- ErrorBox(tmp_char);
- bContinue = true; res = -1;
- break;
- }
- i = do_fitfunc(data, text1, text2, 0L, &parxy, cmdxy, conv, (int)iter, &chi2);
- Dlg->SetText(102, parxy);
- if(i >1 || res == 7) {
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "The Levenberg-Marquart algorithm\nexited after %d iterations.\n\nChi2 = %g", i, chi2);
-#else
- sprintf(TmpTxt, "The Levenberg-Marquart algorithm\nexited after %d iterations.\n\nChi2 = %g", i, chi2);
-#endif
- 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);
- Undo.SetDisp(cdisp);
- while(*Undo.pcb > undo_level) Undo.Pop(cdisp);
- if(res == 1){ //OK pressed
- //get ranges for x- and y data (again).
- chi2 = n_chi2;
- if(Dlg->GetText(401, text1, 100) && (ssXref = (char*)realloc(ssXref, (cb = strlen(text1)+2))))
- rlp_strcpy(ssXref, (int)cb, text1);
- if(Dlg->GetText(403, text2, 100) && (ssYref = (char*)realloc(ssYref, (cb = strlen(text2)+2))))
- rlp_strcpy(ssYref, (int)cb, 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, "Fitted function"))){
- 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);
- Command(CMD_ENDDIALOG, 0L, 0L); 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);
- undo_flags = CheckNewFloat(&xstep, o_xstep, n_xstep, this, undo_flags);
- if(undo_flags){
- 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(0L, UNDO_CONTINUE);
- }
- undo_flags = CheckNewString(&parxy, o_parxy, parxy, this, undo_flags);
- undo_flags = CheckNewString(&cmdxy, o_cmdxy, cmdxy, this, undo_flags);
- if(undo_flags & UNDO_CONTINUE) {
- Undo.ValInt(parent, (int*)&dirty, undo_flags);
- Command(CMD_MRK_DIRTY, 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;
- Command(CMD_ENDDIALOG, 0L, 0L);
- }
- }
- CloseDlgWnd(hDlg);
- delete Dlg;
- if(o_parxy) free(o_parxy); if(o_cmdxy) free(o_cmdxy);
- return bRet;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Create a new normal quantile plot
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *NormQuantDlg_Tmpl =
- "1,2,,DEFAULT,PUSHBUTTON,-1,148,10,45,12\n"
- "2,3,,,PUSHBUTTON,-2,148,25,45,12\n"
- "3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "4,10,100,ISPARENT | CHECKED,SHEET,1,5,10,130,80\n"
- "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
- "100,101,,,LTEXT,2,10,30,60,8\n"
- "101,,,LASTOBJ,RANGEINPUT,-15,20,40,100,10";
-
-bool
-NormQuant::PropertyDlg()
-{
- TabSHEET tab1 = {0, 25, 10, "Data"};
- DlgInfo *QuantDlg;
- void *dyndata[] = {(void*)&tab1, (void*)"range for variables"};
- DlgRoot *Dlg;
- void *hDlg;
- int res;
- char *mrk;
- bool bContinue = false, bRet = false;
-
- if(!parent || !data) return false;
- if(!(QuantDlg = CompileDialog(NormQuantDlg_Tmpl, dyndata))) return false;
- if(data->Command(CMD_GETMARK, &mrk, 0L))rlp_strcpy(TmpTxt, TMP_TXT_SIZE, mrk);
- else UseRangeMark(data, 1, TmpTxt);
- if(!(Dlg = new DlgRoot(QuantDlg, data)))return false;
- hDlg = CreateDlgWnd("Normal Quantiles Plot", 50, 50, 420, 220, 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;
- }
- }while (res < 0);
- if(res == 1 && Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)){
- ssRef = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
- bRet = ProcessData();
- }
- CloseDlgWnd(hDlg); delete Dlg; free(QuantDlg);
- return bRet;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Create a three dimensional graph
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *AddAxis3D_Tmpl =
- "1,2,,DEFAULT, PUSHBUTTON,-1,148,10,45,12\n"
- "2,3,,,PUSHBUTTON,-2,148,25,45,12\n"
- "3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "4,5,50,TOUCHEXIT | ISPARENT,SHEET,1,5,10,130,148\n"
- "5,6,200,ISPARENT | CHECKED,SHEET,2,5,10,130,148\n"
- "6,20,300,ISPARENT,SHEET,3,5,10,130,148\n"
- "20,,,NOSELECT,ODBUTTON,22,142,65,45,45\n"
- "50,51,100,ISPARENT | CHECKED,GROUPBOX,4,10,30,120,36\n"
- "51,120,,,CHECKBOX,5,17,37,80,8\n"
- "100,101,,,RTEXT,6,10,51,35,8\n"
- "101,102,,,EDVAL1,7,48,51,32,10\n"
- "102,103,,,CTEXT,8,81,51,11,8\n"
- "103,,,,EDVAL1,9,93,51,32,10\n"
- "120,,121,ISPARENT | CHECKED,GROUPBOX,10,10,72,120,20\n"
- "121,122,,,RTEXT,11,10,77,25,8\n"
- "122,123,,,EDVAL1,12,37,77,25,10\n"
- "123,124,,,LTEXT,-3,63,77,10,8\n"
- "124,125,,,RTEXT,-11,73,77,25,8\n"
- "125,130,,OWNDIALOG,COLBUTT,14,100,77,25,10\n"
- "130,131,,ISPARENT | CHECKED,GROUPBOX,15,10,98,120,20\n"
- "131,,,,EDTEXT,0,15,103,110,10\n"
- "200,201,,,LTEXT,16,10,23,70,9\n"
- "201,202,,CHECKED | EXRADIO,ODBUTTON,17,20,35,25,25\n"
- "202,203,,EXRADIO,ODBUTTON,17,45,35,25,25\n"
- "203,204,,EXRADIO,ODBUTTON,17,70,35,25,25\n"
- "204,205,,EXRADIO,ODBUTTON,17,95,35,25,25\n"
- "205,206,,EXRADIO,ODBUTTON,17,20,60,25,25\n"
- "206,207,,EXRADIO,ODBUTTON,17,45,60,25,25\n"
- "207,208,,EXRADIO,ODBUTTON,17,70,60,25,25\n"
- "208,209,,EXRADIO,ODBUTTON,17,95,60,25,25\n"
- "209,210,,EXRADIO,ODBUTTON,17,20,85,25,25\n"
- "210,211,,EXRADIO,ODBUTTON,17,45,85,25,25\n"
- "211,212,,EXRADIO,ODBUTTON,17,70,85,25,25\n"
- "212,213,,EXRADIO,ODBUTTON,17,95,85,25,25\n"
- "213,214,,,LTEXT,-12,20,120,70,9\n"
- "214,215,,,LTEXT,-13,20,132,70,9\n"
- "215,216,,,LTEXT,-14,20,144,70,9\n"
- "216,217,250,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "217,218,260,HIDDEN | ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "218,,270,HIDDEN |ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "250,251,,,LTEXT,19,10,110,70,9\n"
- "251,252,,,EDVAL1,0,58,120,32,10\n"
- "252,253,,,LTEXT,-3,92,120,20,9\n"
- "253,254,,,EDVAL1,0,43,132,32,10\n"
- "254,255,,,CTEXT,-7,75,132,7,9\n"
- "255,256,,,EDVAL1,0,82,132,32,10\n"
- "256,257,,,LTEXT,-3,116,132,20,9\n"
- "257,268,,,EDVAL1,0,58,144,32,10\n"
- "260,261,,,LTEXT,20,10,110,70,9\n"
- "261,262,,,EDVAL1,0,43,120,32,10\n"
- "262,263,,,CTEXT,-7,75,120,7,9\n"
- "263,264,,,EDVAL1,0,82,120,32,10\n"
- "264,265,,,LTEXT,-3,116,120,20,9\n"
- "265,266,,,EDVAL1,0,58,132,32,10\n"
- "266,267,,,LTEXT,-3,92,132,20,9\n"
- "267,268,,,EDVAL1,0,58,144,32,10\n"
- "268,,,,LTEXT,-3,92,144,20,9\n"
- "270,271,,,LTEXT,21,10,110,70,9\n"
- "271,272,,,EDVAL1,0,58,120,32,10\n"
- "272,273,,,LTEXT,-3,92,120,20,9\n"
- "273,274,,,EDVAL1,0,58,132,32,10\n"
- "274,275,,,LTEXT,-3,92,132,20,9\n"
- "275,276,,,EDVAL1,0,43,144,32,10\n"
- "276,277,,,CTEXT,-7,75,144,7,9\n"
- "277,278,,,EDVAL1,0,82,144,32,10\n"
- "278,,,,LTEXT,-3,116,144,20,9\n"
- "300,,,LASTOBJ | NOSELECT,ODBUTTON,18,15,30,110,140";
-bool
-Plot3D::AddAxis()
-{
- TabSHEET tab1 = {0, 25, 10, "Axis"};
- TabSHEET tab2 = {25, 52, 10, "Style"};
- TabSHEET tab3 = {52, 78, 10, "Plots"};
- AxisDEF axis, ax_def[12], *caxdef;
- double sizAxLine = DefSize(SIZE_AXIS_LINE);
- DWORD colAxis = 0x0;
- void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)" scaling ", (void*)" automatic scaling",
- (void*)"axis from", (void*)&axis.min, (void*)"to", (void*)&axis.max, (void*)" line ", (void*)"width",
- (void*)&sizAxLine, (void*)0L, (void *)&colAxis, (void*)" axis label ", (void*)"select a template:",
- (void*)(OD_NewAxisTempl3D), (void*)OD_axisplot, (void*)"y-axis at:", (void*)"x-axis at:", (void*)"z-axis at:",
- (void*)(OD_AxisDesc3D)};
- DlgInfo *NewAxisDlg;
- DlgRoot *Dlg;
- void *hDlg;
- int i, j, res, currTempl = 201, ax_type = 2, tick_type = 2;
- double tlb_dx, tlb_dy, lb_x, lb_y;
- TextDEF label_def, tlbdef;
- anyOutput *cdisp = Undo.cdisp;
- Axis *the_new, **tmpAxes;
- bool bAxis = false, bRet = false;
- char **names;
- GraphObj **somePlots;
- Label *label;
-
- if(!Axes || nAxes < 3 || !(NewAxisDlg = CompileDialog(AddAxis3D_Tmpl, dyndata))) return false;
- lb_y = 0.0; lb_x = DefSize(SIZE_AXIS_TICKS)*4.0;
- tlb_dy = 0.0; tlb_dx = -DefSize(SIZE_AXIS_TICKS)*2.0;
- tlbdef.ColTxt = colAxis; tlbdef.ColBg = 0x00ffffffL;
- tlbdef.RotBL = tlbdef.RotCHAR = 0.0f; tlbdef.fSize = DefSize(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(!(names = (char**)calloc(nscp+2, sizeof(char*))))return false;
- if(!(somePlots = (GraphObj**)calloc(nscp+2, sizeof(GraphObj*))))return false;
- for(i = 0; i < 12; i++) {
- ax_def[i].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK;
- ax_def[i].owner = 0L; ax_def[i].breaks = 0L;
- ax_def[i].Center.fx = ax_def[i].Center.fy = ax_def[i].Radius = 0.0;
- ax_def[i].nBreaks = 0L;
- }
- //y-axes
- ax_def[0].min = ax_def[1].min = ax_def[2].min = ax_def[3].min = (caxdef = Axes[1]->GetAxis())->min;
- ax_def[0].max = ax_def[1].max = ax_def[2].max = ax_def[3].max = caxdef->max;
- ax_def[0].Start = ax_def[1].Start = ax_def[2].Start = ax_def[3].Start = caxdef->Start;
- ax_def[0].Step = ax_def[1].Step = ax_def[2].Step = ax_def[3].Step = caxdef->Step;
- ax_def[0].loc[0].fy = ax_def[1].loc[0].fy = ax_def[2].loc[0].fy = ax_def[3].loc[0].fy = caxdef->loc[0].fy;
- ax_def[0].loc[1].fy = ax_def[1].loc[1].fy = ax_def[2].loc[1].fy = ax_def[3].loc[1].fy = caxdef->loc[1].fy;
- ax_def[0].loc[0].fx = ax_def[0].loc[1].fx = ax_def[3].loc[0].fx = ax_def[3].loc[1].fx = cu1.fx;
- ax_def[1].loc[0].fx = ax_def[1].loc[1].fx = ax_def[2].loc[0].fx = ax_def[2].loc[1].fx = cu2.fx;
- ax_def[0].loc[0].fz = ax_def[0].loc[1].fz = ax_def[1].loc[0].fz = ax_def[1].loc[1].fz = cu2.fz;
- ax_def[2].loc[0].fz = ax_def[2].loc[1].fz = ax_def[3].loc[0].fz = ax_def[3].loc[1].fz = cu1.fz;
- ax_def[1].flags = ax_def[2].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_POSTICKS;
- ax_def[0].flags = ax_def[3].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_NEGTICKS;
- //x-axes
- ax_def[4].min = ax_def[6].min = ax_def[8].min = ax_def[10].min = (caxdef = Axes[0]->GetAxis())->min;
- ax_def[4].max = ax_def[6].max = ax_def[8].max = ax_def[10].max = caxdef->max;
- ax_def[4].Start = ax_def[6].Start = ax_def[8].Start = ax_def[10].Start = caxdef->Start;
- ax_def[4].Step = ax_def[6].Step = ax_def[8].Step = ax_def[10].Step = caxdef->Step;
- ax_def[4].loc[0].fx = ax_def[6].loc[0].fx = ax_def[8].loc[0].fx = ax_def[10].loc[0].fx = caxdef->loc[0].fx;
- ax_def[4].loc[1].fx = ax_def[6].loc[1].fx = ax_def[8].loc[1].fx = ax_def[10].loc[1].fx = caxdef->loc[1].fx;
- ax_def[4].loc[0].fy = ax_def[4].loc[1].fy = ax_def[6].loc[0].fy = ax_def[6].loc[1].fy = cu1.fy;
- ax_def[8].loc[0].fy = ax_def[8].loc[1].fy = ax_def[10].loc[0].fy = ax_def[10].loc[1].fy = cu2.fy;
- ax_def[4].loc[0].fz = ax_def[4].loc[1].fz = ax_def[8].loc[0].fz = ax_def[8].loc[1].fz = cu2.fz;
- ax_def[6].loc[0].fz = ax_def[6].loc[1].fz = ax_def[10].loc[0].fz = ax_def[10].loc[1].fz = cu1.fz;
- ax_def[4].flags = ax_def[6].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_NEGTICKS;
- ax_def[8].flags = ax_def[10].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_POSTICKS;
- //z-axes
- ax_def[5].min = ax_def[7].min = ax_def[9].min = ax_def[11].min = (caxdef = Axes[2]->GetAxis())->min;
- ax_def[5].max = ax_def[7].max = ax_def[9].max = ax_def[11].max = caxdef->max;
- ax_def[5].Start = ax_def[7].Start = ax_def[9].Start = ax_def[11].Start = caxdef->Start;
- ax_def[5].Step = ax_def[7].Step = ax_def[9].Step = ax_def[11].Step = caxdef->Step;
- ax_def[5].loc[0].fz = ax_def[7].loc[0].fz = ax_def[9].loc[0].fz = ax_def[11].loc[0].fz = caxdef->loc[0].fz;
- ax_def[5].loc[1].fz = ax_def[7].loc[1].fz = ax_def[9].loc[1].fz = ax_def[11].loc[1].fz = caxdef->loc[1].fz;
- ax_def[5].loc[0].fx = ax_def[5].loc[1].fx = ax_def[9].loc[0].fx = ax_def[9].loc[1].fx = cu2.fx;
- ax_def[7].loc[0].fx = ax_def[7].loc[1].fx = ax_def[11].loc[0].fx = ax_def[11].loc[1].fx = cu1.fx;
- ax_def[5].loc[0].fy = ax_def[5].loc[1].fy = ax_def[7].loc[0].fy = ax_def[7].loc[1].fy = cu1.fy;
- ax_def[9].loc[0].fy = ax_def[9].loc[1].fy = ax_def[11].loc[0].fy = ax_def[11].loc[1].fy = cu2.fy;
- ax_def[5].flags = ax_def[9].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_POSTICKS;
- ax_def[7].flags = ax_def[11].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_NEGTICKS;
- //the default axis is the first
- memcpy(&axis, &ax_def[0], sizeof(AxisDEF));
- if(names[0] = (char*)malloc(10)) rlp_strcpy(names[0], 10, "[none]");
- for(i = 0, j = 1; i < nscp; i++) {
- if(Sc_Plots[i] && Sc_Plots[i]->name){
- names[j] = (char*)memdup(Sc_Plots[i]->name, (int)strlen(Sc_Plots[i]->name)+1, 0);
- somePlots[j++] = Sc_Plots[i];
- }
- }
- OD_axisplot(OD_ACCEPT, 0L, 0L, 0L, names, 0);
- if(!(Dlg = new DlgRoot(NewAxisDlg, data)))return false;
- Dlg->SetValue(251, ax_def[0].loc[0].fx); Dlg->SetValue(253, ax_def[0].loc[0].fy);
- Dlg->SetValue(255, ax_def[0].loc[1].fy); Dlg->SetValue(257, ax_def[0].loc[0].fz);
- if(!nscp){ //must be root plot3d to link to plot
- Dlg->ShowItem(6, false);
- }
- hDlg = CreateDlgWnd("Add Axis to 3D Plot", 50, 50, 400, 360, Dlg, 0x0L);
- do{
- LoopDlgWnd();
- res = Dlg->GetResult();
- switch (res){
- case 4: //the axis sheet
- res = -1;
- bAxis = true;
- break;
- //axis templates
- case 201: case 202: case 203: case 204: case 205: case 206:
- case 207: case 208: case 209: case 210: case 211: case 212:
- i = currTempl-201;
- switch(currTempl){
- case 201: case 202: case 203: case 204: //prevoius is y-template
- Dlg->GetValue(251, &axis.loc[0].fx); Dlg->GetValue(253, &axis.loc[0].fy);
- Dlg->GetValue(255, &axis.loc[1].fy); Dlg->GetValue(257, &axis.loc[0].fz);
- axis.loc[1].fx = axis.loc[0].fx; axis.loc[1].fz = axis.loc[0].fz;
- memcpy(&ax_def[i], &axis, sizeof(AxisDEF));
- break;
- case 205: case 207: case 209: case 211: //prevoius is x-template
- Dlg->GetValue(261, &axis.loc[0].fx); Dlg->GetValue(263, &axis.loc[1].fx);
- Dlg->GetValue(265, &axis.loc[0].fy); Dlg->GetValue(267, &axis.loc[0].fz);
- axis.loc[1].fy = axis.loc[0].fy; axis.loc[1].fz = axis.loc[0].fz;
- memcpy(&ax_def[i], &axis, sizeof(AxisDEF));
- break;
- case 206: case 208: case 210: case 212: //previous is z-template
- Dlg->GetValue(271, &axis.loc[0].fx); Dlg->GetValue(273, &axis.loc[0].fy);
- Dlg->GetValue(275, &axis.loc[0].fz); Dlg->GetValue(277, &axis.loc[1].fz);
- axis.loc[1].fx = axis.loc[0].fx; axis.loc[1].fy = axis.loc[0].fy;
- memcpy(&ax_def[i], &axis, sizeof(AxisDEF));
- break;
- }
- i = res-201;
- switch (res) {
- case 201: case 202: case 203: case 204: //y-template
- Dlg->ShowItem(216, true); Dlg->ShowItem(217, false);
- Dlg->ShowItem(218, false);
- Dlg->SetValue(251, ax_def[i].loc[0].fx); Dlg->SetValue(253, ax_def[i].loc[0].fy);
- Dlg->SetValue(255, ax_def[i].loc[1].fy); Dlg->SetValue(257, ax_def[i].loc[0].fz);
- ax_type = tick_type = 2; tlb_dy = 0.0;
- if(res == 202 || res == 203){
- tlb_dx = DefSize(SIZE_AXIS_TICKS)*2.0;
- tlbdef.Align = TXA_VCENTER | TXA_HLEFT;
- }
- else {
- tlb_dx = -DefSize(SIZE_AXIS_TICKS)*2.0;
- tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
- }
- break;
- case 205: case 207: case 209: case 211: //x-template
- Dlg->ShowItem(216, false); Dlg->ShowItem(217, true);
- Dlg->ShowItem(218, false);
- Dlg->SetValue(261, ax_def[i].loc[0].fx); Dlg->SetValue(263, ax_def[i].loc[1].fx);
- Dlg->SetValue(265, ax_def[i].loc[0].fy); Dlg->SetValue(267, ax_def[i].loc[0].fz);
- ax_type = 1; tick_type = 3; tlb_dx = 0;
- if(res == 205 || res == 207){
- tlb_dy = DefSize(SIZE_AXIS_TICKS)*2.0;
- tlbdef.Align = TXA_VTOP | TXA_HCENTER;
- }
- else {
- tlb_dy = -DefSize(SIZE_AXIS_TICKS)*2.0;
- tlbdef.Align = TXA_VBOTTOM | TXA_HCENTER;
- }
- break;
- case 206: case 208: case 210: case 212: //z-template
- Dlg->ShowItem(216, false); Dlg->ShowItem(217, false);
- Dlg->ShowItem(218, true);
- Dlg->SetValue(271, ax_def[i].loc[0].fx); Dlg->SetValue(273, ax_def[i].loc[0].fy);
- Dlg->SetValue(275, ax_def[i].loc[0].fz); Dlg->SetValue(277, ax_def[i].loc[1].fz);
- ax_type = 3; tick_type = 2; tlb_dy = 0;
- if(res == 206 || res == 210){
- tlb_dx = DefSize(SIZE_AXIS_TICKS)*2.0;
- tlbdef.Align = TXA_VCENTER | TXA_HLEFT;
- }
- else {
- tlb_dx = -DefSize(SIZE_AXIS_TICKS)*2.0;
- tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
- }
- break;
- }
- memcpy(&axis, &ax_def[res-201], sizeof(AxisDEF));
- currTempl = res;
- Dlg->DoPlot(0L);
- res = -1;
- break;
- }
- }while (res < 0);
- if(res == 1) {
- Undo.SetDisp(cdisp);
- Dlg->GetValue(122, &sizAxLine); Dlg->GetColor(125, &colAxis);
- 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;
- tlbdef.ColTxt = colAxis;
- label_def.ColTxt = colAxis; label_def.ColBg = 0x00ffffffL;
- label_def.fSize = DefSize(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;
- if(Dlg->GetCheck(51)) axis.flags |= AXIS_AUTOSCALE;
- if(the_new = new Axis(this, data, &axis, 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);
- the_new->type = ax_type;
- the_new->Command(CMD_TICK_TYPE, &tick_type, 0L);
- if(Dlg->GetText(131, TmpTxt, TMP_TXT_SIZE)) 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 < nAxes && Axes[i]; i++);
- if(i < nAxes) {
- Undo.SetGO(this, (GraphObj**)(&Axes[i]), the_new, 0L);
- bRet = true;
- }
- else {
- if(tmpAxes = (Axis**)calloc(nAxes+1, sizeof(Axis*))){
- memcpy(tmpAxes, Axes, nAxes * sizeof(Axis*));
- Undo.ListGOmoved((GraphObj**)Axes, (GraphObj**)tmpAxes, nAxes);
- Undo.SetGO(this, (GraphObj**)(&tmpAxes[nAxes]), the_new, 0L);
- free(Axes); Axes = tmpAxes;
- i = nAxes++; bRet = true;
- }
- }
- 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; free(NewAxisDlg);
- if(names) {
- for(j = 0; names[j]; j++) if(names[j]) free(names[j]);
- free(names);
- }
- if(somePlots) free(somePlots);
- return bRet;
-}
-
-static char *AddPlot3Dtmpl =
- "1,2,,DEFAULT,PUSHBUTTON,-1,150,10,45,12\n"
- "2,3,,,PUSHBUTTON,-2,150,25,45,12\n"
- "3,,560,ISPARENT | CHECKED,GROUPBOX,1,5,10,140,70\n"
- "560,561,,EXRADIO | CHECKED,ODBUTTON,2,12,20,25,25\n"
- "561,562,,EXRADIO,ODBUTTON,2,37,20,25,25\n"
- "562,563,,EXRADIO,ODBUTTON,2,62,20,25,25\n"
- "563,564,,EXRADIO,ODBUTTON,2,87,20,25,25\n"
- "564,565,,EXRADIO,ODBUTTON,2,112,20,25,25\n"
- "565,566,,EXRADIO,ODBUTTON,2,12,45,25,25\n"
- "566,567,,EXRADIO,ODBUTTON,2,37,45,25,25\n"
- "567,,,LASTOBJ | EXRADIO,ODBUTTON,2,62,45,25,25";
-
-bool
-Plot3D::AddPlot(int family)
-{
- void *dyndata[] = {(void *)" select template ", (void*)(OD_PlotTempl)};
- DlgInfo *PlotsDlg = CompileDialog(AddPlot3Dtmpl, dyndata);
- DlgRoot *Dlg;
- void *hDlg;
- int res, cSel = 560;
- bool bRet = false;
- Plot *p;
-
- if(!(Dlg = new DlgRoot(PlotsDlg, data)))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:
- case 565: case 566: case 567:
- if(res == cSel) res = 1;
- else {
- cSel = res; res = -1;
- }
- break;
- }
- }while (res < 0);
- if(res == 1){ //OK pressed
- switch (cSel) {
- case 560: p = new Scatt3D(this, data, 0x01); break;
- case 561: p = new Scatt3D(this, data, 0x02); break;
- case 562: p = new Scatt3D(this, data, 0x04); break;
- case 563: p = new BubblePlot3D(this, data); break;
- case 564: p = new Scatt3D(this, data, 0x2000); break;
- case 565: p = new Func3D(this, data); break;
- case 566: p = new FitFunc3D(this, data); break;
- case 567: p = new Scatt3D(this, data, 0x4000); break;
- default: p = 0L; break;
- }
- if(p && p->PropertyDlg()) {
- if(!(bRet = Command(CMD_DROP_PLOT, p, (anyOutput *)NULL))) delete p;
- }
- else if(p) delete p;
- }
- CloseDlgWnd(hDlg); delete Dlg; free(PlotsDlg);
- 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 bar chart
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *Base25D_DlgTmpl =
- "1,2,,DEFAULT, PUSHBUTTON,-1,158,10,45,12\n"
- "2,3,,,PUSHBUTTON,-2,158,25,45,12\n"
- "3,,10,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "10,11,100,ISPARENT | CHECKED,SHEET,1,5,10,140,100\n"
- "11,12,200,ISPARENT,SHEET,2,5,10,140,100\n"
- "12,20,300,ISPARENT,SHEET,3,5,10,140,100\n"
- "20,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
- "100,101,,,LTEXT,4,15,30,60,8\n"
- "101,152,,,RANGEINPUT,5,25,40,100,10\n"
- "152,153,,ISPARENT | CHECKED,GROUPBOX,6,12,60,128,45\n"
- "153,154,,,LTEXT,0,25,65,60,8\n"
- "154,155,,,RANGEINPUT,5,25,75,100,10\n"
- "155,156,,,PUSHBUTTON,-8,95,87,30,12\n"
- "156,,,,PUSHBUTTON,-9,60,87,35,12\n"
- "200,201,,,LTEXT,7,20,35,80,8\n"
- "201,202,,,RTEXT,8,48,45,13,8\n"
- "202,203,,,EDVAL1,9,65,45,25,10\n"
- "203,204,,,RTEXT,10,48,57,13,8\n"
- "204,,,,EDVAL1,11,65,57,25,10\n"
- "300,301,,,RADIO1,12,15,35,80,9\n"
- "301,302,,ODEXIT,COLBUTT,13,110,35,20,10\n"
- "302,303,,CHECKED,RADIO1,14,15,55,80,9\n"
- "303,304,,ODEXIT,COLBUTT,15,25,70,10,10\n"
- "304,305,,ODEXIT,COLBUTT,16,37,70,10,10\n"
- "305,306,,ODEXIT,COLBUTT,17,49,70,10,10\n"
- "306,307,,ODEXIT,COLBUTT,18,61,70,10,10\n"
- "307,308,,ODEXIT,COLBUTT,19,73,70,10,10\n"
- "308,309,,ODEXIT,COLBUTT,20,85,70,10,10\n"
- "309,310,,ODEXIT,COLBUTT,21,97,70,10,10\n"
- "310,,,LASTOBJ | ODEXIT,COLBUTT,22,109,70,10,10";
-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;
- double start_z = 1.0;
- void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"range for common x values",
- (void*)TmpTxt, (void*)" ranges for y values ", (void*)"distances:", (void*)"start z =",
- (void*)&start_z, (void*)"step =", (void*)&dspm.fz, (void*)" common color for columns:",
- (void*)&defcol, (void*)" increment color scheme:", (void*)&colarr[0], (void*)&colarr[1],
- (void*)&colarr[2], (void*)&colarr[3], (void*)&colarr[4], (void*)&colarr[5], (void*)&colarr[6],
- (void*)&colarr[7]};
- DlgInfo *Bar3D_Dlg = CompileDialog(Base25D_DlgTmpl, dyndata);
- DlgRoot *Dlg;
- void *hDlg;
- int i, j, ic, res, currYR=0, maxYR=0, nx=0, ny, rx, cx, ry, cy, oax;
- char **rd = 0L;
- 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(!parent || !data) return false;
- if(plots) {
- //Plots alredy defined: jump to config dialog
- return false;
- }
- if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
- TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return false;
- if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
- for(i=100, j= 0; i <= 1000; i +=100){
- if(TmpTxt[i]) rd[j++] = (char*)memdup(TmpTxt+i, (int)strlen(TmpTxt+i)+1, 0);
- }
- if(j) maxYR = j-1;
- }
- if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
- if(!(Dlg = new DlgRoot(Bar3D_Dlg, data))) return false;
- if(rd && rd[currYR] && *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
- 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);
- }
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "y-values # %d/%d", currYR+1, maxYR+1);
-#else
- sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
-#endif
- //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 = DefSize(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;
- }
- 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;
- }
- if(rY) {
- plot->data_desc = rY->RangeDesc(data, 1);
- 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(rX) delete rX; if(rY) delete rY; free(Bar3D_Dlg);
- 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;
- double start_z = 1.0;
- void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"range for common x values",
- (void*)TmpTxt, (void*)" ranges for y values ", (void*)"distances:", (void*)"start z =",
- (void*)&start_z, (void*)"step =", (void*)&dspm.fz, (void*)" common color for ribbons:",
- (void*)&defcol, (void*)" increment color scheme:", (void*)&colarr[0], (void*)&colarr[1],
- (void*)&colarr[2], (void*)&colarr[3], (void*)&colarr[4], (void*)&colarr[5], (void*)&colarr[6],
- (void*)&colarr[7]};
- DlgInfo *Bar3D_Dlg = CompileDialog(Base25D_DlgTmpl, dyndata);
- DlgRoot *Dlg;
- void *hDlg;
- int i, j, res, currYR=0, maxYR=0, nx=0, ny, oax;
- char **rd = 0L, xrange[100];
- double fz;
- bool updateYR = true, bContinue = false, bRet = false, bUseSch;
- AccRange *rX = 0L, *rY = 0L;
- AxisDEF *ax;
- Ribbon *plot;
-
- if(!parent || !data) return false;
- if(plots) {
- //Plots alredy defined: jump to config dialog
- return false;
- }
- if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
- TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return false;
- if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
- for(i=100, j= 0; i <= 1000; i +=100){
- if(TmpTxt[i]) rd[j++] = (char*)memdup(TmpTxt+i, (int)strlen(TmpTxt+i)+1, 0);
- }
- if(j) maxYR = j-1;
- }
- if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
- if(!(Dlg = new DlgRoot(Bar3D_Dlg, data)))return false;
- if(rd && rd[currYR] && *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
- 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);
- }
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "y-values # %d/%d", currYR+1, maxYR+1);
-#else
- sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
-#endif
- //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;
- Dlg->GetText(101, TmpTxt+100, 100);
- 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*))) {
- Dlg->GetText(101, xrange, 100);
- for(i = 0; i < maxYR; i++, fz += dspm.fz) {
- if(plot = new Ribbon(this, data, fz, dspm.fz, xrange, 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; free(Bar3D_Dlg);
- 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, CHECKED, 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, RANGEINPUT, text1, 20, 35, 100, 10},
- {102, 103, 0, 0x0L, LTEXT, (void*)"range for Y Data", 10, 48, 60, 8},
- {103, 104, 0, 0x0L, RANGEINPUT, text2, 20, 58, 100, 10},
- {104, 105, 0, 0x0L, LTEXT, (void*)"range for Z Data", 10, 71, 60, 8},
- {105, 106, 0, 0x0L, RANGEINPUT, 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, RANGEINPUT, 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, count;
- int cx, rx, cy, ry, cz, rz, cr, rr, s_type = 5;
- bool bRet = false;
- double fx, fy, fz, fr;
- Sphere **Balls;
- AccRange *rX, *rY, *rZ, *rR;
- Scatt3D *sc_plot;
-
- if(!data || !parent)return false;
- UseRangeMark(data, 1, text1, text2, text3, text4);
- if(!(Dlg = new DlgRoot(BubDlg3D, data)))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:
- s_type = 5; //absolute size, but use 5 to distinguish
- res = -1; // from symbol
- break;
- 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, TMP_TXT_SIZE)) rX = new AccRange(TmpTxt);
- if(Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE)) rY = new AccRange(TmpTxt);
- if(Dlg->GetText(105, TmpTxt, TMP_TXT_SIZE)) rZ = new AccRange(TmpTxt);
- if(Dlg->GetText(151, TmpTxt, TMP_TXT_SIZE)) 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 || parent->Id == GO_FUNC3D || parent->Id == GO_FITFUNC3D) {
- 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;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Create a 3D function plot
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-bool
-Func3D::PropertyDlg()
-{
- TabSHEET tab1 = {0, 37, 10, "Function"};
- TabSHEET tab2 = {37, 65, 10, "Style"};
- FillDEF newFill;
- DlgInfo FuncDlg[] = {
- {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 160, 10, 45, 12},
- {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 160, 25, 45, 12},
- {3, 10, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
- {4, 5, 100, ISPARENT, SHEET, &tab1, 5, 10, 149, 134},
- {5, 50, 300, ISPARENT | CHECKED, SHEET, &tab2, 5, 10, 149, 134},
- {10, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
- {50, 0, 0, NOSELECT, ODBUTTON, (void*)(OD_AxisDesc3D), 160, 85, 45, 45},
- {100, 101, 0, 0x0L, LTEXT, (void*)"plot user defined function", 10, 30, 100, 8},
- {101, 102, 0, 0x0L, RTEXT, (void*)"where x=", 10, 50, 28, 8},
- {102, 103, 0, 0x0L, EDVAL1, &x1, 38, 50, 25, 10},
- {103, 104, 0, 0x0L, RTEXT, (void*)"until", 61, 50, 17, 8},
- {104, 105, 0, 0x0L, EDVAL1, &x2, 78, 50, 25, 10},
- {105, 106, 0, 0x0L, RTEXT, (void*)"step", 102, 50, 17, 8},
- {106, 107, 0, 0x0L, EDVAL1, &xstep, 119, 50, 25, 10},
- {107, 108, 0, 0x0L, RTEXT, (void*)"z=", 10, 62, 28, 8},
- {108, 109, 0, 0x0L, EDVAL1, &z1, 38, 62, 25, 10},
- {109, 110, 0, 0x0L, EDVAL1, &z2, 78, 62, 25, 10},
- {110, 150, 0, 0x0L, EDVAL1, &zstep, 119, 62, 25, 10},
- {150, 200, 0, 0x0L, RTEXT, (void*)"y=", 10, 91, 10, 8},
- {200, 0, 0, 0x0L, TEXTBOX, (void*)cmdxy, 22, 89, 122, 40},
- {300, 301, 500, CHECKED, GROUPBOX, (void*)" grid ", 10, 40, 140, 100},
- {301, 305, 400, HIDDEN | CHECKED, GROUPBOX, (void*)" surface ", 10, 40, 140, 100},
- {305, 306, 0, CHECKED | TOUCHEXIT, RADIO1, (void*) " grid lines", 15, 25, 50, 10},
- {306, 0, 0, TOUCHEXIT, RADIO1, (void*) " surface", 85, 25, 50, 10},
- {400, 401, 0, 0x0L, RTEXT, (void*)"grid line width", 38, 50, 40, 8},
- {401, 402, 0, 0x0L, EDVAL1, &Line.width, 80, 50, 25, 10},
- {402, 403, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 107, 50, 20, 8},
- {403, 404, 0, 0x0L, RTEXT, (void*)"grid line color", 38, 62, 40, 8},
- {404, 405, 0, OWNDIALOG, COLBUTT, (void *)&Line.color, 80, 62, 25, 10},
- {405, 406, 0, 0x0L, RTEXT,(void*)"plane color" , 38, 74, 40, 8},
- {406, 0, 0, OWNDIALOG, SHADE3D, &newFill, 80, 74, 25, 10},
- {500, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)OD_linedef, 15, 45, 130, 100}};
- DlgRoot *Dlg;
- void *hDlg;
- int res, undo_level = *Undo.pcb;
- bool bRet = false, bNew = true;
- DWORD undo_flags = 0L;
- LineDEF newLine;
- double o_x1, n_x1, o_x2, n_x2, o_xstep, n_xstep;
- double o_z1, n_z1, o_z2, n_z2, o_zstep, n_zstep;
- anyOutput *cdisp = Undo.cdisp;
-
- if(!parent) return false;
-// if(parent->Id == GO_FITFUNC) return parent->PropertyDlg();
- memcpy(&newFill, &Fill, sizeof(FillDEF));
- OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
- if(!(Dlg = new DlgRoot(FuncDlg, data))) 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;
- Dlg->GetValue(108, &o_z1); n_z1 = o_z1;
- Dlg->GetValue(109, &o_z2); n_z2 = o_z2;
- Dlg->GetValue(110, &o_zstep); n_zstep = o_zstep;
- hDlg = CreateDlgWnd("3D Function Plot", 50, 50, 426, 328, Dlg, 0x0L);
- if(bNew) Dlg->SetCheck(4, 0L, true);
- do{
- LoopDlgWnd();
- res = Dlg->GetResult();
- switch (res) {
- case 305: case 306:
- if(Dlg->GetCheck(305)) {
- Dlg->ShowItem(300, true); Dlg->ShowItem(301, false);
- }
- else {
- Dlg->ShowItem(300, false); Dlg->ShowItem(301, true);
- }
- Dlg->DoPlot(0L);
- res = -1;
- break;
- case 0:
- if(Dlg->GetCheck(10)) res = -1;
- break;
- }
- }while (res < 0);
- Undo.SetDisp(cdisp);
- while(*Undo.pcb > undo_level) Undo.Pop(cdisp);
- if(res == 1){ //OK pressed
- if(bNew) { //create function
- if(Dlg->GetCheck(305)) {
- type = 0;
- OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&Line, 0);
- }
- else {
- type = 1;
- memcpy(&Fill, &newFill, sizeof(FillDEF));
- Dlg->GetValue(401, &Line.width);
- Dlg->GetColor(404, &Line.color);
- Line.pattern = 0L;
- Line.patlength = 1;
- }
- Dlg->GetValue(102, &x1); Dlg->GetValue(104, &x2);
- Dlg->GetValue(106, &xstep);
- Dlg->GetValue(108, &z1); Dlg->GetValue(109, &z2);
- Dlg->GetValue(110, &zstep); type = Dlg->GetCheck(305) ? 0 : 1;
- if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
- if(cmdxy) free(cmdxy); cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
- ReshapeFormula(&cmdxy); bRet = Update();
- }
- }
- 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);
- TmpTxt[0] = 0; Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE);
- undo_flags = CheckNewString(&cmdxy, cmdxy, TmpTxt, this, undo_flags);
-// 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 a 3D function to data
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-bool
-FitFunc3D::PropertyDlg()
-{
- TabSHEET tab1 = {0, 22, 10, "Data"};
- TabSHEET tab2 = {22, 59, 10, "Function"};
- TabSHEET tab3 = {59, 87, 10, "Style"};
- char text1[100], text2[100], text3[100];
- FillDEF newFill;
- double iter;
-// bool bNew = (dl == 0L);
- bool bNew = true;
- DlgInfo FuncDlg[] = {
- {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 160, 10, 45, 12},
- {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 160, 25, 45, 12},
- {3, 10, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
- {4, 5, 400, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 149, 134},
- {5, 6, 100, ISPARENT, SHEET, &tab2, 5, 10, 149, 134},
- {6, 7, 300, ISPARENT, SHEET, &tab3, 5, 10, 149, 134},
- {7, 0, 0, 0x0L, PUSHBUTTON, (void*)"Fit", 160, 132, 45, 12},
- {10, 50, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
- {50, 0, 0, NOSELECT, ODBUTTON, (void*)(OD_AxisDesc3D), 160, 65, 45, 45},
- {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*)param, 22, 44, 122, 30},
- {150, 151, 0, 0x0L, LTEXT, (void*)"function, y=f(x,z):", 10, 77, 10, 8},
- {151, 152, 0, 0x0L, RTEXT, (void*)"y=", 10, 91, 10, 8},
- {152, 153, 0, 0x0L, RTEXT, (void*)"converg.:", 20, 128, 26, 8},
- {153, 154, 0, 0x0L, EDVAL1, &conv, 46, 128, 25, 10},
- {154, 155, 0, 0x0L, RTEXT, (void*)"iterations:", 72, 128, 47, 8},
- {155, 200, 0, 0x0L, EDVAL1, &iter, 119, 128, 25, 10},
- {200, 0, 0, 0x0L, TEXTBOX, (void*)cmdxy, 22, 89, 122, 30},
- {300, 301, 550, CHECKED, GROUPBOX, (void*)" grid ", 10, 40, 140, 100},
- {301, 305, 350, HIDDEN | CHECKED, GROUPBOX, (void*)" surface ", 10, 40, 140, 100},
- {305, 306, 0, CHECKED | TOUCHEXIT, RADIO1, (void*) " grid lines", 15, 25, 50, 10},
- {306, 0, 0, TOUCHEXIT, RADIO1, (void*) " surface", 85, 25, 50, 10},
- {350, 351, 0, 0x0L, RTEXT, (void*)"grid line width", 38, 50, 40, 8},
- {351, 352, 0, 0x0L, EDVAL1, &Line.width, 80, 50, 25, 10},
- {352, 353, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 107, 50, 20, 8},
- {353, 354, 0, 0x0L, RTEXT, (void*)"grid line color", 38, 62, 40, 8},
- {354, 355, 0, OWNDIALOG, COLBUTT, (void *)&Line.color, 80, 62, 25, 10},
- {355, 356, 0, 0x0L, RTEXT,(void*)"plane color" , 38, 74, 40, 8},
- {356, 0, 0, OWNDIALOG, SHADE3D, &newFill, 80, 74, 25, 10},
- {400, 401, 0, 0x0L, LTEXT, (void*)"range for X data", 10, 30, 60, 8},
- {401, 402, 0, 0x0L, RANGEINPUT, (void*)text1, 20, 40, 100, 10},
- {402, 403, 0, 0x0L, LTEXT, (void*)"range for Y data", 10, 55, 60, 8},
- {403, 404, 0, 0x0L, RANGEINPUT, (void*)text2, 20, 65, 100, 10},
- {404, 405, 0, 0x0L, LTEXT, (void*)"range for Z data", 10, 80, 60, 8},
- {405, 406, 0, 0x0L, RANGEINPUT, (void*)text3, 20, 90, 100, 10},
- {406, 407, 0, CHECKED, CHECKBOX, (void*)"draw symbols", 20, 110, 60, 8},
- {407, 0, 0, HIDDEN, LTEXT, 0L, 20, 110, 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 ? 45:45, 130, 100}};
- DlgRoot *Dlg;
- void *hDlg;
- int res, undo_level = *Undo.pcb, i, j, k, l, m, n, ns = 0;
- bool bRet = false, bContinue = false;
- DWORD undo_flags = 0L;
- LineDEF newLine;
- double x, y, z, o_x1, n_x1, o_x2, n_x2, o_xstep, n_xstep, n_chi2=chi2, rad;
- AccRange *rX, *rY, *rZ;
- char *o_cmdxy, *o_param, *tmp_char;
- anyOutput *cdisp = Undo.cdisp;
- anyResult *ares;
- Sphere **Balls;
-
- if(!parent || !data) return false;
- UseRangeMark(data, 1, text1, text2, text3);
- if(!(o_cmdxy = (char*)memdup(cmdxy, (int)strlen(cmdxy)+1, 0)))return false;
- if(!(o_param = (char*)memdup(param, (int)strlen(param)+1, 0)))return false;
- rX = rY = rZ = 0L; iter = (double)maxiter;
- OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
- memcpy(&newFill, &Fill, sizeof(FillDEF));
- memcpy(&newLine, &Line, sizeof(LineDEF));
- if(!(Dlg = new DlgRoot(FuncDlg, data))) return false;
- if(!bNew){
- Dlg->ShowItem(10, false); Dlg->Activate(401, false);
- Dlg->Activate(403, false); Dlg->Activate(405, false);
- Dlg->SetCheck(6, 0L, true);
- Dlg->SetCheck(4, 0L, false); Dlg->ShowItem(404, false);
- if(chi2 > 0.0) {
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "Chi 2 = %g", chi2);
-#else
- sprintf(TmpTxt, "Chi 2 = %g", chi2);
-#endif
- 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 in 3D Space", 50, 50, 426, 328, 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 305: case 306:
- if(Dlg->GetCheck(305)) {
- Dlg->ShowItem(300, true); Dlg->ShowItem(301, false);
- }
- else {
- Dlg->ShowItem(300, false); Dlg->ShowItem(301, true);
- }
- Dlg->DoPlot(0L);
- res = -1;
- break;
- case 1:
- if(!bNew){
- if(Dlg->GetText(102, TmpTxt, TMP_TXT_SIZE)) {
- if(param) free(param);
- param = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
- }
- if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
- if(cmdxy) free(cmdxy);
- cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
- }
- ReshapeFormula(¶m); ReshapeFormula(&cmdxy);
- dirty = true;
- break;
- }
- case 7: //Start: do nonlinear regression
- Undo.SetDisp(cdisp);
- if(!Dlg->GetText(401, text1, 100) || !Dlg->GetText(403, text2, 100) || !Dlg->GetText(405, text3, 100)) {
- Dlg->SetCheck(4, 0L, true); bContinue = true;
- InfoBox("Invalid or missing range");
- res = -1;
- }
- else if(Dlg->GetCheck(5)) { // the function tab must be shown
- if(Dlg->CurrDisp) Dlg->CurrDisp->MouseCursor(MC_WAIT, true);
- if(Dlg->GetText(102, TmpTxt, TMP_TXT_SIZE)) {
- if(param) free(param);
- param = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
- }
- if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
- if(cmdxy) free(cmdxy);
- cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
- }
- Dlg->GetValue(153, &conv); Dlg->GetValue(155, &iter);
- ReshapeFormula(¶m); ReshapeFormula(&cmdxy);
- do_formula(data, 0L); //clear any error condition
- ares = do_formula(data, param);
- if(ares->type != ET_VALUE) {
- ErrorBox("Syntax Error in parameters.");
- bContinue = true; res = -1;
- break;
- }
- ares = do_formula(data, cmdxy);
- if(ares->type != ET_VALUE) {
- ErrorBox("Syntax Error in formula.");
- bContinue = true; res = -1;
- break;
- }
- i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE-2, param); i += rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, ";x=1;z=1;");
- rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, cmdxy); yywarn(0L, true);
- ares = do_formula(data, TmpTxt);
- if(tmp_char = yywarn(0L, false)) {
- ErrorBox(tmp_char);
- bContinue = true; res = -1;
- break;
- }
- i = do_fitfunc(data, text1, text2, text3, ¶m, cmdxy, conv, (int)iter, &chi2);
- Dlg->SetText(102, param);
- if(i >1 || res == 7) {
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "The Levenberg-Marquart algorithm\nexited after %d iterations.\n\nChi2 = %g", i, chi2);
-#else
- sprintf(TmpTxt, "The Levenberg-Marquart algorithm\nexited after %d iterations.\n\nChi2 = %g", i, chi2);
-#endif
- 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);
- Undo.SetDisp(cdisp);
- while(*Undo.pcb > undo_level) Undo.Pop(cdisp);
- if(res == 1 && (rX=new AccRange(text1)) && (rY=new AccRange(text2)) && (rZ=new AccRange(text3))){
- //OK pressed
- if(bNew) { //create function
- if(Dlg->GetCheck(305)) {
- type = 0;
- OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&Line, 0);
- }
- else {
- type = 1;
- memcpy(&Fill, &newFill, sizeof(FillDEF));
- Dlg->GetValue(401, &Line.width);
- Dlg->GetColor(404, &Line.color);
- Line.pattern = 0L; Line.patlength = 1;
- }
- 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))
- CheckBounds3D(x,y,z);
- }while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l) && rZ->GetNext(&m, &n));
- x1 = xBounds.fx; x2 = xBounds.fy; xstep = (x2-x1)/10.0;
- z1 = zBounds.fx; z2 = zBounds.fy; zstep = (z2-z1)/10.0;
- if(Dlg->GetText(102, TmpTxt, TMP_TXT_SIZE)) {
- if(param) free(param);
- param = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
- }
- if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
- if(cmdxy) free(cmdxy);
- cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
- }
- ReshapeFormula(¶m); ReshapeFormula(&cmdxy);
- if((bRet = Update()) && gob && nPlots == 1 && (Balls=(Sphere**)calloc(rX->CountItems(), sizeof(Sphere*)))) {
- rX->GetFirst(&i, &j); rX->GetNext(&i, &j);
- rY->GetFirst(&k, &l); rY->GetNext(&k, &l);
- rZ->GetFirst(&m, &n); rZ->GetNext(&m, &n);
- rad = DefSize(SIZE_SYMBOL);
- do {
- if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y) && data->GetValue(n, m, &z)) {
- Balls[ns++] = new Sphere(this, data, 0, x, y, z, rad, i, j, k, l, m, n);
- }
- }while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l) && rZ->GetNext(&m, &n));
- if(ns) {
- plots[1] = (GraphObj*) new Scatt3D(this, data, Balls, ns);
- nPlots = 2;
- }
- else free(Balls);
- }
- if(bRet)Command(CMD_ENDDIALOG, 0L, 0L);
- }
- else { //edit existing function
- Dlg->GetValue(102, &x1); Dlg->GetValue(104, &x2);
- Dlg->GetValue(106, &xstep);
- Dlg->GetValue(108, &z1); Dlg->GetValue(109, &z2);
- Dlg->GetValue(110, &zstep); type = Dlg->GetCheck(305) ? 0 : 1;
- InfoBox("Not Implemented");
- }
- }
- if(rX) delete(rX); if(rY) delete(rY); if(rZ) delete(rZ);
- CloseDlgWnd(hDlg);
- delete Dlg;
- return bRet;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Grid line properties
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *GridLineDlg_Tmpl =
- "1,+,,DEFAULT,PUSHBUTTON, 1,150,10,50,12\n"
- ".,.,,,PUSHBUTTON,2,150,25,50,12\n"
- ".,10,,,PUSHBUTTON,-2,150,40,50,12\n"
- "10,,100,ISPARENT | CHECKED,GROUPBOX,3,5,10,139,123\n"
- "100,+,,NOSELECT,ODBUTTON,4,10,18,130,100\n"
- ".,.,112,HIDDEN | CHECKED,GROUP,0,0,0,0,0\n"
- ".,.,115,HIDDEN | CHECKED,GROUP,0,0,0,0,0\n"
- ".,.,120,HIDDEN | CHECKED,GROUP,0,0,0,0,0\n"
- ".,.,125,HIDDEN | CHECKED,GROUP,0,0,0,0,0\n"
- ".,,130,HIDDEN | CHECKED,GROUP,0,0,0,0,0\n"
- "111,,,,RTEXT,5,15,117,23,8\n"
- "112,+,,,CHECKBOX,-20,41,117,25,8\n"
- ".,.,,,CHECKBOX,-21,105,117,25,8\n"
- ".,111,,,CHECKBOX,-25,70,117,25,8\n"
- "115,+,,,CHECKBOX,-22,41,117,25,8\n"
- ".,.,,,CHECKBOX,-23,105,117,25,8\n"
- ".,111,,,CHECKBOX,-24,70,117,25,8\n"
- "120,+,,,CHECKBOX,-24,55,117,25,8\n"
- ".,135,,,CHECKBOX,-25,90,117,25,8\n"
- "125,+,,,CHECKBOX,-24,55,117,25,8\n"
- ".,135,,,CHECKBOX,-26,90,117,25,8\n"
- "130,+,,,CHECKBOX,-25,55,117,25,8\n"
- ".,135,,,CHECKBOX,-26,90,117,25,8\n"
- "135,,,LASTOBJ,LTEXT,6,15,117,55,8";
-bool
-GridLine::PropertyDlg()
-{
- TabSHEET tab1 = {0, 21, 10, "Line"};
- int dh = ((flags & AXIS_ANGULAR) || (flags & AXIS_RADIAL))? -20 : 0;
- void *dyndata[] = {(void*)"Apply to LINE", (void*)"Apply to AXIS", (void*)" grid line ",
- (void*)OD_linedef, (void*)"line to:", (void*)"parallel to:"};
- DlgInfo *LineDlg;
- DlgRoot *Dlg;
- void *hDlg;
- int res, tmptype;
- bool bRet = false;
- DWORD undo_flags = 0L;
- anyOutput *cdisp = Undo.cdisp;
- LineDEF newLine;
-
- if(!parent || !parent->parent) return false;
- if(!(LineDlg = CompileDialog(GridLineDlg_Tmpl, dyndata)))return false;
- LineDlg[3].h += dh;
- OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
- if(!(Dlg = new DlgRoot(LineDlg, data)))return false;
- if ((flags & AXIS_ANGULAR) || (flags & AXIS_RADIAL)) {
- //no checkboxes, changed sizes
- }
- 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, 310 + 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
- Undo.SetDisp(cdisp);
- 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; free(LineDlg);
- return bRet;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Tick properties
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *TickDlg_Tmpl =
- "1,2,,,PUSHBUTTON,1,120,10,60,12\n"
- "2,3,,DEFAULT, PUSHBUTTON,2,120,25,60,12\n"
- "3,4,,,PUSHBUTTON,-2,120,40,60,12\n"
- "4,,5,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "5,6,100,ISPARENT | CHECKED,SHEET,3,5,10,110,100\n"
- "6,7,200,ISPARENT,SHEET,4,5,10,110,100\n"
- "7,,300,ISPARENT,SHEET,5,5,10,110,100\n"
- "100,101,,,RTEXT,6,10,30,35,8\n"
- "101,102,,,EDVAL1,7,50,30,25,10\n"
- "102,103,,,LTEXT,-3,77,30,20,8\n"
- "103,104,,,CHECKBOX,8,18,45,30, 8\n"
- "104,105,,,LTEXT,9,18,60,20,8\n"
- "105,106,,,RADIO1,0,40,70,35,8\n"
- "106,107,,,RADIO1,0,40,60,35,8\n"
- "107,108,,,RADIO1,10,40,80,35,8\n"
- "108,,,,CHECKBOX,11,18,95,30,8\n"
- "200,201,,,RTEXT,12,10,35,23,8\n"
- "201,202,,,EDVAL1,13,40,35,65,10\n"
- "202,203,,,LTEXT,14,15,55,20,8\n"
- "203,,,,EDTEXT,0,15,67,90,10\n"
- "300,301,,,LTEXT,15,15,30,70,8\n"
- "301,302,,TOUCHEXIT,RADIO1,16,15,42,70,8\n"
- "302,303,,TOUCHEXIT,RADIO1,17,15,52,70,8\n"
- "303,304,,TOUCHEXIT,RADIO1,18,15,74,70,8\n"
- "304,305,,TOUCHEXIT,RADIO1,19,15,84,70,8\n"
- "305,306,,TOUCHEXIT,RADIO1,20,15,94,70,8\n"
- "306,307,,, EDVAL1,21,28,62,35,10\n"
- "307,,,LASTOBJ,LTEXT,22,65,62,20,8";
-
-bool
-Tick::PropertyDlg()
-{
- TabSHEET tab1 = {0, 25, 10, "Tick"};
- TabSHEET tab2 = {64, 90, 10, "Edit"};
- TabSHEET tab3 = {25, 64, 10, "Direction"};
- double tick_rot;
- void *dyndata[] = {(void*)"Apply to TICK", (void*)"Apply to AXIS", (void*)&tab1, (void*)&tab2,
- (void*)&tab3, (void*)"tick size", (void*)&size, (void*)"major tick", (void*)"type:",
- (void*)"symmetric", (void*)"draw grid line(s)", (void*)"value:", (void*)&value, (void*)"label:",
- (void*)"direction of ticks", (void*)"perpendicular to axis", (void*)"fixed angle",
- (void*)"x-axis", (void*)"y-axis", (void*)"z-axis", (void*)&tick_rot, (void*)"deg."};
- DlgInfo *TickDlg;
- DlgRoot *Dlg;
- void *hDlg;
- DWORD old_flags;
- char old_value[80];
- double new_size, old_size, new_angle, old_angle, new_value;
- int res, tmp_type = type;
- bool bRet = false;
- DWORD new_flags = flags, undo_flags = 0;
- anyOutput *cdisp = Undo.cdisp;
- char *old_label = 0L;
- TextDEF *td;
-
- if(!parent || parent->Id != GO_AXIS) return false;
- if(!(TickDlg = CompileDialog(TickDlg_Tmpl, dyndata))) 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, data);
- 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) {
- if(label->Command(CMD_GETTEXT, &TmpTxt, 0L) && TmpTxt[0] &&
- (old_label = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0)))
- 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(flags & AXIS_DATETIME) Dlg->SetText(201, NiceTime(value));
- if(!(Dlg->GetText(201, old_value, sizeof(old_value)))) {
- new_value = value; old_value[0] = 0;
- }
- hDlg = CreateDlgWnd("Tick properties", 50, 50, 375, 265, Dlg, 0x0L);
- do {
- LoopDlgWnd();
- res = Dlg->GetResult();
- switch(res) {
- case 1: case 2:
- Undo.SetDisp(cdisp); 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);
- 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);
- if(Dlg->GetText(201, TmpTxt, 80) && strcmp(TmpTxt, old_value)) {
- Undo.ValFloat(parent, &value, undo_flags); undo_flags |= UNDO_CONTINUE;
- if(flags & AXIS_DATETIME) date_value(TmpTxt, 0L, &value);
- else Dlg->GetValue(201, &value);
- }
- if(label && label->Id == GO_LABEL) {
- td = ((Label*)label)->GetTextDef();
- if(!Dlg->GetText(203, TmpTxt, TMP_TXT_SIZE)) TmpTxt[0] = 0;
- if(undo_flags = CheckNewString(&td->text, td->text, TmpTxt, this, undo_flags))
- 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; free(TickDlg);
- if(old_label) free(old_label);
- return bRet;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Axis properties dialog
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *ssTickTmpl =
- "1,2,,DEFAULT, PUSHBUTTON,-1,113,10,45,12\n"
- "2,3,,, PUSHBUTTON,-2,113,25,45,12\n"
- "3,4,,, LTEXT,1,5,10,100,9\n"
- "4,5,,TOUCHEXIT,RANGEINPUT,4,10,20,90,10\n"
- "5,6,,, LTEXT,2,5, 32, 100, 9\n"
- "6,7,,TOUCHEXIT,RANGEINPUT,5,10,42,90,10\n"
- "7, 8,,,LTEXT,3, 5, 54, 80, 8\n"
- "8,,,LASTOBJ | TOUCHEXIT,RANGEINPUT,6,10,64,90,10";
-
-bool
-Axis::ssTicks()
-{
- void *dyndata[] ={(void*)"range for major tick VALUES:", (void*)"range for major tick LABELS:",
- (void*)"minor tick VALUES:", (void*)ssMATval, (void*)ssMATlbl, (void*)ssMITval};
- DlgInfo *TickDlg = CompileDialog(ssTickTmpl, dyndata);
- DlgRoot *Dlg;
- void *hDlg;
- int res, n, n1, n2, n3;
- bool bRet = false, bContinue = true;
- AccRange *rT, *rL, *rMT;
-
- if(!data) return false;
- n = n1 = n2 = n3 = 0; rT = rL = rMT = 0L;
- if(!(Dlg = new DlgRoot(TickDlg, data)))return false;
- hDlg = CreateDlgWnd("choose ticks from spreadsheet", 50, 50, 330, 190, Dlg, 0x0L);
- Dlg->Activate(4, true);
- do{
- LoopDlgWnd();
- res = Dlg->GetResult();
- switch (res) {
- case 0: // focus lost
- if(bContinue) res = -1;
- break;
- case 4: case 6: case 8:
- bContinue = true;
- res = -1; 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, TMP_TXT_SIZE) && (rT=new AccRange(TmpTxt)) && (n1=rT->CountItems())){
- if(Dlg->GetText(6, TmpTxt, TMP_TXT_SIZE) && (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,TMP_TXT_SIZE) && (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, TMP_TXT_SIZE))
- ssMATval = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
- if(Dlg->GetText(6, TmpTxt, TMP_TXT_SIZE))
- ssMATlbl = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
- if(Dlg->GetText(8, TmpTxt, TMP_TXT_SIZE))
- ssMITval = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
- UpdateTicks();
- }
- bRet = true;
- }
- CloseDlgWnd(hDlg);
- delete Dlg; free(TickDlg);
- 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, COLBUTT, (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;
- anyOutput *cdisp = Undo.cdisp;
- 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;
- if(names[0] = (char*)malloc(15 * sizeof(char))) rlp_strcpy(names[0], 15, "[unchanged]");
- for(i = 0, j = 1; i < res; i++) {
- if(scp[i] && scp[i]->name){
- names[j] = (char*)memdup(scp[i]->name, (int)strlen(scp[i]->name)+1, 0);
- somePlots[j++] = scp[i];
- }
- }
- }
- else if(IsPlot3D(parent) && (res=((Plot3D*)parent)->nscp)){
- scp = ((Plot3D*)parent)->Sc_Plots;
- CurrAxes = ((Plot3D*)parent)->Axes;
- if(!scp || !(names = (char**)calloc(res+2, sizeof(char*))) ||
- !(somePlots = (GraphObj**)calloc(res+2, sizeof(GraphObj*))))
- return false;
- if(names[0] = (char*)malloc(15 * sizeof(char))) rlp_strcpy(names[0], 15, "[unchanged]");
- for(i = 0, j = 1; i < res; i++) {
- if(scp[i] && scp[i]->name){
- names[j] = (char*)memdup(scp[i]->name, (int)strlen(scp[i]->name)+1, 0);
- somePlots[j++] = scp[i];
- }
- }
- }
- else {
- names = (char**)calloc(2, sizeof(char*)); names[0] = (char*)malloc(10*sizeof(char));
- rlp_strcpy(names[0], 10, "n.a.");
- }
- OD_axisplot(OD_ACCEPT, 0L, 0L, 0L, names, 0);
- if(!(Dlg = new DlgRoot(AxisDlg, data)))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 = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
- 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));
- i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, type_txt);
- rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, "xis properties");
- hDlg = CreateDlgWnd(TmpTxt, 50, 50, 436, 390, 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);
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "break # %d/%d", cbrk+1, nbrk+1);
-#else
- sprintf(TmpTxt,"break # %d/%d", cbrk+1, nbrk+1);
-#endif
- 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);
- Undo.SetDisp(cdisp);
- 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((new_a.flags & AXIS_LOG)== AXIS_LOG && new_a.min < defs.min4log) {
- switch(type & 0x0f) {
- case 1:
- new_a.min = parent->GetSize(SIZE_BOUNDS_XMIN); break;
- case 2:
- new_a.min = parent->GetSize(SIZE_BOUNDS_YMIN); break;
- case 3:
- new_a.min = parent->GetSize(SIZE_BOUNDS_ZMIN); break;
- }
- }
- 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;
- axis->Start = axis->min;
- }
- 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, TMP_TXT_SIZE) && TmpTxt[0]) {
- if(old_Label && strcmp(old_Label,TmpTxt) && axisLabel->Id == GO_LABEL){
- lb_def = ((Label*)axisLabel)->GetTextDef();
- undo_flags = CheckNewString(&lb_def->text, old_Label, TmpTxt, this, undo_flags);
- }
- else if(!axisLabel) {
- label_def.ColTxt = colAxis; label_def.ColBg = 0x00ffffffL;
- label_def.fSize = DefSize(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
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *AddPlotTmpl =
- "1,2,,DEFAULT,PUSHBUTTON,-1,150,10,45,12\n"
- "2,3,,,PUSHBUTTON,-2,150,25,45,12\n"
- "3,,520,ISPARENT | CHECKED,GROUPBOX,1,5,10,135,95\n"
- "520,521,,EXRADIO | CHECKED,ODBUTTON,2,10,20,25,25\n"
- "521,522,,EXRADIO,ODBUTTON,2,35,20,25,25\n"
- "522,523,,EXRADIO,ODBUTTON,2,60,20,25,25\n"
- "523,524,,EXRADIO,ODBUTTON,2,85,20,25,25\n"
- "524,525,,EXRADIO,ODBUTTON,2,110,20,25,25\n"
- "525,526,,EXRADIO,ODBUTTON,2,10,45,25,25\n"
- "526,528,,EXRADIO,ODBUTTON,2,35,45,25,25\n"
- "528,529,,EXRADIO,ODBUTTON,2,60,45,25,25\n"
- "529,530,,EXRADIO,ODBUTTON,2,85,45,25,25\n"
- "530,531,,EXRADIO,ODBUTTON,2,110,45,25,25\n"
- "531,532,,EXRADIO,ODBUTTON,2,10,70,25,25\n"
- "532,540,,EXRADIO,ODBUTTON,2,35,70,25,25\n"
- "540,541,,EXRADIO,ODBUTTON,2,60,70,25,25\n"
- "541,,,LASTOBJ | EXRADIO,ODBUTTON, 2, 85,70,25,25";
-
-bool
-Graph::AddPlot(int family)
-{
- void *dyndata[] = {(void *)" select template ",(void*)OD_PlotTempl};
- DlgInfo *GraphDlg = CompileDialog(AddPlotTmpl, dyndata);
- 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, data);
- 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 532: 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, "Function");
- else if(Dlg->GetCheck(530)) p = new FitFunc(this, data);
- else if(Dlg->GetCheck(531)) p = new MultiLines(this, data);
- else if(Dlg->GetCheck(532)) p = new xyStat(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; free(GraphDlg);
- return bRet;
-}
-
-static char *GraphDlgTmpl =
- "1,+,,DEFAULT,PUSHBUTTON,-1,170,10,45,12\n"
- ".,.,,,PUSHBUTTON,-2,170,25,45,12\n"
- ".,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "4,+,100,ISPARENT | CHECKED,SHEET,1,5,10,157,122\n"
- ".,.,200,ISPARENT,SHEET,2,5,10,157,122\n"
- ".,,300,ISPARENT,SHEET,3,5,10,157,122\n"
- "100,+,,,LTEXT,4,10,25,60,8\n"
- ".,.,500,TOUCHEXIT | ISPARENT,SHEET,5,10,37,147,90\n"
- ".,.,520,TOUCHEXIT | ISPARENT,SHEET,6,10,37,147,90\n"
- ".,.,540,TOUCHEXIT | ISPARENT,SHEET,7,10,37,147,90\n"
- ".,,560,TOUCHEXIT | ISPARENT,SHEET,8,10,37,147,90\n"
- "200,+,,,LTEXT,9,10,35,60,8\n"
- ".,.,,,RTEXT,10,5,47,58,8\n"
- ".,.,,,EDVAL1,11,64,47,30,10\n"
- ".,.,,,RTEXT,-5,95,47,10,8\n"
- ".,.,,,EDVAL1,12,107,47,30,10\n"
- ".,.,,,LTEXT,-3,140,47,20,8\n"
- ".,.,,,RTEXT,13,5,59,58,8\n"
- ".,.,,,EDVAL1,14,64,59,30,10\n"
- ".,.,,,RTEXT,-5,95,59,10,8\n"
- ".,.,,,EDVAL1,15,107,59,30,10\n"
- ".,.,,,LTEXT,-3,140,59,20,8\n"
- ".,.,,,LTEXT,16,10,84,60,8\n"
- ".,.,,,RTEXT,17,5,96,58,8\n"
- ".,.,,,EDVAL1,18,64,96,30,10\n"
- ".,.,,,RTEXT,-5,95,96,10,8\n"
- ".,.,,,EDVAL1,19,107,96,30,10\n"
- ".,.,,,LTEXT,-3,140,96,20,8\n"
- ".,.,,,RTEXT,20,5,108,58,8\n"
- ".,.,,,EDVAL1,21,64,108,30,10\n"
- ".,.,,,RTEXT,-5,95,108,10,8\n"
- ".,.,,,EDVAL1,22,107,108,30,10\n"
- ".,,,,LTEXT,-3,140,108,20,8\n"
- "300,+,,,LTEXT,23,20,30,60,8\n"
- ".,400,310,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
- "310,+,,EXRADIO,ODBUTTON,24,20,42,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,24,45,42,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,24,70,42,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,24,95,42,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,24,120,42,25,25\n"
- ".,.,,CHECKED | TOUCHEXIT,RADIO1, 25, 12,85,40,8\n"
- ".,.,,TOUCHEXIT,RADIO1,26,12,93,40,8\n"
- ".,.,,TOUCHEXIT,RADIO1,27,12,101,40,8\n"
- ".,.,,TOUCHEXIT,CHECKBOX,28,80,85,40,8\n"
- ".,,,TOUCHEXIT, CHECKBOX,29,80,93,40,8\n"
- "400,,410,HIDDEN | CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
- "410,+,,EXRADIO,ODBUTTON,30,20,42,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,30,45,42,25,25\n"
- ".,,,EXRADIO, ODBUTTON,30,70,42,25,25\n"
- "500,+,,EXRADIO,ODBUTTON,31,20,60,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,45,60,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,70,60,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,20,85,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,45,85,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,95,85,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,120,85,25,25\n"
- ".,,,EXRADIO,ODBUTTON,31,70,85,25,25\n"
- "520,+,,EXRADIO,ODBUTTON, 31, 20,50,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,45,50,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,70,50,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,95,50,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,120,50,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,20,75,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,45,75,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,70,75,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,95,75,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,120,75,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,20,100,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,45,100,25,25\n"
- ".,,,EXRADIO,ODBUTTON,31,70,100,25,25\n"
- "540,+,,EXRADIO,ODBUTTON,31,20,60,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,45,60,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,70,60,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,95,60,25,25\n"
- ".,,,TOUCHEXIT | ISRADIO,ODBUTTON, 31, 120,60,25,25\n"
- "560,+,,EXRADIO,ODBUTTON, 31,20,60,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,45,60,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,70,60,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,95,60,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,120,60,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,20,85,25,25\n"
- ".,.,,EXRADIO,ODBUTTON,31,45,85,25,25\n"
- ".,,,LASTOBJ | EXRADIO, ODBUTTON, 31, 70,85,25,25";
-
-static int selSheet = 102, selPlt = 520, selAxis = 310;
-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"};
- void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"arrangement of data: select plot",
- (void*)&tab_A, (void*)&tab_B, (void*)&tab_C, (void*)&tab_D, (void*)"bounding rectangle (relative to page)",
- (void*)"upper left corner x", (void*)&GRect.Xmin, (void*)&GRect.Ymin, (void*)"lower right x",
- (void*)&GRect.Xmax, (void*)&GRect.Ymax, (void*)"plotting rectangle (relative to bounding rectangle)",
- (void*)"upper left corner x", (void*)&DRect.Xmin, (void*)&DRect.Ymin, (void*)"lower right x",
- (void*)&DRect.Xmax, (void*)&DRect.Ymax, (void*)"select template:", (void*)(OD_AxisTempl),
- (void*)"ticks outside", (void*)"ticks inside", (void*)"ticks symmetrical", (void*)"horizontal grid lines",
- (void*)"vertical grid lines", (void*)(OD_AxisTempl3D), (void*)(OD_PlotTempl)};
- DlgInfo *GraphDlg = CompileDialog(GraphDlgTmpl, dyndata);
- DlgRoot *Dlg;
- GraphObj *p;
- void *hDlg;
- int i, res;
- bool bRet, bContinue;
- fRECT rc1, rc2;
-
- ODtickstyle = tickstyle;
- AxisTempl = 0;
- if(!parent) return false;
- Dlg = new DlgRoot(GraphDlg, data);
- Dlg->SetCheck(410 + AxisTempl3D, 0L, true);
- if(parent->Id != GO_PAGE) {
- Dlg->Activate(202, false); Dlg->Activate(204, false);
- }
- //restore previous settitings
- switch(selSheet) {
- case 101:
- if(selPlt >= 500 && selPlt <=507) Dlg->SetCheck(selPlt, 0L, true);
- else Dlg->SetCheck(500, 0L, true);
- Dlg->SetCheck(520, 0L, true); Dlg->SetCheck(540, 0L, true);
- Dlg->SetCheck(560, 0L, true); break;
- default:
- if(selPlt >= 520 && selPlt <=532) Dlg->SetCheck(selPlt, 0L, true);
- else Dlg->SetCheck(520, 0L, true); selSheet = 102;
- Dlg->SetCheck(500, 0L, true); Dlg->SetCheck(540, 0L, true);
- Dlg->SetCheck(560, 0L, true); break;
- case 103:
- if(selPlt >= 540 && selPlt <=544) Dlg->SetCheck(selPlt, 0L, true);
- else Dlg->SetCheck(540, 0L, true);
- Dlg->SetCheck(520, 0L, true); Dlg->SetCheck(500, 0L, true);
- Dlg->SetCheck(560, 0L, true); break;
- case 104:
- if(selPlt >= 560 && selPlt <=567) Dlg->SetCheck(selPlt, 0L, true);
- else Dlg->SetCheck(560, 0L, true);
- Dlg->ShowItem(301, false); Dlg->ShowItem(400, true);
- Dlg->SetCheck(520, 0L, true); Dlg->SetCheck(540, 0L, true);
- Dlg->SetCheck(500, 0L, true); break;
- }
- Dlg->SetCheck(selSheet, 0L, true);
- if(selAxis >= 310 && selAxis <= 314) Dlg->SetCheck(selAxis, 0L, true);
- else Dlg->SetCheck(310, 0L, true);
- if(selAxis >= 410 && selAxis <= 412) Dlg->SetCheck(selAxis, 0L, true);
- else Dlg->SetCheck(410, 0L, true);
- //display the dialog
- 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: //only y data
- for(i = 500; i <= 506; i++) if(Dlg->GetCheck(i))selPlt = i;
- Dlg->ShowItem(301, true); Dlg->ShowItem(400, false);
- selSheet = res; res = -1;
- break;
- case 102: //xy data
- for(i = 520; i <= 532; i++) if(Dlg->GetCheck(i))selPlt = i;
- Dlg->ShowItem(301, true); Dlg->ShowItem(400, false);
- selSheet = res; res = -1;
- break;
- case 103: //x many y data
- for(i = 540; i <= 544; i++) if(Dlg->GetCheck(i))selPlt = i;
- Dlg->ShowItem(301, true); Dlg->ShowItem(400, false);
- selSheet = res; res = -1;
- break;
- case 104: //xyz data
- for(i = 560; i <= 567; i++) if(Dlg->GetCheck(i))selPlt = i;
- Dlg->ShowItem(301, false); Dlg->ShowItem(400, true);
- selSheet = res; 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 506: case 507:
- 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 532:
- case 540: case 541: case 542: case 543:
- case 544:
- case 560: case 561: case 562: case 563:
- case 564: case 565: case 566: case 567:
- 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, 0);
- else if(Dlg->GetCheck(505))p = new FreqDist(this, data);
- else if(Dlg->GetCheck(506))p = new NormQuant(this, data, 0L);
- else if(Dlg->GetCheck(507))p = new GroupBars(this, data, 1);
- }
- 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, "Function");
- else if(Dlg->GetCheck(530)) p = new FitFunc(this, data);
- else if(Dlg->GetCheck(531)) p = new MultiLines(this, data);
- else if(Dlg->GetCheck(532)) p = new xyStat(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);
- else if(Dlg->GetCheck(565)) p = new Func3D(this, data);
- else if(Dlg->GetCheck(566)) p = new FitFunc3D(this, data);
- else if(Dlg->GetCheck(567)) p = new Plot3D(this, data, 0x4000);
- }
- 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);
- Command(CMD_SET_DATAOBJ, (void*)data, 0L);
- CloseDlgWnd(hDlg); delete Dlg; free(GraphDlg);
- 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, COLBUTT, (void *)&ColGR, 74, 42, 25, 10},
- {103, 104, 0, 0x0L, RTEXT, (void*)"outline color", 15, 54, 58, 8},
- {104, 105, 0, TOUCHEXIT | OWNDIALOG, COLBUTT, (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, COLBUTT, (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, COLBUTT, (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;
- anyOutput *cdisp = Undo.cdisp;
- bool bRet = false, bContinue = false;
- fRECT o_gr, n_gr, o_dr, n_dr;
-
- if(!(Dlg = new DlgRoot(GraphDlg, data)))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);
- i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, name ? name : (char*)"Graph");
- rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, (char*)" properties");
- hDlg = CreateDlgWnd(TmpTxt, 50, 50, 450, 300, Dlg, 0x0L);
- do{
- LoopDlgWnd(); res = Dlg->GetResult();
- switch (res) {
- case 600: case 601: case 602: case 603:
- Undo.SetDisp(cdisp);
- res = ExecDrawOrderButt(parent, this, res);
- }
- 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);
- break;
- case 6:
- Command(CMD_LAYERS, 0L, 0L);
- bContinue = true;
- res = -1;
- break;
- }
- }while(res <0);
- if(res == 1 && bRet) {
- Undo.SetDisp(cdisp);
- 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]->Id == GO_FUNC3D))
- Plots[0]->SetColor(COL_AXIS | UNDO_STORESET, ColAX);
- }
- }
- else if(res == 2) {
- Undo.SetDisp(cdisp);
- 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;
-}
-
-static char *AddAxisTmpl =
- "1,2,,DEFAULT, PUSHBUTTON,-1,148,10,45,12\n"
- "2,3,,,PUSHBUTTON,-2,148,25,45,12\n"
- "3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "4,5,50,TOUCHEXIT | ISPARENT,SHEET,1,5,10,130,130\n"
- "5,6,200,ISPARENT | CHECKED,SHEET,2,5,10,130,130\n"
- "6,,300,ISPARENT,SHEET,3,5,10,130,130\n"
- "50,51,100,ISPARENT | CHECKED,GROUPBOX,4,10,30,120,36\n"
- "51,120,,,CHECKBOX,5,17,37,80,8\n"
- "100,101,,,RTEXT,6,10,51,35,8\n"
- "101,102,,,EDVAL1,7,48,51,32,10\n"
- "102,103,,,CTEXT,8,81,51,11,8\n"
- "103,,,,EDVAL1,9,93,51,32,10\n"
- "120,,121,ISPARENT | CHECKED,GROUPBOX,10,10,72,120,20\n"
- "121,122,,,RTEXT,11,10,77,25,8\n"
- "122,123,,,EDVAL1,12,37,77,25,10\n"
- "123,124,,,LTEXT,-3,63,77,10,8\n"
- "124,125,,,RTEXT,-11,73,77,25,8\n"
- "125,130,,OWNDIALOG,COLBUTT,14,100,77,25,10\n"
- "130,131,,ISPARENT | CHECKED,GROUPBOX,15,10,98,120,20\n"
- "131,,,,EDTEXT,0,15,103,110,10\n"
- "200,201,,,LTEXT,16,10,30,70,9\n"
- "201,202,,CHECKED | EXRADIO,ODBUTTON,17,20,42,25,25\n"
- "202,203,,EXRADIO,ODBUTTON,17,45,42,25,25\n"
- "203,204,,EXRADIO,ODBUTTON,17,70,42,25,25\n"
- "204,205,,EXRADIO,ODBUTTON,17,95,42,25,25\n"
- "205,206,,EXRADIO,ODBUTTON,17,20,67,25,25\n"
- "206,207,,EXRADIO,ODBUTTON,17,45,67,25,25\n"
- "207,208,,EXRADIO,ODBUTTON,17,70,67,25,25\n"
- "208,210,,EXRADIO,ODBUTTON,17,95,67,25,25\n"
- "210,,220,ISPARENT | CHECKED, GROUPBOX,18,10,97,120,35\n"
- "220,221,,,RTEXT,-4,10,105,15,8\n"
- "221,222,,,EDVAL1,19,27,105,35,10\n"
- "222,223,,,LTEXT,-7,65,105,5,8\n"
- "223,224,,,EDVAL1,20,71,105,35,10\n"
- "224,225,,,LTEXT,-3,109,105,15,8\n"
- "225,226,,,RTEXT,-5,10,117,15,8\n"
- "226,227,,,EDVAL1,21,27,117,35,10\n"
- "227,228,,,LTEXT,-7,65,117,5,8\n"
- "228,229,,,EDVAL1,22,71,117,35,10\n"
- "229,,,,LTEXT,-3,109,117,15,8\n"
- "300,,,LASTOBJ | NOSELECT,ODBUTTON,23,15,30,110,140";
-
-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 = DefSize(SIZE_AXIS_LINE);
- DWORD colAxis = ColAX;
- void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)" scaling ", (void*)" automatic scaling",
- (void*)"axis from", (void*)&y_axis.min, (void*)"to", (void*)&y_axis.max, (void*)" line ", (void*)"width",
- (void*)&sizAxLine, (void*)0L, (void *)&colAxis, (void*)" axis label ", (void*)"select a template:",
- (void*)(OD_NewAxisTempl), (void*)" placement ", (void*)&axis.loc[0].fx, (void*)&axis.loc[1].fx,
- (void*)&axis.loc[0].fy, (void*)&axis.loc[1].fy, (void*)OD_axisplot};
- DlgInfo *NewAxisDlg;
- 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;
- anyOutput *cdisp = Undo.cdisp;
- Axis *the_new, **tmpAxes;
- bool bAxis = false, bRet = false;
- char **names;
- GraphObj **somePlots;
- Label *label;
-
- if(!(NewAxisDlg = CompileDialog(AddAxisTmpl, dyndata)))return false;
- 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*));
- if(names[0] = (char*)malloc(10)) rlp_strcpy(names[0], 10, "[none]");
- for(i = 0, j = 1; i < nscp; i++) {
- if(Sc_Plots[i] && Sc_Plots[i]->name){
- names[j] = (char*)memdup(Sc_Plots[i]->name, (int)strlen(Sc_Plots[i]->name)+1, 0);
- 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, data)))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, 318, 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) {
- Dlg->SetValue(221, hx1); Dlg->SetValue(223, hx2);
- Dlg->SetValue(226, hy1); Dlg->SetValue(228, hy2);
- if(! bAxis) {
- Dlg->SetValue(101, x_axis.min); Dlg->SetValue(103, x_axis.max);
- }
- }
- else {
- Dlg->SetValue(221, vx1); Dlg->SetValue(223, vx2);
- Dlg->SetValue(226, vy1); Dlg->SetValue(228, vy2);
- if(! bAxis) {
- Dlg->SetValue(101, y_axis.min); Dlg->SetValue(103, y_axis.max);
- }
- }
- currTempl = res;
- Dlg->DoPlot(0L);
- res = -1;
- break;
- }
- }while (res < 0);
- if(res == 1) {
- Undo.SetDisp(cdisp);
- 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(DefSize(SIZE_AXIS_TICKS));
- tlb_dx = tlb_dy = 0.0;
- tlbdef.ColTxt = colAxis; tlbdef.ColBg = 0x00ffffffL;
- tlbdef.RotBL = tlbdef.RotCHAR = 0.0f; tlbdef.fSize = DefSize(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 = DefSize(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, TMP_TXT_SIZE)) 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; free(NewAxisDlg);
- 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, cb;
- bool bRet = false, bContinue = false;
-
- FindPaper(GRect.Xmax - GRect.Xmin, GRect.Ymax -GRect.Ymin, .0001);
- if(!(Dlg = new DlgRoot(PageDlg, data)))return false;
- if(name)cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, name);
- else cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Page");
- rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE - cb, " properties");
- 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, 22, 10, "Line"};
- TabSHEET tab2 = {22, 52, 10, "Shapes"};
- TabSHEET tab3 = {52, 82, 10, "Dialogs"};
- TabSHEET tab4 = {82, 116, 10, "Internat."};
- TabSHEET tab5 = {116, 155, 10, "Date/Time"};
- double ts = dlgtxtheight;
- time_t ti = time(0L);
- char dt_info[50], date_info[50], datetime_info[50], time_info[50];
- DlgInfo DefsDlg[] = {
- {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 180, 10, 40, 12},
- {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 180, 25, 40, 12},
- {3, 0, 4, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
- {4, 5, 100, TOUCHEXIT | ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 170, 130},
- {5, 6, 200, TOUCHEXIT | ISPARENT, SHEET, &tab2, 5, 10, 170, 130},
- {6, 7, 300, TOUCHEXIT | ISPARENT, SHEET, &tab3, 5, 10, 170, 130},
- {7, 8, 400, TOUCHEXIT | ISPARENT, SHEET, &tab4, 5, 10, 170, 130},
- {8, 0, 350, TOUCHEXIT | ISPARENT, SHEET, &tab5, 5, 10, 170, 130},
- {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},
- {350, 351, 0, 0x0L, LTEXT, (void*)dt_info, 10, 30, 120, 8},
- {351, 352, 0, 0x0L, LTEXT, (void*)"date format:", 10, 43, 70, 8},
- {352, 353, 0, 0x0L, EDTEXT, (void*)defs.fmt_date, 10, 53, 60, 10},
- {353, 354, 0, 0x0L, LTEXT, (void*)date_info, 80, 54, 40, 10},
- {354, 355, 0, 0x0L, LTEXT, (void*)"date + time format:", 10, 65, 70, 8},
- {355, 356, 0, 0x0L, EDTEXT, (void*)defs.fmt_datetime, 10, 75, 60, 10},
- {356, 357, 0, 0x0L, LTEXT, (void*)datetime_info, 80, 76, 40, 10},
- {357, 358, 0, 0x0L, LTEXT, (void*)"time format:", 10, 87, 70, 8},
- {358, 359, 0, 0x0L, EDTEXT, (void*)defs.fmt_time, 10, 97, 60, 10},
- {359, 360, 0, 0x0L, LTEXT, (void*)time_info, 80, 98, 40, 10},
- {360, 361, 0, 0x0L, LTEXT, (void*)"For further information about formats see", 10, 119, 140, 8},
- {361, 362, 0, HREF | TOUCHEXIT, LTEXT, (void*)"http://rlplot.sourceforge.net/Docs/functions/datetime.html", 10, 127, 140, 8},
- {362, 0, 0, 0x0L, PUSHBUTTON, (void*)"Test", 130, 107, 40, 12},
- {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 i, cb, res, tmpUnits = cUnits;
- bool bRet = false, bContinue = false;
- double dt;
- 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);
- cb = rlp_strcpy(dt_info, 20, "today is ");
-#ifdef USE_WIN_SECURE
- ctime_s(dt_info+cb, 50-cb, &ti);
-#else
- rlp_strcpy(dt_info+cb, 50-cb, ctime(&ti));
-#endif
- dt_info[cb+24] = 0;
- date_value(dt_info+13, "x z H:M:S Y", &dt);
- rlp_strcpy(date_info, 50, value_date(dt, defs.fmt_date));
- rlp_strcpy(datetime_info, 50, value_date(dt, defs.fmt_datetime));
- rlp_strcpy(time_info, 50, value_date(dt, defs.fmt_time));
- Dlg = new DlgRoot(DefsDlg, 0L);
- 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;
- }
-#ifdef _WINDOWS
- for(i = 360; i <= 361; i++) Dlg->TextSize(i, 12);
-#else
- for(i = 360; i <= 361; i++) Dlg->TextSize(i, 10);
-#endif
- hDlg = CreateDlgWnd("Edit Global Preferences", 50, 50, 460, 316, Dlg, 0x0L);
- do{
- LoopDlgWnd();
- res = Dlg->GetResult();
- switch(res) {
- case 0:
- if(bContinue) res = -1;
- break;
- case 362: //update date/time display
- ti = time(0L); cb = rlp_strcpy(dt_info, 20, "today is ");
-#ifdef USE_WIN_SECURE
- ctime_s(dt_info+cb, 50-cb, &ti);
-#else
- rlp_strcpy(dt_info+cb, 50-cb, ctime(&ti));
-#endif
- dt_info[cb+24] = 0; Dlg->SetText(350, dt_info);
- date_value(dt_info+13, "x z H:M:S Y", &dt);
- if(!(Dlg->GetText(352, date_info, 50))) rlp_strcpy(date_info, 50, defs.fmt_date);
- rlp_strcpy(date_info, 50, value_date(dt, date_info)); Dlg->SetText(353, date_info);
- if(!(Dlg->GetText(355, datetime_info, 50))) rlp_strcpy(datetime_info, 50, defs.fmt_datetime);
- rlp_strcpy(datetime_info, 50, value_date(dt, datetime_info)); Dlg->SetText(356, datetime_info);
- if(!(Dlg->GetText(358, time_info, 50))) rlp_strcpy(time_info, 50, defs.fmt_time);
- rlp_strcpy(time_info, 50, value_date(dt, time_info)); Dlg->SetText(359, time_info);
- bContinue = false; res = -1;
- break;
- case 361: //call browser
- bContinue = true; res = -1;
- break;
- case 4: case 5: case 6: case 7:
- bContinue = false; res = -1;
- break;
- case 8:
- bContinue = true; 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, TMP_TXT_SIZE)) DecPoint[0] = TmpTxt[0];
- if(Dlg->GetText(404, TmpTxt, TMP_TXT_SIZE)) ColSep[0] = TmpTxt[0];
- 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);
- if(Dlg->GetText(352, date_info, 50) && date_info[0] && strcmp(date_info, defs.fmt_date)) {
- if(defs.fmt_date = (char*)realloc(defs.fmt_date, (cb = (int)strlen(date_info) +2)))
- rlp_strcpy(defs.fmt_date, cb, date_info);
- }
- if(Dlg->GetText(355, datetime_info, 50) && datetime_info[0] && strcmp(datetime_info, defs.fmt_datetime)) {
- if(defs.fmt_datetime = (char*)realloc(defs.fmt_datetime, (cb = (int)strlen(datetime_info) +2)))
- rlp_strcpy(defs.fmt_datetime, cb, datetime_info);
- }
- if(Dlg->GetText(358, time_info, 50) && time_info[0] && strcmp(time_info, defs.fmt_time)) {
- if(defs.fmt_time = (char*)realloc(defs.fmt_time, (cb = (int)strlen(time_info) +2)))
- rlp_strcpy(defs.fmt_time, cb, time_info);
- }
- bRet = true;
- }
- CloseDlgWnd(hDlg);
- delete Dlg;
- return bRet;
-}
+//PropertyDlg.cpp, Copyright (c) 2001-2008 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 <time.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
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *SymDlg_DlgTmpl =
+ "1,+,,DEFAULT,PUSHBUTTON,-1,145,10,60,12\n"
+ ".,.,,,PUSHBUTTON,2,145,25,60,12\n"
+ ".,.,,,PUSHBUTTON,-2,145,40,60,12\n"
+ ".,50,5,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
+ ".,+,100,TOUCHEXIT | ISPARENT | CHECKED,SHEET,3,5,10,130,113\n"
+ ".,.,200,TOUCHEXIT | ISPARENT,SHEET,4,5,10,130,113\n"
+ ".,,300,TOUCHEXIT | ISPARENT,SHEET,5,5,10,130,113\n"
+ "50,,,TOUCHEXIT,SYMBUTT,0,155,75,40,40\n"
+ "100,+,,,RTEXT,6,5,25,45,8\n"
+ ".,.,,TOUCHEXIT,INCDECVAL1,9,55,25,32,10\n"
+ ".,.,,,LTEXT,-3,89,25,20,8\n"
+ ".,.,,,RTEXT,10,5,37,45,8\n"
+ ".,.,,TOUCHEXIT,INCDECVAL1,11,55,37,32,10\n"
+ ".,.,,,LTEXT,-3,89,37,20,8\n"
+ ".,.,,,RTEXT,12,5,49,45,8\n"
+ ".,.,,TOUCHEXIT | OWNDIALOG, COLBUTT,13,55,49,25,10\n"
+ ".,.,,,RTEXT,14,5,61,45,8\n"
+ ".,401,,TOUCHEXIT | OWNDIALOG,COLBUTT,15,55,61,25,10\n"
+ "200,204,201,CHECKED | ISPARENT, GROUPBOX,16,12,28,50,39\n"
+ ".,+,,TOUCHEXIT, RADIO1,17,15,33,45,8\n"
+ ".,.,,TOUCHEXIT, RADIO1,18,15,43,45,8\n"
+ ".,,,TOUCHEXIT, RADIO1,19,15,53,43,8\n"
+ ".,250,205,CHECKED | ISPARENT, GROUPBOX,20,72,28,57,39\n"
+ "205,+,,TOUCHEXIT, CHECKBOX,21,75,33,25,8\n"
+ ".,.,,TOUCHEXIT, CHECKBOX,22,75,43,25,8\n"
+ ".,,,TOUCHEXIT, CHECKBOX,23,75,53,25,8\n"
+ "250,+,,TOUCHEXIT | CHECKED, RADIO1,24,10,75,45,8\n"
+ ".,.,,,EDTEXT,25,60,75,68,10\n"
+ ".,.,,TOUCHEXIT,RADIO1,26,10,92,60,8\n"
+ ".,,,,RANGEINPUT,27,20,102,100,10\n"
+ "300,+,,,RTEXT,-12,5,30,45,8\n"
+ ".,.,,,EDVAL1,7,55,30,45,10\n"
+ ".,.,,,RTEXT,-13,5,50,45,8\n"
+ ".,,,LASTOBJ,EDVAL1,8,55,50,45,10";
+
+bool
+Symbol::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 47, 10, "Size & Color"};
+ TabSHEET tab2 = {47, 70, 10, "Text"};
+ TabSHEET tab3 = {70, 92, 10, "Edit"};
+ Symbol *PrevSym = 0L;
+ char text1[40], text2[100];
+ void *dyndata[] = {(void*)"Apply to Symbol", (void*)"Apply to PLOT", (void*)&tab1,
+ (void*)&tab2, (void*)&tab3, (void*)"size", (void*)&fPos.fx, (void*)&fPos.fy,
+ (void*)&size, (void*)"line width", (void*)&SymLine.width, (void*)"line color",
+ (void *)&SymLine.color, (void*)"fill color", (void *)&SymFill.color, (void*)" font ",
+ (void*)"Helvetica", (void*)"Times", (void*)"Courier", (void*)" style ", (void*)"bold",
+ (void*)"italic", (void*)"underlined", (void*)"fixed text:", (void*)text1,
+ (void*)"from spreadsheet range:", (void*)text2};
+ DlgInfo *SymDlg;
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, k, ix, iy, tmpType, res, width, height, n_syms;
+ DWORD tmpCol, undo_flags = 0L;
+ double tmpVal, o_size, n_size, o_lwidth, n_lwidth;
+ TextDEF textdef;
+ bool bContinue = false;
+ anyOutput *cdisp = Undo.cdisp;
+ lfPOINT o_pos, n_pos;
+ static const int syms[] = {SYM_CIRCLE, SYM_CIRCLEF, SYM_CIRCLEC, SYM_RECT, SYM_RECTF, SYM_RECTC,
+ SYM_TRIAU, SYM_TRIAUF, SYM_TRIAUC, SYM_TRIAUL, SYM_TRIAUR, SYM_TRIAD, SYM_TRIADF, SYM_TRIADC,
+ SYM_TRIADL, SYM_TRIADR, SYM_DIAMOND, SYM_DIAMONDF, SYM_DIAMONDC, SYM_5GON, SYM_5GONF, SYM_5GONC,
+ SYM_4STAR, SYM_4STARF, SYM_5STAR, SYM_5STARF, SYM_6STAR, SYM_6STARF, SYM_1QUAD, SYM_2QUAD,
+ SYM_3QUAD, SYM_PLUS, SYM_CROSS, SYM_STAR, SYM_HLINE, SYM_VLINE, SYM_TEXT};
+
+ if(!(SymDlg = CompileDialog(SymDlg_DlgTmpl, dyndata)))return false;
+ if(!Command(CMD_GETTEXT, (void*)text1, 0L)) rlp_strcpy(text1, 40, "text");
+#ifdef USE_WIN_SECURE
+ if(parent && data && data->GetSize(&width, &height)) sprintf_s(text2, 100, "b1:b%d", height);
+#else
+ if(parent && data && data->GetSize(&width, &height)) sprintf(text2, "b1:b%d", height);
+#endif
+ else rlp_strcpy(text2, 100, "(not available)");
+ n_syms = sizeof(syms)/sizeof(int);
+ for(k = 1; !(SymDlg[k-1].flags & LASTOBJ); k++);
+ if(!parent) n_syms--;
+ if(!(SymDlg = (DlgInfo *)realloc(SymDlg, (k+n_syms)*sizeof(DlgInfo)))) return false;
+ SymDlg[k-1].flags &= (~LASTOBJ);
+ for(i = 1, iy = 66; i <= n_syms; i++, ix += 10) {
+ if((i%11) == 1) {
+ iy += 10; ix = 15;
+ }
+ SymDlg[k].id = 400 + i; SymDlg[k].next = 400 + i + 1;
+ SymDlg[k].first = 0; SymDlg[k].flags = TOUCHEXIT;
+ SymDlg[k].type = SYMRADIO; SymDlg[k].ptype = (void*)&syms[i-1];
+ SymDlg[k].x = ix; SymDlg[k].y = iy;
+ if(type == syms[i-1]) SymDlg[k].flags |= CHECKED;
+ SymDlg[k].w = SymDlg[k].h = 10; k++;
+ }
+ SymDlg[k-1].flags |= LASTOBJ; if(parent) SymDlg[k-1].w = 30;
+ if(parent) {
+ SymDlg[0].ptype = dyndata[0];
+ }
+ else {
+ SymDlg[5].flags |= HIDDEN; SymDlg[6].flags |= HIDDEN;
+ SymDlg[1].flags |= HIDDEN; SymDlg[2].y = 25;
+ SymDlg[0].w = SymDlg[2].w = 45; SymDlg[7].x = 145;
+ }
+ 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;
+ SymDlg[7].ptype = (void*)&PrevSym;
+ }
+ if(PrevSym && (Dlg = new DlgRoot(SymDlg, data))) {
+ 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);
+ 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 && parent->name) {
+ width = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Symbol of ");
+ rlp_strcpy(TmpTxt+width, TMP_TXT_SIZE-width, parent->name);
+ width =10;
+ }
+ else {
+ rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Symbol properties");
+ }
+ if(!(hDlg = CreateDlgWnd(TmpTxt, 50, 50, parent ? 430 : 400, 292, Dlg, 0x4L)))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 0:
+ if(bContinue) res = -1;
+ break;
+ case 1: case 2:
+ Undo.SetDisp(cdisp);
+ if(parent && PrevSym->type == SYM_TEXT && Dlg->GetCheck(250)){
+ Dlg->GetText(251, text1, 40);
+ 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(parent && PrevSym->type == SYM_TEXT && Dlg->GetCheck(252)) {
+ if(Dlg->GetCheck(252) && Dlg->GetText(253, text2, 100))
+ PrevSym->Command(CMD_RANGETEXT, &text2, 0L);
+ }
+ Dlg->GetValue(101, &n_size); Dlg->GetValue(104, &n_lwidth);
+ break;
+ case 5: case 7:
+ bContinue = false; res = -1;
+ case 6: //the text sheets
+ if(parent)Dlg->SetCheck(400+n_syms, 0L, true);
+ if(PrevSym->type != SYM_TEXT) {
+ PrevSym->type = SYM_TEXT; Dlg->DoPlot(0L);
+ }
+ res = -1; bContinue = true;
+ 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(0L);
+ }
+ res = -1;
+ break;
+ default: //symbol selection ?
+ if(res > 400 && res <= (400+n_syms)) tmpType = syms[res-401];
+ else break;
+ 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 50: //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,40))PrevSym->Command(CMD_SETTEXT, text1, 0L);
+ else if(Dlg->GetCheck(252) && Dlg->GetText(253, text2,100))
+ PrevSym->Command(CMD_RANGETEXT, text2, 0L);
+ }
+ Dlg->DoPlot(0L);
+ 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,40))PrevSym->Command(CMD_SETTEXT, text1, 0L);
+ else if(Dlg->GetCheck(252) && Dlg->GetText(253, text2, 100))
+ 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);
+ undo_flags |= UNDO_CONTINUE;
+ 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, 100))
+ 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; free(SymDlg);
+ delete PrevSym; return undo_flags != 0;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Bubble properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *BubDlg_DlgTmpl =
+ "1,+,,DEFAULT,PUSHBUTTON,1,130,10,60,12\n"
+ ".,.,,,PUSHBUTTON,2,130,25,60,12\n"
+ ".,.,,,PUSHBUTTON,-2,130,40,60,12\n"
+ ".,,5,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
+ "5,+,100,ISPARENT | CHECKED,SHEET,3,5,10,120,100\n"
+ ".,.,200,ISPARENT,SHEET,4,5,10,120,100\n"
+ ".,,300,ISPARENT,SHEET,5,5,10,120,100\n"
+ "100,109,,NOSELECT,ODBUTTON,6,18,57,90,50\n"
+ "109,+,,ISRADIO,ODBUTTON,7,30,30,20,20\n"
+ ".,.,,ISRADIO,ODBUTTON,7,50,30,20,20\n"
+ ".,.,,ISRADIO,ODBUTTON,7,70,30,20,20\n"
+ ".,,,ISRADIO,ODBUTTON,7,90,30,20,20\n"
+ "200,+,,,LTEXT,8,10,30,110,8\n"
+ ".,.,210,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ ".,.,,,LTEXT,9,10,64,110,8\n"
+ ".,,220,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "210,+,,,RADIO1,-3,40,38,45,8\n"
+ ".,.,,,RADIO1,10,40,46,45,8\n"
+ ".,,,,RADIO1,11,40,54,45,8\n"
+ "220,+,,,RADIO1,12,40,72,45,8\n"
+ ".,.,,,RADIO1,13,40,80,45,8\n"
+ ".,,,,RADIO1,14,40,88,45,8\n"
+ "300,+,,,RTEXT,-12,10,40,45,8\n"
+ ".,.,,,EDVAL1,15,60,40,35,10\n"
+ ".,.,,,RTEXT,-13,10,60,45,8\n"
+ ".,.,,,EDVAL1,16,60,60,35,10\n"
+ ".,.,,,RTEXT,17,10,80,45,8\n"
+ ".,,,LASTOBJ,EDVAL1,18,60,80,35,10";
+
+bool
+Bubble::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 52, 10, "Shape & Color"};
+ TabSHEET tab2 = {52, 84, 10, "Scaling"};
+ TabSHEET tab3 = {84, 106, 10, "Edit"};
+ int syms[] = {SYM_CIRCLE, SYM_RECT, SYM_TRIAU, SYM_TRIAD};
+ void *dyndata[] = {(void*)"Apply to BUBBLE", (void*)"Apply to PLOT", (void*)&tab1, (void*)&tab2,
+ (void*)&tab3, (void*)&OD_filldef, (void *)OD_BubbleTempl, (void*)"sizes are given as",
+ (void*)"proportionality (relative to circle)", (void*)"scaling with X axis",
+ (void*)"scaling with Y axis", (void*)"diameter", (void*)"circumference", (void*)"area", (void*)&fPos.fx,
+ (void*)&fPos.fy, (void*)"size", (void*)&fs};
+ DlgInfo *BubDlg = CompileDialog(BubDlg_DlgTmpl, dyndata);
+ DlgRoot *Dlg;
+ void *hDlg;
+ int cb, res, tmpType;
+ lfPOINT o_pos, n_pos;
+ LineDEF newLine, newFillLine;
+ FillDEF newFill;
+ DWORD undo_flags = 0L;
+ anyOutput *cdisp = Undo.cdisp;
+ 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, data);
+ 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) {
+ cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Bubble of ");
+ rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+ }
+ else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Bubble Properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 396, 260, Dlg, 0x4L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 1: //accept for current bubble only
+ case 2: //accept for plot
+ Undo.SetDisp(cdisp);
+ 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; free(BubDlg); return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Bar properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *BarDlg_DlgTmpl =
+ "1,+,,DEFAULT,PUSHBUTTON,1,130,10,55,12\n"
+ ".,.,,,PUSHBUTTON,2,130,25,55,12\n"
+ ".,.,,,PUSHBUTTON,-2,130,40,55,12\n"
+ ".,,5,CHECKED | ISPARENT,GROUP,0,138,40,55,12\n"
+ "5,+,100,ISPARENT | CHECKED,SHEET,3,5,10,120,120\n"
+ ".,.,200,ISPARENT,SHEET,4,5,10,120,120\n"
+ ".,,300,ISPARENT,SHEET,5,5,10,120,120\n"
+ "100,109,,NOSELECT,ODBUTTON,6,18,30,90,50\n"
+ "109,+,,,LTEXT,7,10,80,45,8\n"
+ ".,.,,,RADIO1,8,20,92,25,8\n"
+ ".,.,,,EDTEXT,9,60,92,25,10\n"
+ ".,.,,,LTEXT,-3,87,92,20,8\n"
+ ".,.,,,RADIO1,10,20,104,25,8\n"
+ ".,.,,,EDTEXT,11,60,104,25,10\n"
+ ".,,,,LTEXT,-10,87,104,10,8\n"
+ "200,+,,TOUCHEXIT,RADIO2,12,20,30,45,8\n"
+ ".,205,202,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
+ ".,+,,TOUCHEXIT,RADIO1,13,30,40,35,8\n"
+ ".,.,,TOUCHEXIT,RADIO1,14,30,48,35,8\n"
+ ".,,,TOUCHEXIT,RADIO1,15,30,56,35,8\n"
+ "205,+,,,EDVAL1,16,65,56,35,10\n"
+ ".,.,,TOUCHEXIT,RADIO2,17,20,70,45,8\n"
+ ".,211,208,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
+ "208,+,,TOUCHEXIT,RADIO1,18,30,80,35,8\n"
+ ".,.,,TOUCHEXIT,RADIO1,19,30,88,35,8\n"
+ ".,,,TOUCHEXIT,RADIO1,20,30,96,35,8\n"
+ "211,+,,,EDVAL1,21,65,96,35,10\n"
+ ".,,,,CHECKBOX,22,20,113,50,8\n"
+ "300,+,,,RTEXT,-12,10,50,45,8\n"
+ ".,.,,,EDVAL1,23,60,50,40,10\n"
+ ".,.,,,RTEXT,-13,10,75,45,8\n"
+ ".,,,LASTOBJ,EDVAL1,24,60,75,40,10";
+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];
+ void *dyndata[] = {(void*)"Apply to BAR", (void*)"Apply to PLOT", (void*)&tab1,
+ (void*)&tab2, (void*)&tab3, (void*)OD_filldef, (void*)"bar width:", (void*)" fixed",
+ (void*)&sTxt1[1], (void*)" relative", (void*)&sTxt2[1], (void*)"vertical bars",
+ (void*)"bottom baseline", (void*)"top", (void*)"user y =", (void*)&BarBase.fy,
+ (void*)"horizontal bars", (void*)"left baseline", (void*)"right", (void*)"user x =",
+ (void*)&BarBase.fx, (void*)"bars centered across baseline", (void*)&fPos.fx, (void*)&fPos.fy};
+ DlgInfo *BarDlg = CompileDialog(BarDlg_DlgTmpl, dyndata);
+ DlgRoot *Dlg;
+ void *hDlg;
+ double n_size;
+ int cb, res, tmpType = type;
+ bool bRet = false;
+ LineDEF newLine, newFillLine;
+ FillDEF newFill;
+ DWORD undo_flags = 0L;
+ anyOutput *cdisp = Undo.cdisp;
+ 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, DefSize(SIZE_BAR));
+ }
+ else {
+ WriteNatFloatToBuff(sTxt1, size);
+ rlp_strcpy(sTxt2, 20, " 50");
+ }
+ Dlg = new DlgRoot(BarDlg, data);
+ 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->name) {
+ cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Bar of ");
+ rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+ }
+ else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "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, 300, Dlg, 0x4L);
+ 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:
+ Undo.SetDisp(cdisp);
+ 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; free(BarDlg);
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Data line properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *LineDlg_DlgTmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,-1,150,10,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,150,25,45,12\n"
+ "3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "4,5,100,ISPARENT | CHECKED,SHEET,1,5,10,139,120\n"
+ "5,6,200,ISPARENT,SHEET,2,5,10,139,120\n"
+ "6,,300,ISPARENT | HIDDEN,SHEET,3,5,10,139,120\n"
+ "100,,,NOSELECT,ODBUTTON,9,10,38,130,100\n"
+ "200,201,,,LTEXT,-27,10,32,130,100\n"
+ "201,202,,EXRADIO,ODBUTTON,10,12,45,25,25\n"
+ "202,203,,EXRADIO,ODBUTTON,10,37,45,25,25\n"
+ "203,204,,EXRADIO,ODBUTTON,10,62,45,25,25\n"
+ "204,205,,EXRADIO,ODBUTTON,10,87,45,25,25\n"
+ "205,206,,EXRADIO,ODBUTTON,10,112,45,25,25\n"
+ "206,207,,EXRADIO,ODBUTTON,10,37,70,25,25\n"
+ "207,208,,EXRADIO,ODBUTTON,10,62,70,25,25\n"
+ "208,209,,EXRADIO,ODBUTTON,10,87,70,25,25\n"
+ "209,210,,EXRADIO,ODBUTTON,10,112,70,25,25\n"
+ "210,211,,EXRADIO,ODBUTTON,10,37,95,25,25\n"
+ "211,212,,EXRADIO,ODBUTTON,10,62,95,25,25\n"
+ "212,,,EXRADIO,ODBUTTON,10,87,95,25,25\n"
+ "300,301,,,LTEXT,5,15,30,80,9\n"
+ "301,302,,,EDTEXT,7,15,40,119,10\n"
+ "302,303,,,LTEXT,6,15,55,80,9\n"
+ "303,,,LASTOBJ,EDTEXT,8,15,65,119,10";
+
+bool
+DataLine::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 40, 10, "Line"};
+ TabSHEET tab2 = {40, 80, 10, "Style"};
+ TabSHEET tab3 = {80, 120, 10, "Edit"};
+ void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)0L,
+ (void*)"range for x-values", (void*)"range for y-values", (void*)ssXref, (void*)ssYref,
+ (void*)OD_linedef, (void*)(OD_LineStyleTempl)};
+ DlgInfo *LineDlg = CompileDialog(LineDlg_DlgTmpl, dyndata);
+ DlgRoot *Dlg;
+ void *hDlg;
+ int cb, res, tmpType = type;
+ DWORD undo_flags = 0L;
+ LineDEF newLine;
+ bool bRet = false;
+ anyOutput *cdisp = Undo.cdisp;
+
+ 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, data)))return false;
+ Dlg->SetCheck(201 + (type & 0x0f), 0L, true);
+ if(ssXref && ssYref) Dlg->ShowItem(6, true);
+ if(parent->name) {
+ cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Line of ");
+ rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+ }
+ else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Line properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 410, 300, Dlg, 0x4L);
+ 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: case 210: case 211: case 212:
+ if((tmpType & 0x0f) == (res-201)) res = 1;
+ else {
+ tmpType &= ~0x0f; tmpType |= (res-201);
+ res = -1;
+ }
+ break;
+ }
+ }while (res < 0);
+ if(res == 1){ //OK pressed
+ Undo.SetDisp(cdisp);
+ if(ssXref && ssYref) {
+ TmpTxt[0] = 0; Dlg->GetText(301, TmpTxt, TMP_TXT_SIZE);
+ undo_flags = CheckNewString(&ssXref, ssXref, TmpTxt, this, undo_flags);
+ TmpTxt[0] = 0; Dlg->GetText(303, TmpTxt, TMP_TXT_SIZE);
+ undo_flags = CheckNewString(&ssYref, ssYref, TmpTxt, this, undo_flags);
+ if(undo_flags & UNDO_CONTINUE) {
+ Command(CMD_UPDATE, 0L, cdisp); parent->Command(CMD_MRK_DIRTY, 0L, cdisp);
+ }
+ }
+ 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; free(LineDlg); return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Data polygon properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *PolygonDlg_DlgTmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,-1,120,10,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,120,25,45,12\n"
+ "3,,4,CHECKED,GROUP,0,0,0,0,0\n"
+ "4,5,100,ISPARENT | CHECKED, SHEET,1, 5,10,110,75\n"
+ "5,,200,ISPARENT,SHEET,2,5,10,110,75\n"
+ "100,,,NOSELECT,ODBUTTON,3,23,30,90,50\n"
+ "200,201,,,LTEXT,-27,10,32,130,100\n"
+ "201,202,,EXRADIO,ODBUTTON,4,10,45,25,25\n"
+ "202,203,,EXRADIO,ODBUTTON,4,35,45,25,25\n"
+ "203,213,,EXRADIO,ODBUTTON,4,60,45,25,25\n"
+ "213,,,LASTOBJ | EXRADIO,ODBUTTON,4,85,45,25,25";
+bool
+DataPolygon::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 40, 10, "Polygon"};
+ TabSHEET tab2 = {40, 70, 10, "Style"};
+ void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)OD_filldef, (void*)OD_PolygonStyleTempl};
+ DlgInfo *PolygonDlg;
+ DlgRoot *Dlg;
+ void *hDlg;
+ LineDEF newLine, newFillLine;
+ FillDEF newFill;
+ DWORD undo_flags = 0L;
+ anyOutput *cdisp = Undo.cdisp;
+ int cb, res, tmpType = type;
+ bool bRet = false;
+
+ if(!data || !parent) return false;
+ if(!(PolygonDlg = CompileDialog(PolygonDlg_DlgTmpl, dyndata))) return false;
+ OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
+ OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&pgFill, 0);
+ Dlg = new DlgRoot(PolygonDlg, data);
+ switch (type & 0x0f) {
+ case 0: default:
+ Dlg->SetCheck(201, 0L, true);
+ break;
+ case 1: case 2: case 12:
+ Dlg->SetCheck(201+type, 0L, true);
+ break;
+ }
+ if(parent->name) {
+ cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Polygon of ");
+ rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+ }
+ else if(parent->Id == GO_TICK) {
+ cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Isopleth \"");
+ if(parent->Command(CMD_GETTEXT, TmpTxt+cb, 0L)) {
+ cb = (int)strlen(TmpTxt); TmpTxt[cb++] = '"'; TmpTxt[cb++] = ' ';
+ }
+ else cb--;
+ cb += rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE, "Properties");
+ }
+ else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Polygon Properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 348, 210, Dlg, 0x4L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 201: case 202: case 203: case 213:
+ if((tmpType & 0x0f) == (res-201)) res = 1;
+ else {
+ tmpType &= ~0x0f; tmpType |= (res-201);
+ res = -1;
+ }
+ break;
+ }
+ }while (res < 0);
+ if(res == 1){ //OK pressed
+ Undo.SetDisp(cdisp);
+ 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;
+ undo_flags = CheckNewInt(&type, type, tmpType, parent, undo_flags);
+ if(undo_flags & UNDO_CONTINUE) bRet = true;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg; free(PolygonDlg); 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[60], text2[60], text3[60], text4[60], text5[60];
+ 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 cb, res, tmpType;
+ bool bRet = false;
+ LineDEF newLine;
+ DWORD undo_flags = 0L;
+ anyOutput *cdisp = Undo.cdisp;
+ 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;
+ }
+#ifdef USE_WIN_SECURE
+ sprintf_s(text1, 60, "%s = %.3lf + %.3lf * %s (n = %ld)", ty, l1.fx, l1.fy, tx, nPoints);
+ sprintf_s(text2, 60, "%s = %.3lf + %.3lf * %s", ty, l2.fx, l2.fy, tx);
+ sprintf_s(text3, 60, "%s = %.3lf + %.3lf * %s", ty, l3.fx, l3.fy, tx);
+ sprintf_s(text4, 60, "%s = %.3lf + %.3lf * %s", ty, l4.fx, l4.fy, tx);
+ sprintf_s(text5, 60, "%s = a + b * %s", ty, tx);
+#else
+ 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);
+#endif
+ if(!(Dlg = new DlgRoot(LineDlg, data))) 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->name) {
+ cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Regression line of ");
+ rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+ }
+ else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Regression line properties");
+ hDlg = CreateDlgWnd(cp ? TmpTxt :
+ (char*)"Linear regression analysis step 2/2", 50, 50, 420, 320, Dlg, 0x4L);
+ 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
+ Undo.SetDisp(cdisp);
+ 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
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char* SdEllipseDlg_Tmpl =
+ "1,+,,DEFAULT,PUSHBUTTON,-1,150,10,45,12\n"
+ ".,.,,,PUSHBUTTON,-2,150,25,45,12\n"
+ ".,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "4,+,100,ISPARENT | CHECKED,SHEET,1,5,10,139,140\n"
+ ".,,200,ISPARENT,SHEET,2,5,10,139,140\n"
+ "100,,,NOSELECT,ODBUTTON,3,10,48,130,100\n"
+ "200,+,,,CHECKBOX,4,20,26,80,9\n"
+ ".,.,250,CHECKED, GROUPBOX,5,10,45,129,100\n"
+ "250,+,,,LTEXT,6,25,82,60,8\n"
+ ".,.,,,RTEXT,7,20,92,60,8\n"
+ ".,.,,,LTEXT,0,82,92,30,8\n"
+ ".,.,,,RTEXT,8,20,100,60,8\n"
+ ".,.,,,LTEXT,0,82,100,30,8\n"
+ ".,.,,,LTEXT,9,25,112,60,8\n"
+ ".,.,,,RTEXT,10,20,122,60,8\n"
+ ".,.,,,LTEXT,0,82,122,30,8\n"
+ ".,.,,,RTEXT,11,20,130,60,8\n"
+ ".,.,,,LTEXT,0,82,130,30,8\n"
+ ".,.,,,LTEXT,12,25,52,30,8\n"
+ ".,.,,,RADIO1,13,50,52,30,8\n"
+ ".,.,,,RADIO1,14,50,61,30,8\n"
+ ".,,,LASTOBJ,RADIO1,15,50,70,30,8";
+bool
+SDellipse::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 40, 10, "Line"};
+ TabSHEET tab2 = {40, 80, 10, "Details"};
+ void *dyndata[] = {(void*)&tab1, (void*) &tab2, (void*)OD_linedef, (void*)" show regression line",
+ (void*)" ellipse ", (void*)"center (means of data)", (void*)"x =", (void*)"y =",
+ (void*)"standard deviation (S.D.)", (void*)"major axis", (void*)"minor axis", (void*)"size:",
+ (void*)" 1 x S.D.", (void*)" 2 x S.D.", (void*)" 3 x S.D."};
+ DlgInfo *ellDlg;
+ DlgRoot *Dlg;
+ void *hDlg;
+ int cb, res, tmpType;
+ LineDEF newLine;
+ bool bRet = false;
+ DWORD undo_flags = 0L;
+ anyOutput *cdisp = Undo.cdisp;
+
+ if(!parent) return false;
+ if(!(ellDlg = CompileDialog(SdEllipseDlg_Tmpl, dyndata))) return false;
+ OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
+ if(!(Dlg = new DlgRoot(ellDlg, data))) 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);
+ rlp_strcpy(TmpTxt, 4, "+/-");
+ WriteNatFloatToBuff(TmpTxt+3, sd1); Dlg->SetText(259, TmpTxt);
+ WriteNatFloatToBuff(TmpTxt+3, sd2); Dlg->SetText(257, TmpTxt);
+ switch(type & 0x60000) {
+ case 0x20000: Dlg->SetCheck(262, 0L, true); break;
+ case 0x40000: Dlg->SetCheck(263, 0L, true); break;
+ default: Dlg->SetCheck(261, 0L, true); break;
+ }
+ tmpType = type;
+ if(parent->name) {
+ cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "SD ellipse of ");
+ rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+ }
+ else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "SD ellipse properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 410, 340, Dlg, 0x4L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ }while (res < 0);
+ if(res == 1){ //OK pressed
+ Undo.SetDisp(cdisp);
+ 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;
+ tmpType &= ~0x60000;
+ if(Dlg->GetCheck(262)) tmpType |= 0x20000;
+ else if(Dlg->GetCheck(263)) tmpType |= 0x40000;
+ undo_flags = CheckNewInt(&type, type, tmpType, parent, undo_flags);
+ if(undo_flags & UNDO_CONTINUE) bRet = true;
+ }
+ CloseDlgWnd(hDlg); delete Dlg; free(ellDlg);
+ 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, TOUCHEXIT | 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, COLBUTT, (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, 30, 28, 8},
+ {301, 302, 0, 0x0L, EDVAL1, &fPos.fx, 46, 30, 35, 10},
+ {302, 303, 0, 0x0L, RTEXT, (void*)"y-value", 15, 45, 28, 8},
+ {303, 304, 0, 0x0L, EDVAL1, &fPos.fy, 46, 45, 35, 10},
+ {304, 305, 0, 0x0L, RTEXT, (void*)"error", 15, 60, 28, 8},
+ {305, 306, 0, 0x0L, EDVAL1, &ferr, 46, 60, 35, 10},
+ {306, 307, 0, 0x0L, LTEXT, (void*)"description:", 10, 80, 70, 8},
+ {307, 0, 0, 0x0L, EDTEXT, (void*)name, 10, 90, 80, 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 cb, 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;
+ anyOutput *cdisp = Undo.cdisp;
+ bool bRet = false;
+ char desc[80];
+
+ if(!parent) return false;
+ desc[0] = 0;
+ if(!(Dlg = new DlgRoot(ErrDlg, data)))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->name) {
+ cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Error bar of ");
+ rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+ }
+ else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Error bar properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 328, 260, Dlg, 0x4L);
+ 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 7: //edit tab
+ Dlg->Activate(307, true); res = -1; break;
+ case 1: //accept for this object
+ case 2: // or all objects of plot
+ desc[0] = 0;
+ Undo.SetDisp(cdisp); Dlg->GetText(307, desc, 80);
+ 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(&ferr, o_err, n_err, 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 = CheckNewString(&name, name, desc, this, undo_flags);
+ 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);
+ 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);
+ if(desc[0] || name) parent->Command(CMD_ERRDESC, desc, 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, COLBUTT, (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 cb, res, tmptype = type, undo_level = *Undo.pcb;
+ bool bRet = false;
+ DWORD o_col, n_col, undo_flags = 0L;
+ anyOutput *cdisp = Undo.cdisp;
+
+ if(!parent) return false;
+ if(!(Dlg = new DlgRoot(ArrowDlg, data))) 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->name) {
+ cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Arrow of ");
+ rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+ }
+ else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Arrow properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 328, 260, Dlg, 0x4L);
+ do {
+ LoopDlgWnd(); res = Dlg->GetResult();
+ switch (res) {
+ case 600: case 601: case 602: case 603:
+ Undo.SetDisp(cdisp);
+ res = ExecDrawOrderButt(parent, this, res);
+ }
+ 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:
+ Undo.SetDisp(cdisp);
+ 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
+ Undo.SetDisp(cdisp);
+ 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 cb, res, tmpType = type;
+ FillDEF newFill;
+ LineDEF newLine, newHatchLine;
+ DWORD undo_flags = 0L;
+ anyOutput *cdisp = Undo.cdisp;
+ 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, DefSize(SIZE_BAR));
+ }
+ else {
+ WriteNatFloatToBuff(sTxt1, size);
+ rlp_strcpy(sTxt2, 20, " 50");
+ }
+ Dlg = new DlgRoot(BoxDlg, data);
+ 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->name) {
+ cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Box of ");
+ rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+ }
+ else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Box properties");
+ Dlg->GetValue(309, &o_size);
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 390, 290, Dlg, 0x4L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 1: //accept for this object
+ case 2: // or all objects of plot
+ Undo.SetDisp(cdisp);
+ 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, &n_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
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *WhiskerDlgTmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,1,100,10,64,12\n"
+ "2,3,,,PUSHBUTTON,2,100,25,64,12\n"
+ "3,4,,,PUSHBUTTON,-2, 100, 40, 64, 12\n"
+ "4,,5,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "5,6,100,ISPARENT | CHECKED,SHEET,3, 5, 10, 90, 100\n"
+ "6,7,500,ISPARENT,SHEET,4,5,10,90,100\n"
+ "7,,300,ISPARENT,SHEET,5,5,10,90,100\n"
+ "100,101,,,RTEXT,6,15,40,28,8\n"
+ "101,102,,,EDVAL1,7,46,40,25,10\n"
+ "102,103,,,LTEXT,-3,73,40,20,8\n"
+ "103,104,,,RTEXT,8,15,55,28,8\n"
+ "104,105,,,EDVAL1,9,46,55,25,10\n"
+ "105,106,,,LTEXT,-3,73,55,20,8\n"
+ "106,107,,,RTEXT,10,15,70,28,8\n"
+ "107,,,OWNDIALOG,COLBUTT,11,46,70,25,10\n"
+ "300,301,,,RTEXT,12,15,30,28,8\n"
+ "301,302,,,EDVAL1,13,46,30,35,10\n"
+ "302,303,,,RTEXT,-5,15,42,28,8\n"
+ "303,304,,,EDVAL1,14,46,42,35,10\n"
+ "304,305,,,RTEXT,15,15,55,28,8\n"
+ "305,306,,,EDVAL1,16,46,55,35,10\n"
+ "306,307,,,RTEXT,-5,15,67,28,8\n"
+ "307,308,,,EDVAL1,17,46,67,35,10\n"
+ "308,309,,,LTEXT,18,10,85,70,8\n"
+ "309,,,,EDTEXT,19,10,95,80,10\n"
+ "500,501,,EXRADIO,ODBUTTON,20,32,40,18,18\n"
+ "501,502,,EXRADIO,ODBUTTON,20,14,40,18,18\n"
+ "502,503,,EXRADIO,ODBUTTON,20,50,40,18,18\n"
+ "503,504,,EXRADIO,ODBUTTON,20,68,40,18,18\n"
+ "504,,,LASTOBJ,LTEXT,-27,14,30,30,9";
+bool
+Whisker::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 38, 10, "Whisker"};
+ TabSHEET tab2 = {65, 90, 10, "Edit"};
+ TabSHEET tab3 = {38, 65, 10, "Style"};
+ void *dyndata[] = {(void*)"Apply to WHISKER", (void*)"Apply to PLOT", (void*)&tab1,
+ (void*)&tab3, (void*)&tab2, (void*)"cap width", (void*)&size, (void*)"line width",
+ (void*)&LineDef.width, (void*)"line color", (void *)&LineDef.color, (void*)"point 1 x",
+ (void*)&pos1.fx, (void*)&pos1.fy, (void*)"point 2 x", (void*)&pos2.fx, (void*)&pos2.fy,
+ (void*)"description:", (void*)name, (void*)(OD_WhiskerTempl)};
+ DlgInfo *ErrDlg = CompileDialog(WhiskerDlgTmpl, dyndata);
+ DlgRoot *Dlg;
+ void *hDlg;
+ int cb, res, tmp_type;
+ DWORD undo_flags = 0L, n_col = LineDef.color;
+ anyOutput *cdisp = Undo.cdisp;
+ lfPOINT n_pos;
+ double tmpVal, o_size, n_size, o_lw, n_lw;
+ bool bRet = false;
+ char desc[80];
+
+ if(!parent) return false;
+ desc[0] = 0; tmp_type = type;
+ Dlg = new DlgRoot(ErrDlg, data);
+ Dlg->SetCheck(500 + (tmp_type & 0x03), 0L, true);
+ Dlg->GetValue(101, &o_size); Dlg->GetValue(104, &o_lw);
+ if(parent->name) {
+ cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Whisker of ");
+ rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+ }
+ else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Whisker properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 339, 260, Dlg, 0x4L);
+ 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
+ Undo.SetDisp(cdisp); Dlg->GetValue(101, &n_size);
+ Dlg->GetValue(104, &n_lw); Dlg->GetColor(107, &n_col);
+ desc[0] = 0; Dlg->GetText(309, desc, 80);
+ break;
+ }
+ }while (res <0);
+ switch (res) {
+ case 1: //new setting for current whisker
+ undo_flags = CheckNewString(&name, name, desc, this, undo_flags);
+ 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 && !desc[0] && !name) break;
+ parent->Command(CMD_SAVE_ERRS, 0L, 0L);
+ if(desc[0] || name) parent->Command(CMD_ERRDESC, desc, 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; free(ErrDlg);
+ 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 cb, res, tmptype;
+ bool bRet = false;
+ LineDEF newLine;
+ DWORD undo_flags = 0L;
+ anyOutput * cdisp = Undo.cdisp;
+ lfPOINT o_pos, n_pos;
+
+ if(!parent) return false;
+ OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
+ Dlg = new DlgRoot(LineDlg, data);
+ 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) {
+ cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Dropline of ");
+ rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+ }
+ else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Dropline properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 415, 300, Dlg, 0x4L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 1: //this line
+ case 2: //all lines of plot
+ Undo.SetDisp(cdisp); 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 cb, res, tmptype, i;
+ bool bRet = false;
+ LineDEF newLine;
+ DWORD undo_flags = 0L;
+ anyOutput *cdisp = Undo.cdisp;
+ fPOINT3D o_pos, n_pos;
+
+ if(!parent) return false;
+ OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
+ Dlg = new DlgRoot(LineDlg, data);
+ 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) {
+ cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Dropline of ");
+ rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+ }
+ else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Dropline properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 415, 300, Dlg, 0x4L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 1: //this line
+ case 2: //all lines of plot
+ Undo.SetDisp(cdisp);
+ 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, INCDECVAL1, &size, 46, 35, 32, 10},
+ {102, 103, 0, 0x0L, LTEXT, (void*)type_text[type < 4 ? type : 0], 80, 35, 15, 8},
+ {103, 104, 0, 0x0L, RTEXT, (void*)"line width", 15, 47, 28, 8},
+ {104, 105, 0, 0x0L, INCDECVAL1, &Line.width, 46, 47, 32, 10},
+ {105, 106, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 80, 47, 15, 8},
+ {106, 107, 0, 0x0L, RTEXT, (void*)"line color", 15, 59, 28, 8},
+ {107, 108, 0, OWNDIALOG, COLBUTT, (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 cb, res;
+ bool bRet = false, bContinue = false;
+ fPOINT3D n_pos, o_pos;
+ DWORD new_lcolor = Line.color, undo_flags = 0L;
+ anyOutput *cdisp = Undo.cdisp;
+ double o_size, n_size, o_lsize, n_lsize;
+
+ if(!parent) return false;
+ memcpy(&newFill, &Fill, sizeof(FillDEF));
+ Dlg = new DlgRoot(BallDlg, data);
+ 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) {
+ cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Ball of ");
+ rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+ }
+ else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Ball properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 335, 220, Dlg, 0x4L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 0:
+ if(bContinue) res = -1;
+ bContinue = false;
+ break;
+ case 1: case 2:
+ Undo.SetDisp(cdisp); 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
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *Plane3D_DlgTmpl =
+ "1,2,,DEFAULT, PUSHBUTTON,1,115,10,55,12\n"
+ "2,3,,,PUSHBUTTON,2,115,25,55,12\n"
+ "3,4,,,PUSHBUTTON,-2,115,40,55,12\n"
+ "4,,10,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "10,,100,ISPARENT | CHECKED,SHEET,3,5,10,105,85\n"
+ "100,101,,,RTEXT,4,15,30,36,8\n"
+ "101,102,,,EDVAL1,5,53,30,25,10\n"
+ "102,103,,,LTEXT,-3,80,30,15,8\n"
+ "103,104,,,RTEXT,6,15,42,36,8\n"
+ "104,105,,OWNDIALOG,COLBUTT,7,53,42,25,10\n"
+ "105,106,,,RTEXT,8,15,54,36,8\n"
+ "106,200,,OWNDIALOG,SHADE3D,9,53,54,25,10\n"
+ "200,,201,CHECKED,GROUP,0,0,0,0,0\n"
+ "201,202,,,RTEXT,10,15,66,36,8\n"
+ "202,203,,,INCDECVAL1,11,53,66,25,10\n"
+ "203,204,,,LTEXT,-10,80,66,5,8\n"
+ "204,205,,,RTEXT,12,15,78,36,8\n"
+ "205,206,,,EDVAL1,13,53,78,25,10\n"
+ "206,,,LASTOBJ,LTEXT,14,80,78,40,8";
+
+bool
+Plane3D::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 27, 10, "Plane"};
+ double rb_width = 0.0, rb_z = 0.0;
+ FillDEF newFill;
+ void *dyndata[] = {(void*)"Apply to PLANE", (void*)"Apply to PLOT", (void*)&tab1,
+ (void*)"line width", (void*)&Line.width, (void*)"line color", (void *)&Line.color,
+ (void*)"fill color", (void*)&newFill, (void*)"ribbon width", (void*)&rb_width,
+ (void*)"ribbon pos.", (void*)&rb_z, (void*)"[z-data]"};
+ DlgInfo *PlaneDlg = CompileDialog(Plane3D_DlgTmpl, dyndata);
+ DlgRoot *Dlg;
+ void *hDlg;
+ int cb, res;
+ bool bRet = false;
+ DWORD new_lcolor = Line.color, undo_flags = 0L;
+ anyOutput *cdisp = Undo.cdisp;
+ double o_lsize, n_lsize, o_rbw, n_rbw, o_rbz, n_rbz;
+
+ if(!parent) return false;
+ if(parent->Id == GO_GRID3D) return parent->PropertyDlg();
+ 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, data);
+ Dlg->GetValue(101, &o_lsize); Dlg->GetValue(202, &o_rbw);
+ Dlg->GetValue(205, &o_rbz);
+ if(parent && ((parent->Id==GO_RIBBON && parent->type > 1) || parent->Id==GO_GRID3D))
+ Dlg->ShowItem(200, false); //paravent plot
+ if(parent->Id == GO_RIBBON && parent->type >2) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "3D Surface Properties");
+ else if(parent->name) {
+ cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Plane of ");
+ rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+ }
+ else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Plane properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 355, 226, Dlg, 0x4L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 1: case 2:
+ Undo.SetDisp(cdisp); 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, COLBUTT, (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 cb, res;
+ bool bRet = false;
+ DWORD col1 = Line.color, undo_flags = 0L;
+ anyOutput *cdisp = Undo.cdisp;
+ 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, data);
+ 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) {
+ cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Column of ");
+ rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+ }
+ else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Column properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 405, 296, Dlg, 0x4L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 1: case 2:
+ Undo.SetDisp(cdisp); 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
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *Arrow3D_DlgTmpl =
+ "1,2,,DEFAULT, PUSHBUTTON,1,100,10,57,12\n"
+ "2,3,,,PUSHBUTTON,2,100,25,57,12\n"
+ "3,4,,,PUSHBUTTON,-2,100,40,57,12\n"
+ "4,,5,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "5,6,100,ISPARENT | CHECKED,SHEET,3,5,10,90,100\n"
+ "6,7,200,ISPARENT,SHEET,4,5,10,90,100\n"
+ "7,,300,ISPARENT,SHEET,5,5,10,90,100\n"
+ "100,101,,,RTEXT,6,15,40,28,8\n"
+ "101,102,,,EDVAL1,7,46,40,25,10\n"
+ "102,103,,,LTEXT,-3,73,40,20,8\n"
+ "103,104,,,RTEXT,8,15,52,28,8\n"
+ "104,105,,,EDVAL1,9,46,52,25,10\n"
+ "105,106,,,LTEXT,-3,73,52,20,8\n"
+ "106,107,,,RTEXT,10,15,70,28,8\n"
+ "107,108,,,EDVAL1,11,46,70,25,10\n"
+ "108,109,,,LTEXT,-3,73,70,20,8\n"
+ "109,110,,,RTEXT,-11,15,82,28,8\n"
+ "110,,,OWNDIALOG,COLBUTT,12,46,82,25,10\n"
+ "200,201,,TOUCHEXIT,RADIO1,13,15,40,60,8\n"
+ "201,202,,TOUCHEXIT,RADIO1,14,15,55,60,8\n"
+ "202,,,TOUCHEXIT,RADIO1,15,15,70,60,8\n"
+ "300,301,,,RTEXT,-12,10,25,28,8\n"
+ "301,302,,,EDVAL1,16,46,25,35,10\n"
+ "302,303,,,RTEXT,-13,10,36,28,8\n"
+ "303,304,,,EDVAL1,17,46,36,35,10\n"
+ "304,305,,,RTEXT,-14,10,47,28,8\n"
+ "305,306,,,EDVAL1,18,46,47,35,10\n"
+ "306,307,,,RTEXT,19,10,60,28,8\n"
+ "307,308,,,EDVAL1,20,46,60,35,10\n"
+ "308,309,,,RTEXT,-5,10,71,28,8\n"
+ "309,310,,,EDVAL1,21,46,71,35,10\n"
+ "310,311,,,RTEXT,-6,10,82,28,8\n"
+ "311,312,,,EDVAL1,22,46,82,35,10\n"
+ "312,,,LASTOBJ,CHECKBOX,23,16,95,70,8";
+
+bool
+Arrow3D::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 29, 10, "Arrow"};
+ TabSHEET tab2 = {29, 59, 10, "Type"};
+ TabSHEET tab3 = {59, 90, 10, "Edit"};
+ void *dyndata[] = {(void*)"Apply to ARROW", (void*)"Apply to PLOT", (void*)&tab1,
+ (void*)&tab2, (void*)&tab3, (void*)"cap width", (void*)&cw, (void*)"length",
+ (void*)&cl, (void*)"line width", (void*)&Line.width, (void *)&Line.color,
+ (void*)"line only", (void*)"arrow with lines", (void*)"filled arrow",
+ (void*)&fPos2.fx, (void*)&fPos2.fy, (void*)&fPos2.fz, (void*)"origin x",
+ (void*)&fPos1.fx, (void*)&fPos1.fy, (void*)&fPos1.fz, (void*)"set common origin"};
+ DlgInfo *ArrowDlg = CompileDialog(Arrow3D_DlgTmpl, dyndata);
+ 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 cb, res, tmptype = type, undo_level = *Undo.pcb;
+ bool bRet = false;
+ DWORD o_col, n_col, undo_flags = 0L;
+ anyOutput *cdisp = Undo.cdisp;
+
+ if(!parent) return false;
+ if(!(Dlg = new DlgRoot(ArrowDlg, data))) 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) {
+ cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Arrow of ");
+ rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+ }
+ else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Arrow properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 328, 260, Dlg, 0x4L);
+ 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:
+ Undo.SetDisp(cdisp);
+ 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; free(ArrowDlg); 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 cb, res;
+ bool bRet = false;
+ LineDEF newLine;
+ anyOutput *cdisp = Undo.cdisp;
+
+ if(!parent) return false;
+ if(parent->Id == GO_GRID3D) return parent->PropertyDlg();
+ OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
+ if(!(Dlg = new DlgRoot(LineDlg, data)))return false;
+ if(parent->name) {
+ cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Line of ");
+ rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+ }
+ else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Line properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 410, 314, Dlg, 0x4L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ }while (res < 0);
+ switch(res) {
+ case 1: //OK pressed
+ Undo.SetDisp(cdisp);
+ 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"};
+ bool isDataLabel = ((parent) && (parent->Id == GO_PLOTSCATT || parent->Id == GO_XYSTAT || parent->Id == GO_BOXPLOT
+ || parent->Id == GO_CONTOUR));
+ int bwidth = isDataLabel ? 55 : 45;
+ double lspc = 100.0;
+ DlgInfo LabelDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, isDataLabel ? (void*)"Apply to LABEL" : (void*)"OK", 170, 10, bwidth, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 170, isDataLabel ? 40 : 25, bwidth, 12},
+ {3, isDataLabel ? 10 : 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},
+ {10, 50, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 170, 25, bwidth, 12},
+ {50, 0, 600, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
+ {100, 101, 0, 0x0L, RTEXT, (void*)"size", 30, 33, 45, 8},
+ {101, 102, 0, 0x0L, INCDECVAL1, &TextDef.fSize, 80, 33, 33, 10},
+ {102, 103, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 115, 33, 20, 8},
+ {103, 104, 0, 0x0L, RTEXT, (void*)"color", 30, 45, 45, 8},
+ {104, 107, 0, OWNDIALOG, COLBUTT, (void *)&TextDef.ColTxt, 80, 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", 30, 57, 45, 8},
+ {108, 109, 0, 0x0L, EDVAL1, &TextDef.RotBL, 80, 57, 25, 10},
+ {109, 150, 0, 0x0L, LTEXT, (void *)"deg.", 107, 57, 20, 8},
+ {150, 154, 151, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
+ {151, 152, 0, 0x0L, RTEXT, (void *)"line spacing", 30, 69, 45, 8},
+ {152, 153, 0, 0x0L, INCDECVAL1, &lspc, 80, 69, 33, 10},
+ {153, 0, 0, 0x0L, LTEXT, (void *)"%", 115, 69, 20, 8},
+ {154, 105, 0, 0x0L, CHECKBOX, (void*) " moveable", 80, 83, 60, 9},
+ {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, 185, 45, 15, 15},
+ {601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 185, 60, 15, 15},
+ {602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 185, 75, 15, 15},
+ {603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 185, 90, 15, 15}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, i, c_style, c_font;
+ bool RetVal = false, check;
+ double tmp;
+ DWORD undo_flags = 0x0;
+ anyOutput *cdisp = Undo.cdisp;
+ lfPOINT o_pos, o_dist, n_pos, n_dist;
+ TextDEF OldTxtDef, NewTxtDef;
+ Axis *pa;
+ fmtText *fmt = 0L;
+
+ if(!parent) return false;
+ if(parent->Id == GO_MLABEL) {
+ lspc = 100.0 * parent->GetSize(SIZE_LSPC);
+ }
+ if (lspc < 50.0) lspc = 100.0;
+ if(Dlg = new DlgRoot(LabelDlg, data)) {
+ if(parent->Id == GO_MLABEL) Dlg->ShowItem(150, true);
+ 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);
+ if(moveable){
+ Dlg->SetCheck(154, 0L, true);
+ }
+ 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) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(axis)");
+ else if(parent->parent->Id == GO_TICK) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(tick)");
+ }
+ else {
+ if(parent->Id == GO_AXIS) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(axis)");
+ else if(parent->Id == GO_TICK) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(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) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(axis)");
+ if(parent->parent->Id == GO_TICK) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(tick)");
+ }
+ else {
+ if(parent->Id == GO_AXIS) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(axis)");
+ if(parent->Id == GO_TICK) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "(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, isDataLabel ? 470 : 450, 258, Dlg, 0x4L);
+ do{
+ LoopDlgWnd(); res = Dlg->GetResult();
+ switch (res) {
+ case 600: case 601: case 602: case 603:
+ Undo.SetDisp(cdisp);
+ res = ExecDrawOrderButt(parent, this, res);
+ }
+ switch (res) {
+ case 10:
+ Undo.SetDisp(cdisp);
+ parent->Command(CMD_SAVE_LABELS, 0L, 0L);
+ undo_flags |= UNDO_CONTINUE;
+ 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, TMP_TXT_SIZE))) 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 || res == 10) {
+ Undo.SetDisp(cdisp);
+ 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;
+ }
+ i = Dlg->GetCheck(154) ? 1 : 0;
+ if(i != moveable) {
+ Undo.ValInt(parent, &moveable, undo_flags);
+ moveable = i; undo_flags |= UNDO_CONTINUE;
+ }
+ TmpTxt[0] = 0; Dlg->GetText(106, TmpTxt, TMP_TXT_SIZE);
+ if(res == 1) undo_flags = CheckNewString(&TextDef.text, TextDef.text, TmpTxt, this, undo_flags);
+ if(cmpTextDEF(&OldTxtDef, &NewTxtDef)){
+ if(NewTxtDef.ColTxt != TextDef.ColTxt) bBGvalid = false;
+ if (pa) pa->Command(CMD_TLB_TXTDEF, &NewTxtDef, 0L);
+ else if(res == 10 || 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(res == 10 || parent->Id == GO_MLABEL) {
+ if(n_dist.fx != o_dist.fx && parent->SetSize(SIZE_LB_XDIST, n_dist.fx)) RetVal = true;
+ if(n_dist.fy != o_dist.fy && 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(parent->Id == GO_MLABEL && Dlg->GetValue(152, &tmp) && tmp != lspc) {
+ parent->SetSize(SIZE_LSPC, tmp/100.0); RetVal = true;
+ }
+ if(undo_flags & UNDO_CONTINUE) RetVal = true;
+ }
+ CloseDlgWnd(hDlg);
+ if(fmt) delete(fmt);
+ delete Dlg;
+ return RetVal;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Text frame properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+TextFrame::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 27, 10, "Text"};
+ TabSHEET tab2 = {27, 57, 10, "Frame"};
+ double lspc2, lspc1 = lspc2 = lspc * 100.0;
+ DlgInfo TextFrmDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 130, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 25, 45, 12},
+ {3, 50, 4, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 119, 100},
+ {5, 0, 200, ISPARENT, SHEET, &tab2, 5, 10, 119, 100},
+ {50, 0, 600, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {100, 101, 0, 0x0L, RTEXT, (void*)"size", 10, 33, 45, 8},
+ {101, 102, 0, 0x0L, INCDECVAL1, &TextDef.fSize, 60, 33, 33, 10},
+ {102, 103, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 95, 33, 20, 8},
+ {103, 104, 0, 0x0L, RTEXT, (void*)"color", 10, 45, 45, 8},
+ {104, 150, 0, OWNDIALOG, COLBUTT, (void *)&TextDef.ColTxt, 60, 45, 25, 10},
+ {150, 0, 151, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {151, 152, 0, 0x0L, RTEXT, (void *)"line spacing", 10, 57, 45, 8},
+ {152, 153, 0, 0x0L, INCDECVAL1, &lspc1, 60, 57, 33, 10},
+ {153, 0, 0, 0x0L, LTEXT, (void *)"%", 95, 57, 20, 8},
+ {200, 0, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 20, 30, 90, 50},
+ {600, 601, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 145, 45, 15, 15},
+ {601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 145, 60, 15, 15},
+ {602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 145, 75, 15, 15},
+ {603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 145, 90, 15, 15}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ anyOutput *cdisp = Undo.cdisp;
+ int i, res;
+ bool bRet = false;
+ LineDEF newLine, newFillLine;
+ FillDEF newFill;
+ DWORD undo_flags = 0L;
+ TextDEF OldTxtDef, NewTxtDef;
+
+ if(!parent || !data) return 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(TextFrmDlg, data)))return false;
+ memcpy(&OldTxtDef, &TextDef, sizeof(TextDEF)); OldTxtDef.text = 0L;
+ Dlg->GetValue(101, &OldTxtDef.fSize); memcpy(&NewTxtDef, &OldTxtDef, sizeof(TextDEF));
+ Dlg->GetValue(152, &lspc1);
+ hDlg = CreateDlgWnd("Text Frame", 50, 50, 370, 258, Dlg, 0x4L);
+ do{
+ LoopDlgWnd(); res = Dlg->GetResult();
+ switch (res) {
+ case 1:
+ Dlg->GetValue(101, &NewTxtDef.fSize); Dlg->GetColor(104, &NewTxtDef.ColTxt);
+ Dlg->GetValue(152, &lspc2); lspc1 /= 100.0; lspc2 /= 100.0;
+ break;
+ case 600: case 601: case 602: case 603:
+ Undo.SetDisp(cdisp);
+ res = ExecDrawOrderButt(parent, this, res);
+ break;
+ }
+ }while (res < 0);
+ if(res == 1){ //OK pressed
+ Undo.SetDisp(cdisp);
+ OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
+ OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&newFill, 0);
+ memcpy(&newFillLine, &FillLine, sizeof(LineDEF));
+ if(newFill.hatch) memcpy(&newFillLine, newFill.hatch, sizeof(LineDEF));
+ if(cmpTextDEF(&OldTxtDef, &NewTxtDef)){
+ Undo.TextDef(this, &TextDef, undo_flags);
+ memcpy(&TextDef, &NewTxtDef, sizeof(TextDEF));
+ undo_flags |= UNDO_CONTINUE; TextDef.text = 0L;
+ }
+ undo_flags = CheckNewFloat(&lspc, lspc1, lspc2, parent, undo_flags);
+ if(cmpLineDEF(&Line, &newLine)) {
+ Undo.Line(parent, &Line, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&Line, &newLine, sizeof(LineDEF));
+ }
+ if(newFill.type && cmpLineDEF(&FillLine, &newFillLine)) {
+ Undo.Line(parent, &FillLine, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&FillLine, &newFillLine, sizeof(LineDEF));
+ }
+ if(cmpFillDEF(&Fill, &newFill)) {
+ Undo.Fill(parent, &Fill, undo_flags); undo_flags |= UNDO_CONTINUE;
+ memcpy(&Fill, &newFill, sizeof(FillDEF));
+ }
+ Fill.hatch = &FillLine;
+ if(undo_flags & UNDO_CONTINUE){
+ bRet = bModified = true; lines2text();
+ Undo.TextBuffer(this, &csize, &cpos, &text, undo_flags, cdisp);
+ if(lines) {
+ for(i = 0; i < nlines; i++) if(lines[i]) free(lines[i]);
+ free(lines); lines = 0L;
+ }
+ HideTextCursor(); cur_pos.x = cur_pos.y = 0;
+ }
+ }
+ CloseDlgWnd(hDlg); delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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;
+ anyOutput *cdisp = Undo.cdisp;
+
+ 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, data);
+ 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, 0x4L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 1: case 2:
+ Undo.SetDisp(cdisp);
+ 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;
+ anyOutput *cdisp = Undo.cdisp;
+ bool bRet = false;
+ LineDEF newLine;
+
+ if(!parent) return false;
+ OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&pgLine, 0);
+ if(!(Dlg = new DlgRoot(LineDlg, data)))return false;
+ if(parent->Id == GO_GRAPH || parent->Id == GO_PAGE) Dlg->ShowItem(50, true);
+ hDlg = CreateDlgWnd("line properties", 50, 50, 410, 314, Dlg, 0x4L);
+ do{
+ LoopDlgWnd(); res = Dlg->GetResult();
+ switch (res) {
+ case 600: case 601: case 602: case 603:
+ Undo.SetDisp(cdisp);
+ res = ExecDrawOrderButt(parent, this, res); break;
+ case 1: case 2:
+ Undo.SetDisp(cdisp); break;
+ }
+ }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;
+ anyOutput *cdisp = Undo.cdisp;
+ 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, data);
+ if(parent->Id == GO_GRAPH || parent->Id == GO_PAGE) Dlg->ShowItem(50, true);
+ hDlg = CreateDlgWnd("polygon properties", 50, 50, 310, 224, Dlg, 0x4L);
+ do{
+ LoopDlgWnd(); res = Dlg->GetResult();
+ switch(res) {
+ case 600: case 601: case 602: case 603:
+ Undo.SetDisp(cdisp);
+ res = ExecDrawOrderButt(parent, this, res); break;
+ case 1: case 2:
+ Undo.SetDisp(cdisp); break;
+ }
+ }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;
+ anyOutput *cdisp = Undo.cdisp;
+ 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, data)))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, 0x4L);
+ do{
+ LoopDlgWnd(); res = Dlg->GetResult();
+ switch(res) {
+ case 600: case 601: case 602: case 603:
+ Undo.SetDisp(cdisp);
+ res = ExecDrawOrderButt(parent, this, res); break;
+ case 1: case 2:
+ Undo.SetDisp(cdisp); break;
+ }
+ }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, CHECKED, 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, RANGEINPUT, 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;
+ double x, y;
+ AccRange *rY = 0L;
+ LineDEF Line;
+ FillDEF Fill;
+
+ if(!parent || !data) return false;
+ 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);
+ UseRangeMark(data, 1, TmpTxt);
+ if(!(Dlg = new DlgRoot(BarDlg, data)))return false;
+ hDlg = CreateDlgWnd("Simple Bar Chart", 50, 50, 370, 280, Dlg, 0x4L);
+ 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, TMP_TXT_SIZE)){
+ rY = new AccRange(TmpTxt);
+ yRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
+ }
+ else {
+ rY = 0L; yRange = 0L;
+ }
+ 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, TOUCHEXIT | ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 131, 100},
+ {5, 6, 200, TOUCHEXIT | ISPARENT, SHEET, &tab2, 5, 10, 131, 100},
+ {6, 7, 300, TOUCHEXIT | ISPARENT, SHEET, &tab3, 5, 10, 131, 100},
+ {7, 10, 400, TOUCHEXIT | ISPARENT, SHEET, &tab4, 5, 10, 131, 100},
+ {10, 0, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"range for X Data", 10, 30, 60, 8},
+ {101, 102, 0, 0x0L, RANGEINPUT, text1, 20, 40, 100, 10},
+ {102, 103, 0, 0x0L, LTEXT, (void*)"range for Y Data", 10, 55, 60, 8},
+ {103, 104, 0, 0x0L, RANGEINPUT, 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, RANGEINPUT, 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, RANGEINPUT, 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, BarType, nVals, nTxt, nTime;
+ double x, y, e;
+ lfPOINT fp1, fp2;
+ bool bRet = false, bLayout = false, bContinue = false, bValid;
+ anyResult xRes, yRes;
+ TextDEF lbdef = {defs.Color(COL_TEXT), defs.Color(COL_BG), DefSize(SIZE_TEXT), 0.0f, 0.0f, 0,
+ TXA_HLEFT | TXA_VBOTTOM, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, TmpTxt};
+ AccRange *rX, *rY, *rE, *rL;
+
+ if(!parent || !data) return false;
+ if(Id == GO_BARCHART) return CreateBarChart();
+ UseRangeMark(data, 1, text1, text2, text3, text4);
+ rX = rY = rE = rL = 0L;
+ if(!(Dlg = new DlgRoot(XYDlg, data)))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, 0x4L);
+ 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 4: // the data tab sheet
+ Dlg->Activate(101, true); res = -1; break;
+ case 5: // the layout tab sheet
+ bLayout = true; res = -1; break;
+ case 6: // the error tab sheet
+ Dlg->Activate(304, true); res = -1; break;
+ case 7: // the label tab sheet
+ Dlg->Activate(402, 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, TMP_TXT_SIZE)) 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, TMP_TXT_SIZE)) 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, TMP_TXT_SIZE)) 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, TMP_TXT_SIZE)) 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, TMP_TXT_SIZE)) xRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
+ if(Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE)) yRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ data_desc = rY->RangeDesc(data, 1);
+ //analyse data types
+ if(rX->DataTypes(data, &nVals, &nTxt, &nTime)){
+ if(!nVals && nTxt > 1 && nTxt > nTime) x_tv = new TextValue();
+ else if(!nVals && nTime > 1 && nTime > nTxt) x_dtype = ET_DATETIME;
+ }
+ if(rY->DataTypes(data, &nVals, &nTxt, &nTime)){
+ if(!nVals && nTxt > 1 && nTxt > nTime) y_tv = new TextValue();
+ else if(!nVals && nTime > 1 && nTime > nTxt) y_dtype = ET_DATETIME;
+ }
+ //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, TMP_TXT_SIZE)){
+ ErrRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
+ rE->GetFirst(&m, &n); rE->GetNext(&m, &n);
+ }
+ else {
+ rE = 0L; ErrRange = 0L;
+ }
+ }
+ if(Dlg->GetCheck(400) && rL) { //labels ?
+ Labels = (Label**)calloc(nPoints, sizeof(Label*));
+ if(Dlg->GetText(402, TmpTxt, TMP_TXT_SIZE)) LbRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
+ 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 {
+ bValid = false;
+ if(data->GetResult(&xRes, j, i, false) && data->GetResult(&yRes, l, k, false)) {
+ bValid = true;
+ if(x_tv) {
+ if(xRes.type == ET_TEXT) x = x_tv->GetValue(xRes.text);
+ else bValid = false;
+ }
+ else if(x_dtype == ET_DATETIME) {
+ if(xRes.type == ET_DATE || xRes.type == ET_TIME || xRes.type == ET_DATETIME) x = xRes.value;
+ else bValid = false;
+ }
+ else {
+ if(xRes.type == ET_VALUE) x = xRes.value;
+ else bValid = false;
+ }
+ if(y_tv) {
+ if(yRes.type == ET_TEXT) y = y_tv->GetValue(yRes.text);
+ else bValid = false;
+ }
+ else if(y_dtype == ET_DATETIME) {
+ if(yRes.type == ET_DATE || yRes.type == ET_TIME || yRes.type == ET_DATETIME) y = yRes.value;
+ else bValid = false;
+ }
+ else {
+ if(yRes.type == ET_VALUE) y = yRes.value;
+ else bValid = false;
+ }
+ }
+ if(bValid){
+ 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);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// calculate means and error to create a xy-plot
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+xyStat::PropertyDlg()
+{
+ char text1[100], text2[100];
+ DlgInfo StatDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 130, 10, 45, 12},
+ {2, 10, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 25, 45, 12},
+ {10, 100, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"range for grouping variable", 10, 10, 90, 9},
+ {101, 102, 0, 0x0L, LTEXT, (void*)"(X data)", 10, 20, 60, 9},
+ {102, 103, 0, 0x0L, RANGEINPUT, text1, 10, 30, 100, 10},
+ {103, 104, 0, 0x0L, LTEXT, (void*)"range for Y data", 10, 45, 90, 9},
+ {104, 200, 0, 0x0L, RANGEINPUT, text2, 10, 55, 100, 10},
+ {200, 300, 201, ISPARENT | CHECKED, GROUPBOX, (void*) " draw means ", 10, 75, 165, 50},
+ {201, 202, 0, CHECKED, CHECKBOX, (void*)" line", 15, 80, 50, 9},
+ {202, 203, 0, CHECKED, CHECKBOX, (void*)" symbols", 15, 90, 50, 9},
+ {203, 204, 0, 0x0L, CHECKBOX, (void*)" bars", 15, 100, 50, 9},
+ {204, 205, 0, 0x0L, LTEXT, (void*)"using", 65, 90, 30, 9},
+ {205, 206, 0, CHECKED, RADIO1, (void*)" arithmetic mean", 95, 80, 50, 9},
+ {206, 207, 0, 0x0L, RADIO1, (void*)" geometric mean", 95, 90, 50, 9},
+ {207, 208, 0, 0x0L, RADIO1, (void*)" harmonic mean", 95, 100, 50, 9},
+ {208, 0, 0, 0x0L, RADIO1, (void*)" median", 95, 110, 50, 9},
+ {300, 400, 301, ISPARENT | CHECKED, GROUPBOX, (void*) " draw error bars ", 10, 130, 165, 40},
+ {301, 302, 0, ISRADIO | CHECKED, CHECKBOX, (void*)" std. deviation (SD)", 15, 135, 70, 9},
+ {302, 303, 0, ISRADIO, CHECKBOX, (void*)" std. error (SEM)", 15, 145, 70, 9},
+ {303, 304, 0, ISRADIO, CHECKBOX, (void*)" 25, 75% percentiles", 95, 135, 70, 9},
+ {304, 305, 0, ISRADIO, CHECKBOX, (void*)" min and max", 95, 145, 70, 9},
+ {305, 306, 0, ISRADIO, CHECKBOX, (void*)" ", 15, 155, 70, 9},
+ {306, 307, 0, 0x0L, EDVAL1, &ci, 28, 154, 15, 10},
+ {307, 0, 0, 0x0L, LTEXT, (void*) "% conf. interval", 45, 155, 70, 9},
+ {400, 0, 401, ISPARENT | CHECKED, GROUPBOX, (void*) " number of cases ", 10, 175, 165, 30},
+ {401, 402, 0, ISRADIO | CHECKED, CHECKBOX, (void*)" on top of error", 15, 180, 70, 9},
+ {402, 403, 0, ISRADIO, CHECKBOX, (void*)" on top of mean", 95, 180, 70, 9},
+ {403, 404, 0, 0x0L, LTEXT, (void*)"prefix:", 15, 190, 24, 9},
+ {404, 0, 0, LASTOBJ, EDTEXT, (void*)"n = ", 40, 189, 30, 10}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ bool bRet = false;
+ int i, res, width, height, cb_mdesc;
+ double x, y, e, f, dx, dy;
+ lfPOINT fp1, fp2;
+ char errdesc[40], *mdesc;
+ TextDEF lbdef = {defs.Color(COL_TEXT), defs.Color(COL_BG), DefSize(SIZE_TEXT), 0.0f, 0.0f, 0,
+ TXA_HLEFT | TXA_VBOTTOM, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, TmpTxt};
+
+ if(!parent || !data) return false;
+ UseRangeMark(data, 1, text1, text2);
+ if(!(Dlg = new DlgRoot(StatDlg, data)))return false;
+ text1[0] = text2[0] = 0;
+ hDlg = CreateDlgWnd("Mean and Error Plot", 50, 50, 370, 450, Dlg, 0x4L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 0:
+ if(Dlg->GetCheck(10)) res=-1;
+ break;
+ case 1:
+ if(!(Dlg->GetText(102, text1, 100) && Dlg->GetText(104, text2, 100) && text1[0] && text2[0])) res = 2;
+ break;
+ }
+ }while (res <0);
+ if(res == 1) {
+ xRange = (char*)memdup(text1, ((int)strlen(text1))+2, 0);
+ yRange = (char*)memdup(text2, ((int)strlen(text2))+2, 0);
+ type = 0;
+ if(Dlg->GetCheck(201)) type |= 0x0001; if(Dlg->GetCheck(202)) type |= 0x0002;
+ if(Dlg->GetCheck(203)) type |= 0x0004;
+ if(Dlg->GetCheck(205)) type |= 0x0010; if(Dlg->GetCheck(206)) type |= 0x0020;
+ if(Dlg->GetCheck(207)) type |= 0x0040; if(Dlg->GetCheck(208)) type |= 0x0080;
+ if(Dlg->GetCheck(301)) type |= 0x0100; if(Dlg->GetCheck(302)) type |= 0x0200;
+ if(Dlg->GetCheck(303)) type |= 0x0400; if(Dlg->GetCheck(304)) type |= 0x0800;
+ if(Dlg->GetCheck(305)) type |= 0x1000;
+ if(Dlg->GetCheck(401)) type |= 0x2000; if(Dlg->GetCheck(402)) type |= 0x4000;
+ Dlg->GetValue(306, &ci); TmpTxt[0] = 0;
+ if(Dlg->GetText(404, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0]) case_prefix = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
+ CreateData();
+ if(type && curr_data) {
+ switch (type & 0x00f0) {
+ case 0x0010: mdesc = "Mean"; break;
+ case 0x0020: mdesc = "Geometric mean"; break;
+ case 0x0040: mdesc = "Harmonic mean"; break;
+ case 0x0080: mdesc = "Median"; break;
+ default: mdesc = "n.a."; break;
+ }
+ cb_mdesc = (int)strlen(mdesc);
+ curr_data->GetSize(&width, &height); nPoints = height;
+#ifdef USE_WIN_SECURE
+ sprintf_s(text1, 100, "a1:a%d", height); sprintf_s(text2, 100, "b1:b%d", height);
+#else
+ sprintf(text1, "a1:a%d", height); sprintf(text2, "b1:b%d", height);
+#endif
+ Bounds.Xmin = Bounds.Ymin = HUGE_VAL; Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+ if(type & 0x0001) {
+ if(nPoints >1 && (TheLine = new DataLine(this, curr_data, text1, text2)) &&
+ (TheLine->name = (char*)malloc(cb_mdesc+2))) rlp_strcpy(TheLine->name, cb_mdesc+2, mdesc);
+ }
+ if((type & 0x0002) && (Symbols = (Symbol**)calloc(nPoints, sizeof(Symbol*)))) {
+ for(i = 0; i < height; i++) {
+ if(curr_data->GetValue(i, 0, &x) && curr_data->GetValue(i, 1, &y)
+ && (Symbols[i] = new Symbol(this, curr_data, x, y, DefSym, 0, i, 1, i))){
+ Symbols[i]->idx = i;
+ if(Symbols[i]->name = (char*)malloc(cb_mdesc+2))
+ rlp_strcpy(Symbols[i]->name, cb_mdesc+2, mdesc);
+ }
+ }
+ }
+ if((type & 0x0004) && (Bars = (Bar**)calloc(nPoints, sizeof(Bar*)))) {
+ for(i = 0; i < height; i++) {
+ if(curr_data->GetValue(i, 0, &x) && curr_data->GetValue(i, 1, &y)
+ && (Bars[i] = new Bar(this, curr_data, x, y, BAR_VERTB | BAR_RELWIDTH, 0, i, 1, i))){
+ if(Bars[i]->name = (char*)malloc(cb_mdesc+2))
+ rlp_strcpy(Bars[i]->name, cb_mdesc+2, mdesc);
+ }
+ }
+ }
+ if(type & 0x1f00) {
+ Errors = (ErrorBar**)calloc(nPoints, sizeof(ErrorBar*));
+ switch(type & 0x1f00) {
+ case 0x0100: rlp_strcpy(errdesc, 40, "Std. Dev."); break;
+ case 0x0200: rlp_strcpy(errdesc, 40, "Std. Err."); break;
+ case 0x0400: rlp_strcpy(errdesc, 40, "25, 75% Perc."); break;
+ case 0x0800: rlp_strcpy(errdesc, 40, "Min./Max."); break;
+#ifdef USE_WIN_SECURE
+ case 0x1000: sprintf_s(errdesc, 40, "'%g%% CI", ci); break;
+#else
+ case 0x1000: sprintf(errdesc, "'%g%% CI", ci); break;
+#endif
+ default: rlp_strcpy(errdesc, 40, "error");
+ }
+ }
+ if((type & 0x1300) && Errors) {
+ for(i = 0; i < height; i++) {
+ if(curr_data->GetValue(i, 0, &x) && curr_data->GetValue(i, 1, &y)
+ && curr_data->GetValue(i, 2, &e)) {
+ Errors[i]= new ErrorBar(this, curr_data, x, y, e, 0, 0, i, 1, i, 2, i);
+ if(Errors[i]) Errors[i]->Command(CMD_ERRDESC, errdesc, 0L);
+ }
+ }
+ }
+ if((type & 0x0c00) && Errors) {
+ for(i = 0; i < height; i++) {
+ if(curr_data->GetValue(i, 0, &x) && curr_data->GetValue(i, 2, &e) && curr_data->GetValue(i, 3, &f)){
+ fp1.fx = fp2.fx = x; fp1.fy = e; fp2.fy = f;
+ Errors[i]= (ErrorBar*)new Whisker(this, curr_data, fp1, fp2, 0, 0, i, 2, i, 0, i, 3, i);
+ if(Errors[i]) Errors[i]->Command(CMD_ERRDESC, errdesc, 0L);
+ }
+ }
+ }
+ if((type & 0x6000) && (Labels = (Label**)calloc(nPoints, sizeof(Label*)))) {
+ dy = -0.4 * DefSize(SIZE_SYMBOL);
+ if(type & 0x2000){
+ lbdef.Align = TXA_HCENTER | TXA_VBOTTOM;
+ dx = 0.0;
+ }
+ else {
+ lbdef.Align = TXA_HLEFT | TXA_VBOTTOM;
+ dx = -dy;
+ }
+ for(i = 0; i < height; i++) {
+ if(curr_data->GetValue(i, 0, &x) && curr_data->GetText(i, 5, TmpTxt, TMP_TXT_SIZE, false)){
+ if((type & 0x2000) && curr_data->GetValue(i, 4, &y))
+ Labels[i] = new Label(this, curr_data, x, y, &lbdef,
+ LB_X_DATA | LB_Y_DATA, 0, i, 4, i, 5, i);
+ else if((type & 0x4000) && curr_data->GetValue(i, 1, &y))
+ Labels[i] = new Label(this, curr_data, x, y, &lbdef,
+ LB_X_DATA | LB_Y_DATA, 0, i, 1, i, 5, i);
+ if(Labels[i]){
+ Labels[i]->SetSize(SIZE_LB_YDIST, dy);
+ Labels[i]->SetSize(SIZE_LB_XDIST, dx);
+ }
+ }
+ }
+ }
+ Command(CMD_AUTOSCALE, 0L, 0L);
+ bRet = true;
+ }
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Frequency distribution
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *FreqDlg_Tmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,-1,130,10,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,130,25,45,12\n"
+ "3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "4,5,100,ISPARENT | CHECKED,SHEET,1,5,10,120,153\n"
+ "5,10,200,ISPARENT,SHEET,2,5,10,120,153\n"
+ "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+ "100,101,,,LTEXT,3,10,25,60,8\n"
+ "101,102,,,RANGEINPUT,-15,10,38,110,10\n"
+ "102,103,120,ISPARENT | CHECKED,GROUPBOX,4,10,55,110,42\n"
+ "103,,150,ISPARENT | CHECKED,GROUPBOX,5,10,102,110,57\n"
+ "120,121,,CHECKED,RADIO1,6,15,60,30,9\n"
+ "121,122,,, EDVAL1,7,47,60,15,10\n"
+ "122,123,,, LTEXT,8,64,60,35,8\n"
+ "123,124,,, RADIO1,9, 15, 72, 45, 9\n"
+ "124,125,,, EDTEXT,-16,65,72,50,10\n"
+ "125,126,,, RTEXT,10,15,84, 47,8\n"
+ "126,,,,EDTEXT,-16,65,84,50,10\n"
+ "150,151,,ISRADIO,CHECKBOX,13,15,107,30, 8\n"
+ "151,152,,ISRADIO,CHECKBOX,14,15,117,30, 8\n"
+ "152,153,,ISRADIO,CHECKBOX,15,65,107,30, 8\n"
+ "153,154,,ISRADIO,CHECKBOX,16,65,117,30,8\n"
+ "154,155,,ISRADIO,CHECKBOX,17,15,127,30,8\n"
+ "155,156,,ISRADIO,CHECKBOX,18,15,137,30,8\n"
+ "156,,,ISRADIO,CHECKBOX,19,15,147,30,8\n"
+ "200,, 210,ISPARENT | CHECKED,GROUPBOX,11,10,27,110,61\n"
+ "210,,,LASTOBJ | NOSELECT,ODBUTTON,12,25,34,90,50";
+
+bool
+FreqDist::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 25, 10, "Data"};
+ TabSHEET tab2 = {25, 52, 10, "Style"};
+ void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)"spread sheet range for values",
+ (void*)" classes ", (void*)" plot distribution ", (void*)"create", (void*)&step,
+ (void*)"classes and bars", (void*)"class size is", (void*)"starting at",
+ (void*)" bar style ", (void*)OD_filldef, (void*)" normal", (void*)" log-normal",
+ (void*)" binomial", (void*)" poisson", (void*)" exponential", (void*)" rectangular",
+ (void*)" chi-square"};
+ DlgInfo *FreqDlg;
+ DlgRoot *Dlg;
+ void *hDlg;
+ bool bRet = false;
+ int res, r, c;
+ double tmp;
+ char *mrk;
+ AccRange *aR;
+
+ if(!parent || !data) return false;
+ if(!(FreqDlg = CompileDialog(FreqDlg_Tmpl, dyndata))) return false;
+ step = 7; TmpTxt[100] = 0;
+ OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)&BarLine, 0);
+ OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)&BarFill, 0);
+ if(data->Command(CMD_GETMARK, &mrk, 0L)) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, mrk);
+ else TmpTxt[0] = 0;
+ if(!(Dlg = new DlgRoot(FreqDlg, data)))return false;
+ hDlg = CreateDlgWnd("Frequency Distribution", 50, 50, 370, 370, Dlg, 0x4L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 0:
+ if(Dlg->GetCheck(10)) res=-1;
+ break;
+ case 1:
+ if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) ssRef = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
+ if(Dlg->GetCheck(150)) type = 1;
+ else if(Dlg->GetCheck(151)) type = 2;
+ else if(Dlg->GetCheck(154)) type = 3;
+ else if(Dlg->GetCheck(155)) type = 4;
+ else if(Dlg->GetCheck(156)) type = 5;
+ else if(Dlg->GetCheck(152)) type = 10;
+ else if(Dlg->GetCheck(153)) type = 11;
+ else type = 0;
+ break;
+ }
+ }while (res <0);
+ if(res==1 && (plots = (GraphObj**)calloc(nPlots=3, 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(y_info = (char*)malloc(25*sizeof(char))) rlp_strcpy(y_info, 25, "No. of observations");
+ if(x_info = (char*)malloc(25*sizeof(char))){
+ rlp_strcpy(x_info, 25, "Categories");
+ if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE) && (aR = new AccRange(TmpTxt))) {
+ if(aR->GetFirst(&c, &r) && !data->GetValue(r, c, &tmp) && data->GetText(r, c, TmpTxt, 150, false))
+ rlp_strcpy(x_info, 25, TmpTxt);
+ delete aR;
+ }
+ }
+ if(plots[0]) bRet = true;
+ }
+ CloseDlgWnd(hDlg); delete Dlg; free(FreqDlg);
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Regression properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char* RegDlg_Tmpl =
+ "1,+,,DEFAULT,PUSHBUTTON,-1,140,10,45,12\n"
+ ".,.,,,PUSHBUTTON,-2,140,25,45,12\n"
+ ".,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "4,+,100,ISPARENT | CHECKED,SHEET,1,5,10,130,85\n"
+ ".,10,200,ISPARENT,SHEET,2,5,10,130,85\n"
+ "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+ "100,+,,,LTEXT,3,10,22,60,8\n"
+ ".,.,,,RANGEINPUT,-16,20,32,100,10\n"
+ ".,.,,,LTEXT,4,10,45,60,8\n"
+ ".,.,,,RANGEINPUT,-17,20,55,100,10\n"
+ ".,.,,CHECKED,CHECKBOX,5,10,70,100,8\n"
+ ".,,,,CHECKBOX,6,10,80,100,8\n"
+ "200,210,201,CHECKED | ISPARENT, GROUPBOX,7,10,30,58,56\n"
+ "201,+,,CHECKED, RADIO1,8,20,40,30,8\n"
+ ".,.,,,RADIO1,9,20,50,30,8\n"
+ ".,.,,,RADIO1,10,20,60,30,8\n"
+ ".,,,,RADIO1,11,20,70,30,8\n"
+ "210,,211,CHECKED | ISPARENT,GROUPBOX,12,72,30,58,56\n"
+ ".,+,,CHECKED,RADIO1,13,82,40,30,8\n"
+ ".,.,,,RADIO1,14,82,50,30,8\n"
+ ".,.,,,RADIO1,15,82,60,30,8\n"
+ ".,,,LASTOBJ,RADIO1,16,82,70,30,8";
+
+bool
+Regression::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 28, 10, "Data"};
+ TabSHEET tab2 = {28, 70, 10, "Transform"};
+ void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)"range for X Data",
+ (void*)"range for Y Data", (void*)" include symbols in plot", (void*) " draw SD ellipse",
+ (void*)" x-values ", (void*)"x = x", (void*)"x = log(x)", (void*)"x = 1/x",
+ (void*)"x = sqrt(x)", (void*)" y-values ", (void*)"y = y", (void*)"y = log(y)",
+ (void*)"y = 1/y",(void*)"y = sqrt(y)"};
+ DlgInfo *RegDlg;
+ DlgRoot *Dlg;
+ void *hDlg;
+ int c, i, j, k, l, ic, res, n;
+ double x, y;
+ AccRange *rX, *rY;
+ bool bRet = false, bContinue = false, dValid;
+ lfPOINT *values = 0L;
+
+ if(!parent || !data) return false;
+ if(!(RegDlg = CompileDialog(RegDlg_Tmpl, dyndata))) return false;
+ rX = rY = 0L;
+ UseRangeMark(data, 1, TmpTxt+100, TmpTxt+200);
+ if(!(Dlg = new DlgRoot(RegDlg, data)))return false;
+ hDlg = CreateDlgWnd("Linear regression analysis step 1/2", 50, 50, 380, 230, Dlg, 0x4L);
+ 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, TMP_TXT_SIZE)) 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, TMP_TXT_SIZE)) 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, TMP_TXT_SIZE)) xRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
+ if(Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE)) yRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 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);
+ 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 | 0x20002))&&
+ (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;
+ free(RegDlg); if(values) free(values);
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Bubble plot properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *BubPlotDlg_Tmpl =
+ "1, 2, 0, DEFAULT, PUSHBUTTON,-1,148,10,45,12\n"
+ "2, 3, 0, 0x0L, PUSHBUTTON,-2,148,25,45,12\n"
+ "3, 500, 4, ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "4, 5, 100, ISPARENT | CHECKED,SHEET,1,5,10,130,120\n"
+ "5, 6, 200, ISPARENT, SHEET,2,5,10,130,120\n"
+ "6, 10, 300, ISPARENT, SHEET,3,5,10,130,120\n"
+ "10,,, CHECKED,CHECKPIN,0,5,0,12,8\n"
+ "100,+,,,LTEXT,4,10,40,60,8\n"
+ ".,.,,,RANGEINPUT,-15,20,50,100,10\n"
+ ".,.,,,LTEXT,5,10,65,60,8\n"
+ ".,.,,,RANGEINPUT,-16,20,75,100,10\n"
+ ".,.,,,LTEXT,6,10,90,60,8\n"
+ ".,,,,RANGEINPUT,-17,20,100,100,10\n"
+ "200,+,,,LTEXT,-27,10,30,110,8\n"
+ ".,.,,ISRADIO | CHECKED,ODBUTTON,7,30,40,20,20\n"
+ ".,.,,ISRADIO,ODBUTTON,7,50,40,20,20\n"
+ ".,.,,ISRADIO,ODBUTTON,7,70,40,20,20\n"
+ ".,.,,ISRADIO,ODBUTTON,7,90,40,20,20\n"
+ ".,.,,,LTEXT,8,7,67,45,8\n"
+ ".,.,,,RTEXT,9,7,75,20,8\n"
+ ".,.,,OWNDIALOG,COLBUTT,10,29,75,25,10\n"
+ ".,.,,,RTEXT,11,67,75,20,8\n"
+ ".,.,,,EDVAL1,12,88,75,25,10\n"
+ ".,.,,,LTEXT,-3,114,75,15,8\n"
+ ".,.,,,LTEXT,13,7,97,45,8\n"
+ ".,.,,,RTEXT,-11,7,105,20,8\n"
+ ".,.,,TOUCHEXIT | OWNDIALOG,COLBUTT,14,29,105,25,10\n"
+ ".,.,,,RTEXT,15,67,105,20,8\n"
+ ".,,,TOUCHEXIT | OWNDIALOG,FILLBUTTON,16,88,105,25,10\n"
+ "300,+,,,LTEXT,17,10,30,110,8\n"
+ ".,.,400,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ ".,.,,,LTEXT,18,10,75,110,8\n"
+ ".,,410,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "400,+,,CHECKED,RADIO1,-3,40,40,45,8\n"
+ ".,.,,,RADIO1,19,40,50,45,8\n"
+ ".,,,,RADIO1,20,40,60,45,8\n"
+ "410,+,,CHECKED,RADIO1,21,40,85,45,8\n"
+ ".,.,,,RADIO1,22,40,95,45,8\n"
+ ".,,,LASTOBJ,RADIO1,23,40,105,45,8";
+bool
+BubblePlot::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 25, 10, "Data"};
+ TabSHEET tab2 = {25, 57, 10, "Layout"};
+ TabSHEET tab3 = {57, 90, 10, "Scaling"};
+ int syms[] = {SYM_CIRCLE, SYM_RECT, SYM_TRIAU, SYM_TRIAD};
+ FillDEF ShowFill;
+ void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"range for X Data",
+ (void*)"range for Y Data", (void*)"range for sizes", (void*)OD_BubbleTempl,
+ (void*)"outline:", (void*)"color", (void *)&BubbleLine.color, (void*)"line width",
+ (void*)&BubbleLine.width, (void*)"fill:", (void *)&BubbleFill.color, (void*)"pattern",
+ (void *)&ShowFill, (void*)"sizes are given as", (void*)"proportionality (relative to circle)",
+ (void*)"scaling with X axis", (void*)"scaling with Y axis", (void*)"diameter",
+ (void*)"circumference", (void*)"area"};
+ DlgInfo *PlotDlg;
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, j, k, l, m, n, ic, res, 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};
+
+ if(!parent || !data) return false;
+ if(!(PlotDlg = CompileDialog(BubPlotDlg_Tmpl, dyndata))) return false;
+ UseRangeMark(data, 1, TmpTxt, TmpTxt+100, TmpTxt+200);
+ memcpy(&ShowFill, &BubbleFill, sizeof(FillDEF));
+ if(BubbleFill.hatch) memcpy(&ShowFillLine, BubbleFill.hatch, sizeof(LineDEF));
+ ShowFill.hatch = &ShowFillLine;
+ if(!(Dlg = new DlgRoot(PlotDlg, data)))return false;
+ hDlg = CreateDlgWnd("Create Bubble Plot", 50, 50, 400, 300, Dlg, 0x4L);
+ 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, TmpTxt, 100) && Dlg->GetText(103, TmpTxt+100, 100) &&
+ Dlg->GetText(105, TmpTxt+200, 100) && (rX = new AccRange(TmpTxt)) &&
+ (rY = new AccRange(TmpTxt+100)) && (rS = new AccRange(TmpTxt+200))) {
+ 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; free(PlotDlg); return bRetVal;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Polar plot properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *AddPolDlg_Tmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,-1,140,14,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,140,29,45,12\n"
+ "3,10,200,ISPARENT | CHECKED,GROUPBOX,1,5,14,131,96\n"
+ "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+ "200,201,,CHECKED | EXRADIO,ODBUTTON,2,10,24,20,20\n"
+ "201,202,,EXRADIO,ODBUTTON,2,30,24,20,20\n"
+ "202,203,,EXRADIO,ODBUTTON,2,50,24,20,20\n"
+ "203,204,,EXRADIO,ODBUTTON,2,70,24,20,20\n"
+ "204,210,,EXRADIO,ODBUTTON,2,90,24,20,20\n"
+ "210,211,,,LTEXT,3,10,50,50,8\n"
+ "211,212,,,RANGEINPUT,-15,20,62,100,10\n"
+ "212,213,,,LTEXT,4,10,75,50,8\n"
+ "213,,,LASTOBJ,RANGEINPUT,-16,20,87,100,10";
+
+bool
+PolarPlot::AddPlot()
+{
+ void *dyndata[] = {(void*)" select template and data range ", (void*)OD_PolarTempl,
+ (void*)"range for x-data (circular or angular data)",
+ (void*)"range for y-data (radial data)"};
+ DlgInfo *PolDlg;
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, j, k, l, ic, n, res, cType = 200;
+ bool bRet = false, bContinue = false;
+ double x, y;
+ AccRange *rX = 0L, *rY = 0L;
+ Symbol **Symbols = 0L;
+ DataLine *TheLine = 0L;
+ Plot **tmpPlots;
+ Function *func;
+ anyOutput *cdisp = Undo.cdisp;
+
+ if(!parent || !data) return false;
+ if(!(PolDlg = CompileDialog(AddPolDlg_Tmpl, dyndata))) return false;
+ UseRangeMark(data, 1, TmpTxt, TmpTxt+100);
+ if(!(Dlg = new DlgRoot(PolDlg, data)))return false;
+ Dlg->bModal = false;
+ hDlg = CreateDlgWnd("Add Polar Plot", 50, 50, 388, 260, Dlg, 0x4L);
+ 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 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, TmpTxt, 100) && Dlg->GetText(213, TmpTxt+100, 100) &&
+ (rX = new AccRange(TmpTxt)) && (rY = new AccRange(TmpTxt+100)) &&
+ (n = rX ? rX->CountItems() : 0) &&
+ (tmpPlots = (Plot**)realloc(Plots, (nPlots+2)*sizeof(Plot*)))) {
+ Undo.SetDisp(cdisp);
+ 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, TmpTxt, TmpTxt+100);
+ else if(Dlg->GetCheck(203))
+ TheLine = new DataPolygon(this, data, TmpTxt, TmpTxt+100);
+ else if(Dlg->GetCheck(204)) {
+ if(func = new Function(this, data, "Function")){
+ 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; free(PolDlg);
+ 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, data);
+ if(!(type & 0x01))Dlg->SetCheck(101, 0L, true);
+ hDlg = CreateDlgWnd("Polar Plot properties", 50, 50, 310, 234, Dlg, 0x4L);
+ 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 | TOUCHEXIT, SHEET, &tab1, 5, 10, 131, 100},
+ {5, 10, 200, ISPARENT | TOUCHEXIT | CHECKED, SHEET, &tab2, 5, 10, 131, 100},
+ {10, 0, 0, CHECKED, 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, RANGEINPUT, (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, RANGEINPUT, (void*)text2, 20, 92, 100, 10}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, 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(!parent || !data) return false;
+ if(Plots) return Config();
+ 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;
+ UseRangeMark(data, 1, text1, text2);
+ tlbdef.ColTxt = defs.Color(COL_AXIS);
+ tlbdef.ColBg = 0x00ffffffL;
+ tlbdef.RotBL = tlbdef.RotCHAR = 0.0f;
+ tlbdef.fSize = DefSize(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, data)))return false;
+ hDlg = CreateDlgWnd("Create Polar Plot", 50, 50, 388, 260, Dlg, 0x4L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 0:
+ if(Dlg->GetCheck(10)) res = -1;
+ break;
+ case 5: case 4:
+ bType = true;
+ res = -1;
+ break;
+ case 1:
+ if(!bType) { //the 'Coordinates' sheet must have been visited
+ bType = true;
+ Dlg->SetCheck(4, 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, 100) && Dlg->GetText(213, text2, 100) &&
+ (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, "Function")){
+ 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(-DefSize(SIZE_AXIS_TICKS)*6.0));
+ Axes[1]->SetSize(SIZE_TLB_XDIST,
+ NiceValue(-DefSize(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
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static int boxplot_mode_sel = 52;
+bool
+BoxPlot::PropertyDlg()
+{
+ DlgInfo PlotDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 130, 10, 45, 12},
+ {2, 10, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 25, 45, 12},
+ {10, 50, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
+ {50, 60, 51, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {51, 52, 0, 0x0L, LTEXT, (void*)"Data Source:", 10, 12, 40, 9},
+ {52, 53, 0, TOUCHEXIT, RADIO2, (void*)" user values", 60, 12, 50, 9},
+ {53, 0, 0, TOUCHEXIT, RADIO2, (void*)" statistical data", 60, 22, 60, 9},
+ {60, 61, 100, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {61, 0, 200, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {100, 102, 0, 0x0L, LTEXT, (void*)"range for grouping variable (X data)", 10, 39, 140, 9},
+ {102, 103, 0, 0x0L, RANGEINPUT, TmpTxt+100, 10, 49, 165, 10},
+ {103, 104, 0, 0x0L, LTEXT, (void*)"range for Y data", 10, 60, 90, 9},
+ {104, 150, 0, 0x0L, RANGEINPUT, TmpTxt+200, 10, 70, 165, 10},
+ {150, 160, 151, ISPARENT | CHECKED, GROUPBOX, (void*) " draw means ", 10, 87, 165, 45},
+ {151, 152, 0, 0x0L, CHECKBOX, (void*)" line", 15, 92, 50, 9},
+ {152, 153, 0, CHECKED, CHECKBOX, (void*)" symbols", 15, 101, 50, 9},
+ {153, 154, 0, 0x0L, LTEXT, (void*)"using", 65, 101, 30, 9},
+ {154, 155, 0, 0x0L, RADIO1, (void*)" arithmetic mean", 95, 90, 50, 9},
+ {155, 156, 0, 0x0L, RADIO1, (void*)" geometric mean", 95, 99, 50, 9},
+ {156, 157, 0, 0x0L, RADIO1, (void*)" harmonic mean", 95, 108, 50, 9},
+ {157, 0, 0, CHECKED, RADIO1, (void*)" median", 95, 117, 50, 9},
+ {160, 170, 161, ISPARENT | CHECKED, GROUPBOX, (void*) " draw boxes ", 10, 137, 165, 38},
+ {161, 162, 0, ISRADIO, CHECKBOX, (void*)" std. deviation (SD)", 15, 142, 70, 9},
+ {162, 163, 0, ISRADIO, CHECKBOX, (void*)" std. error (SEM)", 15, 151, 70, 9},
+ {163, 164, 0, ISRADIO | CHECKED, CHECKBOX, (void*)" 25, 75% percentiles", 95, 142, 70, 9},
+ {164, 165, 0, ISRADIO, CHECKBOX, (void*)" min and max", 95, 151, 70, 9},
+ {165, 166, 0, ISRADIO, CHECKBOX, (void*)" ", 15, 161, 70, 9},
+ {166, 167, 0, 0x0L, EDVAL1, &ci_box, 28, 160, 15, 10},
+ {167, 0, 0, 0x0L, LTEXT, (void*) "% conf. interval", 45, 161, 70, 9},
+ {170, 400, 171, ISPARENT | CHECKED, GROUPBOX, (void*) " draw whiskers ", 10, 180, 165, 38},
+ {171, 172, 0, ISRADIO, CHECKBOX, (void*)" std. deviation (SD)", 15, 185, 70, 9},
+ {172, 173, 0, ISRADIO, CHECKBOX, (void*)" std. error (SEM)", 15, 194, 70, 9},
+ {173, 174, 0, ISRADIO, CHECKBOX, (void*)" 25, 75% percentiles", 95, 185, 70, 9},
+ {174, 175, 0, ISRADIO | CHECKED, CHECKBOX, (void*)" min and max", 95, 194, 70, 9},
+ {175, 176, 0, ISRADIO, CHECKBOX, (void*)" ", 15, 204, 70, 9},
+ {176, 177, 0, 0x0L, EDVAL1, &ci_err, 28, 203, 15, 10},
+ {177, 0, 0, 0x0L, LTEXT, (void*) "% conf. interval", 45, 203, 70, 9},
+ {200, 202, 0, 0x0L, LTEXT, (void*)"range for common X values", 10, 39, 140, 9},
+ {202, 250, 0, 0x0L, RANGEINPUT, TmpTxt+100, 10, 49, 165, 10},
+ {250, 260, 251, ISPARENT | CHECKED, GROUPBOX, (void*) " ", 10, 68, 165, 30},
+ {251, 252, 0, 0x0L, CHECKBOX, (void*)" draw line", 15, 63, 50, 9},
+ {252, 253, 0, 0x0L, LTEXT, (void*)"range for line values", 15, 73, 80, 9},
+ {253, 0, 0, 0x0L, RANGEINPUT, TmpTxt+200, 15, 83, 155, 10},
+ {260, 270, 261, ISPARENT | CHECKED, GROUPBOX, (void*) " ", 10, 106, 165, 30},
+ {261, 262, 0, CHECKED, CHECKBOX, (void*)" draw symbols", 15, 101, 50, 9},
+ {262, 263, 0, 0x0L, LTEXT, (void*)"range for symbol values", 15, 111, 80, 9},
+ {263, 0, 0, 0x0L, RANGEINPUT, TmpTxt+200, 15, 121, 155, 10},
+ {270, 280, 271, ISPARENT | CHECKED, GROUPBOX, (void*) " ", 10, 144, 165, 50},
+ {271, 272, 0, CHECKED, CHECKBOX, (void*)" draw boxes", 15, 139, 50, 9},
+ {272, 273, 0, 0x0L, LTEXT, (void*)"range for HI values", 15, 149, 80, 9},
+ {273, 274, 0, 0x0L, RANGEINPUT, TmpTxt+300, 15, 159, 155, 10},
+ {274, 275, 0, 0x0L, LTEXT, (void*)"range for LO values", 15, 169, 80, 9},
+ {275, 0, 0, 0x0L, RANGEINPUT, TmpTxt+400, 15, 179, 155, 10},
+ {280, 0, 281, ISPARENT | CHECKED, GROUPBOX, (void*) " ", 10, 202, 165, 50},
+ {281, 282, 0, CHECKED, CHECKBOX, (void*)" draw whiskers", 15, 197, 50, 9},
+ {282, 283, 0, 0x0L, LTEXT, (void*)"range for HI values", 15, 207, 80, 9},
+ {283, 284, 0, 0x0L, RANGEINPUT, TmpTxt+500, 15, 217, 155, 10},
+ {284, 285, 0, 0x0L, LTEXT, (void*)"range for LO values", 15, 227, 80, 9},
+ {285, 0, 0, 0x0L, RANGEINPUT, TmpTxt+600, 15, 237, 155, 10},
+ {400, 0, 401, ISPARENT | CHECKED, GROUPBOX, (void*) " number of cases ", 10, 223, 165, 30},
+ {401, 402, 0, ISRADIO | CHECKED, CHECKBOX, (void*)" on top of error", 15, 228, 70, 9},
+ {402, 403, 0, ISRADIO, CHECKBOX, (void*)" on top of mean", 95, 228, 70, 9},
+ {403, 404, 0, 0x0L, LTEXT, (void*)"prefix:", 15, 238, 24, 9},
+ {404, 0, 0, LASTOBJ, EDTEXT, (void*)"n = ", 40, 237, 30, 10}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ bool bRet = false;
+ int i, j, k, k1, l, l1, n, ic, c, res, cb, width, height;
+ double x, y1, y2, dx, dy;
+ char errdesc[40], boxdesc[40], symdesc[40];
+ lfPOINT fp1, fp2;
+ TextDEF lbdef = {defs.Color(COL_TEXT), defs.Color(COL_BG), DefSize(SIZE_TEXT), 0.0f, 0.0f, 0,
+ TXA_HLEFT | TXA_VBOTTOM, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, TmpTxt};
+ AccRange *rX = 0L, *rY1 = 0L, *rY2 = 0L;
+
+ if(!parent || !data) return false;
+ UseRangeMark(data, 1, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400, TmpTxt+500, TmpTxt+600);
+ ci_box = ci_err = 95.0;
+ if(!(Dlg = new DlgRoot(PlotDlg, data)))return false;
+ TmpTxt[0] = TmpTxt[100] = 0;
+ //restore previous style
+ if(boxplot_mode_sel == 53) {
+ Dlg->ShowItem(61, false); Dlg->SetCheck(53, 0L, true);
+ }
+ else {
+ Dlg->SetCheck(52, 0L, true); Dlg->ShowItem(60, false);
+ }
+ hDlg = CreateDlgWnd("Box and Whisker Plot", 50, 50, 370, 550, Dlg, 0x4L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 0:
+ if(Dlg->GetCheck(10)) res=-1;
+ break;
+ case 52: case 53:
+ boxplot_mode_sel = res;
+ if(res == 53) {
+ Dlg->ShowItem(60, true); Dlg->ShowItem(61, false);
+ }
+ else {
+ Dlg->ShowItem(60, false); Dlg->ShowItem(61, true);
+ }
+ Dlg->Command(CMD_REDRAW, 0L, 0L); res=-1;
+ break;
+ }
+ }while (res <0);
+ if(res == 1) {
+ type = 0; dirty = true;
+ if(Dlg->GetCheck(52) && Dlg->GetText(202, TmpTxt+100, 50) && TmpTxt[100] &&(rX = new AccRange(TmpTxt+100))) {
+ xRange = (char*)memdup(TmpTxt+100, ((int)strlen(TmpTxt+100))+2, 0);
+ n = rX->CountItems(); nPoints = n;
+ // data line
+ if(n > 1 && Dlg->GetCheck(251) && Dlg->GetText(253, TmpTxt, TMP_TXT_SIZE)) {
+ TheLine = new DataLine(this, data, TmpTxt+100, TmpTxt);
+ bRet = true;
+ }
+ // symbols
+ if(n > 0 && Dlg->GetCheck(261) && Dlg->GetText(263, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0]
+ && (Symbols = (Symbol**)calloc(n, sizeof(Symbol*)))
+ && (rY1 = new AccRange(TmpTxt))) {
+ yRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
+ rX->GetFirst(&i, &j); rY1->GetFirst(&k, &l);
+ rX->GetNext(&i, &j); rY1->GetNext(&k, &l);
+ ic = c = 0;
+ do {
+ if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y1)) {
+ if(Symbols[ic] = new Symbol(this, data, x, y1, SYM_PLUS, i, j, k, l))
+ Symbols[ic++]->idx = c;
+ }
+ c++;
+ }while(rX->GetNext(&i, &j) && rY1->GetNext(&k, &l));
+ delete rY1; rY1 = 0L;
+ if(ic) bRet = true;
+ }
+ // boxes
+ if(n > 0 && Dlg->GetCheck(271) && Dlg->GetText(273, TmpTxt+300, 50) && Dlg->GetText(275, TmpTxt+400, 50)
+ && (Boxes = (Box**)calloc(n, sizeof(Box*)))
+ && (rY1 = new AccRange(TmpTxt+300)) && (rY2 = new AccRange(TmpTxt+400))) {
+ rX->GetFirst(&i, &j); rY1->GetFirst(&k, &l); rY2->GetFirst(&k1, &l1);
+ rX->GetNext(&i, &j); rY1->GetNext(&k, &l); rY2->GetNext(&k1, &l1);
+ ic = 0;
+ do {
+ if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y1) && data->GetValue(l1, k1, &y2)) {
+ fp1.fy = y1; fp2.fy = y2; fp1.fx = fp2.fx = x;
+ Boxes[ic] = new Box(this, data, fp1, fp2, BAR_RELWIDTH, i, j, k, l, i, j, k1, l1);
+ if(Boxes[ic]) Boxes[ic++]->SetSize(SIZE_BOX, 60.0);
+ }
+ }while(rX->GetNext(&i, &j) && rY1->GetNext(&k, &l) && rY2->GetNext(&k1, &l1));
+ delete rY1; rY1 = 0L; delete rY2; rY2 = 0L;
+ if(ic) bRet = true;
+ }
+ // whiskers
+ if(n > 0 && Dlg->GetCheck(281) && Dlg->GetText(283, TmpTxt+300, 50) && Dlg->GetText(285, TmpTxt+400, 50)
+ && (Whiskers = (Whisker**)calloc(n, sizeof(Whisker*)))
+ && (rY1 = new AccRange(TmpTxt+300)) && (rY2 = new AccRange(TmpTxt+400))) {
+ rX->GetFirst(&i, &j); rY1->GetFirst(&k, &l); rY2->GetFirst(&k1, &l1);
+ rX->GetNext(&i, &j); rY1->GetNext(&k, &l); rY2->GetNext(&k1, &l1);
+ ic = 0;
+ do {
+ if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y1) && data->GetValue(l1, k1, &y2)) {
+ fp1.fy = y1; fp2.fy = y2; fp1.fx = fp2.fx = x;
+ Whiskers[ic++] = new Whisker(this, data, fp1, fp2, 0, i, j, k, l, i, j, k1, l1);
+ }
+ }while(rX->GetNext(&i, &j) && rY1->GetNext(&k, &l) && rY2->GetNext(&k1, &l1));
+ delete rY1; rY1 = 0L; delete rY2; rY2 = 0L;
+ if(ic) bRet = true;
+ }
+ if (bRet) Command(CMD_AUTOSCALE, 0L, 0L);
+ }
+ else if(Dlg->GetText(102, TmpTxt+100, 50) && TmpTxt[100] && Dlg->GetText(104, TmpTxt+200, 50) && TmpTxt[200]){
+ xRange = (char*)memdup(TmpTxt+100, ((int)strlen(TmpTxt+100))+2, 0);
+ yRange = (char*)memdup(TmpTxt+200, ((int)strlen(TmpTxt+200))+2, 0);
+ if((rX = new AccRange(xRange)) && (rY1 = new AccRange(yRange))) {
+ x_info = rX->RangeDesc(data, 2); y_info = rY1->RangeDesc(data, 2);
+ delete rX; delete rY1; rX = rY1 = 0L;
+ }
+ if(Dlg->GetCheck(154)) type |= 0x0001; if(Dlg->GetCheck(155)) type |= 0x0002;
+ if(Dlg->GetCheck(156)) type |= 0x0003; if(Dlg->GetCheck(157)) type |= 0x0004;
+ if(Dlg->GetCheck(161)) type |= 0x0010; if(Dlg->GetCheck(162)) type |= 0x0020;
+ if(Dlg->GetCheck(163)) type |= 0x0030; if(Dlg->GetCheck(164)) type |= 0x0040;
+ if(Dlg->GetCheck(165)) type |= 0x0050;
+ if(Dlg->GetCheck(171)) type |= 0x0100; if(Dlg->GetCheck(172)) type |= 0x0200;
+ if(Dlg->GetCheck(173)) type |= 0x0300; if(Dlg->GetCheck(174)) type |= 0x0400;
+ if(Dlg->GetCheck(175)) type |= 0x0500;
+ if(Dlg->GetCheck(151)) type |= 0x1000; if(Dlg->GetCheck(152)) type |= 0x2000;
+ if(Dlg->GetCheck(401)) type |= 0x4000; if(Dlg->GetCheck(402)) type |= 0x8000;
+ Dlg->GetValue(166, &ci_box); Dlg->GetValue(176, &ci_err);
+ if(Dlg->GetText(404, TmpTxt, TMP_TXT_SIZE)) case_prefix = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
+ CreateData();
+ if(curr_data && type) {
+ curr_data->GetSize(&width, &height);
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt+100, 50, "a1:a%d", height); sprintf_s(TmpTxt+200, 50, "b1:b%d", height);
+#else
+ sprintf(TmpTxt+100, "a1:a%d", height); sprintf(TmpTxt+200, "b1:b%d", height);
+#endif
+ nPoints = height;
+ if(nPoints > 1 && (type & 0x1000)) {
+ TheLine = new DataLine(this, curr_data, TmpTxt+100, TmpTxt+200);
+ bRet = true;
+ }
+ if(nPoints > 0 && (type & 0x2000) && (Symbols = (Symbol**)calloc(nPoints, sizeof(Symbol*)))) {
+ switch(type & 0x000f) {
+ case 0x0001: cb = rlp_strcpy(symdesc, 40, "Mean"); break;
+ case 0x0002: cb = rlp_strcpy(symdesc, 40, "Geometric mean"); break;
+ case 0x0003: cb = rlp_strcpy(symdesc, 40, "Harmonic mean"); break;
+ case 0x0004: cb = rlp_strcpy(symdesc, 40, "Median"); break;
+ default: cb = rlp_strcpy(symdesc, 40, "n.a."); break;
+ }
+ for(i = 0; i < height; i++) {
+ if(curr_data->GetValue(i, 0, &x) && curr_data->GetValue(i, 1, &y1)
+ && (Symbols[i] = new Symbol(this, curr_data, x, y1, SYM_PLUS, 0, i, 1, i))){
+ Symbols[i]->idx = i;
+ Symbols[i]->name = (char*)memdup(symdesc, cb+1, 0);
+ }
+ }
+ bRet = true;
+ }
+ if(nPoints > 0 && (type & 0x00f0) && (Boxes = (Box**)calloc(nPoints, sizeof(Box*)))) {
+ switch(type & 0x00f0) {
+ case 0x0010: cb = rlp_strcpy(boxdesc, 40, "Std. Dev."); break;
+ case 0x0020: cb = rlp_strcpy(boxdesc, 40, "Std. Err."); break;
+ case 0x0030: cb = rlp_strcpy(boxdesc, 40, "25, 75% Perc."); break;
+ case 0x0040: cb = rlp_strcpy(boxdesc, 40, "Min./Max."); break;
+#ifdef USE_WIN_SECURE
+ case 0x0500: cb = sprintf_s(boxdesc, 40, "'%g%% CI", ci_err); break;
+#else
+ case 0x0500: cb = sprintf(boxdesc, "'%g%% CI", ci_err); break;
+#endif
+ default: cb = rlp_strcpy(boxdesc, 40, "n.a.");
+ }
+ for(i = 0; i < height; i++) {
+ if(curr_data->GetValue(i, 0, &x) && curr_data->GetValue(i, 2, &y1)
+ && curr_data->GetValue(i, 3, &y2)) {
+ fp1.fy = y1; fp2.fy = y2; fp1.fx = fp2.fx = x;
+ Boxes[i] = new Box(this, curr_data, fp1, fp2, BAR_RELWIDTH, 0, i, 2, i, 0, i, 3, i);
+ if(Boxes[i]){
+ Boxes[i]->SetSize(SIZE_BOX, 60.0);
+ Boxes[i]->name = (char*)memdup(boxdesc, cb+1, 0);
+ }
+ }
+ }
+ bRet = true;
+ }
+ if(nPoints > 0 && (type & 0x0f00) && (Whiskers = (Whisker**)calloc(nPoints, sizeof(Whisker*)))) {
+ switch(type & 0x0f00) {
+ case 0x0100: rlp_strcpy(errdesc, 40, "Std. Dev."); break;
+ case 0x0200: rlp_strcpy(errdesc, 40, "Std. Err."); break;
+ case 0x0300: rlp_strcpy(errdesc, 40, "25, 75% Perc."); break;
+ case 0x0400: rlp_strcpy(errdesc, 40, "Min./Max."); break;
+#ifdef USE_WIN_SECURE
+ case 0x0500: sprintf_s(errdesc, 40, "'%g%% CI", ci_err); break;
+#else
+ case 0x0500: sprintf(errdesc, "'%g%% CI", ci_err); break;
+#endif
+ default: rlp_strcpy(errdesc, 40, "error");
+ }
+ for(i = 0; i < height; i++) {
+ if(curr_data->GetValue(i, 0, &x) && curr_data->GetValue(i, 4, &y1)
+ && curr_data->GetValue(i, 5, &y2)) {
+ fp1.fy = y1; fp2.fy = y2; fp1.fx = fp2.fx = x;
+ Whiskers[i] = new Whisker(this, curr_data, fp1, fp2, 0, 0, i, 4, i, 0, i, 5, i);
+ if(Whiskers[i]) Whiskers[i]->Command(CMD_ERRDESC, errdesc, 0L);
+ }
+ }
+ bRet = true;
+ }
+ if(nPoints > 0 && (type & 0xc000) && (Labels = (Label**)calloc(nPoints, sizeof(Label*)))) {
+ dy = -0.4 * DefSize(SIZE_SYMBOL);
+ if(type & 0x4000){
+ lbdef.Align = TXA_HCENTER | TXA_VBOTTOM;
+ dx = 0.0;
+ }
+ else {
+ lbdef.Align = TXA_HLEFT | TXA_VBOTTOM;
+ dx = -dy;
+ }
+ for(i = 0; i < height; i++) {
+ if(curr_data->GetValue(i, 0, &x) && curr_data->GetText(i, 7, TmpTxt, TMP_TXT_SIZE)){
+ if(curr_data->GetValue(i, 6, &y1))Labels[i] = new Label(this, curr_data, x, y1, &lbdef,
+ LB_X_DATA | LB_Y_DATA, 0, i, 6, i, 7, i);
+ if(Labels[i]){
+ Labels[i]->SetSize(SIZE_LB_YDIST, dy); Labels[i]->SetSize(SIZE_LB_XDIST, dx);
+ }
+ }
+ }
+ bRet = true;
+ }
+ }
+ }
+ }
+ if(bRet) {
+ dirty = true;
+ Command(CMD_AUTOSCALE, 0L, 0L);
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(rX) delete rX;
+ 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, CHECKED, 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, RANGEINPUT, text1, 20, 40, 100, 10},
+ {102, 103, 0, 0x0L, LTEXT, (void*)"range for width (density) data", 10, 55, 60, 8},
+ {103, 104, 0, 0x0L, RANGEINPUT, 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, align = 0;
+ bool bRet = false, bContinue = false, bVert;
+ AccRange *rX = 0L, *rY = 0L;
+
+ if(!parent || !data) return false;
+ OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)defs.GetOutLine(), 0);
+ OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)defs.GetFill(), 0);
+ UseRangeMark(data, 1, text1, text2);
+ if(!(Dlg = new DlgRoot(PlotDlg, data)))return false;
+ hDlg = CreateDlgWnd("Density profile", 50, 50, 420, 260, Dlg, 0x4L);
+ 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, TMP_TXT_SIZE)) 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, TMP_TXT_SIZE) && (rY = new AccRange(TmpTxt))){
+ if(n != rY->CountItems()) {
+ ErrorBox("both ranges must be given\nand must have the same size");
+ bContinue = true;
+ res = -1;
+ }
+ }
+ }
+ }while (res < 0);
+ if(res == 1 && n && rX && rY) {
+ if(Dlg->GetCheck(104)) {
+ y_info = rX->RangeDesc(data, 0); x_info = rY->RangeDesc(data, 0);
+ }
+ else {
+ x_info = rX->RangeDesc(data, 0); y_info = rY->RangeDesc(data, 0);
+ }
+ type = (bVert = Dlg->GetCheck(104)) ? align | 0x10 : align;
+ if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) xRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
+ if(Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE)) yRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
+ 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
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+static char *StackBar_DlgTmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,-1,158,10,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,158,25,45,12\n"
+ "3,,10,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "10,11,100,ISPARENT | CHECKED, SHEET,1,5,10,140,100\n"
+ "11,12,200,ISPARENT,SHEET,2,5,10,140,100\n"
+ "12,20,300,ISPARENT,SHEET,3,5,10,140,100\n"
+ "20,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+ "100,101,,,LTEXT,4,15,30,60,8\n"
+ "101,152,,,RANGEINPUT,5,25,40,100,10\n"
+ "152,153,,ISPARENT | CHECKED,GROUPBOX,6, 12, 60, 128, 45\n"
+ "153,154,,,LTEXT,0,25,65,60,8\n"
+ "154,155,,,RANGEINPUT,5,25,75,100,10\n"
+ "155,156,0,,PUSHBUTTON,-8,95,87,30,12\n"
+ "156,,,,PUSHBUTTON,-9,60,87,35,12\n"
+ "200,201,,CHECKED,RADIO1,7,25,35,60,8\n"
+ "201,202,,,RADIO1,8,25,50,60,8\n"
+ "202,203,,,RTEXT,9,31,65,38,8\n"
+ "203,204,,,EDVAL1,10,70,65,30,10\n"
+ "204,,,,CHECKBOX,11,25,90,60,8\n"
+ "300,,,LASTOBJ | NOSELECT, ODBUTTON,12,20,35,80,60";
+
+bool
+StackBar::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 25, 10, "Data"};
+ TabSHEET tab2 = {25, 55, 10, "Details"};
+ TabSHEET tab3 = {55, 90, 10, "Scheme"};
+ void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"range for common x values",
+ (void*)TmpTxt, (void*)" ranges for y values ", (void*)" add each y to start value",
+ (void*)" subtract each y from start value", (void*)"start value:", (void*)&StartVal,
+ (void*)" horizontal plot", (void*)(OD_scheme)};
+ DlgInfo *StackBarDlg;
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, sc, j, res, currYR = 0, maxYR = 0, nx = 0, ny, c_num, c_txt, c_datetime;
+ bool updateYR = true, bContinue = false, bSub, bRet = false, bHor;
+ char **rd = 0L, *rname;
+ AccRange *rX = 0L, *rY = 0L;
+ TextValue *tv = 0L;
+
+ if(!parent || !data) return false;
+ if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
+ TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return false;
+ if(!(StackBarDlg = CompileDialog(StackBar_DlgTmpl, dyndata))) return false;
+ if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
+ for(i=100, j= 0; i <= 1000; i +=100) if(TmpTxt[i])
+ rd[j++] = (char*)memdup(TmpTxt+i, ((int)strlen(TmpTxt+i))+2, 0); maxYR = j-1;
+ }
+ if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
+ if(!(Dlg = new DlgRoot(StackBarDlg, data))) return false;
+ if(rd && rd[currYR] && *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
+ hDlg = CreateDlgWnd(Id == GO_STACKBAR ? (char*)"Stacked Bar Plot" :
+ (char*)"Stacked Polygons", 50, 50, 420, 260, Dlg, 0x4L);
+ do {
+ if(updateYR) {
+ if(currYR >0) {
+ Dlg->ShowItem(156, true); Dlg->Activate(101, false);
+ }
+ else {
+ Dlg->ShowItem(156, false); Dlg->Activate(101, true);
+ }
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "y-values # %d/%d", currYR+1, maxYR+1);
+#else
+ sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
+#endif
+ //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) TmpTxt[j++] = '&';
+ j+= rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, rd[i]);
+ }
+ rX->DataTypes(data, &c_num, &c_txt, &c_datetime);
+ if(!c_num && (c_txt + c_datetime) > 0 ) tv = new TextValue();
+ if(Dlg->GetCheck(204)) {
+ y_info = rX->RangeDesc(data, 3); y_tv = tv;
+ }
+ else {
+ x_info = rX->RangeDesc(data, 3); x_tv = tv;
+ }
+ ssYrange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+1, 0);
+ if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) ssXrange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+1, 0);;
+ 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(rY)delete rY; rY = 0L;
+ if(Id == GO_STACKBAR){
+ numPlots = maxYR;
+ if(Boxes = (BoxPlot**)calloc(numPlots, sizeof(BoxPlot*)))
+ for(i = sc = 0; i < (maxYR) && rd[i] && *rd[i]; i++) {
+ rY = new AccRange(rd[i]); rname = rY->RangeDesc(data, 3);
+ if(Boxes[i]= new BoxPlot(0L, CumData, Dlg->GetCheck(204)? 2:1, 0, i+1, i+2, rname)){
+ Boxes[i]->Command(CMD_UPDATE, 0L, 0L); Boxes[i]->parent = this;
+ Boxes[i]->Command(CMD_AUTOSCALE, 0L, 0L);
+ Boxes[i]->Command(CMD_BOX_FILL, GetSchemeFill(&sc), 0L);
+ Boxes[i]->SetSize(SIZE_BOX, 60.0);
+ if(rname) free(rname); delete rY; rY = 0L;
+ }
+ }
+ }
+ //do stacked polygon
+ else if(Id == GO_STACKPG){
+ numPG = maxYR;
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, 20, "a1:a%d", nx*2);
+#else
+ sprintf(TmpTxt, "a1:a%d", nx*2);
+#endif
+ if(Polygons=(DataPolygon**)calloc(numPG,sizeof(DataPolygon*)))
+ for(i=sc=0; i < maxYR && rd[i] && *rd[i];i++){
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt+20, 20, "%c1:%c%d", 'c'+i, 'c'+i, nx*2);
+#else
+ sprintf(TmpTxt+20, "%c1:%c%d", 'c'+i, 'c'+i, nx*2);
+#endif
+ rY = new AccRange(rd[i]); rname = rY->RangeDesc(data, 3);
+ if(Dlg->GetCheck(204)) Polygons[i]=new DataPolygon(this,CumData,TmpTxt+20,TmpTxt, rname);
+ else Polygons[i] = new DataPolygon(this, CumData, TmpTxt, TmpTxt+20, rname);
+ if(Polygons[i]) {
+ Polygons[i]->Command(CMD_AUTOSCALE, 0L, 0L);
+ Polygons[i]->Command(CMD_PG_FILL, GetSchemeFill(&sc), 0L);
+ }
+ if(rname) free(rname); delete rY; rY = 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; free(StackBarDlg);
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create grouped bars chart
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *GBDlg_Tmpl =
+ "1,+,,DEFAULT,PUSHBUTTON,-1,140,10,45,12\n"
+ ".,.,,,PUSHBUTTON,-2,140,25,45,12\n"
+ ".,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "4,+,99,ISPARENT | CHECKED | TOUCHEXIT,SHEET,1,5,10,128,100\n"
+ ".,.,200,ISPARENT,SHEET,2,5,10,128,100\n"
+ ".,.,300,ISPARENT,SHEET,3,5,10,128,100\n"
+ ".,10,250,ISPARENT | TOUCHEXIT,SHEET,16,5,10,128,100\n"
+ "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+ "99,100,110,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "100,,160,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "101,+,,,LTEXT,0,25,39,60,8\n"
+ ".,.,,,RANGEINPUT,-15,25,49,100,10\n"
+ ".,.,,,LTEXT,0,25,61,60,8\n"
+ ".,.,,,RANGEINPUT,-16,25,71,100,10\n"
+ ".,.,,,PUSHBUTTON,-8,95,87,30,12\n"
+ ".,,,,PUSHBUTTON,-9,60,87,35,12\n"
+ "110,+,,,LTEXT,4,10,25,60,8\n"
+ ".,150,,,LTEXT,5,10,33,60,8\n"
+ "150,,153,ISPARENT | CHECKED,GROUPBOX,6,10,50,118,55\n"
+ "160,101,,ISPARENT | CHECKED,GROUPBOX,19,10,30,118,75\n"
+ "153,+,,,LTEXT,0,15,60,60,8\n"
+ ".,.,,,RANGEINPUT,-1,15,70,108,10\n"
+ ".,.,,,PUSHBUTTON,-8,93,87,30,12\n"
+ ".,,,,PUSHBUTTON,-9,58,87,35,12\n"
+ "200,+,,,RTEXT,7,10,35,38,8\n"
+ ".,.,,,EDVAL1,8,58,35,35,10\n"
+ ".,.,,,RTEXT,9,10,50,38,8\n"
+ ".,.,,,EDVAL1,10,58,50,35,10\n"
+ ".,.,,,RTEXT,11,10,65,38,8\n"
+ ".,.,,,EDVAL1,12,58,65,35,10\n"
+ ".,.,,,LTEXT,-10,95,65,8,8\n"
+ ".,.,,,RTEXT,13,10,80,38,8\n"
+ ".,.,,,EDVAL1,14,58,80,35,10\n"
+ ".,,,,LTEXT,-10,95,80,8,8\n"
+ "250,+,TOUCHEXIT,CHECKED,RADIO1,17,20,35,70,8\n"
+ ".,.,,TOUCHEXIT,RADIO1,18,20,50,70,8\n"
+ ".,,,,RANGEINPUT,0,15,65,108,10\n"
+ "300,,,LASTOBJ | NOSELECT,ODBUTTON,15,24,30,90,60";
+
+bool
+GroupBars::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 27, 10, "Data"};
+ TabSHEET tab2 = {27, 59, 10, "Details"};
+ TabSHEET tab3 = {59, 96, 10, "Scheme"};
+ TabSHEET tab4 = {96, 128, 10, "Labels"};
+ double start = 1.0, step = 1.0, bw = 100.0, gg = 100.0;
+ void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"Get values from spreadsheet:",
+ (void*)"All ranges should have equal size!", (void*)" ranges for y values ", (void*)"start value",
+ (void*)&start, (void*)"group step", (void*)&step, (void*)"bar width", (void*)&bw,
+ (void*)"group gap", (void*)&gg, (void*)(OD_scheme), (void*)&tab4, (void*)" no group labels",
+ (void*)"from spreadsheet range:", (void*)" ranges for y- and error- data "};
+ DlgInfo *GBDlg;
+ DlgRoot *Dlg;
+ void *hDlg;
+ bool bRet = false, updateYR = true, bContinue = false, bError;
+ char **rd=0L, **rdx=0L, **rdy=0L, *desc;
+ Bar **bars = 0L;
+ ErrorBar **errs = 0L;
+ AccRange *rX = 0L, *rY = 0L;
+ anyResult ares;
+ int i, j, ic, res, ix, iy, ex, ey, ny, s1, s2, sc = 0, currYR = 0, maxYR = 0;
+ double x, y, xinc, e, ebw;
+
+ if(!parent || !data) return false;
+ if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
+ TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return false;
+ if(!(GBDlg = CompileDialog(GBDlg_Tmpl, dyndata)))return false;
+ if(mode == 0 && TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
+ for(i=0, j= 0; i <= 1000; i +=100)
+ if(TmpTxt[i]) rd[j++] = (char*)memdup(TmpTxt+i, ((int)strlen(TmpTxt+i))+2, 0);
+ maxYR = j-1;
+ }
+ else if(mode == 1 && TmpTxt[0] && TmpTxt[100] && (rdx = (char**)calloc(12, sizeof(char*)))
+ && (rdy = (char**)calloc(12, sizeof(char*)))) {
+ for(i=j=0; i <= 1000; i +=200) if(TmpTxt[i]) {
+ rdx[j] = (char*)memdup(TmpTxt+i, (int)strlen(TmpTxt)+1, 0);
+ rdy[j] = (char*)memdup(TmpTxt+i+100, (int)strlen(TmpTxt+i+100)+1, 0); maxYR = j++;
+ }
+ }
+ Id = GO_STACKBAR;
+ if(mode == 0 && !rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
+ if(mode == 1 && !rdx && !rdy && !(rdx = (char**)calloc(1, sizeof(char*)))
+ && !(rdy = (char**)calloc(1, sizeof(char*))))return false;
+ if(!(Dlg = new DlgRoot(GBDlg, data)))return false;
+ if(mode == 1) {
+ Dlg->ShowItem(99, false); Dlg->ShowItem(100, true);
+ }
+ else {
+ Dlg->ShowItem(99, true); Dlg->ShowItem(100, false);
+ }
+ if(rd && rd[currYR] && *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
+ else Dlg->SetText(154, "");
+ hDlg = CreateDlgWnd(mode == 0 ? (char*)"Grouped Bar Chart" : (char*)"Grouped Bar Chart with Error Bars", 50, 50, 390, 260, Dlg, 0x4L);
+ do {
+ if(updateYR) {
+ if(currYR >0) {
+ Dlg->ShowItem(156, true); Dlg->ShowItem(106, true);
+ }
+ else {
+ Dlg->ShowItem(156, false); Dlg->ShowItem(106, false);
+ }
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, 20, "y-values # %d/%d", currYR+1, maxYR+1);
+ sprintf_s(TmpTxt+100, 20, "errors # %d/%d", currYR+1, maxYR+1);
+#else
+ sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
+ sprintf(TmpTxt+100,"errors # %d/%d", currYR+1, maxYR+1);
+#endif
+ //SetText will also cause a redraw of the whole dialog
+ if(mode == 0) Dlg->SetText(153, TmpTxt);
+ else {
+ Dlg->SetText(101, TmpTxt); Dlg->SetText(103, TmpTxt+100);
+ }
+ updateYR = false;
+ }
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 0:
+ if(bContinue || Dlg->GetCheck(10)) res = -1;
+ break;
+ case -1:
+ bContinue = false;
+ break;
+ case 250: case 251:
+ case 7:
+ Dlg->Activate(252, true);
+ res = -1; break;
+ case 4:
+ Dlg->Activate(mode ? 102:154, true);
+ res = -1; break;
+ case 1:
+ Dlg->GetValue(201, &start); Dlg->GetValue(203, &step);
+ Dlg->GetValue(205, &bw); Dlg->GetValue(208, &gg);
+ res = com_StackDlg(res, Dlg, 0L, 0L, &rd, &currYR,
+ &rY, &bContinue, &ny, &maxYR, &updateYR);
+ if(!mode) break;
+ case 105: //next button
+ bError=false; s1 = s2 = 0;
+ if(Dlg->GetText(102, TmpTxt, 100)) {
+ if(rX = new AccRange(TmpTxt)) {
+ s1 = rX->CountItems();
+ if(s1 < 2) {
+ ErrorBox("y-range not valid");
+ bContinue=bError=true;
+ Dlg->Activate(102, true);
+ }
+ delete rX;
+ }
+ else bError = true;
+ }
+ else bError = true;
+ if(Dlg->GetText(104, TmpTxt+100, 100) && !bError) {
+ if(rY = new AccRange(TmpTxt+100)) {
+ s2 = rY->CountItems();
+ if(s2 < 2) {
+ ErrorBox("error-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("Y-range and error-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));
+ rdx[currYR] = rdx[currYR+1] = rdy[currYR] = rdy[currYR+1] = 0L;
+ maxYR = currYR+1;
+ }
+ if(rdx[currYR]) free(rdx[currYR]); //store x-range
+ rdx[currYR] = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+ if(rdy[currYR]) free(rdy[currYR]); //store y range
+ rdy[currYR] = (char*)memdup(TmpTxt+100, (int)strlen(TmpTxt+100)+1, 0);
+ updateYR = true; 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, TmpTxt, 100) && Dlg->GetText(104, TmpTxt+100, 100)){
+ if(rdx[currYR]) free(rdx[currYR]); if(rdy[currYR]) free(rdy[currYR]);
+ rdx[currYR] = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+ rdy[currYR] = (char*)memdup(TmpTxt+100, (int)strlen(TmpTxt+100)+1, 0);
+ }
+ else if(currYR == maxYR) maxYR--;
+ currYR--;
+ Dlg->SetText(102, rdx[currYR]);
+ Dlg->SetText(104, rdy[currYR]); Dlg->Activate(102, true);
+ updateYR = true;
+ res = -1;
+ break;
+ 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])||(rdx && rdy && rdx[0] && rdy[0] && rdx[0][0] && rdy[0][0]))){
+ //accept settings and create plots
+ if((mode == 0 && rd[maxYR]) || (mode == 1 && rdx[maxYR])) maxYR++;
+ ebw = defs.GetSize(SIZE_ERRBAR)*9.0/((double)(s1*maxYR));
+ if(Dlg->GetCheck(251) && Dlg->GetText(252, TmpTxt, 100) && (rX = new AccRange(TmpTxt))
+ && rX->GetFirst(&ix, &iy)){
+ x_tv = new TextValue(); rX->GetNext(&ix, &iy);
+ i = 1; start = step = 1.0;
+ do {
+ if(data->GetResult(&ares, iy, ix, false)) switch(ares.type) {
+ case ET_TEXT:
+ x_tv->GetValue(ares.text); break;
+ case ET_VALUE: case ET_DATE: case ET_TIME:
+ case ET_DATETIME: case ET_BOOL:
+ TranslateResult(&ares);
+ x_tv->GetValue(ares.text); break;
+ }
+ i++;
+ }while(rX->GetNext(&ix, &iy));
+ }
+ if(rX) delete rX; rX = 0L;
+ 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, desc = 0L; i < maxYR; i++) {
+ x = start + xinc * (double)i;
+ if(mode == 0 && rd) {
+ if(rd[i] && (rY = new AccRange(rd[i]))) ny = rY->CountItems();
+ else {
+ rY = 0L; ny = 0;
+ }
+ }
+ else if(mode == 1 && rdx && rdy) {
+ if(rdx[i] && (rY = new AccRange(rdx[i]))) ny = rY->CountItems();
+ else {
+ rY = 0L; ny = 0;
+ }
+ }
+ if(rY) {
+ desc = rY->RangeDesc(data, 1);
+ rY->GetFirst(&ix, &iy);
+ if(mode == 1 && (rX = new AccRange(rdy[i]))) {
+ errs = (ErrorBar**)calloc(ny, sizeof(ErrorBar*));
+ rX->GetFirst(&ex, &ey);
+ }
+ rY->GetNext(&ix, &iy);
+ if(ny && rY && (bars = (Bar **)calloc(ny, sizeof(Bar*)))){
+ for(ic = 0; ic < ny; ic++) {
+ if(bContinue = data->GetValue(iy, ix, &y)){
+ bars[ic] = new Bar(0L, data, x, y, BAR_VERTB | BAR_RELWIDTH,
+ -1, -1, ix, iy, desc);
+ CheckBounds(x, y);
+ }
+ if(errs && rX && rX->GetNext(&ex, &ey) && data->GetValue(ey, ex, &e)) {
+ if(bContinue && (errs[ic] = new ErrorBar(0L, data, x, y, e, 0, -1, -1, ix, iy, ex, ey)))
+ errs[ic]->SetSize(SIZE_ERRBAR, ebw);
+ CheckBounds(x, y+e); CheckBounds(x, y-e);
+ }
+ x += step;
+ rY->GetNext(&ix, &iy);
+ }
+ xyPlots[numXY++] = new PlotScatt(this, data, ic, bars, errs);
+ 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]);
+ if(errs) for(ic = 0; ic < ny; ic++) if(errs[ic]) delete(errs[ic]);
+ free(bars); if(errs) free(errs); bRet = true;
+ }
+ delete(rY); if(desc) free(desc); rY = 0L;
+ }
+ }
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(rd) {
+ for (i = 0; i < maxYR; i++) if(rd[i]) free(rd[i]);
+ free(rd);
+ }
+ 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(rY) delete rY; if(rX) delete rX; free(GBDlg);
+ 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, CHECKED, 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, RANGEINPUT, 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, RANGEINPUT, TmpTxt, 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, COLBUTT, (void*)&defcol, 105, 35, 20, 10},
+ {302, 303, 0, 0x0L, RADIO1, (void*)" increment color scheme:", 20, 55, 80, 9},
+ {303, 304, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[0], 25, 70, 10, 10},
+ {304, 305, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[1], 37, 70, 10, 10},
+ {305, 306, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[2], 49, 70, 10, 10},
+ {306, 307, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[3], 61, 70, 10, 10},
+ {307, 308, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[4], 73, 70, 10, 10},
+ {308, 309, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[5], 85, 70, 10, 10},
+ {309, 310, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[6], 97, 70, 10, 10},
+ {310, 0, 0, OWNDIALOG | TOUCHEXIT, COLBUTT, (void*)&colarr[7], 109, 70, 10, 10},
+ {500, 0, 0, LASTOBJ, NONE, 0L, 0, 0, 0, 0}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, j, res, currYR=0, maxYR=0, nx=0, ny;
+ char **rd = 0L;
+ bool updateYR = true, bContinue = false, bRet = false, bUseSch;
+ AccRange *rX = 0L, *rY = 0L;
+
+ if(!parent || !data) return false;
+ if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
+ TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return false;
+ if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
+ for(i=100, j= 0; i <= 1000; i +=100) if(TmpTxt[i])
+ rd[j++] = (char*)memdup(TmpTxt+i, ((int)strlen(TmpTxt+i))+2, 0);
+ maxYR = j-1;
+ }
+ if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
+ if(!(Dlg = new DlgRoot(StackBarDlg, data))) return false;
+ if(rd && rd[currYR] && *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
+ hDlg = CreateDlgWnd("Create Waterfall Plot", 50, 50, 420, 260, Dlg, 0x4L);
+ do {
+ if(updateYR) {
+ if(currYR >0) {
+ Dlg->ShowItem(156, true); Dlg->Activate(101, false);
+ }
+ else {
+ Dlg->ShowItem(156, false); Dlg->Activate(101, true);
+ }
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, 20, "y-values # %d/%d", currYR+1, maxYR+1);
+#else
+ sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
+#endif
+ //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, 100);
+ 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
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *MultiLineDlg_Tmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,-1,158,10,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,158,25,45,12\n"
+ "3,,10,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "10,11,100,ISPARENT | CHECKED,SHEET,1,5,10,140,100\n"
+ "11,12,300,ISPARENT,SHEET,2,5,10,140,100\n"
+ "12,20,200,ISPARENT,SHEET,15,5,10,140,100\n"
+ "20,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+ "100,101,,ISPARENT | CHECKED,GROUPBOX,3,12,30,128,75\n"
+ "101,102,,,LTEXT,0,25,39,60,8\n"
+ "102,103,,,RANGEINPUT,-15,25,49,100,10\n"
+ "103,104,,,LTEXT,0,25,61,60,8\n"
+ "104,105,,,RANGEINPUT,-16,25,71,100,10\n"
+ "105,106,,,PUSHBUTTON,-8,95,87,30,12\n"
+ "106,107,,,PUSHBUTTON,-9,60,87,35,12\n"
+ "107,108,,OWNDIALOG,COLBUTT,4,25,87,20,12\n"
+ "108,,,,LTEXT,12,47,90,30,9\n"
+ "200,201,,CHECKED,CHECKBOX,16,25,35,80,9\n"
+ "201,202,,ODEXIT,SYMBUTT,17,25,70,10,10\n"
+ "202,203,,ODEXIT,SYMBUTT,18,37,70,10,10\n"
+ "203,204,,ODEXIT,SYMBUTT,19,49,70,10,10\n"
+ "204,205,,ODEXIT,SYMBUTT,20,61,70,10,10\n"
+ "205,206,,ODEXIT,SYMBUTT,21,73,70,10,10\n"
+ "206,207,,ODEXIT,SYMBUTT,22,85,70,10,10\n"
+ "207,208,,ODEXIT,SYMBUTT,23,97,70,10,10\n"
+ "208,209,,ODEXIT,SYMBUTT,24,109,70,10,10\n"
+ "209,,,CHECKED,CHECKBOX,25,25,50,80,9\n"
+ "300,301,,TOUCHEXIT,RADIO1,13,20,35,80,9\n"
+ "301,302,,ODEXIT,COLBUTT,4,105,35,20,10\n"
+ "302,303,,CHECKED | TOUCHEXIT, RADIO1,14,20,55,80,9\n"
+ "303,304,,ODEXIT,COLBUTT,4,25,70,10,10\n"
+ "304,305,,ODEXIT,COLBUTT,5,37,70,10,10\n"
+ "305,306,,ODEXIT,COLBUTT,6,49,70,10,10\n"
+ "306,307,,ODEXIT,COLBUTT,7,61,70,10,10\n"
+ "307,308,,ODEXIT,COLBUTT,8,73,70,10,10\n"
+ "308,309,,ODEXIT,COLBUTT,9,85,70,10,10\n"
+ "309,310,,ODEXIT,COLBUTT,10,97,70,10,10\n"
+ "310,,,LASTOBJ | ODEXIT,COLBUTT,11,109,70,10,10\n";
+
+bool
+MultiLines::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 25, 10, "Data"};
+ TabSHEET tab2 = {25, 60, 10, "Scheme"};
+ TabSHEET tab3 = {60, 97, 10, "Symbols"};
+ static DWORD colarr[] = {0x00000000L, 0x00ff0000L, 0x0000ff00L, 0x000000ffL,
+ 0x00ff00ff, 0x00ffff00L, 0x0000ffff, 0x00c0c0c0};
+ Symbol *syms[8], **lsyms;
+ static DWORD defcol = 0x0L;
+ char x_txt[100], y_txt[100];
+ DlgInfo *StackBarDlg;
+ void *dyndata[] = {(void*) &tab1, (void*)&tab2, (void*)" ranges for x- and y- values ",
+ (void*)&colarr[0], (void*)&colarr[1], (void*)&colarr[2], (void*)&colarr[3],
+ (void*)&colarr[4], (void*)&colarr[5], (void*)&colarr[6], (void*)&colarr[7],
+ (void*)"line color", (void*)" common color for lines:", (void*)" increment color scheme:",
+ (void*) &tab3, (void*)" draw symbols", (void*)&syms[0], (void*)&syms[1], (void*)&syms[2],
+ (void*)&syms[3], (void*)&syms[4], (void*)&syms[5], (void*)&syms[6], (void*)&syms[7],
+ (void*) " use line color for symbols"};
+ DlgRoot *Dlg;
+ void *hDlg;
+ char **rdx=0L, **rdy=0L;
+ DWORD *rdc = 0L, curr_col;
+ int i, j, nd, res, currYR=0, maxYR=0, s1, s2, rx, ry, cx, cy;
+ double symsize, x, y;
+ bool updateYR = true, bContinue = false, bError, bRet = false;
+ AccRange *rX = 0L, *rY = 0L;
+ DataLine *dl;
+
+ if(!parent || !data) return false;
+ symsize = NiceValue(defs.GetSize(SIZE_SYMBOL)*.8);
+ for(i = 0; i < 8; i++) if(syms[i] = new Symbol(0L, data, 0.0, 0.0, i)) {
+ if(i != 2 && i != 3)syms[i]->SetSize(SIZE_SYMBOL, symsize);
+ }
+ if(!(StackBarDlg = CompileDialog(MultiLineDlg_Tmpl, dyndata)))return false;
+ if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
+ TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return false;
+ if(TmpTxt[0] && TmpTxt[100] && (rdx = (char**)calloc(12, sizeof(char*)))
+ && (rdy = (char**)calloc(12, sizeof(char*))) && (rdc = (DWORD*)malloc(12*sizeof(DWORD)))) {
+ for(i=100, j= 0; i <= 1000; i +=100) if(TmpTxt[i]) {
+ rdx[j] = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0); rdc[j] = colarr[j%8];
+ rdy[j] = (char*)memdup(TmpTxt+i, (int)strlen(TmpTxt+i)+1, 0); maxYR = j++;
+ }
+ }
+ if(!(Dlg = new DlgRoot(StackBarDlg, data))) return false;
+ hDlg = CreateDlgWnd("Create Multi Line Plot", 50, 50, 420, 260, Dlg, 0x4L);
+ do {
+ if(updateYR) {
+ if(currYR >0) {
+ Dlg->ShowItem(106, true); Dlg->ShowItem(108, false);
+ }
+ else {
+ Dlg->ShowItem(106, false); Dlg->ShowItem(108, true);
+ }
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "x-range # %d/%d", currYR+1, maxYR+1);
+#else
+ sprintf(TmpTxt,"x-range # %d/%d", currYR+1, maxYR+1);
+#endif
+ //SetText will also cause a redraw of the whole dialog
+ Dlg->SetText(101, TmpTxt);
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "y-range # %d/%d", currYR+1, maxYR+1);
+#else
+ sprintf(TmpTxt,"y-range # %d/%d", currYR+1, maxYR+1);
+#endif
+ 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, 100)) {
+ 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, 100) && !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]); //store x-range
+ rdx[currYR] = (char*)memdup(x_txt, (int)strlen(x_txt)+1, 0);
+ if(rdy[currYR]) free(rdy[currYR]); //store y range
+ rdy[currYR] = (char*)memdup(y_txt, (int)strlen(y_txt)+1, 0);
+ 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, 100) && Dlg->GetText(104, y_txt, 100)){
+ if(rdx[currYR]) free(rdx[currYR]); if(rdy[currYR]) free(rdy[currYR]);
+ rdx[currYR] = (char*)memdup(x_txt, (int)strlen(x_txt)+1, 0);
+ rdy[currYR] = (char*)memdup(y_txt, (int)strlen(y_txt)+1, 0);
+ 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 201: case 202: case 203: case 204:
+ case 205: case 206: case 207: case 208:
+ res = -1;
+ 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);
+ i = res-303;
+ if(rdx && rdy && i <= maxYR && rdc[i] == colarr[i]) {
+ Dlg->GetColor(res, &colarr[i]); rdc[i] = colarr[i];
+ Dlg->SetColor(107, rdc[currYR]);
+ }
+ else {
+ Dlg->GetColor(res, &colarr[i]);
+ }
+ res = -1; break;
+ }
+ }while (res < 0);
+ if(res == 1 && rdx && rdy && maxYR) {
+ maxYR++; rX = rY = 0L;
+ 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(Dlg->GetCheck(200) && (rX = new AccRange(rdx[i])) && (rY = new AccRange(rdy[i]))) {
+ lsyms = (Symbol**)calloc(rX->CountItems()+1, sizeof(Symbol*));
+ symsize = syms[i &0x07]->GetSize(SIZE_SYMBOL);
+ for(nd = 0, rX->GetFirst(&cx, &rx), rY->GetFirst(&cy, &ry); rX->GetNext(&cx, &rx), rY->GetNext(&cy, &ry); ) {
+ if(data->GetValue(rx, cx, &x) && data->GetValue(ry, cy, &y)) {
+ lsyms[nd] = new Symbol(0L, data, x, y, syms[i &0x07]->type, cx, rx, cy, ry);
+ if(Dlg->GetCheck(209)) lsyms[nd]->SetColor(COL_SYM_LINE, Dlg->GetCheck(300) ? defcol : rdc[i & 0x07]);
+ else {
+ lsyms[nd]->SetColor(COL_SYM_LINE, syms[i &0x07]->GetColor(COL_SYM_LINE));
+ lsyms[nd]->SetColor(COL_SYM_FILL, syms[i &0x07]->GetColor(COL_SYM_FILL));
+ }
+ lsyms[nd]->SetSize(SIZE_SYMBOL, symsize);
+ nd++;
+ }
+ }
+ }
+ else {
+ nd = 0; lsyms = 0L;
+ }
+ if(dl = new DataLine(this, data, rdx[i], rdy[i])) {
+ dl->SetColor(COL_DATA_LINE, Dlg->GetCheck(300) ? defcol : rdc[i & 0xf]);
+ if(xyPlots[numXY] = new PlotScatt(this, data, nd, lsyms, dl)) {
+ if(rY) xyPlots[numXY]->data_desc = rY->RangeDesc(data, 1);
+ numXY++;
+ }
+ else delete dl;
+ }
+ if(rX)delete rX; if(rY)delete rY; rX = rY = 0L;
+ }
+ }
+ 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);
+ }
+ for(i = 0; i < 8; i++) if(syms[i]) delete syms[i];
+ free(StackBarDlg); if(rdc) free(rdc);
+ if(bRet) {
+ Bounds.Xmax = Bounds.Ymax = -HUGE_VAL; Bounds.Xmin = Bounds.Ymin = HUGE_VAL;
+ Command(CMD_AUTOSCALE, 0L, 0L);
+ }
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Pie and ring chart properties
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *PieDlgTmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,-1,130,10,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,130,25,45,12\n"
+ "3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "4,5,100,ISPARENT | CHECKED,SHEET,1,5,10,120,103\n"
+ "5,6,200,ISPARENT,SHEET,2,5,10,120,103\n"
+ "6,10,300,ISPARENT,SHEET,3,5,10,120,103\n"
+ "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+ "100,+,,,LTEXT,4,10,25,60,8\n"
+ ".,105,,,RANGEINPUT,-15,15,35,100,10\n"
+ "105,.,500,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ ".,.,600,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ ".,.,,,EDVAL1,6,58,59,30,10\n"
+ ".,,,,LTEXT,-3,89,59,15,8\n"
+ "200,+,,,LTEXT,7,15,30,60,8\n"
+ ".,.,,,RTEXT,-4,2,42,20,8\n"
+ ".,204,,,EDVAL1,8,23,42,30,10\n"
+ "204,.,,,RTEXT,-5,47,42,20,8\n"
+ ".,.,,,EDVAL1,9,68,42,30,10\n"
+ ".,.,,,LTEXT,-3,99,42,15,8\n"
+ ".,.,,,RTEXT,10,27,58,20,8\n"
+ ".,.,,,EDVAL1,11,48,58,30,10\n"
+ ".,210,,,LTEXT,12,79,58,15,8\n"
+ "210,.,400,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ ".,.,410,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ ".,,,,LTEXT,-27,15,80,30,8\n"
+ "300,,,NOSELECT,ODBUTTON,14,20,35,80,60\n"
+ "400,+,,EXRADIO | CHECKED,ODBUTTON,15,55,75,30,30\n"
+ ".,,,EXRADIO,ODBUTTON,15,85,75,30,30\n"
+ "410,+,,EXRADIO | CHECKED,ODBUTTON,15,55,75,30,30\n"
+ ".,,,EXRADIO,ODBUTTON,15,85,75,30,30\n"
+ "500,+,,CHECKED,RADIO1,16,10,59,20,8\n"
+ ".,.,,,RADIO1,17,10,71,40,8\n"
+ ".,.,,,RANGEINPUT,-16,15,82,100,10\n"
+ ".,.,,,LTEXT,19,15,94,10,8\n"
+ ".,.,,,EDVAL1,20,42,94,25,10\n"
+ ".,,,,LTEXT,21,70,94,15,8\n"
+ "600,+,,,RTEXT,22,8,59,45,8\n"
+ ".,.,,,RTEXT,23,8,74,45,8\n"
+ ".,.,,,EDVAL1,24,58,74,30,10\n"
+ ".,,,LASTOBJ,LTEXT,-3,89,74,15,8";
+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];
+ void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"spread sheet range for values",
+ (void*)0L, (void*)&frad, (void*)"position of center:", (void*)&fcx, (void*)&fcy,
+ (void*)"start angle", (void*)&CtDef.fx, (void*)"degree", (void*)0L, (void*)(OD_scheme),
+ (void*)(OD_PieTempl), (void*)"fixed radius", (void*)"pick radii from spreadsheet range",
+ (void*)0L, (void*)"x factor", (void*)&FacRad, (void*)&txt2, (void*)"outer radius",
+ (void*)"inner radius", (void*)&firad};
+ DlgInfo *PieDlg = CompileDialog(PieDlgTmpl, dyndata);
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, ix, iy, rix, riy, ny, res, cf, cb;
+ bool bRet = false, bContinue = false;
+ double sum = 0.0, dang1, dang2;
+ double fv;
+ lfPOINT fpCent;
+ AccRange *rY = 0L, *rR = 0L;
+
+ if(!parent || !data) return false;
+ UseRangeMark(data, 1, TmpTxt, TmpTxt+100);
+ cb = rlp_strcpy(txt2, 80, "= ["); cb += rlp_strcpy(txt2+cb, 80-cb, Units[defs.cUnits].display);
+ rlp_strcpy(txt2+cb, 80-cb, "]");
+ 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;
+ if(!(Dlg = new DlgRoot(PieDlg, data)))return false;
+ 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, 266, Dlg, 0x4L);
+ 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, TMP_TXT_SIZE) && 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, TMP_TXT_SIZE) &&
+ (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, TMP_TXT_SIZE)) ssRefA = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+ if(rR && Dlg->GetText(502, TmpTxt, TMP_TXT_SIZE)) ssRefR = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+ 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; free(PieDlg);
+ 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(DefSize(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, CHECKED, 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, RANGEINPUT, 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, RANGEINPUT, (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, DefSize(SIZE_TEXT), 0.0, 0.0, 0,
+ TXA_HCENTER | TXA_VCENTER, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, 0L};
+
+ if(!parent || !data) return false;
+ data->GetSize(&width, &height);
+#ifdef USE_WIN_SECURE
+ sprintf_s(txt1, 80,"a1:a%d", height); sprintf_s(txt2, 80, "= [%s]", Units[defs.cUnits].display);
+#else
+ sprintf(txt1, "a1:a%d", height); sprintf(txt2, "= [%s]", Units[defs.cUnits].display);
+#endif
+ 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, data)))return false;
+ hDlg = CreateDlgWnd("Create star chart", 50, 50, 370, 260, Dlg, 0x4L);
+ 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, TMP_TXT_SIZE) && 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, TMP_TXT_SIZE) && 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;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Grid3D represents a surface in space
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Grid3D::PropertyDlg()
+{
+ return Configure();
+}
+
+bool
+Grid3D::Configure()
+{
+ TabSHEET tab1 = {0, 37, 10, "Function"};
+ TabSHEET tab2 = {37, 65, 10, "Style"};
+ FillDEF newFill;
+ DlgInfo GridDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 155, 10, 50, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 155, 25, 50, 12},
+ {3, 0, 300, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
+ {300, 301, 500, HIDDEN | CHECKED, GROUPBOX, (void*)" grid lines ", 10, 10, 140, 100},
+ {301, 305, 400, HIDDEN | CHECKED, GROUPBOX, (void*)" surface ", 10, 10, 140, 100},
+ {305, 306, 0, TOUCHEXIT, RADIO1, (void*) " grid lines", 155, 45, 50, 10},
+ {306, 0, 0, TOUCHEXIT, RADIO1, (void*) " surface", 155, 57, 50, 10},
+ {400, 401, 0, 0x0L, RTEXT, (void*)"grid line width", 38, 20, 40, 8},
+ {401, 402, 0, 0x0L, EDVAL1, &Line.width, 80, 20, 25, 10},
+ {402, 403, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 107, 20, 20, 8},
+ {403, 404, 0, 0x0L, RTEXT, (void*)"grid line color", 38, 32, 40, 8},
+ {404, 405, 0, OWNDIALOG, COLBUTT, (void *)&Line.color, 80, 32, 25, 10},
+ {405, 406, 0, 0x0L, RTEXT,(void*)"plane color" , 38, 44, 40, 8},
+ {406, 0, 0, OWNDIALOG, SHADE3D, &newFill, 80, 44, 25, 10},
+ {500, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)OD_linedef, 15, 15, 130, 100}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, cb, new_type, undo_level = *Undo.pcb;
+ bool bRet = false;
+ double tmp;
+ DWORD new_col;
+ LineDEF newLine;
+ anyOutput *cdisp = Undo.cdisp;
+
+ if(!parent) return false;
+ memcpy(&newFill, &Fill, sizeof(FillDEF));
+ OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
+ if(!(Dlg = new DlgRoot(GridDlg, data))) return false;
+ if(!type) {
+ Dlg->ShowItem(300, true); Dlg->SetCheck(305, 0L, true);
+ }
+ else {
+ Dlg->ShowItem(301, true); Dlg->SetCheck(306, 0L, true);
+ }
+ if(parent->name) {
+ cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Grid of ");
+ rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, parent->name);
+ }
+ else rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "3D Grid");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 426, 260, Dlg, 0x4L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 305: case 306:
+ if(Dlg->GetCheck(305)) {
+ Dlg->ShowItem(300, true); Dlg->ShowItem(301, false);
+ }
+ else {
+ Dlg->ShowItem(300, false); Dlg->ShowItem(301, true);
+ }
+ Dlg->Command(CMD_REDRAW, 0L, 0L);
+ res = -1;
+ break;
+ }
+ }while (res < 0);
+ Undo.SetDisp(cdisp);
+ while(*Undo.pcb > undo_level) Undo.Pop(cdisp);
+ if(res == 1) {
+ if(Dlg->GetCheck(305) && type == 0) {
+ OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
+ if(cmpLineDEF(&Line, &newLine)) {
+ Command(CMD_SET_LINE, &newLine, 0L);
+ bRet = true;
+ }
+ }
+ else if(Dlg->GetCheck(306) && type == 1) {
+ Dlg->GetValue(401, &tmp); Dlg->GetColor(404, &new_col);
+ if(planes && (cmpFillDEF(&Fill, &newFill) || tmp != Line.width || new_col != Line.color)) {
+ Command(CMD_SAVE_SYMBOLS, 0L, 0L);
+ Command(CMD_SYM_FILL, &newFill, 0L);
+ if(tmp != Line.width) SetSize(SIZE_SYM_LINE, tmp);
+ if(new_col != Line.color) SetColor(COL_POLYLINE, new_col);
+ bRet = true;
+ }
+ }
+ else {
+ Undo.ValInt(parent, &type, 0L);
+ Undo.Line(this, &Line, UNDO_CONTINUE); Undo.Fill(this, &Fill, UNDO_CONTINUE);
+ if(Dlg->GetCheck(305)) {
+ new_type = 0;
+ OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&Line, 0);
+ }
+ else {
+ new_type = 1;
+ memcpy(&Fill, &newFill, sizeof(FillDEF));
+ Dlg->GetValue(401, &Line.width);
+ Dlg->GetColor(404, &Line.color);
+ Line.pattern = 0L;
+ Line.patlength = 1;
+ }
+ if(planes && nPlanes) Undo.DropListGO(parent, (GraphObj***)&planes, &nPlanes, UNDO_CONTINUE);
+ if(lines && nLines) Undo.DropListGO(parent, (GraphObj***)&lines, &nLines, UNDO_CONTINUE);
+ Undo.VoidPtr(parent, (void**)&planes, 0L, 0L, UNDO_CONTINUE);
+ Undo.VoidPtr(parent, (void**)&lines, 0L, 0L, UNDO_CONTINUE);
+ type = new_type;
+ CreateObs(true);
+ bRet = true;
+ }
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Scatt3D is a layer representing most simple 3D plots
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *Dlg3DTmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,-1,142,10,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,142,25,45,12\n"
+ "3,50,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "4,5,100,TOUCHEXIT | ISPARENT | CHECKED, SHEET,1,5,10,131,100\n"
+ "5,6,200,TOUCHEXIT | ISPARENT, SHEET,2,5,10,131,100\n"
+ "6,10,400, TOUCHEXIT | ISPARENT, SHEET,3,5,10,131,100\n"
+ "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+ "50,60,,NOSELECT, ODBUTTON,4,142,65,45,45\n"
+ "60,61,,,ICON,5,10,114,20,20\n"
+ "61,62,,,LTEXT,6,30,116,100,6\n"
+ "62,,,,LTEXT,7,30,122,100,6\n"
+ "100,101,,,LTEXT,8,10,30,60,8\n"
+ "101,102,,,RANGEINPUT,9,20,40,100,10\n"
+ "102,103,,,LTEXT,10,10,55,60,8\n"
+ "103,104,,,RANGEINPUT,11,20,65,100,10\n"
+ "104,105,,,LTEXT,12,10,80,60,8\n"
+ "105,,,,RANGEINPUT,13,20,90,100,10\n"
+ "200,201,,,LTEXT,-27,25,30,60,8\n"
+ "201,202,,,CHECKBOX,15,30,55,60,8\n"
+ "202,203,,TOUCHEXIT,CHECKBOX,16,30,65,60,8\n"
+ "203,204,,TOUCHEXIT,CHECKBOX,17,30,45,60,8\n"
+ "204,205,,TOUCHEXIT,CHECKBOX,18,30,75,60,8\n"
+ "205,,,TOUCHEXIT,CHECKBOX,19,30,85,60,8\n"
+ "400,410,,,LTEXT,20,20,30,60,8\n"
+ "410,411,,EXRADIO,ODBUTTON,21,20,42,25,25\n"
+ "411,412,,EXRADIO,ODBUTTON,21,45,42,25,25\n"
+ "412,,,LASTOBJ | EXRADIO,ODBUTTON,21,70,42,25,25";
+
+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;
+ void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)(OD_AxisDesc3D), (void*)&icon,
+ (void*)"Use [arrow keys], [shift]+[arrow key],", (void*)"and [r], [R], [l] or [L] to rotate graph.",
+ (void*)"range for X Data", (void*)text1, (void*)"range for Y Data", (void*)text2,
+ (void*)"range for Z Data", (void*)text3, (void*)0L, (void*)" balls", (void*)" columns",
+ (void*)" line", (void*)" drop lines", (void*)" arrows", (void*)"select template:",
+ (void*)(OD_AxisTempl3D)};
+ DlgInfo *Dlg3D = CompileDialog(Dlg3DTmpl, dyndata);
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, n1, n2, n3, ic = 0;
+ int i, j, k, l, m, n, i2, j2, k2, l2, m2, cb;
+ double x, y, z, bar_w, bar_d, rad;
+ bool bRet = false, bContinue = false;
+ AccRange *rX, *rY, *rZ;
+ fPOINT3D pos1, pos2;
+
+ if(!data || !parent)return false;
+ UseRangeMark(data, 1, text1, text2, text3);
+ if(!(Dlg = new DlgRoot(Dlg3D, data)))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 || c_flags == 0x4000) {
+ Dlg->ShowItem(5, false); Dlg->ShowItem(6, false);
+ }
+ else Dlg->ShowItem(6, (c_flags & 0x1000) == 0x1000);
+ rX = rY = rZ = 0L; rad = DefSize(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 Paravent Plot":
+ c_flags == 0x4000 ? (char*)"Delauney Surface" : (char*)"Create 3D Plot", 50, 50, 388, 300, Dlg, 0x4L);
+ 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, 100) && (rX = new AccRange(text1))) n1 = rX->CountItems();
+ if(Dlg->GetText(103, text2, 100) && (rY = new AccRange(text2))) n2 = rY->CountItems();
+ if(Dlg->GetText(105, text3, 100) && (rZ = new AccRange(text3))) n3 = rZ->CountItems();
+ if(n1 && n2 && n3){
+ if(c_flags == 0x2000 || c_flags == 0x4000) {
+ //no more but a ribbon or surface
+ }
+ 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 {
+ cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Ranges for ");
+ if(!n1) cb += rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, "\n- X Data");
+ if(!n2) cb += rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, "\n- Y Data");
+ if(!n3) cb += rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, "\n- Z Data");
+ rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE-cb, "\nnot given or not valid.");
+ 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 = (DefSize(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, 2, text1, text2, text3);
+ }
+ else if(c_flags == 0x4000){
+ rib = new Ribbon(this, data, 3, 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; free(Dlg3D);
+ 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, 600, 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, NOSELECT, ODBUTTON, (void*)OD_linedef, 15, 25, 130, 100},
+ {600, 601, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 170, 45, 15, 15},
+ {601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 170, 60, 15, 15},
+ {602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 170, 75, 15, 15},
+ {603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 170, 90, 15, 15}};
+ 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;
+ anyOutput *cdisp = Undo.cdisp;
+
+ 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, data))) 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, 0x4L);
+ if(bNew) Dlg->SetCheck(4, 0L, true);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 0:
+ if(Dlg->GetCheck(10)) res = -1;
+ break;
+ case 600: case 601: case 602: case 603:
+ Undo.SetDisp(cdisp);
+ res = ExecDrawOrderButt(parent, this, res);
+ }
+ }while (res < 0);
+ Undo.SetDisp(cdisp);
+ if(res == 2) while(*Undo.pcb > undo_level) Undo.Restore(true, cdisp);
+ else 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, TMP_TXT_SIZE);
+ cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+ ReshapeFormula(&cmdxy); 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);
+ if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE))
+ undo_flags = CheckNewString(&cmdxy, cmdxy, TmpTxt, this, undo_flags);
+ if(undo_flags & UNDO_CONTINUE){
+ Update(0L, UNDO_CONTINUE); Command(CMD_MRK_DIRTY, 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;
+ 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, CHECKED, 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, RANGEINPUT, (void*)text1, 20, 40, 100, 10},
+ {402, 403, 0, 0x0L, LTEXT, (void*)"range for Y Data", 10, 55, 60, 8},
+ {403, 404, 0, 0x0L, RANGEINPUT, (void*)text2, 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;
+ size_t cb;
+ 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;
+ anyOutput *cdisp = Undo.cdisp;
+ anyResult *ares;
+
+ if(!parent || !data) return false;
+ if(!(o_cmdxy = (char*)memdup(cmdxy, (int)strlen(cmdxy)+1, 0))) return false;;
+ if(!(o_parxy = (char*)memdup(parxy, (int)strlen(parxy)+1, 0))) return false;;
+ UseRangeMark(data, 1, text1, text2);
+ iter = (double)maxiter;
+ OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
+ if(!(Dlg = new DlgRoot(FuncDlg, data))) 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) {
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "Chi 2 = %g", chi2);
+#else
+ sprintf(TmpTxt, "Chi 2 = %g", chi2);
+#endif
+ 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, 0x4L);
+ 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, TMP_TXT_SIZE)) {
+ if(parxy = (char*)realloc(parxy, (cb = strlen(TmpTxt)+2)))
+ rlp_strcpy(parxy, (int)cb, TmpTxt);
+ }
+ if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
+ if(cmdxy = (char*)realloc(cmdxy, (cb = strlen(TmpTxt)+2)))
+ rlp_strcpy(cmdxy, (int)cb, TmpTxt);
+ }
+ ReshapeFormula(&parxy); ReshapeFormula(&cmdxy);
+ dirty = true;
+ break;
+ }
+ case 7: //Start: do nonlinear regression
+ Undo.SetDisp(cdisp);
+ if(Dlg->GetCheck(5)) { // the function tab must be shown
+ if(Dlg->CurrDisp) Dlg->CurrDisp->MouseCursor(MC_WAIT, true);
+ Dlg->GetText(401, text1, 100); Dlg->GetText(403, text2, 100);
+ if(Dlg->GetText(102, TmpTxt, TMP_TXT_SIZE)) {
+ if(parxy = (char*)realloc(parxy, (cb = strlen(TmpTxt)+2)))
+ rlp_strcpy(parxy, (int)cb, TmpTxt);
+ }
+ if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
+ if(cmdxy = (char*)realloc(cmdxy, (cb = strlen(TmpTxt)+2)))
+ rlp_strcpy(cmdxy, (int)cb, TmpTxt);
+ }
+ Dlg->GetValue(153, &conv); Dlg->GetValue(155, &iter);
+ ReshapeFormula(&parxy); ReshapeFormula(&cmdxy);
+ do_formula(data, 0L); //clear any error condition
+ ares = do_formula(data, parxy);
+ if(ares->type != ET_VALUE) {
+ ErrorBox("Syntax Error in parameters.");
+ bContinue = true; res = -1;
+ break;
+ }
+ ares = do_formula(data, cmdxy);
+ if(ares->type != ET_VALUE) {
+ ErrorBox("Syntax Error in formula.");
+ bContinue = true; res = -1;
+ break;
+ }
+ i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE-2, parxy); i += rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, ";x=1;");
+ rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, cmdxy); yywarn(0L, true);
+ ares = do_formula(data, TmpTxt);
+ if(tmp_char = yywarn(0L, false)) {
+ ErrorBox(tmp_char);
+ bContinue = true; res = -1;
+ break;
+ }
+ i = do_fitfunc(data, text1, text2, 0L, &parxy, cmdxy, conv, (int)iter, &chi2);
+ Dlg->SetText(102, parxy);
+ if(i >1 || res == 7) {
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "The Levenberg-Marquart algorithm\nexited after %d iterations.\n\nChi2 = %g", i, chi2);
+#else
+ sprintf(TmpTxt, "The Levenberg-Marquart algorithm\nexited after %d iterations.\n\nChi2 = %g", i, chi2);
+#endif
+ 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);
+ Undo.SetDisp(cdisp);
+ while(*Undo.pcb > undo_level) Undo.Pop(cdisp);
+ if(res == 1){ //OK pressed
+ //get ranges for x- and y data (again).
+ chi2 = n_chi2;
+ if(Dlg->GetText(401, text1, 100) && (ssXref = (char*)realloc(ssXref, (cb = strlen(text1)+2))))
+ rlp_strcpy(ssXref, (int)cb, text1);
+ if(Dlg->GetText(403, text2, 100) && (ssYref = (char*)realloc(ssYref, (cb = strlen(text2)+2))))
+ rlp_strcpy(ssYref, (int)cb, 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, "Fitted function"))){
+ 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);
+ Command(CMD_ENDDIALOG, 0L, 0L); 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);
+ undo_flags = CheckNewFloat(&xstep, o_xstep, n_xstep, this, undo_flags);
+ if(undo_flags){
+ 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(0L, UNDO_CONTINUE);
+ }
+ undo_flags = CheckNewString(&parxy, o_parxy, parxy, this, undo_flags);
+ undo_flags = CheckNewString(&cmdxy, o_cmdxy, cmdxy, this, undo_flags);
+ if(undo_flags & UNDO_CONTINUE) {
+ Undo.ValInt(parent, (int*)&dirty, undo_flags);
+ Command(CMD_MRK_DIRTY, 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;
+ Command(CMD_ENDDIALOG, 0L, 0L);
+ }
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(o_parxy) free(o_parxy); if(o_cmdxy) free(o_cmdxy);
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Create a new normal quantile plot
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *NormQuantDlg_Tmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,-1,148,10,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,148,25,45,12\n"
+ "3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "4,10,100,ISPARENT | CHECKED,SHEET,1,5,10,130,80\n"
+ "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+ "100,101,,,LTEXT,2,10,30,60,8\n"
+ "101,,,LASTOBJ,RANGEINPUT,-15,20,40,100,10";
+
+bool
+NormQuant::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 25, 10, "Data"};
+ DlgInfo *QuantDlg;
+ void *dyndata[] = {(void*)&tab1, (void*)"range for variables"};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res;
+ char *mrk;
+ bool bContinue = false, bRet = false;
+
+ if(!parent || !data) return false;
+ if(!(QuantDlg = CompileDialog(NormQuantDlg_Tmpl, dyndata))) return false;
+ if(data->Command(CMD_GETMARK, &mrk, 0L))rlp_strcpy(TmpTxt, TMP_TXT_SIZE, mrk);
+ else UseRangeMark(data, 1, TmpTxt);
+ if(!(Dlg = new DlgRoot(QuantDlg, data)))return false;
+ hDlg = CreateDlgWnd("Normal Quantiles Plot", 50, 50, 420, 220, Dlg, 0x4L);
+ 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;
+ }
+ }while (res < 0);
+ if(res == 1 && Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)){
+ ssRef = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+ bRet = ProcessData();
+ }
+ CloseDlgWnd(hDlg); delete Dlg; free(QuantDlg);
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Contour Plot
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *ContourPlot_Tmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,-1,142,10,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,142,25,45,12\n"
+ "3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "4,5,100,ISPARENT | CHECKED,SHEET,1,5,10,131,100\n"
+ "5,6,200,ISPARENT,SHEET,5,5,10,131,100\n"
+ "6,10,300,ISPARENT,SHEET,13,5,10,131,100\n"
+ "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+ "100,+,,,LTEXT,2,10,30,60,8\n"
+ ".,.,,,RANGEINPUT,-15,20,40,100,10\n"
+ ".,.,,,LTEXT,3,10,55,60,8\n"
+ ".,.,,,RANGEINPUT,-16,20,65,100,10\n"
+ ".,.,,,LTEXT,4,10,80,60,8\n"
+ ".,,,,RANGEINPUT,-17,20,90,100,10\n"
+ "200,,201,CHECKED,GROUPBOX,6,10,30,121,70\n"
+ ".,+,,CHECKED,RADIO1,7,20,38,60,9\n"
+ ".,.,,,RADIO1,8,20,48,60,9\n"
+ ".,.,,,RADIO1,9,20,58,60,9\n"
+ ".,.,,,RADIO1,10,20,68,60,9\n"
+ ".,.,,,EDVAL1,11,50,78,30,10\n"
+ ".,,,,RTEXT,12,15,79,33,8\n"
+ "300,310,301,CHECKED,GROUPBOX,14,10,30,121,55\n"
+ ".,+,,CHECKED,RADIO1,15,20,38,60,9\n"
+ ".,.,,,RADIO1,16,20,48,60,9\n"
+ ".,.,,,RADIO1,17,20,58,60,9\n"
+ ".,,,,RADIO1,18,20,68,60,9\n"
+ "310,,,LASTOBJ,CHECKBOX,19,20,90,60,9";
+
+bool
+ContourPlot::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 25, 10, "Data"};
+ TabSHEET tab2 = {25,56, 10, "Details"};
+ TabSHEET tab3 = {56,92, 10, "Symbols"};
+ void *dyndata[] = {(void*)&tab1, (void*)"range for x-data", (void*)"range for y-data",
+ (void*)"range for z-data", (void*)&tab2, (void*)" super rectangle ", (void*)" at z minimum",
+ (void*)" at z maximum", (void*)" at z mean", (void*)" at user defined level,", (void*)&sr_zval, (void*)"z =",
+ (void*)&tab3, (void*)" draw symbols ", (void*)" no symbols", (void*)" draw minima", (void*)" draw maxima",
+ (void*)" draw all source data", (void*)" symbols with labels"};
+ DlgInfo *DlgInf;
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res;
+ bool bRet = false, bContinue = false;
+
+ if(!data || !parent)return false;
+ if(!(DlgInf = CompileDialog(ContourPlot_Tmpl, dyndata)))return false;
+ UseRangeMark(data, 1, TmpTxt, TmpTxt+100, TmpTxt+200);
+ if(!(Dlg = new DlgRoot(DlgInf, data)))return false;
+ hDlg = CreateDlgWnd((char*)"Create Contour Plot", 50, 50, 388, 260, Dlg, 0x4L);
+ 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:
+ res = -1; bContinue = false;
+ if(Dlg->GetCheck(202))flags = 0x01;
+ else if(Dlg->GetCheck(203))flags = 0x02;
+ else if(Dlg->GetCheck(204)){
+ flags = 0x03; Dlg->GetValue(205, &sr_zval);
+ }
+ else flags = 0x00;
+ if(Dlg->GetCheck(302)) flags |= 0x10;
+ else if(Dlg->GetCheck(303)) flags |= 0x20;
+ else if(Dlg->GetCheck(304)) flags |= 0x30;
+ if(Dlg->GetCheck(310)) flags |= 0x40;
+ if(Dlg->GetText(101, TmpTxt, 100) && Dlg->GetText(103, TmpTxt+100, 100)
+ && Dlg->GetText(105, TmpTxt+200, 100)){
+ if(LoadData(TmpTxt, TmpTxt+100, TmpTxt+200)) {
+ ssRefX = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+ ssRefY = (char*)memdup(TmpTxt+100, (int)strlen(TmpTxt+100)+1, 0);
+ ssRefZ = (char*)memdup(TmpTxt+200, (int)strlen(TmpTxt+200)+1, 0);
+ res = 1; bRet = true;
+ }
+ }
+ if(res != 1) {
+ bContinue = true;
+ ErrorBox("Missing or too\nfew data\n");
+ }
+ break;
+ }
+ }while (res <0);
+ CloseDlgWnd(hDlg); delete Dlg; free(DlgInf);
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Create a three dimensional graph
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *AddAxis3D_Tmpl =
+ "1,2,,DEFAULT, PUSHBUTTON,-1,148,10,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,148,25,45,12\n"
+ "3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "4,5,50,TOUCHEXIT | ISPARENT,SHEET,1,5,10,130,148\n"
+ "5,6,200,ISPARENT | CHECKED,SHEET,2,5,10,130,148\n"
+ "6,20,300,ISPARENT,SHEET,3,5,10,130,148\n"
+ "20,,,NOSELECT,ODBUTTON,22,142,65,45,45\n"
+ "50,51,100,ISPARENT | CHECKED,GROUPBOX,4,10,30,120,36\n"
+ "51,120,,,CHECKBOX,5,17,37,80,8\n"
+ "100,101,,,RTEXT,6,10,51,35,8\n"
+ "101,102,,,EDVAL1,7,48,51,32,10\n"
+ "102,103,,,CTEXT,8,81,51,11,8\n"
+ "103,,,,EDVAL1,9,93,51,32,10\n"
+ "120,,121,ISPARENT | CHECKED,GROUPBOX,10,10,72,120,20\n"
+ "121,122,,,RTEXT,11,10,77,25,8\n"
+ "122,123,,,EDVAL1,12,37,77,25,10\n"
+ "123,124,,,LTEXT,-3,63,77,10,8\n"
+ "124,125,,,RTEXT,-11,73,77,25,8\n"
+ "125,130,,OWNDIALOG,COLBUTT,14,100,77,25,10\n"
+ "130,131,,ISPARENT | CHECKED,GROUPBOX,15,10,98,120,20\n"
+ "131,,,,EDTEXT,0,15,103,110,10\n"
+ "200,201,,,LTEXT,16,10,23,70,9\n"
+ "201,202,,CHECKED | EXRADIO,ODBUTTON,17,20,35,25,25\n"
+ "202,203,,EXRADIO,ODBUTTON,17,45,35,25,25\n"
+ "203,204,,EXRADIO,ODBUTTON,17,70,35,25,25\n"
+ "204,205,,EXRADIO,ODBUTTON,17,95,35,25,25\n"
+ "205,206,,EXRADIO,ODBUTTON,17,20,60,25,25\n"
+ "206,207,,EXRADIO,ODBUTTON,17,45,60,25,25\n"
+ "207,208,,EXRADIO,ODBUTTON,17,70,60,25,25\n"
+ "208,209,,EXRADIO,ODBUTTON,17,95,60,25,25\n"
+ "209,210,,EXRADIO,ODBUTTON,17,20,85,25,25\n"
+ "210,211,,EXRADIO,ODBUTTON,17,45,85,25,25\n"
+ "211,212,,EXRADIO,ODBUTTON,17,70,85,25,25\n"
+ "212,213,,EXRADIO,ODBUTTON,17,95,85,25,25\n"
+ "213,214,,,LTEXT,-12,20,120,70,9\n"
+ "214,215,,,LTEXT,-13,20,132,70,9\n"
+ "215,216,,,LTEXT,-14,20,144,70,9\n"
+ "216,217,250,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "217,218,260,HIDDEN | ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "218,,270,HIDDEN |ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "250,251,,,LTEXT,19,10,110,70,9\n"
+ "251,252,,,EDVAL1,0,58,120,32,10\n"
+ "252,253,,,LTEXT,-3,92,120,20,9\n"
+ "253,254,,,EDVAL1,0,43,132,32,10\n"
+ "254,255,,,CTEXT,-7,75,132,7,9\n"
+ "255,256,,,EDVAL1,0,82,132,32,10\n"
+ "256,257,,,LTEXT,-3,116,132,20,9\n"
+ "257,268,,,EDVAL1,0,58,144,32,10\n"
+ "260,261,,,LTEXT,20,10,110,70,9\n"
+ "261,262,,,EDVAL1,0,43,120,32,10\n"
+ "262,263,,,CTEXT,-7,75,120,7,9\n"
+ "263,264,,,EDVAL1,0,82,120,32,10\n"
+ "264,265,,,LTEXT,-3,116,120,20,9\n"
+ "265,266,,,EDVAL1,0,58,132,32,10\n"
+ "266,267,,,LTEXT,-3,92,132,20,9\n"
+ "267,268,,,EDVAL1,0,58,144,32,10\n"
+ "268,,,,LTEXT,-3,92,144,20,9\n"
+ "270,271,,,LTEXT,21,10,110,70,9\n"
+ "271,272,,,EDVAL1,0,58,120,32,10\n"
+ "272,273,,,LTEXT,-3,92,120,20,9\n"
+ "273,274,,,EDVAL1,0,58,132,32,10\n"
+ "274,275,,,LTEXT,-3,92,132,20,9\n"
+ "275,276,,,EDVAL1,0,43,144,32,10\n"
+ "276,277,,,CTEXT,-7,75,144,7,9\n"
+ "277,278,,,EDVAL1,0,82,144,32,10\n"
+ "278,,,,LTEXT,-3,116,144,20,9\n"
+ "300,,,LASTOBJ | NOSELECT,ODBUTTON,18,15,30,110,140";
+bool
+Plot3D::AddAxis()
+{
+ TabSHEET tab1 = {0, 25, 10, "Axis"};
+ TabSHEET tab2 = {25, 52, 10, "Style"};
+ TabSHEET tab3 = {52, 78, 10, "Plots"};
+ AxisDEF axis, ax_def[12], *caxdef;
+ double sizAxLine = DefSize(SIZE_AXIS_LINE);
+ DWORD colAxis = 0x0;
+ void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)" scaling ", (void*)" automatic scaling",
+ (void*)"axis from", (void*)&axis.min, (void*)"to", (void*)&axis.max, (void*)" line ", (void*)"width",
+ (void*)&sizAxLine, (void*)0L, (void *)&colAxis, (void*)" axis label ", (void*)"select a template:",
+ (void*)(OD_NewAxisTempl3D), (void*)OD_axisplot, (void*)"y-axis at:", (void*)"x-axis at:", (void*)"z-axis at:",
+ (void*)(OD_AxisDesc3D)};
+ DlgInfo *NewAxisDlg;
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, j, res, currTempl = 201, ax_type = 2, tick_type = 2;
+ double tlb_dx, tlb_dy, lb_x, lb_y;
+ TextDEF label_def, tlbdef;
+ anyOutput *cdisp = Undo.cdisp;
+ Axis *the_new, **tmpAxes;
+ bool bAxis = false, bRet = false;
+ char **names;
+ GraphObj **somePlots;
+ Label *label;
+
+ if(!Axes || nAxes < 3 || !(NewAxisDlg = CompileDialog(AddAxis3D_Tmpl, dyndata))) return false;
+ lb_y = 0.0; lb_x = DefSize(SIZE_AXIS_TICKS)*4.0;
+ tlb_dy = 0.0; tlb_dx = -DefSize(SIZE_AXIS_TICKS)*2.0;
+ tlbdef.ColTxt = colAxis; tlbdef.ColBg = 0x00ffffffL;
+ tlbdef.RotBL = tlbdef.RotCHAR = 0.0f; tlbdef.fSize = DefSize(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(!(names = (char**)calloc(nscp+2, sizeof(char*))))return false;
+ if(!(somePlots = (GraphObj**)calloc(nscp+2, sizeof(GraphObj*))))return false;
+ for(i = 0; i < 12; i++) {
+ ax_def[i].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK;
+ ax_def[i].owner = 0L; ax_def[i].breaks = 0L;
+ ax_def[i].Center.fx = ax_def[i].Center.fy = ax_def[i].Radius = 0.0;
+ ax_def[i].nBreaks = 0L;
+ }
+ //y-axes
+ ax_def[0].min = ax_def[1].min = ax_def[2].min = ax_def[3].min = (caxdef = Axes[1]->GetAxis())->min;
+ ax_def[0].max = ax_def[1].max = ax_def[2].max = ax_def[3].max = caxdef->max;
+ ax_def[0].Start = ax_def[1].Start = ax_def[2].Start = ax_def[3].Start = caxdef->Start;
+ ax_def[0].Step = ax_def[1].Step = ax_def[2].Step = ax_def[3].Step = caxdef->Step;
+ ax_def[0].loc[0].fy = ax_def[1].loc[0].fy = ax_def[2].loc[0].fy = ax_def[3].loc[0].fy = caxdef->loc[0].fy;
+ ax_def[0].loc[1].fy = ax_def[1].loc[1].fy = ax_def[2].loc[1].fy = ax_def[3].loc[1].fy = caxdef->loc[1].fy;
+ ax_def[0].loc[0].fx = ax_def[0].loc[1].fx = ax_def[3].loc[0].fx = ax_def[3].loc[1].fx = cu1.fx;
+ ax_def[1].loc[0].fx = ax_def[1].loc[1].fx = ax_def[2].loc[0].fx = ax_def[2].loc[1].fx = cu2.fx;
+ ax_def[0].loc[0].fz = ax_def[0].loc[1].fz = ax_def[1].loc[0].fz = ax_def[1].loc[1].fz = cu2.fz;
+ ax_def[2].loc[0].fz = ax_def[2].loc[1].fz = ax_def[3].loc[0].fz = ax_def[3].loc[1].fz = cu1.fz;
+ ax_def[1].flags = ax_def[2].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_POSTICKS;
+ ax_def[0].flags = ax_def[3].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_NEGTICKS;
+ //x-axes
+ ax_def[4].min = ax_def[6].min = ax_def[8].min = ax_def[10].min = (caxdef = Axes[0]->GetAxis())->min;
+ ax_def[4].max = ax_def[6].max = ax_def[8].max = ax_def[10].max = caxdef->max;
+ ax_def[4].Start = ax_def[6].Start = ax_def[8].Start = ax_def[10].Start = caxdef->Start;
+ ax_def[4].Step = ax_def[6].Step = ax_def[8].Step = ax_def[10].Step = caxdef->Step;
+ ax_def[4].loc[0].fx = ax_def[6].loc[0].fx = ax_def[8].loc[0].fx = ax_def[10].loc[0].fx = caxdef->loc[0].fx;
+ ax_def[4].loc[1].fx = ax_def[6].loc[1].fx = ax_def[8].loc[1].fx = ax_def[10].loc[1].fx = caxdef->loc[1].fx;
+ ax_def[4].loc[0].fy = ax_def[4].loc[1].fy = ax_def[6].loc[0].fy = ax_def[6].loc[1].fy = cu1.fy;
+ ax_def[8].loc[0].fy = ax_def[8].loc[1].fy = ax_def[10].loc[0].fy = ax_def[10].loc[1].fy = cu2.fy;
+ ax_def[4].loc[0].fz = ax_def[4].loc[1].fz = ax_def[8].loc[0].fz = ax_def[8].loc[1].fz = cu2.fz;
+ ax_def[6].loc[0].fz = ax_def[6].loc[1].fz = ax_def[10].loc[0].fz = ax_def[10].loc[1].fz = cu1.fz;
+ ax_def[4].flags = ax_def[6].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_NEGTICKS;
+ ax_def[8].flags = ax_def[10].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_POSTICKS;
+ //z-axes
+ ax_def[5].min = ax_def[7].min = ax_def[9].min = ax_def[11].min = (caxdef = Axes[2]->GetAxis())->min;
+ ax_def[5].max = ax_def[7].max = ax_def[9].max = ax_def[11].max = caxdef->max;
+ ax_def[5].Start = ax_def[7].Start = ax_def[9].Start = ax_def[11].Start = caxdef->Start;
+ ax_def[5].Step = ax_def[7].Step = ax_def[9].Step = ax_def[11].Step = caxdef->Step;
+ ax_def[5].loc[0].fz = ax_def[7].loc[0].fz = ax_def[9].loc[0].fz = ax_def[11].loc[0].fz = caxdef->loc[0].fz;
+ ax_def[5].loc[1].fz = ax_def[7].loc[1].fz = ax_def[9].loc[1].fz = ax_def[11].loc[1].fz = caxdef->loc[1].fz;
+ ax_def[5].loc[0].fx = ax_def[5].loc[1].fx = ax_def[9].loc[0].fx = ax_def[9].loc[1].fx = cu2.fx;
+ ax_def[7].loc[0].fx = ax_def[7].loc[1].fx = ax_def[11].loc[0].fx = ax_def[11].loc[1].fx = cu1.fx;
+ ax_def[5].loc[0].fy = ax_def[5].loc[1].fy = ax_def[7].loc[0].fy = ax_def[7].loc[1].fy = cu1.fy;
+ ax_def[9].loc[0].fy = ax_def[9].loc[1].fy = ax_def[11].loc[0].fy = ax_def[11].loc[1].fy = cu2.fy;
+ ax_def[5].flags = ax_def[9].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_POSTICKS;
+ ax_def[7].flags = ax_def[11].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_NEGTICKS;
+ //the default axis is the first
+ memcpy(&axis, &ax_def[0], sizeof(AxisDEF));
+ if(names[0] = (char*)malloc(10)) rlp_strcpy(names[0], 10, "[none]");
+ for(i = 0, j = 1; i < nscp; i++) {
+ if(Sc_Plots[i] && Sc_Plots[i]->name){
+ names[j] = (char*)memdup(Sc_Plots[i]->name, (int)strlen(Sc_Plots[i]->name)+1, 0);
+ somePlots[j++] = Sc_Plots[i];
+ }
+ }
+ OD_axisplot(OD_ACCEPT, 0L, 0L, 0L, names, 0);
+ if(!(Dlg = new DlgRoot(NewAxisDlg, data)))return false;
+ Dlg->SetValue(251, ax_def[0].loc[0].fx); Dlg->SetValue(253, ax_def[0].loc[0].fy);
+ Dlg->SetValue(255, ax_def[0].loc[1].fy); Dlg->SetValue(257, ax_def[0].loc[0].fz);
+ if(!nscp){ //must be root plot3d to link to plot
+ Dlg->ShowItem(6, false);
+ }
+ hDlg = CreateDlgWnd("Add Axis to 3D Plot", 50, 50, 400, 360, Dlg, 0x4L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res){
+ case 4: //the axis sheet
+ res = -1;
+ bAxis = true;
+ break;
+ //axis templates
+ case 201: case 202: case 203: case 204: case 205: case 206:
+ case 207: case 208: case 209: case 210: case 211: case 212:
+ i = currTempl-201;
+ switch(currTempl){
+ case 201: case 202: case 203: case 204: //prevoius is y-template
+ Dlg->GetValue(251, &axis.loc[0].fx); Dlg->GetValue(253, &axis.loc[0].fy);
+ Dlg->GetValue(255, &axis.loc[1].fy); Dlg->GetValue(257, &axis.loc[0].fz);
+ axis.loc[1].fx = axis.loc[0].fx; axis.loc[1].fz = axis.loc[0].fz;
+ memcpy(&ax_def[i], &axis, sizeof(AxisDEF));
+ break;
+ case 205: case 207: case 209: case 211: //prevoius is x-template
+ Dlg->GetValue(261, &axis.loc[0].fx); Dlg->GetValue(263, &axis.loc[1].fx);
+ Dlg->GetValue(265, &axis.loc[0].fy); Dlg->GetValue(267, &axis.loc[0].fz);
+ axis.loc[1].fy = axis.loc[0].fy; axis.loc[1].fz = axis.loc[0].fz;
+ memcpy(&ax_def[i], &axis, sizeof(AxisDEF));
+ break;
+ case 206: case 208: case 210: case 212: //previous is z-template
+ Dlg->GetValue(271, &axis.loc[0].fx); Dlg->GetValue(273, &axis.loc[0].fy);
+ Dlg->GetValue(275, &axis.loc[0].fz); Dlg->GetValue(277, &axis.loc[1].fz);
+ axis.loc[1].fx = axis.loc[0].fx; axis.loc[1].fy = axis.loc[0].fy;
+ memcpy(&ax_def[i], &axis, sizeof(AxisDEF));
+ break;
+ }
+ i = res-201;
+ switch (res) {
+ case 201: case 202: case 203: case 204: //y-template
+ Dlg->ShowItem(216, true); Dlg->ShowItem(217, false);
+ Dlg->ShowItem(218, false);
+ Dlg->SetValue(251, ax_def[i].loc[0].fx); Dlg->SetValue(253, ax_def[i].loc[0].fy);
+ Dlg->SetValue(255, ax_def[i].loc[1].fy); Dlg->SetValue(257, ax_def[i].loc[0].fz);
+ ax_type = tick_type = 2; tlb_dy = 0.0;
+ if(res == 202 || res == 203){
+ tlb_dx = DefSize(SIZE_AXIS_TICKS)*2.0;
+ tlbdef.Align = TXA_VCENTER | TXA_HLEFT;
+ }
+ else {
+ tlb_dx = -DefSize(SIZE_AXIS_TICKS)*2.0;
+ tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
+ }
+ break;
+ case 205: case 207: case 209: case 211: //x-template
+ Dlg->ShowItem(216, false); Dlg->ShowItem(217, true);
+ Dlg->ShowItem(218, false);
+ Dlg->SetValue(261, ax_def[i].loc[0].fx); Dlg->SetValue(263, ax_def[i].loc[1].fx);
+ Dlg->SetValue(265, ax_def[i].loc[0].fy); Dlg->SetValue(267, ax_def[i].loc[0].fz);
+ ax_type = 1; tick_type = 3; tlb_dx = 0;
+ if(res == 205 || res == 207){
+ tlb_dy = DefSize(SIZE_AXIS_TICKS)*2.0;
+ tlbdef.Align = TXA_VTOP | TXA_HCENTER;
+ }
+ else {
+ tlb_dy = -DefSize(SIZE_AXIS_TICKS)*2.0;
+ tlbdef.Align = TXA_VBOTTOM | TXA_HCENTER;
+ }
+ break;
+ case 206: case 208: case 210: case 212: //z-template
+ Dlg->ShowItem(216, false); Dlg->ShowItem(217, false);
+ Dlg->ShowItem(218, true);
+ Dlg->SetValue(271, ax_def[i].loc[0].fx); Dlg->SetValue(273, ax_def[i].loc[0].fy);
+ Dlg->SetValue(275, ax_def[i].loc[0].fz); Dlg->SetValue(277, ax_def[i].loc[1].fz);
+ ax_type = 3; tick_type = 2; tlb_dy = 0;
+ if(res == 206 || res == 210){
+ tlb_dx = DefSize(SIZE_AXIS_TICKS)*2.0;
+ tlbdef.Align = TXA_VCENTER | TXA_HLEFT;
+ }
+ else {
+ tlb_dx = -DefSize(SIZE_AXIS_TICKS)*2.0;
+ tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
+ }
+ break;
+ }
+ memcpy(&axis, &ax_def[res-201], sizeof(AxisDEF));
+ currTempl = res;
+ Dlg->DoPlot(0L);
+ res = -1;
+ break;
+ }
+ }while (res < 0);
+ if(res == 1) {
+ Undo.SetDisp(cdisp);
+ Dlg->GetValue(122, &sizAxLine); Dlg->GetColor(125, &colAxis);
+ 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;
+ tlbdef.ColTxt = colAxis;
+ label_def.ColTxt = colAxis; label_def.ColBg = 0x00ffffffL;
+ label_def.fSize = DefSize(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;
+ if(Dlg->GetCheck(51)) axis.flags |= AXIS_AUTOSCALE;
+ if(the_new = new Axis(this, data, &axis, 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);
+ the_new->type = ax_type;
+ the_new->Command(CMD_TICK_TYPE, &tick_type, 0L);
+ if(Dlg->GetText(131, TmpTxt, TMP_TXT_SIZE)) 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 < nAxes && Axes[i]; i++);
+ if(i < nAxes) {
+ Undo.SetGO(this, (GraphObj**)(&Axes[i]), the_new, 0L);
+ bRet = true;
+ }
+ else {
+ if(tmpAxes = (Axis**)calloc(nAxes+1, sizeof(Axis*))){
+ memcpy(tmpAxes, Axes, nAxes * sizeof(Axis*));
+ Undo.ListGOmoved((GraphObj**)Axes, (GraphObj**)tmpAxes, nAxes);
+ Undo.SetGO(this, (GraphObj**)(&tmpAxes[nAxes]), the_new, 0L);
+ free(Axes); Axes = tmpAxes;
+ i = nAxes++; bRet = true;
+ }
+ }
+ 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; free(NewAxisDlg);
+ if(names) {
+ for(j = 0; names[j]; j++) if(names[j]) free(names[j]);
+ free(names);
+ }
+ if(somePlots) free(somePlots);
+ return bRet;
+}
+
+static char *AddPlot3Dtmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,-1,150,10,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,150,25,45,12\n"
+ "3,,560,ISPARENT | CHECKED,GROUPBOX,1,5,10,140,70\n"
+ "560,561,,EXRADIO | CHECKED,ODBUTTON,2,12,20,25,25\n"
+ "561,562,,EXRADIO,ODBUTTON,2,37,20,25,25\n"
+ "562,563,,EXRADIO,ODBUTTON,2,62,20,25,25\n"
+ "563,564,,EXRADIO,ODBUTTON,2,87,20,25,25\n"
+ "564,565,,EXRADIO,ODBUTTON,2,112,20,25,25\n"
+ "565,566,,EXRADIO,ODBUTTON,2,12,45,25,25\n"
+ "566,567,,EXRADIO,ODBUTTON,2,37,45,25,25\n"
+ "567,,,LASTOBJ | EXRADIO,ODBUTTON,2,62,45,25,25";
+
+bool
+Plot3D::AddPlot(int family)
+{
+ void *dyndata[] = {(void *)" select template ", (void*)(OD_PlotTempl)};
+ DlgInfo *PlotsDlg = CompileDialog(AddPlot3Dtmpl, dyndata);
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, cSel = 560;
+ bool bRet = false;
+ Plot *p;
+
+ if(!(Dlg = new DlgRoot(PlotsDlg, data)))return false;
+ Dlg->bModal = false;
+ hDlg = CreateDlgWnd("Add Plot", 50, 50, 410, 204, Dlg, 0x4L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 560: case 561: case 562: case 563: case 564:
+ case 565: case 566: case 567:
+ if(res == cSel) res = 1;
+ else {
+ cSel = res; res = -1;
+ }
+ break;
+ }
+ }while (res < 0);
+ if(res == 1){ //OK pressed
+ switch (cSel) {
+ case 560: p = new Scatt3D(this, data, 0x01); break;
+ case 561: p = new Scatt3D(this, data, 0x02); break;
+ case 562: p = new Scatt3D(this, data, 0x04); break;
+ case 563: p = new BubblePlot3D(this, data); break;
+ case 564: p = new Scatt3D(this, data, 0x2000); break;
+ case 565: p = new Func3D(this, data); break;
+ case 566: p = new FitFunc3D(this, data); break;
+ case 567: p = new Scatt3D(this, data, 0x4000); break;
+ default: p = 0L; break;
+ }
+ if(p && p->PropertyDlg()) {
+ if(!(bRet = Command(CMD_DROP_PLOT, p, (anyOutput *)NULL))) delete p;
+ }
+ else if(p) delete p;
+ }
+ CloseDlgWnd(hDlg); delete Dlg; free(PlotsDlg);
+ 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 bar chart
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *Base25D_DlgTmpl =
+ "1,2,,DEFAULT, PUSHBUTTON,-1,158,10,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,158,25,45,12\n"
+ "3,,10,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "10,11,100,ISPARENT | CHECKED,SHEET,1,5,10,140,100\n"
+ "11,12,200,ISPARENT,SHEET,2,5,10,140,100\n"
+ "12,20,300,ISPARENT,SHEET,3,5,10,140,100\n"
+ "20,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+ "100,101,,,LTEXT,4,15,30,60,8\n"
+ "101,152,,,RANGEINPUT,5,25,40,100,10\n"
+ "152,153,,ISPARENT | CHECKED,GROUPBOX,6,12,60,128,45\n"
+ "153,154,,,LTEXT,0,25,65,60,8\n"
+ "154,155,,,RANGEINPUT,5,25,75,100,10\n"
+ "155,156,,,PUSHBUTTON,-8,95,87,30,12\n"
+ "156,,,,PUSHBUTTON,-9,60,87,35,12\n"
+ "200,201,,,LTEXT,7,20,35,80,8\n"
+ "201,202,,,RTEXT,8,48,45,13,8\n"
+ "202,203,,,EDVAL1,9,65,45,25,10\n"
+ "203,204,,,RTEXT,10,48,57,13,8\n"
+ "204,,,,EDVAL1,11,65,57,25,10\n"
+ "300,301,,,RADIO1,12,15,35,80,9\n"
+ "301,302,,ODEXIT,COLBUTT,13,110,35,20,10\n"
+ "302,303,,CHECKED,RADIO1,14,15,55,80,9\n"
+ "303,304,,ODEXIT,COLBUTT,15,25,70,10,10\n"
+ "304,305,,ODEXIT,COLBUTT,16,37,70,10,10\n"
+ "305,306,,ODEXIT,COLBUTT,17,49,70,10,10\n"
+ "306,307,,ODEXIT,COLBUTT,18,61,70,10,10\n"
+ "307,308,,ODEXIT,COLBUTT,19,73,70,10,10\n"
+ "308,309,,ODEXIT,COLBUTT,20,85,70,10,10\n"
+ "309,310,,ODEXIT,COLBUTT,21,97,70,10,10\n"
+ "310,,,LASTOBJ | ODEXIT,COLBUTT,22,109,70,10,10";
+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;
+ double start_z = 1.0;
+ void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"range for common x values",
+ (void*)TmpTxt, (void*)" ranges for y values ", (void*)"distances:", (void*)"start z =",
+ (void*)&start_z, (void*)"step =", (void*)&dspm.fz, (void*)" common color for columns:",
+ (void*)&defcol, (void*)" increment color scheme:", (void*)&colarr[0], (void*)&colarr[1],
+ (void*)&colarr[2], (void*)&colarr[3], (void*)&colarr[4], (void*)&colarr[5], (void*)&colarr[6],
+ (void*)&colarr[7]};
+ DlgInfo *Bar3D_Dlg = CompileDialog(Base25D_DlgTmpl, dyndata);
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, j, ic, res, currYR=0, maxYR=0, nx=0, ny, rx, cx, ry, cy, oax;
+ char **rd = 0L;
+ 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(!parent || !data) return false;
+ if(plots) {
+ //Plots alredy defined: jump to config dialog
+ return false;
+ }
+ if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
+ TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return false;
+ if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
+ for(i=100, j= 0; i <= 1000; i +=100){
+ if(TmpTxt[i]) rd[j++] = (char*)memdup(TmpTxt+i, (int)strlen(TmpTxt+i)+1, 0);
+ }
+ if(j) maxYR = j-1;
+ }
+ if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
+ if(!(Dlg = new DlgRoot(Bar3D_Dlg, data))) return false;
+ if(rd && rd[currYR] && *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
+ hDlg = CreateDlgWnd("Create 3D Bar Chart", 50, 50, 420, 260, Dlg, 0x4L);
+ do {
+ if(updateYR) {
+ if(currYR >0) {
+ Dlg->ShowItem(156, true);
+ Dlg->Activate(101, false);
+ }
+ else {
+ Dlg->ShowItem(156, false);
+ Dlg->Activate(101, true);
+ }
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "y-values # %d/%d", currYR+1, maxYR+1);
+#else
+ sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
+#endif
+ //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 = DefSize(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;
+ }
+ 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;
+ }
+ if(rY) {
+ plot->data_desc = rY->RangeDesc(data, 1);
+ 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(rX) delete rX; if(rY) delete rY; free(Bar3D_Dlg);
+ 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;
+ double start_z = 1.0;
+ void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"range for common x values",
+ (void*)TmpTxt, (void*)" ranges for y values ", (void*)"distances:", (void*)"start z =",
+ (void*)&start_z, (void*)"step =", (void*)&dspm.fz, (void*)" common color for ribbons:",
+ (void*)&defcol, (void*)" increment color scheme:", (void*)&colarr[0], (void*)&colarr[1],
+ (void*)&colarr[2], (void*)&colarr[3], (void*)&colarr[4], (void*)&colarr[5], (void*)&colarr[6],
+ (void*)&colarr[7]};
+ DlgInfo *Bar3D_Dlg = CompileDialog(Base25D_DlgTmpl, dyndata);
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, j, res, currYR=0, maxYR=0, nx=0, ny, oax;
+ char **rd = 0L, xrange[100];
+ double fz;
+ bool updateYR = true, bContinue = false, bRet = false, bUseSch;
+ AccRange *rX = 0L, *rY = 0L;
+ AxisDEF *ax;
+ Ribbon *plot;
+
+ if(!parent || !data) return false;
+ if(plots) {
+ //Plots alredy defined: jump to config dialog
+ return false;
+ }
+ if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
+ TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return false;
+ if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
+ for(i=100, j= 0; i <= 1000; i +=100){
+ if(TmpTxt[i]) rd[j++] = (char*)memdup(TmpTxt+i, (int)strlen(TmpTxt+i)+1, 0);
+ }
+ if(j) maxYR = j-1;
+ }
+ if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return false;
+ if(!(Dlg = new DlgRoot(Bar3D_Dlg, data)))return false;
+ if(rd && rd[currYR] && *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
+ hDlg = CreateDlgWnd("Create 3D Ribbon Chart", 50, 50, 420, 260, Dlg, 0x4L);
+ do {
+ if(updateYR) {
+ if(currYR >0) {
+ Dlg->ShowItem(156, true); Dlg->Activate(101, false);
+ }
+ else {
+ Dlg->ShowItem(156, false); Dlg->Activate(101, true);
+ }
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "y-values # %d/%d", currYR+1, maxYR+1);
+#else
+ sprintf(TmpTxt,"y-values # %d/%d", currYR+1, maxYR+1);
+#endif
+ //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;
+ Dlg->GetText(101, TmpTxt+100, 100);
+ 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*))) {
+ Dlg->GetText(101, xrange, 100);
+ for(i = 0; i < maxYR; i++, fz += dspm.fz) {
+ if(plot = new Ribbon(this, data, fz, dspm.fz, xrange, 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; free(Bar3D_Dlg);
+ 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, CHECKED, 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, RANGEINPUT, text1, 20, 35, 100, 10},
+ {102, 103, 0, 0x0L, LTEXT, (void*)"range for Y Data", 10, 48, 60, 8},
+ {103, 104, 0, 0x0L, RANGEINPUT, text2, 20, 58, 100, 10},
+ {104, 105, 0, 0x0L, LTEXT, (void*)"range for Z Data", 10, 71, 60, 8},
+ {105, 106, 0, 0x0L, RANGEINPUT, 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, RANGEINPUT, 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, count;
+ int cx, rx, cy, ry, cz, rz, cr, rr, s_type = 5;
+ bool bRet = false;
+ double fx, fy, fz, fr;
+ Sphere **Balls;
+ AccRange *rX, *rY, *rZ, *rR;
+ Scatt3D *sc_plot;
+
+ if(!data || !parent)return false;
+ UseRangeMark(data, 1, text1, text2, text3, text4);
+ if(!(Dlg = new DlgRoot(BubDlg3D, data)))return false;
+ rX = rY = rZ = rR = 0L;
+ Dlg->SetCheck(410 + AxisTempl3D, 0L, true);
+ hDlg = CreateDlgWnd("Bubble Plot 3D", 50, 50, 388, 340, Dlg, 0x4L);
+ 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:
+ s_type = 5; //absolute size, but use 5 to distinguish
+ res = -1; // from symbol
+ break;
+ 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, TMP_TXT_SIZE)) rX = new AccRange(TmpTxt);
+ if(Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE)) rY = new AccRange(TmpTxt);
+ if(Dlg->GetText(105, TmpTxt, TMP_TXT_SIZE)) rZ = new AccRange(TmpTxt);
+ if(Dlg->GetText(151, TmpTxt, TMP_TXT_SIZE)) 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 || parent->Id == GO_FUNC3D || parent->Id == GO_FITFUNC3D) {
+ 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;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Create a 3D function plot
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Func3D::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 37, 10, "Function"};
+ TabSHEET tab2 = {37, 65, 10, "Style"};
+ FillDEF newFill;
+ DlgInfo FuncDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 160, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 160, 25, 45, 12},
+ {3, 10, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
+ {4, 5, 100, ISPARENT, SHEET, &tab1, 5, 10, 149, 134},
+ {5, 50, 300, ISPARENT | CHECKED, SHEET, &tab2, 5, 10, 149, 134},
+ {10, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
+ {50, 0, 0, NOSELECT, ODBUTTON, (void*)(OD_AxisDesc3D), 160, 85, 45, 45},
+ {100, 101, 0, 0x0L, LTEXT, (void*)"plot user defined function", 10, 30, 100, 8},
+ {101, 102, 0, 0x0L, RTEXT, (void*)"where x=", 10, 50, 28, 8},
+ {102, 103, 0, 0x0L, EDVAL1, &x1, 38, 50, 25, 10},
+ {103, 104, 0, 0x0L, RTEXT, (void*)"until", 61, 50, 17, 8},
+ {104, 105, 0, 0x0L, EDVAL1, &x2, 78, 50, 25, 10},
+ {105, 106, 0, 0x0L, RTEXT, (void*)"step", 102, 50, 17, 8},
+ {106, 107, 0, 0x0L, EDVAL1, &xstep, 119, 50, 25, 10},
+ {107, 108, 0, 0x0L, RTEXT, (void*)"z=", 10, 62, 28, 8},
+ {108, 109, 0, 0x0L, EDVAL1, &z1, 38, 62, 25, 10},
+ {109, 110, 0, 0x0L, EDVAL1, &z2, 78, 62, 25, 10},
+ {110, 150, 0, 0x0L, EDVAL1, &zstep, 119, 62, 25, 10},
+ {150, 200, 0, 0x0L, RTEXT, (void*)"y=", 10, 91, 10, 8},
+ {200, 0, 0, 0x0L, TEXTBOX, (void*)cmdxy, 22, 89, 122, 40},
+ {300, 301, 500, CHECKED, GROUPBOX, (void*)" grid ", 10, 40, 140, 100},
+ {301, 305, 400, HIDDEN | CHECKED, GROUPBOX, (void*)" surface ", 10, 40, 140, 100},
+ {305, 306, 0, CHECKED | TOUCHEXIT, RADIO1, (void*) " grid lines", 15, 25, 50, 10},
+ {306, 0, 0, TOUCHEXIT, RADIO1, (void*) " surface", 85, 25, 50, 10},
+ {400, 401, 0, 0x0L, RTEXT, (void*)"grid line width", 38, 50, 40, 8},
+ {401, 402, 0, 0x0L, EDVAL1, &Line.width, 80, 50, 25, 10},
+ {402, 403, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 107, 50, 20, 8},
+ {403, 404, 0, 0x0L, RTEXT, (void*)"grid line color", 38, 62, 40, 8},
+ {404, 405, 0, OWNDIALOG, COLBUTT, (void *)&Line.color, 80, 62, 25, 10},
+ {405, 406, 0, 0x0L, RTEXT,(void*)"plane color" , 38, 74, 40, 8},
+ {406, 0, 0, OWNDIALOG, SHADE3D, &newFill, 80, 74, 25, 10},
+ {500, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)OD_linedef, 15, 45, 130, 100}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, undo_level = *Undo.pcb;
+ bool bRet = false, bNew = true;
+ DWORD undo_flags = 0L;
+ LineDEF newLine;
+ double o_x1, n_x1, o_x2, n_x2, o_xstep, n_xstep;
+ double o_z1, n_z1, o_z2, n_z2, o_zstep, n_zstep;
+ anyOutput *cdisp = Undo.cdisp;
+
+ if(!parent) return false;
+// if(parent->Id == GO_FITFUNC) return parent->PropertyDlg();
+ memcpy(&newFill, &Fill, sizeof(FillDEF));
+ OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
+ if(!(Dlg = new DlgRoot(FuncDlg, data))) 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;
+ Dlg->GetValue(108, &o_z1); n_z1 = o_z1;
+ Dlg->GetValue(109, &o_z2); n_z2 = o_z2;
+ Dlg->GetValue(110, &o_zstep); n_zstep = o_zstep;
+ hDlg = CreateDlgWnd("3D Function Plot", 50, 50, 426, 328, Dlg, 0x4L);
+ if(bNew) Dlg->SetCheck(4, 0L, true);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 305: case 306:
+ if(Dlg->GetCheck(305)) {
+ Dlg->ShowItem(300, true); Dlg->ShowItem(301, false);
+ }
+ else {
+ Dlg->ShowItem(300, false); Dlg->ShowItem(301, true);
+ }
+ Dlg->DoPlot(0L);
+ res = -1;
+ break;
+ case 0:
+ if(Dlg->GetCheck(10)) res = -1;
+ break;
+ }
+ }while (res < 0);
+ Undo.SetDisp(cdisp);
+ while(*Undo.pcb > undo_level) Undo.Pop(cdisp);
+ if(res == 1){ //OK pressed
+ if(bNew) { //create function
+ if(Dlg->GetCheck(305)) {
+ type = 0;
+ OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&Line, 0);
+ }
+ else {
+ type = 1;
+ memcpy(&Fill, &newFill, sizeof(FillDEF));
+ Dlg->GetValue(401, &Line.width);
+ Dlg->GetColor(404, &Line.color);
+ Line.pattern = 0L;
+ Line.patlength = 1;
+ }
+ Dlg->GetValue(102, &x1); Dlg->GetValue(104, &x2);
+ Dlg->GetValue(106, &xstep);
+ Dlg->GetValue(108, &z1); Dlg->GetValue(109, &z2);
+ Dlg->GetValue(110, &zstep); type = Dlg->GetCheck(305) ? 0 : 1;
+ if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
+ if(cmdxy) free(cmdxy); cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+ ReshapeFormula(&cmdxy); bRet = Update();
+ }
+ }
+ 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);
+ TmpTxt[0] = 0; Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE);
+ undo_flags = CheckNewString(&cmdxy, cmdxy, TmpTxt, this, undo_flags);
+// 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 a 3D function to data
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+FitFunc3D::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 22, 10, "Data"};
+ TabSHEET tab2 = {22, 59, 10, "Function"};
+ TabSHEET tab3 = {59, 87, 10, "Style"};
+ char text1[100], text2[100], text3[100];
+ FillDEF newFill;
+ double iter;
+// bool bNew = (dl == 0L);
+ bool bNew = true;
+ DlgInfo FuncDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 160, 10, 45, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 160, 25, 45, 12},
+ {3, 10, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
+ {4, 5, 400, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 149, 134},
+ {5, 6, 100, ISPARENT, SHEET, &tab2, 5, 10, 149, 134},
+ {6, 7, 300, ISPARENT, SHEET, &tab3, 5, 10, 149, 134},
+ {7, 0, 0, 0x0L, PUSHBUTTON, (void*)"Fit", 160, 132, 45, 12},
+ {10, 50, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
+ {50, 0, 0, NOSELECT, ODBUTTON, (void*)(OD_AxisDesc3D), 160, 65, 45, 45},
+ {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*)param, 22, 44, 122, 30},
+ {150, 151, 0, 0x0L, LTEXT, (void*)"function, y=f(x,z):", 10, 77, 10, 8},
+ {151, 152, 0, 0x0L, RTEXT, (void*)"y=", 10, 91, 10, 8},
+ {152, 153, 0, 0x0L, RTEXT, (void*)"converg.:", 20, 128, 26, 8},
+ {153, 154, 0, 0x0L, EDVAL1, &conv, 46, 128, 25, 10},
+ {154, 155, 0, 0x0L, RTEXT, (void*)"iterations:", 72, 128, 47, 8},
+ {155, 200, 0, 0x0L, EDVAL1, &iter, 119, 128, 25, 10},
+ {200, 0, 0, 0x0L, TEXTBOX, (void*)cmdxy, 22, 89, 122, 30},
+ {300, 301, 550, CHECKED, GROUPBOX, (void*)" grid ", 10, 40, 140, 100},
+ {301, 305, 350, HIDDEN | CHECKED, GROUPBOX, (void*)" surface ", 10, 40, 140, 100},
+ {305, 306, 0, CHECKED | TOUCHEXIT, RADIO1, (void*) " grid lines", 15, 25, 50, 10},
+ {306, 0, 0, TOUCHEXIT, RADIO1, (void*) " surface", 85, 25, 50, 10},
+ {350, 351, 0, 0x0L, RTEXT, (void*)"grid line width", 38, 50, 40, 8},
+ {351, 352, 0, 0x0L, EDVAL1, &Line.width, 80, 50, 25, 10},
+ {352, 353, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 107, 50, 20, 8},
+ {353, 354, 0, 0x0L, RTEXT, (void*)"grid line color", 38, 62, 40, 8},
+ {354, 355, 0, OWNDIALOG, COLBUTT, (void *)&Line.color, 80, 62, 25, 10},
+ {355, 356, 0, 0x0L, RTEXT,(void*)"plane color" , 38, 74, 40, 8},
+ {356, 0, 0, OWNDIALOG, SHADE3D, &newFill, 80, 74, 25, 10},
+ {400, 401, 0, 0x0L, LTEXT, (void*)"range for X data", 10, 30, 60, 8},
+ {401, 402, 0, 0x0L, RANGEINPUT, (void*)text1, 20, 40, 100, 10},
+ {402, 403, 0, 0x0L, LTEXT, (void*)"range for Y data", 10, 55, 60, 8},
+ {403, 404, 0, 0x0L, RANGEINPUT, (void*)text2, 20, 65, 100, 10},
+ {404, 405, 0, 0x0L, LTEXT, (void*)"range for Z data", 10, 80, 60, 8},
+ {405, 406, 0, 0x0L, RANGEINPUT, (void*)text3, 20, 90, 100, 10},
+ {406, 407, 0, CHECKED, CHECKBOX, (void*)"draw symbols", 20, 110, 60, 8},
+ {407, 0, 0, HIDDEN, LTEXT, 0L, 20, 110, 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 ? 45:45, 130, 100}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, undo_level = *Undo.pcb, i, j, k, l, m, n, ns = 0;
+ bool bRet = false, bContinue = false;
+ DWORD undo_flags = 0L;
+ LineDEF newLine;
+ double x, y, z, o_x1, n_x1, o_x2, n_x2, o_xstep, n_xstep, n_chi2=chi2, rad;
+ AccRange *rX, *rY, *rZ;
+ char *o_cmdxy, *o_param, *tmp_char;
+ anyOutput *cdisp = Undo.cdisp;
+ anyResult *ares;
+ Sphere **Balls;
+
+ if(!parent || !data) return false;
+ UseRangeMark(data, 1, text1, text2, text3);
+ if(!(o_cmdxy = (char*)memdup(cmdxy, (int)strlen(cmdxy)+1, 0)))return false;
+ if(!(o_param = (char*)memdup(param, (int)strlen(param)+1, 0)))return false;
+ rX = rY = rZ = 0L; iter = (double)maxiter;
+ OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
+ memcpy(&newFill, &Fill, sizeof(FillDEF));
+ memcpy(&newLine, &Line, sizeof(LineDEF));
+ if(!(Dlg = new DlgRoot(FuncDlg, data))) return false;
+ if(!bNew){
+ Dlg->ShowItem(10, false); Dlg->Activate(401, false);
+ Dlg->Activate(403, false); Dlg->Activate(405, false);
+ Dlg->SetCheck(6, 0L, true);
+ Dlg->SetCheck(4, 0L, false); Dlg->ShowItem(404, false);
+ if(chi2 > 0.0) {
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "Chi 2 = %g", chi2);
+#else
+ sprintf(TmpTxt, "Chi 2 = %g", chi2);
+#endif
+ 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 in 3D Space", 50, 50, 426, 328, Dlg, 0x4L);
+ 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 305: case 306:
+ if(Dlg->GetCheck(305)) {
+ Dlg->ShowItem(300, true); Dlg->ShowItem(301, false);
+ }
+ else {
+ Dlg->ShowItem(300, false); Dlg->ShowItem(301, true);
+ }
+ Dlg->DoPlot(0L);
+ res = -1;
+ break;
+ case 1:
+ if(!bNew){
+ if(Dlg->GetText(102, TmpTxt, TMP_TXT_SIZE)) {
+ if(param) free(param);
+ param = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+ }
+ if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
+ if(cmdxy) free(cmdxy);
+ cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+ }
+ ReshapeFormula(¶m); ReshapeFormula(&cmdxy);
+ dirty = true;
+ break;
+ }
+ case 7: //Start: do nonlinear regression
+ Undo.SetDisp(cdisp);
+ if(!Dlg->GetText(401, text1, 100) || !Dlg->GetText(403, text2, 100) || !Dlg->GetText(405, text3, 100)) {
+ Dlg->SetCheck(4, 0L, true); bContinue = true;
+ InfoBox("Invalid or missing range");
+ res = -1;
+ }
+ else if(Dlg->GetCheck(5)) { // the function tab must be shown
+ if(Dlg->CurrDisp) Dlg->CurrDisp->MouseCursor(MC_WAIT, true);
+ if(Dlg->GetText(102, TmpTxt, TMP_TXT_SIZE)) {
+ if(param) free(param);
+ param = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+ }
+ if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
+ if(cmdxy) free(cmdxy);
+ cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+ }
+ Dlg->GetValue(153, &conv); Dlg->GetValue(155, &iter);
+ ReshapeFormula(¶m); ReshapeFormula(&cmdxy);
+ do_formula(data, 0L); //clear any error condition
+ ares = do_formula(data, param);
+ if(ares->type != ET_VALUE) {
+ ErrorBox("Syntax Error in parameters.");
+ bContinue = true; res = -1;
+ break;
+ }
+ ares = do_formula(data, cmdxy);
+ if(ares->type != ET_VALUE) {
+ ErrorBox("Syntax Error in formula.");
+ bContinue = true; res = -1;
+ break;
+ }
+ i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE-2, param); i += rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, ";x=1;z=1;");
+ rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, cmdxy); yywarn(0L, true);
+ ares = do_formula(data, TmpTxt);
+ if(tmp_char = yywarn(0L, false)) {
+ ErrorBox(tmp_char);
+ bContinue = true; res = -1;
+ break;
+ }
+ i = do_fitfunc(data, text1, text2, text3, ¶m, cmdxy, conv, (int)iter, &chi2);
+ Dlg->SetText(102, param);
+ if(i >1 || res == 7) {
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "The Levenberg-Marquart algorithm\nexited after %d iterations.\n\nChi2 = %g", i, chi2);
+#else
+ sprintf(TmpTxt, "The Levenberg-Marquart algorithm\nexited after %d iterations.\n\nChi2 = %g", i, chi2);
+#endif
+ 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);
+ Undo.SetDisp(cdisp);
+ while(*Undo.pcb > undo_level) Undo.Pop(cdisp);
+ if(res == 1 && (rX=new AccRange(text1)) && (rY=new AccRange(text2)) && (rZ=new AccRange(text3))){
+ //OK pressed
+ if(bNew) { //create function
+ if(Dlg->GetCheck(305)) {
+ type = 0;
+ OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&Line, 0);
+ }
+ else {
+ type = 1;
+ memcpy(&Fill, &newFill, sizeof(FillDEF));
+ Dlg->GetValue(401, &Line.width);
+ Dlg->GetColor(404, &Line.color);
+ Line.pattern = 0L; Line.patlength = 1;
+ }
+ 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))
+ CheckBounds3D(x,y,z);
+ }while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l) && rZ->GetNext(&m, &n));
+ x1 = xBounds.fx; x2 = xBounds.fy; xstep = (x2-x1)/10.0;
+ z1 = zBounds.fx; z2 = zBounds.fy; zstep = (z2-z1)/10.0;
+ if(Dlg->GetText(102, TmpTxt, TMP_TXT_SIZE)) {
+ if(param) free(param);
+ param = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+ }
+ if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE)) {
+ if(cmdxy) free(cmdxy);
+ cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+ }
+ ReshapeFormula(¶m); ReshapeFormula(&cmdxy);
+ if((bRet = Update()) && gob && nPlots == 1 && (Balls=(Sphere**)calloc(rX->CountItems(), sizeof(Sphere*)))) {
+ rX->GetFirst(&i, &j); rX->GetNext(&i, &j);
+ rY->GetFirst(&k, &l); rY->GetNext(&k, &l);
+ rZ->GetFirst(&m, &n); rZ->GetNext(&m, &n);
+ rad = DefSize(SIZE_SYMBOL);
+ do {
+ if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y) && data->GetValue(n, m, &z)) {
+ Balls[ns++] = new Sphere(this, data, 0, x, y, z, rad, i, j, k, l, m, n);
+ }
+ }while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l) && rZ->GetNext(&m, &n));
+ if(ns) {
+ plots[1] = (GraphObj*) new Scatt3D(this, data, Balls, ns);
+ nPlots = 2;
+ }
+ else free(Balls);
+ }
+ if(bRet)Command(CMD_ENDDIALOG, 0L, 0L);
+ }
+ else { //edit existing function
+ Dlg->GetValue(102, &x1); Dlg->GetValue(104, &x2);
+ Dlg->GetValue(106, &xstep);
+ Dlg->GetValue(108, &z1); Dlg->GetValue(109, &z2);
+ Dlg->GetValue(110, &zstep); type = Dlg->GetCheck(305) ? 0 : 1;
+ InfoBox("Not Implemented");
+ }
+ }
+ if(rX) delete(rX); if(rY) delete(rY); if(rZ) delete(rZ);
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Grid line properties
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *GridLineDlg_Tmpl =
+ "1,+,,DEFAULT,PUSHBUTTON, 1,150,10,50,12\n"
+ ".,.,,,PUSHBUTTON,2,150,25,50,12\n"
+ ".,10,,,PUSHBUTTON,-2,150,40,50,12\n"
+ "10,,100,ISPARENT | CHECKED,GROUPBOX,3,5,10,139,123\n"
+ "100,+,,NOSELECT,ODBUTTON,4,10,18,130,100\n"
+ ".,.,112,HIDDEN | CHECKED,GROUP,0,0,0,0,0\n"
+ ".,.,115,HIDDEN | CHECKED,GROUP,0,0,0,0,0\n"
+ ".,.,120,HIDDEN | CHECKED,GROUP,0,0,0,0,0\n"
+ ".,.,125,HIDDEN | CHECKED,GROUP,0,0,0,0,0\n"
+ ".,,130,HIDDEN | CHECKED,GROUP,0,0,0,0,0\n"
+ "111,,,,RTEXT,5,15,117,23,8\n"
+ "112,+,,,CHECKBOX,-20,41,117,25,8\n"
+ ".,.,,,CHECKBOX,-21,105,117,25,8\n"
+ ".,111,,,CHECKBOX,-25,70,117,25,8\n"
+ "115,+,,,CHECKBOX,-22,41,117,25,8\n"
+ ".,.,,,CHECKBOX,-23,105,117,25,8\n"
+ ".,111,,,CHECKBOX,-24,70,117,25,8\n"
+ "120,+,,,CHECKBOX,-24,55,117,25,8\n"
+ ".,135,,,CHECKBOX,-25,90,117,25,8\n"
+ "125,+,,,CHECKBOX,-24,55,117,25,8\n"
+ ".,135,,,CHECKBOX,-26,90,117,25,8\n"
+ "130,+,,,CHECKBOX,-25,55,117,25,8\n"
+ ".,135,,,CHECKBOX,-26,90,117,25,8\n"
+ "135,,,LASTOBJ,LTEXT,6,15,117,55,8";
+bool
+GridLine::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 21, 10, "Line"};
+ int dh = ((flags & AXIS_ANGULAR) || (flags & AXIS_RADIAL))? -20 : 0;
+ void *dyndata[] = {(void*)"Apply to LINE", (void*)"Apply to AXIS", (void*)" grid line ",
+ (void*)OD_linedef, (void*)"line to:", (void*)"parallel to:"};
+ DlgInfo *LineDlg;
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, tmptype;
+ bool bRet = false;
+ DWORD undo_flags = 0L;
+ anyOutput *cdisp = Undo.cdisp;
+ LineDEF newLine;
+
+ if(!parent || !parent->parent) return false;
+ if(!(LineDlg = CompileDialog(GridLineDlg_Tmpl, dyndata)))return false;
+ LineDlg[3].h += dh;
+ OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
+ if(!(Dlg = new DlgRoot(LineDlg, data)))return false;
+ if ((flags & AXIS_ANGULAR) || (flags & AXIS_RADIAL)) {
+ //no checkboxes, changed sizes
+ }
+ 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, 310 + dh*2, Dlg, 0x4L);
+ do{ //dh*2 means dh * ybase
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 1: //this line
+ case 2: //all lines of plot
+ Undo.SetDisp(cdisp);
+ 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; free(LineDlg);
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Tick properties
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *TickDlg_Tmpl =
+ "1,2,,,PUSHBUTTON,1,120,10,60,12\n"
+ "2,3,,DEFAULT, PUSHBUTTON,2,120,25,60,12\n"
+ "3,4,,,PUSHBUTTON,-2,120,40,60,12\n"
+ "4,,5,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "5,6,100,ISPARENT | CHECKED,SHEET,3,5,10,110,100\n"
+ "6,7,200,ISPARENT,SHEET,4,5,10,110,100\n"
+ "7,,300,ISPARENT,SHEET,5,5,10,110,100\n"
+ "100,101,,,RTEXT,6,10,30,35,8\n"
+ "101,102,,,EDVAL1,7,50,30,25,10\n"
+ "102,103,,,LTEXT,-3,77,30,20,8\n"
+ "103,104,,,CHECKBOX,8,18,45,30, 8\n"
+ "104,105,,,LTEXT,9,18,60,20,8\n"
+ "105,106,,,RADIO1,0,40,70,35,8\n"
+ "106,107,,,RADIO1,0,40,60,35,8\n"
+ "107,108,,,RADIO1,10,40,80,35,8\n"
+ "108,,,,CHECKBOX,11,18,95,30,8\n"
+ "200,201,,,RTEXT,12,10,35,23,8\n"
+ "201,202,,,EDVAL1,13,40,35,65,10\n"
+ "202,203,,,LTEXT,14,15,55,20,8\n"
+ "203,,,,EDTEXT,0,15,67,90,10\n"
+ "300,301,,,LTEXT,15,15,30,70,8\n"
+ "301,302,,TOUCHEXIT,RADIO1,16,15,42,70,8\n"
+ "302,303,,TOUCHEXIT,RADIO1,17,15,52,70,8\n"
+ "303,304,,TOUCHEXIT,RADIO1,18,15,74,70,8\n"
+ "304,305,,TOUCHEXIT,RADIO1,19,15,84,70,8\n"
+ "305,306,,TOUCHEXIT,RADIO1,20,15,94,70,8\n"
+ "306,307,,, EDVAL1,21,28,62,35,10\n"
+ "307,,,LASTOBJ,LTEXT,22,65,62,20,8";
+
+bool
+Tick::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 25, 10, "Tick"};
+ TabSHEET tab2 = {64, 90, 10, "Edit"};
+ TabSHEET tab3 = {25, 64, 10, "Direction"};
+ double tick_rot;
+ void *dyndata[] = {(void*)"Apply to TICK", (void*)"Apply to AXIS", (void*)&tab1, (void*)&tab2,
+ (void*)&tab3, (void*)"tick size", (void*)&size, (void*)"major tick", (void*)"type:",
+ (void*)"symmetric", (void*)"draw grid line(s)", (void*)"value:", (void*)&value, (void*)"label:",
+ (void*)"direction of ticks", (void*)"perpendicular to axis", (void*)"fixed angle",
+ (void*)"x-axis", (void*)"y-axis", (void*)"z-axis", (void*)&tick_rot, (void*)"deg."};
+ DlgInfo *TickDlg;
+ DlgRoot *Dlg;
+ void *hDlg;
+ DWORD old_flags;
+ char old_value[80];
+ double new_size, old_size, new_angle, old_angle, new_value;
+ int res, tmp_type = type;
+ bool bRet = false;
+ DWORD new_flags = flags, undo_flags = 0;
+ anyOutput *cdisp = Undo.cdisp;
+ char *old_label = 0L;
+ TextDEF *td;
+
+ if(!parent || parent->Id != GO_AXIS) return false;
+ if(!(TickDlg = CompileDialog(TickDlg_Tmpl, dyndata))) 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, data);
+ 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) {
+ if(label->Command(CMD_GETTEXT, &TmpTxt, 0L) && TmpTxt[0] &&
+ (old_label = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0)))
+ 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(flags & AXIS_DATETIME) Dlg->SetText(201, NiceTime(value));
+ if(!(Dlg->GetText(201, old_value, sizeof(old_value)))) {
+ new_value = value; old_value[0] = 0;
+ }
+ hDlg = CreateDlgWnd("Tick properties", 50, 50, 375, 265, Dlg, 0x4L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 1: case 2:
+ Undo.SetDisp(cdisp); 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);
+ 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);
+ if(Dlg->GetText(201, TmpTxt, 80) && strcmp(TmpTxt, old_value)) {
+ Undo.ValFloat(parent, &value, undo_flags); undo_flags |= UNDO_CONTINUE;
+ if(flags & AXIS_DATETIME) date_value(TmpTxt, 0L, &value);
+ else Dlg->GetValue(201, &value);
+ }
+ if(label && label->Id == GO_LABEL) {
+ td = ((Label*)label)->GetTextDef();
+ if(!Dlg->GetText(203, TmpTxt, TMP_TXT_SIZE)) TmpTxt[0] = 0;
+ if(undo_flags = CheckNewString(&td->text, td->text, TmpTxt, this, undo_flags))
+ 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; free(TickDlg);
+ if(old_label) free(old_label);
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Axis properties dialog
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *ssTickTmpl =
+ "1,2,,DEFAULT, PUSHBUTTON,-1,113,10,45,12\n"
+ "2,3,,, PUSHBUTTON,-2,113,25,45,12\n"
+ "3,4,,, LTEXT,1,5,10,100,9\n"
+ "4,5,,TOUCHEXIT,RANGEINPUT,4,10,20,90,10\n"
+ "5,6,,, LTEXT,2,5, 32, 100, 9\n"
+ "6,7,,TOUCHEXIT,RANGEINPUT,5,10,42,90,10\n"
+ "7, 8,,,LTEXT,3, 5, 54, 80, 8\n"
+ "8,,,LASTOBJ | TOUCHEXIT,RANGEINPUT,6,10,64,90,10";
+
+bool
+Axis::ssTicks()
+{
+ void *dyndata[] ={(void*)"range for major tick VALUES:", (void*)"range for major tick LABELS:",
+ (void*)"minor tick VALUES:", (void*)ssMATval, (void*)ssMATlbl, (void*)ssMITval};
+ DlgInfo *TickDlg = CompileDialog(ssTickTmpl, dyndata);
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, n, n1, n2, n3;
+ bool bRet = false, bContinue = true;
+ AccRange *rT, *rL, *rMT;
+
+ if(!data) return false;
+ n = n1 = n2 = n3 = 0; rT = rL = rMT = 0L;
+ if(!(Dlg = new DlgRoot(TickDlg, data)))return false;
+ hDlg = CreateDlgWnd("choose ticks from spreadsheet", 50, 50, 330, 190, Dlg, 0x4L);
+ Dlg->Activate(4, true);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 0: // focus lost
+ if(bContinue) res = -1;
+ break;
+ case 4: case 6: case 8:
+ bContinue = true;
+ res = -1; 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, TMP_TXT_SIZE) && (rT=new AccRange(TmpTxt)) && (n1=rT->CountItems())){
+ if(Dlg->GetText(6, TmpTxt, TMP_TXT_SIZE) && (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,TMP_TXT_SIZE) && (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, TMP_TXT_SIZE))
+ ssMATval = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+ if(Dlg->GetText(6, TmpTxt, TMP_TXT_SIZE))
+ ssMATlbl = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+ if(Dlg->GetText(8, TmpTxt, TMP_TXT_SIZE))
+ ssMITval = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+ UpdateTicks();
+ }
+ bRet = true;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg; free(TickDlg);
+ if(rT) delete rT; if(rL) delete rL; if(rMT) delete rMT;
+ return bRet;
+}
+
+static char *AxisPropDlg_Tmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,-1,186,10,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,186,25,45,12\n"
+ "3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "4,5,50,ISPARENT | CHECKED,SHEET,1,5,10,168,165\n"
+ "5,6,200,ISPARENT,SHEET,2,5,10,168,165\n"
+ "6,7,300,ISPARENT,SHEET,3,5,10,168,165\n"
+ "7,8,400,ISPARENT,SHEET,4,5,10,168,165\n"
+ "8,9,500,HIDDEN | ISPARENT,SHEET,5,5,10,168,165\n"
+ "9,,550,HIDDEN | ISPARENT,SHEET,6,5,10,168,165\n"
+ "50,+,100,ISPARENT | CHECKED,GROUPBOX,7,10,30,158,36\n"
+ ".,104,,TOUCHEXIT,CHECKBOX,8,17,37,80,8\n"
+ "100,+,,,RTEXT,9,10,51,35,8\n"
+ ".,.,,,EDVAL1,10,48,51,51,10\n"
+ ".,.,,,CTEXT,11,100,51,11,8\n"
+ ".,,,,EDVAL1,12,112,51,51,10\n"
+ ".,120,105,ISPARENT | CHECKED,GROUPBOX,13,10,72,158,45\n"
+ ".,106,,TOUCHEXIT | ISRADIO,CHECKBOX,-20,54,77,20,8\n"
+ ".,.,,TOUCHEXIT | ISRADIO,CHECKBOX,-21,84,77,20,8\n"
+ ".,.,,TOUCHEXIT | ISRADIO,CHECKBOX,-22,54,77,20,8\n"
+ ".,.,,TOUCHEXIT | ISRADIO,CHECKBOX,-23,84,77,20,8\n"
+ ".,.,,,RTEXT,-4,10,-50,15,8\n"
+ ".,.,,,EDVAL1,14,27,-50,45,10\n"
+ ".,.,,,LTEXT,-7,75,-50,5,8\n"
+ ".,.,,,EDVAL1,15,81,-50,45,10\n"
+ ".,.,,,LTEXT,0,129,-50,15,8\n"
+ ".,.,,,RTEXT,-5,10,-38,15,8\n"
+ ".,.,,,EDVAL1,16,27,-38,45,10\n"
+ ".,.,,,LTEXT,-7,75,-38,5,8\n"
+ ".,.,,,EDVAL1,17,81,-38,45,10\n"
+ ".,150,,,LTEXT,0,129,-38,15,8\n"
+ "150,+,,,RTEXT,-6,10,-26,15,8\n"
+ ".,.,,,EDVAL1,18,27,-26,45,10\n"
+ ".,.,,,LTEXT,-7,75,-26,5,8\n"
+ ".,.,,,EDVAL1,19,81,-26,45,10\n"
+ ".,,,,LTEXT,0,129,-26,15,8\n"
+ "120,180, 121, ISPARENT | CHECKED,GROUPBOX,20,10,123,158,20\n"
+ ".,+,,,RTEXT,21,20,128,25,8\n"
+ ".,.,,,EDVAL1,22,47,128,25,10\n"
+ ".,.,,,LTEXT,-3,73,128, 10,8\n"
+ ".,.,,,RTEXT,-11,102,128,25,8\n"
+ ".,130,,OWNDIALOG, COLBUTT,23,129,128,25,10\n"
+ "130,,131,ISPARENT | CHECKED,GROUPBOX,24,10,149,158,20\n"
+ "131,,,,EDTEXT,0,15,154,148,10\n"
+ "180,,181,HIDDEN | ISPARENT | CHECKED,GROUPBOX,25,10,72,158,45\n"
+ "181,+,,,RTEXT,26,10,-38,50,8\n"
+ ".,.,,,EDVAL1,27,62,-38,45,10\n"
+ ".,.,,,LTEXT,-3,109,-38,15,8\n"
+ ".,.,,,RTEXT,-5,10,-50,50,8\n"
+ ".,.,,,EDVAL1,28,62,-50,45,10\n"
+ ".,.,,,LTEXT,-3,109,-50,15,8\n"
+ ".,.,,,RTEXT,29,10,-38,50,8\n"
+ ".,.,,,EDVAL1,30,62,-38,45,10\n"
+ ".,.,,,LTEXT,-3,109,-38,15,8\n"
+ "200,+,,TOUCHEXIT,RADIO1,31,20,35,40,8\n"
+ ".,.,,TOUCHEXIT,RADIO1,32,20,47,40,8\n"
+ ".,204,,TOUCHEXIT,RADIO1,33,20,59,40,8\n"
+ ".,.,,TOUCHEXIT,RADIO1,34,20,71,40,8\n"
+ ".,203,250,CHECKED | ISPARENT,GROUPBOX,35,15,75,148,50\n"
+ ".,206,,,PUSHBUTTON,36,30,130,90,12\n"
+ ".,,,TOUCHEXIT,RADIO1,0,20,130,8,8\n"
+ "250,+,,,RTEXT,37,35,83,45,8\n"
+ ".,.,,,EDVAL1,38,87,83,65,10\n"
+ ".,.,,,RTEXT,39,35,95,45,8\n"
+ ".,.,,,EDVAL1,40,87,95,65,10\n"
+ ".,.,,,RTEXT,41,25,107,75,8\n"
+ ".,,,,EDTEXT,42,107,107,45,10\n"
+ "300,+,,,LTEXT,43,20,30,110,8\n"
+ ".,.,,TOUCHEXIT,RADIO1,44,40,45,70,8\n"
+ ".,.,,TOUCHEXIT,RADIO1,45,40,57,70,8\n"
+ ".,.,,TOUCHEXIT,RADIO1,46,40,69,70,8\n"
+ ".,.,,TOUCHEXIT,RADIO1,47,40,81,70,8\n"
+ ".,,,,CHECKBOX,48,20,115,80,12\n"
+ "400,450,,,LTEXT,-27,10,30,110,8\n"
+ ".,402,,ISRADIO,ODBUTTON,49,49,40,25,25\n"
+ ".,.,,ISRADIO,ODBUTTON,49,74,40,25,25\n"
+ ".,.,,ISRADIO,ODBUTTON,49,99,40,25,25\n"
+ ".,.,,ISRADIO,ODBUTTON,49,124,40,25,25\n"
+ ".,.,,,RTEXT,50,25,75,48,8\n"
+ ".,.,,,EDVAL1,51,75,75,29,10\n"
+ ".,.,,,LTEXT,-3,107,75,10,8\n"
+ ".,.,,,RTEXT,52,25,87,48,8\n"
+ ".,.,,,EDVAL1,53,75,87,29,10\n"
+ ".,,,,LTEXT,-3,107,87,10,8\n"
+ "450,+,,ISPARENT | CHECKED,GROUPBOX,54,10,110,158,50\n"
+ ".,.,,,LTEXT,0,30,115,60,8\n"
+ ".,.,,,PUSHBUTTON,-8,108,142,41,12\n"
+ ".,.,,,PUSHBUTTON,-9,67,142,41,12\n"
+ ".,.,,,RTEXT,55,25,125,20,8\n"
+ ".,.,,,EDTEXT,0,47,125,41,10\n"
+ ".,.,,,RTEXT,56,92,125,9,8\n"
+ ".,.,,,EDTEXT,0,103,125,41,10\n"
+ ".,401,,,PUSHBUTTON,57,26,142,41,12\n"
+ "500,,,NOSELECT,ODBUTTON,58,25,30,140,140\n"
+ "550,,551,ISPARENT | CHECKED,GROUPBOX,59,15,30,148,123\n"
+ ".,+,,TOUCHEXIT,RADIO1,60,30,38,75,9\n"
+ ".,.,,ODEXIT,COLBUTT,61,112,37,25,10\n"
+ ".,.,,TOUCHEXIT,RADIO1,62,30,52,80,9\n"
+ ".,.,,TOUCHEXIT,RADIO1,63,30,76,80,9\n"
+ ".,.,,TOUCHEXIT,RADIO1,64,30,88,80,9\n"
+ ".,.,,TOUCHEXIT,RADIO1,65,30,64,80,9\n"
+ ".,.,,OWNDIALOG | TOUCHEXIT,COLBUTT,66,50,100,25,10\n"
+ ".,.,,,CTEXT,56,76,100,18,9\n"
+ ".,.,,ODEXIT,COLBUTT,67,95,100,25,10\n"
+ ".,.,,,CHECKBOX,68,30,115,80,9\n"
+ ".,.,,,RTEXT,69,30,128,45,9\n"
+ ".,.,,,INCDECVAL1,70,77,128,32,10\n"
+ ".,,,LASTOBJ,LTEXT,-10,111,128,10,9";
+
+bool
+Axis::PropertyDlg()
+{
+ TabSHEET tab1 = {0, 25, 10, "Axis"};
+ TabSHEET tab2 = {25, 50, 10, "Ticks"};
+ TabSHEET tab3 = {50, 97, 10, "Transforms"};
+ TabSHEET tab4 = {97, 128, 10, "Breaks"};
+ TabSHEET tab5 = {128, 153, 10, "Plots"};
+ TabSHEET tab6 = {97, 135, 10, "Gradient"};
+ int v1 = (axis->flags & AXIS_3D) ? 77 : (axis->flags & AXIS_RADIAL) ? 83 : 89;
+ double transp = (double)iround((double)((gTrans>>24) & 0xff)/2.55);
+ void *dyndata[] ={(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)&tab4, (void*)&tab5, (void*)&tab6,
+ (void*)" scaling ", (void*)" automatic scaling", (void*)"axis from", (void*)&axis->min, (void*)"to",
+ (void*)&axis->max, (void*)" placement ", (void*)&axis->loc[0].fx, (void*)&axis->loc[1].fx,
+ (void*)&axis->loc[0].fy, (void*)&axis->loc[1].fy, (void*)&axis->loc[0].fz, (void*)&axis->loc[1].fz,
+ (void*)" line ", (void*)"width", (void*)&sizAxLine, (void*)&colAxis, (void*)" axis label ",
+ (void*)" placement ", (void*)"center x", (void*)&axis->Center.fx, (void*)&axis->Center.fy,
+ (void*)"radius", (void*)&axis->Radius, (void*)"no ticks", (void*)"automatic", (void*)"leave unchanged",
+ (void*)"set manually", (void*)" ", (void*)"use spread sheet values",
+ (void*)"start value", (void*)&axis->Start, (void*)"interval", (void*)&axis->Step,
+ (void*)"minor ticks per interval", (void*)"0", (void*)"Transforms:", (void*)"none (linear)",
+ (void*)"logarithmic (log base 10)", (void*)"reciprocal (1/x)",(void*)"square root",
+ (axis->loc[0].fx == axis->loc[1].fx) ? (void*)"low vaues top of graph" : (void*)"low values right of graph",
+ (void*)(OD_BreakTempl), (void*)"break gap", (void*)&brkgap, (void*)"symbol size", (void*)&brksymsize,
+ (void*)" break data ", (void*)"from", (void*)"to", (void*)"Delete", (void*)OD_axisplot,
+ (void*)" color gradient ", (void*)"use common fill color:", (void *)&gCol_0,
+ (void*)"rainbow color gradient I", (void*)"extented rainbow colors", (void*)"simple color gradient",
+ (void*)"rainbow color gradient II", (void *)&gCol_1, (void *)&gCol_2, (void*)"invert gradient",
+ (void*)"transparency", (void*)&transp};
+ DlgInfo *AxisPropDlg;
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, j, res, nbrk, cbrk, ttmpl, n_gradient;
+ double tmp, tmp2, old_x1, old_x2, old_y1, old_y2;
+ bool bRet = false, bChanged = false, upd_brk = true;
+ bool bContinue = false, bUpdPG = false;
+ double use_step = 10.0, use_minmax[] = {0.0, 100.0};
+ DWORD new_color, undo_flags = 0L;
+ anyOutput *cdisp = Undo.cdisp;
+ 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(!(AxisPropDlg = CompileDialog(AxisPropDlg_Tmpl, dyndata))) return false;
+ n_gradient = grad_type;
+ //adjust dialog to 3D plot, polar plot ...
+ for(i = 0, v1+= 50; !(AxisPropDlg[i].flags & LASTOBJ); i++) {
+ if(AxisPropDlg[i].y < 0) AxisPropDlg[i].y += v1;
+ }
+ 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;
+ if(names[0] = (char*)malloc(15 * sizeof(char))) rlp_strcpy(names[0], 15, "[unchanged]");
+ for(i = 0, j = 1; i < res; i++) {
+ if(scp[i] && scp[i]->name){
+ names[j] = (char*)memdup(scp[i]->name, (int)strlen(scp[i]->name)+1, 0);
+ somePlots[j++] = scp[i];
+ }
+ }
+ }
+ else if(IsPlot3D(parent) && (res=((Plot3D*)parent)->nscp)){
+ scp = ((Plot3D*)parent)->Sc_Plots;
+ CurrAxes = ((Plot3D*)parent)->Axes;
+ if(!scp || !(names = (char**)calloc(res+2, sizeof(char*))) ||
+ !(somePlots = (GraphObj**)calloc(res+2, sizeof(GraphObj*))))
+ return false;
+ if(names[0] = (char*)malloc(15 * sizeof(char))) rlp_strcpy(names[0], 15, "[unchanged]");
+ for(i = 0, j = 1; i < res; i++) {
+ if(scp[i] && scp[i]->name){
+ names[j] = (char*)memdup(scp[i]->name, (int)strlen(scp[i]->name)+1, 0);
+ somePlots[j++] = scp[i];
+ }
+ }
+ }
+ else {
+ names = (char**)calloc(2, sizeof(char*)); names[0] = (char*)malloc(10*sizeof(char));
+ rlp_strcpy(names[0], 10, "n.a.");
+ }
+ OD_axisplot(OD_ACCEPT, 0L, 0L, 0L, names, 0);
+ if(!(Dlg = new DlgRoot(AxisPropDlg, data)))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;
+ }
+ 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);
+ }
+ }
+ //align to frame ?
+ 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 = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+ 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;
+ case 4: type_txt = (char*)(&"Gradient 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));
+ i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, type_txt);
+ rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, "xis Properties");
+ if((type &0x0f) == 4) {
+ Dlg->ShowItem(7, false); Dlg->ShowItem(8, false);
+ Dlg->ShowItem(9, true); upd_brk = false;
+ switch(grad_type & 0x0f) {
+ case 0:
+ Dlg->SetCheck(551, 0L, true); break;
+ case 1: default:
+ grad_type = n_gradient = 1;
+ Dlg->SetCheck(553, 0L, true); break;
+ case 2: case 3: case 4:
+ Dlg->SetCheck(552+(grad_type & 0x0f), 0L, true); break;
+ }
+ if(grad_type & 0x10) Dlg->SetCheck(560, 0L, true);
+ Dlg->ItemCmd(562, CMD_STEP, (void*)&use_step);
+ Dlg->ItemCmd(562, CMD_MINMAX, (void*)&use_minmax);
+ }
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 476, 390, Dlg, 0x4L);
+ 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);
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "break # %d/%d", cbrk+1, nbrk+1);
+#else
+ sprintf(TmpTxt,"break # %d/%d", cbrk+1, nbrk+1);
+#endif
+ 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;
+ case 551:
+ n_gradient = 0;
+ res = -1; break;
+ case 552: //gradient color button 0
+ Dlg->SetCheck(551, 0L, true); n_gradient = 0; res = -1;
+ break;
+ case 553: case 554: case 555: case 556:
+ n_gradient = (res-552);
+ res = -1; break;
+ case 557: case 559: //gradient color button 1 and 2
+ Dlg->SetCheck(555, 0L, true); n_gradient = 3; res = -1;
+ break;
+ }
+ }while (res < 0);
+ Undo.SetDisp(cdisp);
+ switch (res) {
+ case 1: //OK pressed
+ bModified = true;
+ 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((new_a.flags & AXIS_LOG)== AXIS_LOG && new_a.min < defs.min4log) {
+ switch(type & 0x0f) {
+ case 1:
+ new_a.min = parent->GetSize(SIZE_BOUNDS_XMIN); break;
+ case 2:
+ new_a.min = parent->GetSize(SIZE_BOUNDS_YMIN); break;
+ case 3:
+ new_a.min = parent->GetSize(SIZE_BOUNDS_ZMIN); break;
+ }
+ }
+ 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;
+ axis->Start = axis->min;
+ }
+ 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((!(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) {
+ if((axis->flags & AXIS_RADIAL)||(axis->flags & AXIS_ANGULAR))
+ parent->Command(CMD_AXIS, this, 0L);
+ if(parent->Id == GO_CONTOUR) parent->Command(CMD_RECALC, 0L, 0L);
+ }
+ 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->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, TMP_TXT_SIZE) && TmpTxt[0]) {
+ if(old_Label && strcmp(old_Label,TmpTxt) && axisLabel->Id == GO_LABEL){
+ lb_def = ((Label*)axisLabel)->GetTextDef();
+ undo_flags = CheckNewString(&lb_def->text, old_Label, TmpTxt, this, undo_flags);
+ }
+ else if(!axisLabel) {
+ label_def.ColTxt = colAxis; label_def.ColBg = 0x00ffffffL;
+ label_def.fSize = DefSize(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((type & 0x0f) == 4) {
+ if(Dlg->GetColor(552, &new_color) && gCol_0 != new_color){
+ Undo.ValDword(this, &gCol_0, undo_flags);
+ gCol_0 = new_color;
+ undo_flags |= UNDO_CONTINUE; bUpdPG = true;
+ }
+ if(Dlg->GetColor(557, &new_color) && gCol_1 != new_color){
+ Undo.ValDword(this, &gCol_1, undo_flags);
+ gCol_1 = new_color;
+ undo_flags |= UNDO_CONTINUE; bUpdPG = true;
+ }
+ if(Dlg->GetColor(559, &new_color) && gCol_2 != new_color){
+ Undo.ValDword(this, &gCol_2, undo_flags);
+ gCol_2 = new_color;
+ undo_flags |= UNDO_CONTINUE; bUpdPG = true;
+ }
+ Dlg->GetValue(562, &transp);
+ new_color = ((((int)(transp*2.55))<<24)&0xff000000);
+ if(gTrans != new_color){
+ Undo.ValDword(this, &gTrans, undo_flags);
+ gTrans = new_color;
+ undo_flags |= UNDO_CONTINUE; bUpdPG = true;
+ }
+ if(Dlg->GetCheck(560)) n_gradient |= 0x10;
+ else n_gradient &= ~0x10;
+ if(n_gradient != grad_type) {
+ Undo.ValInt(this, &grad_type, undo_flags);
+ grad_type = n_gradient;
+ undo_flags |= UNDO_CONTINUE; bUpdPG = true;
+ }
+ if(bUpdPG){
+ Command(CMD_UPDPG, 0L, 0L); bRet= true;
+ }
+ }
+ if(undo_flags & UNDO_CONTINUE) bRet= true;
+ 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); free(AxisPropDlg);
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Graph dialogs
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *AddPlotTmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,-1,150,10,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,150,25,45,12\n"
+ "3,,520,ISPARENT | CHECKED,GROUPBOX,1,5,10,135,95\n"
+ "520,521,,EXRADIO | CHECKED,ODBUTTON,2,10,20,25,25\n"
+ "521,522,,EXRADIO,ODBUTTON,2,35,20,25,25\n"
+ "522,523,,EXRADIO,ODBUTTON,2,60,20,25,25\n"
+ "523,524,,EXRADIO,ODBUTTON,2,85,20,25,25\n"
+ "524,525,,EXRADIO,ODBUTTON,2,110,20,25,25\n"
+ "525,526,,EXRADIO,ODBUTTON,2,10,45,25,25\n"
+ "526,528,,EXRADIO,ODBUTTON,2,35,45,25,25\n"
+ "528,529,,EXRADIO,ODBUTTON,2,60,45,25,25\n"
+ "529,530,,EXRADIO,ODBUTTON,2,85,45,25,25\n"
+ "530,531,,EXRADIO,ODBUTTON,2,110,45,25,25\n"
+ "531,532,,EXRADIO,ODBUTTON,2,10,70,25,25\n"
+ "532,540,,EXRADIO,ODBUTTON,2,35,70,25,25\n"
+ "540,541,,EXRADIO,ODBUTTON,2,60,70,25,25\n"
+ "541,,,LASTOBJ | EXRADIO,ODBUTTON, 2, 85,70,25,25";
+
+bool
+Graph::AddPlot(int family)
+{
+ void *dyndata[] = {(void *)" select template ",(void*)OD_PlotTempl};
+ DlgInfo *GraphDlg = CompileDialog(AddPlotTmpl, dyndata);
+ 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, data); Dlg->bModal = false;
+ hDlg = CreateDlgWnd("Add Plot", 50, 50, 410, 240, Dlg, 0x4L);
+ 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 532: 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, "Function");
+ else if(Dlg->GetCheck(530)) p = new FitFunc(this, data);
+ else if(Dlg->GetCheck(531)) p = new MultiLines(this, data);
+ else if(Dlg->GetCheck(532)) p = new xyStat(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; free(GraphDlg);
+ return bRet;
+}
+
+static char *GraphDlgTmpl =
+ "1,+,,DEFAULT,PUSHBUTTON,-1,170,10,45,12\n"
+ ".,.,,,PUSHBUTTON,-2,170,25,45,12\n"
+ ".,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "4,+,100,ISPARENT | CHECKED,SHEET,1,5,10,157,122\n"
+ ".,.,200,ISPARENT,SHEET,2,5,10,157,122\n"
+ ".,,300,ISPARENT,SHEET,3,5,10,157,122\n"
+ "100,+,,,LTEXT,4,10,25,60,8\n"
+ ".,.,500,TOUCHEXIT | ISPARENT,SHEET,5,10,37,147,90\n"
+ ".,.,520,TOUCHEXIT | ISPARENT,SHEET,6,10,37,147,90\n"
+ ".,.,540,TOUCHEXIT | ISPARENT,SHEET,7,10,37,147,90\n"
+ ".,,560,TOUCHEXIT | ISPARENT,SHEET,8,10,37,147,90\n"
+ "200,+,,,LTEXT,9,10,35,60,8\n"
+ ".,.,,,RTEXT,10,5,47,58,8\n"
+ ".,.,,,EDVAL1,11,64,47,30,10\n"
+ ".,.,,,RTEXT,-5,95,47,10,8\n"
+ ".,.,,,EDVAL1,12,107,47,30,10\n"
+ ".,.,,,LTEXT,-3,140,47,20,8\n"
+ ".,.,,,RTEXT,13,5,59,58,8\n"
+ ".,.,,,EDVAL1,14,64,59,30,10\n"
+ ".,.,,,RTEXT,-5,95,59,10,8\n"
+ ".,.,,,EDVAL1,15,107,59,30,10\n"
+ ".,.,,,LTEXT,-3,140,59,20,8\n"
+ ".,.,,,LTEXT,16,10,84,60,8\n"
+ ".,.,,,RTEXT,17,5,96,58,8\n"
+ ".,.,,,EDVAL1,18,64,96,30,10\n"
+ ".,.,,,RTEXT,-5,95,96,10,8\n"
+ ".,.,,,EDVAL1,19,107,96,30,10\n"
+ ".,.,,,LTEXT,-3,140,96,20,8\n"
+ ".,.,,,RTEXT,20,5,108,58,8\n"
+ ".,.,,,EDVAL1,21,64,108,30,10\n"
+ ".,.,,,RTEXT,-5,95,108,10,8\n"
+ ".,.,,,EDVAL1,22,107,108,30,10\n"
+ ".,,,,LTEXT,-3,140,108,20,8\n"
+ "300,+,,,LTEXT,23,20,30,60,8\n"
+ ".,400,310,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
+ "310,+,,EXRADIO,ODBUTTON,24,20,42,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,24,45,42,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,24,70,42,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,24,95,42,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,24,120,42,25,25\n"
+ ".,.,,CHECKED | TOUCHEXIT,RADIO1, 25, 12,85,40,8\n"
+ ".,.,,TOUCHEXIT,RADIO1,26,12,93,40,8\n"
+ ".,.,,TOUCHEXIT,RADIO1,27,12,101,40,8\n"
+ ".,.,,TOUCHEXIT,CHECKBOX,28,80,85,40,8\n"
+ ".,,,TOUCHEXIT, CHECKBOX,29,80,93,40,8\n"
+ "400,,410,HIDDEN | CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
+ "410,+,,EXRADIO,ODBUTTON,30,20,42,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,30,45,42,25,25\n"
+ ".,,,EXRADIO, ODBUTTON,30,70,42,25,25\n"
+ "500,+,,EXRADIO,ODBUTTON,31,20,60,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,45,60,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,70,60,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,20,85,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,45,85,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,95,85,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,120,85,25,25\n"
+ ".,,,EXRADIO,ODBUTTON,31,70,85,25,25\n"
+ "520,+,,EXRADIO,ODBUTTON, 31, 20,50,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,45,50,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,70,50,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,95,50,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,120,50,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,20,75,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,45,75,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,70,75,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,95,75,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,120,75,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,20,100,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,45,100,25,25\n"
+ ".,,,EXRADIO,ODBUTTON,31,70,100,25,25\n"
+ "540,+,,EXRADIO,ODBUTTON,31,20,60,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,45,60,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,70,60,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,95,60,25,25\n"
+ ".,,,TOUCHEXIT | ISRADIO,ODBUTTON, 31, 120,60,25,25\n"
+ "560,+,,EXRADIO,ODBUTTON, 31,20,60,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,45,60,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,70,60,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,95,60,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,120,60,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,20,85,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,45,85,25,25\n"
+ ".,.,,EXRADIO,ODBUTTON,31,70,85,25,25\n"
+ ".,,,LASTOBJ | EXRADIO, ODBUTTON,31,95,85,25,25";
+
+static int selSheet = 102, selPlt = 520, selAxis = 310;
+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"};
+ void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"arrangement of data: select plot",
+ (void*)&tab_A, (void*)&tab_B, (void*)&tab_C, (void*)&tab_D, (void*)"bounding rectangle (relative to page)",
+ (void*)"upper left corner x", (void*)&GRect.Xmin, (void*)&GRect.Ymin, (void*)"lower right x",
+ (void*)&GRect.Xmax, (void*)&GRect.Ymax, (void*)"plotting rectangle (relative to bounding rectangle)",
+ (void*)"upper left corner x", (void*)&DRect.Xmin, (void*)&DRect.Ymin, (void*)"lower right x",
+ (void*)&DRect.Xmax, (void*)&DRect.Ymax, (void*)"select template:", (void*)(OD_AxisTempl),
+ (void*)"ticks outside", (void*)"ticks inside", (void*)"ticks symmetrical", (void*)"horizontal grid lines",
+ (void*)"vertical grid lines", (void*)(OD_AxisTempl3D), (void*)(OD_PlotTempl)};
+ DlgInfo *GraphDlg = CompileDialog(GraphDlgTmpl, dyndata);
+ DlgRoot *Dlg;
+ GraphObj *p;
+ void *hDlg;
+ int i, res;
+ bool bRet, bContinue;
+ fRECT rc1, rc2;
+
+ ODtickstyle = tickstyle;
+ AxisTempl = 0;
+ if(!parent) return false;
+ Dlg = new DlgRoot(GraphDlg, data); Dlg->bModal = false;
+ Dlg->SetCheck(410 + AxisTempl3D, 0L, true);
+ if(parent->Id != GO_PAGE) {
+ Dlg->Activate(202, false); Dlg->Activate(204, false);
+ }
+ //restore previous settitings
+ switch(selSheet) {
+ case 101:
+ if(selPlt >= 500 && selPlt <=507) Dlg->SetCheck(selPlt, 0L, true);
+ else Dlg->SetCheck(500, 0L, true);
+ Dlg->SetCheck(520, 0L, true); Dlg->SetCheck(540, 0L, true);
+ Dlg->SetCheck(560, 0L, true); break;
+ default:
+ if(selPlt >= 520 && selPlt <=532) Dlg->SetCheck(selPlt, 0L, true);
+ else Dlg->SetCheck(520, 0L, true); selSheet = 102;
+ Dlg->SetCheck(500, 0L, true); Dlg->SetCheck(540, 0L, true);
+ Dlg->SetCheck(560, 0L, true); break;
+ case 103:
+ if(selPlt >= 540 && selPlt <=544) Dlg->SetCheck(selPlt, 0L, true);
+ else Dlg->SetCheck(540, 0L, true);
+ Dlg->SetCheck(520, 0L, true); Dlg->SetCheck(500, 0L, true);
+ Dlg->SetCheck(560, 0L, true); break;
+ case 104:
+ if(selPlt >= 560 && selPlt <=568) Dlg->SetCheck(selPlt, 0L, true);
+ else Dlg->SetCheck(560, 0L, true);
+ Dlg->ShowItem(301, false); Dlg->ShowItem(400, true);
+ Dlg->SetCheck(520, 0L, true); Dlg->SetCheck(540, 0L, true);
+ Dlg->SetCheck(500, 0L, true); break;
+ }
+ Dlg->SetCheck(selSheet, 0L, true);
+ if(selAxis >= 310 && selAxis <= 314) Dlg->SetCheck(selAxis, 0L, true);
+ else Dlg->SetCheck(310, 0L, true);
+ if(selAxis >= 410 && selAxis <= 412) Dlg->SetCheck(selAxis, 0L, true);
+ else Dlg->SetCheck(410, 0L, true);
+ //display the dialog
+ hDlg = CreateDlgWnd("Create graph", 50, 50, 450, 300, Dlg, 0x4L);
+ 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: //only y data
+ for(i = 500; i <= 506; i++) if(Dlg->GetCheck(i))selPlt = i;
+ Dlg->ShowItem(301, true); Dlg->ShowItem(400, false);
+ selSheet = res; res = -1;
+ break;
+ case 102: //xy data
+ for(i = 520; i <= 532; i++) if(Dlg->GetCheck(i))selPlt = i;
+ Dlg->ShowItem(301, true); Dlg->ShowItem(400, false);
+ selSheet = res; res = -1;
+ break;
+ case 103: //x many y data
+ for(i = 540; i <= 544; i++) if(Dlg->GetCheck(i))selPlt = i;
+ Dlg->ShowItem(301, true); Dlg->ShowItem(400, false);
+ selSheet = res; res = -1;
+ break;
+ case 104: //xyz data
+ for(i = 560; i <= 567; i++) if(Dlg->GetCheck(i))selPlt = i;
+ Dlg->ShowItem(301, false); Dlg->ShowItem(400, true);
+ selSheet = res; 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 506: case 507:
+ 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 532:
+ case 540: case 541: case 542: case 543:
+ case 544:
+ case 560: case 561: case 562: case 563:
+ case 564: case 565: case 566: case 567: case 568:
+ 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, 0);
+ else if(Dlg->GetCheck(505))p = new FreqDist(this, data);
+ else if(Dlg->GetCheck(506))p = new NormQuant(this, data, 0L);
+ else if(Dlg->GetCheck(507))p = new GroupBars(this, data, 1);
+ }
+ 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, "Function");
+ else if(Dlg->GetCheck(530)) p = new FitFunc(this, data);
+ else if(Dlg->GetCheck(531)) p = new MultiLines(this, data);
+ else if(Dlg->GetCheck(532)) p = new xyStat(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);
+ else if(Dlg->GetCheck(565)) p = new Func3D(this, data);
+ else if(Dlg->GetCheck(566)) p = new FitFunc3D(this, data);
+ else if(Dlg->GetCheck(567)) p = new Plot3D(this, data, 0x4000);
+ else if(Dlg->GetCheck(568)) p = new ContourPlot(this, data);
+ }
+ 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);
+ Command(CMD_SET_DATAOBJ, (void*)data, 0L);
+ CloseDlgWnd(hDlg); delete Dlg; free(GraphDlg);
+ 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, COLBUTT, (void *)&ColGR, 74, 42, 25, 10},
+ {103, 104, 0, 0x0L, RTEXT, (void*)"outline color", 15, 54, 58, 8},
+ {104, 105, 0, TOUCHEXIT | OWNDIALOG, COLBUTT, (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, COLBUTT, (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, COLBUTT, (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;
+ anyOutput *cdisp = Undo.cdisp;
+ bool bRet = false, bContinue = false;
+ fRECT o_gr, n_gr, o_dr, n_dr;
+
+ if(!(Dlg = new DlgRoot(GraphDlg, data)))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);
+ i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, name ? name : (char*)"Graph");
+ rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, (char*)" properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 450, 300, Dlg, 0x4L);
+ do{
+ LoopDlgWnd(); res = Dlg->GetResult();
+ switch (res) {
+ case 600: case 601: case 602: case 603:
+ Undo.SetDisp(cdisp);
+ res = ExecDrawOrderButt(parent, this, res);
+ }
+ 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);
+ break;
+ case 6:
+ Command(CMD_LAYERS, 0L, 0L);
+ bContinue = true;
+ res = -1;
+ break;
+ }
+ }while(res <0);
+ if(res == 1 && bRet) {
+ Undo.SetDisp(cdisp);
+ 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]->Id == GO_FUNC3D))
+ Plots[0]->SetColor(COL_AXIS | UNDO_STORESET, ColAX);
+ }
+ }
+ else if(res == 2) {
+ Undo.SetDisp(cdisp);
+ 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;
+}
+
+static char *AddAxisTmpl =
+ "1,2,,DEFAULT, PUSHBUTTON,-1,148,10,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,148,25,45,12\n"
+ "3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "4,5,50,TOUCHEXIT | ISPARENT,SHEET,1,5,10,130,130\n"
+ "5,6,200,ISPARENT | CHECKED,SHEET,2,5,10,130,130\n"
+ "6,,300,ISPARENT,SHEET,3,5,10,130,130\n"
+ "50,51,100,ISPARENT | CHECKED,GROUPBOX,4,10,30,120,36\n"
+ "51,120,,,CHECKBOX,5,17,37,80,8\n"
+ "100,101,,,RTEXT,6,10,51,35,8\n"
+ "101,102,,,EDVAL1,7,48,51,32,10\n"
+ "102,103,,,CTEXT,8,81,51,11,8\n"
+ "103,,,,EDVAL1,9,93,51,32,10\n"
+ "120,,121,ISPARENT | CHECKED,GROUPBOX,10,10,72,120,20\n"
+ "121,122,,,RTEXT,11,10,77,25,8\n"
+ "122,123,,,EDVAL1,12,37,77,25,10\n"
+ "123,124,,,LTEXT,-3,63,77,10,8\n"
+ "124,125,,,RTEXT,-11,73,77,25,8\n"
+ "125,130,,OWNDIALOG,COLBUTT,14,100,77,25,10\n"
+ "130,131,,ISPARENT | CHECKED,GROUPBOX,15,10,98,120,20\n"
+ "131,,,,EDTEXT,0,15,103,110,10\n"
+ "200,201,,,LTEXT,16,10,30,70,9\n"
+ "201,202,,CHECKED | EXRADIO,ODBUTTON,17,20,42,25,25\n"
+ "202,203,,EXRADIO,ODBUTTON,17,45,42,25,25\n"
+ "203,204,,EXRADIO,ODBUTTON,17,70,42,25,25\n"
+ "204,205,,EXRADIO,ODBUTTON,17,95,42,25,25\n"
+ "205,206,,EXRADIO,ODBUTTON,17,20,67,25,25\n"
+ "206,207,,EXRADIO,ODBUTTON,17,45,67,25,25\n"
+ "207,208,,EXRADIO,ODBUTTON,17,70,67,25,25\n"
+ "208,210,,EXRADIO,ODBUTTON,17,95,67,25,25\n"
+ "210,,220,ISPARENT | CHECKED, GROUPBOX,18,10,97,120,35\n"
+ "220,221,,,RTEXT,-4,10,105,15,8\n"
+ "221,222,,,EDVAL1,19,27,105,35,10\n"
+ "222,223,,,LTEXT,-7,65,105,5,8\n"
+ "223,224,,,EDVAL1,20,71,105,35,10\n"
+ "224,225,,,LTEXT,-3,109,105,15,8\n"
+ "225,226,,,RTEXT,-5,10,117,15,8\n"
+ "226,227,,,EDVAL1,21,27,117,35,10\n"
+ "227,228,,,LTEXT,-7,65,117,5,8\n"
+ "228,229,,,EDVAL1,22,71,117,35,10\n"
+ "229,,,,LTEXT,-3,109,117,15,8\n"
+ "300,,,LASTOBJ | NOSELECT,ODBUTTON,23,15,30,110,140";
+
+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 = DefSize(SIZE_AXIS_LINE);
+ DWORD colAxis = ColAX;
+ void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)" scaling ", (void*)" automatic scaling",
+ (void*)"axis from", (void*)&y_axis.min, (void*)"to", (void*)&y_axis.max, (void*)" line ", (void*)"width",
+ (void*)&sizAxLine, (void*)0L, (void *)&colAxis, (void*)" axis label ", (void*)"select a template:",
+ (void*)(OD_NewAxisTempl), (void*)" placement ", (void*)&axis.loc[0].fx, (void*)&axis.loc[1].fx,
+ (void*)&axis.loc[0].fy, (void*)&axis.loc[1].fy, (void*)OD_axisplot};
+ DlgInfo *NewAxisDlg;
+ 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;
+ anyOutput *cdisp = Undo.cdisp;
+ Axis *the_new, **tmpAxes;
+ bool bAxis = false, bRet = false;
+ char **names;
+ GraphObj **somePlots;
+ Label *label;
+
+ if(!(NewAxisDlg = CompileDialog(AddAxisTmpl, dyndata)))return false;
+ 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*));
+ if(names[0] = (char*)malloc(10)) rlp_strcpy(names[0], 10, "[none]");
+ for(i = 0, j = 1; i < nscp; i++) {
+ if(Sc_Plots[i] && Sc_Plots[i]->name){
+ names[j] = (char*)memdup(Sc_Plots[i]->name, (int)strlen(Sc_Plots[i]->name)+1, 0);
+ 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, data)))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, 318, Dlg, 0x4L);
+ 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) {
+ Dlg->SetValue(221, hx1); Dlg->SetValue(223, hx2);
+ Dlg->SetValue(226, hy1); Dlg->SetValue(228, hy2);
+ if(! bAxis) {
+ Dlg->SetValue(101, x_axis.min); Dlg->SetValue(103, x_axis.max);
+ }
+ }
+ else {
+ Dlg->SetValue(221, vx1); Dlg->SetValue(223, vx2);
+ Dlg->SetValue(226, vy1); Dlg->SetValue(228, vy2);
+ if(! bAxis) {
+ Dlg->SetValue(101, y_axis.min); Dlg->SetValue(103, y_axis.max);
+ }
+ }
+ currTempl = res;
+ Dlg->DoPlot(0L);
+ res = -1;
+ break;
+ }
+ }while (res < 0);
+ if(res == 1) {
+ Undo.SetDisp(cdisp);
+ 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(DefSize(SIZE_AXIS_TICKS));
+ tlb_dx = tlb_dy = 0.0;
+ tlbdef.ColTxt = colAxis; tlbdef.ColBg = 0x00ffffffL;
+ tlbdef.RotBL = tlbdef.RotCHAR = 0.0f; tlbdef.fSize = DefSize(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 = DefSize(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, TMP_TXT_SIZE)) 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; free(NewAxisDlg);
+ 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, cb;
+ bool bRet = false, bContinue = false;
+
+ FindPaper(GRect.Xmax - GRect.Xmin, GRect.Ymax -GRect.Ymin, .0001);
+ if(!(Dlg = new DlgRoot(PageDlg, data)))return false;
+ if(name)cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, name);
+ else cb = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Page");
+ rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE - cb, " properties");
+ hDlg = CreateDlgWnd(TmpTxt, 50, 50, 380, 300, Dlg, 0x4L);
+ 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, 22, 10, "Line"};
+ TabSHEET tab2 = {22, 52, 10, "Shapes"};
+ TabSHEET tab3 = {52, 82, 10, "Dialogs"};
+ TabSHEET tab4 = {82, 116, 10, "Internat."};
+ TabSHEET tab5 = {116, 155, 10, "Date/Time"};
+ double ts = dlgtxtheight;
+ time_t ti = time(0L);
+ char dt_info[50], date_info[50], datetime_info[50], time_info[50];
+ DlgInfo DefsDlg[] = {
+ {1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 180, 10, 40, 12},
+ {2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 180, 25, 40, 12},
+ {3, 0, 4, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+ {4, 5, 100, TOUCHEXIT | ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 170, 130},
+ {5, 6, 200, TOUCHEXIT | ISPARENT, SHEET, &tab2, 5, 10, 170, 130},
+ {6, 7, 300, TOUCHEXIT | ISPARENT, SHEET, &tab3, 5, 10, 170, 130},
+ {7, 8, 400, TOUCHEXIT | ISPARENT, SHEET, &tab4, 5, 10, 170, 130},
+ {8, 0, 350, TOUCHEXIT | ISPARENT, SHEET, &tab5, 5, 10, 170, 130},
+ {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},
+ {350, 351, 0, 0x0L, LTEXT, (void*)dt_info, 10, 30, 120, 8},
+ {351, 352, 0, 0x0L, LTEXT, (void*)"date format:", 10, 43, 70, 8},
+ {352, 353, 0, 0x0L, EDTEXT, (void*)defs.fmt_date, 10, 53, 60, 10},
+ {353, 354, 0, 0x0L, LTEXT, (void*)date_info, 80, 54, 40, 10},
+ {354, 355, 0, 0x0L, LTEXT, (void*)"date + time format:", 10, 65, 70, 8},
+ {355, 356, 0, 0x0L, EDTEXT, (void*)defs.fmt_datetime, 10, 75, 60, 10},
+ {356, 357, 0, 0x0L, LTEXT, (void*)datetime_info, 80, 76, 40, 10},
+ {357, 358, 0, 0x0L, LTEXT, (void*)"time format:", 10, 87, 70, 8},
+ {358, 359, 0, 0x0L, EDTEXT, (void*)defs.fmt_time, 10, 97, 60, 10},
+ {359, 360, 0, 0x0L, LTEXT, (void*)time_info, 80, 98, 40, 10},
+ {360, 361, 0, 0x0L, LTEXT, (void*)"For further information about formats see", 10, 119, 140, 8},
+ {361, 362, 0, HREF | TOUCHEXIT, LTEXT, (void*)"http://rlplot.sourceforge.net/Docs/functions/datetime.html", 10, 127, 140, 8},
+ {362, 0, 0, 0x0L, PUSHBUTTON, (void*)"Test", 130, 107, 40, 12},
+ {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 i, cb, res, tmpUnits = cUnits;
+ bool bRet = false, bContinue = false;
+ double dt;
+ 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);
+ cb = rlp_strcpy(dt_info, 20, "today is ");
+#ifdef USE_WIN_SECURE
+ ctime_s(dt_info+cb, 50-cb, &ti);
+#else
+ rlp_strcpy(dt_info+cb, 50-cb, ctime(&ti));
+#endif
+ dt_info[cb+24] = 0;
+ date_value(dt_info+13, "x z H:M:S Y", &dt);
+ rlp_strcpy(date_info, 50, value_date(dt, defs.fmt_date));
+ rlp_strcpy(datetime_info, 50, value_date(dt, defs.fmt_datetime));
+ rlp_strcpy(time_info, 50, value_date(dt, defs.fmt_time));
+ Dlg = new DlgRoot(DefsDlg, 0L);
+ 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;
+ }
+#ifdef _WINDOWS
+ for(i = 360; i <= 361; i++) Dlg->TextSize(i, 12);
+#else
+ for(i = 360; i <= 361; i++) Dlg->TextSize(i, 10);
+#endif
+ hDlg = CreateDlgWnd("Edit Global Preferences", 50, 50, 460, 316, Dlg, 0x4L);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 0:
+ if(bContinue) res = -1;
+ break;
+ case 362: //update date/time display
+ ti = time(0L); cb = rlp_strcpy(dt_info, 20, "today is ");
+#ifdef USE_WIN_SECURE
+ ctime_s(dt_info+cb, 50-cb, &ti);
+#else
+ rlp_strcpy(dt_info+cb, 50-cb, ctime(&ti));
+#endif
+ dt_info[cb+24] = 0; Dlg->SetText(350, dt_info);
+ date_value(dt_info+13, "x z H:M:S Y", &dt);
+ if(!(Dlg->GetText(352, date_info, 50))) rlp_strcpy(date_info, 50, defs.fmt_date);
+ rlp_strcpy(date_info, 50, value_date(dt, date_info)); Dlg->SetText(353, date_info);
+ if(!(Dlg->GetText(355, datetime_info, 50))) rlp_strcpy(datetime_info, 50, defs.fmt_datetime);
+ rlp_strcpy(datetime_info, 50, value_date(dt, datetime_info)); Dlg->SetText(356, datetime_info);
+ if(!(Dlg->GetText(358, time_info, 50))) rlp_strcpy(time_info, 50, defs.fmt_time);
+ rlp_strcpy(time_info, 50, value_date(dt, time_info)); Dlg->SetText(359, time_info);
+ bContinue = false; res = -1;
+ break;
+ case 361: //call browser
+ bContinue = true; res = -1;
+ break;
+ case 4: case 5: case 6: case 7:
+ bContinue = false; res = -1;
+ break;
+ case 8:
+ bContinue = true; 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, TMP_TXT_SIZE)) DecPoint[0] = TmpTxt[0];
+ if(Dlg->GetText(404, TmpTxt, TMP_TXT_SIZE)) ColSep[0] = TmpTxt[0];
+ 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);
+ if(Dlg->GetText(352, date_info, 50) && date_info[0] && strcmp(date_info, defs.fmt_date)) {
+ if(defs.fmt_date = (char*)realloc(defs.fmt_date, (cb = (int)strlen(date_info) +2)))
+ rlp_strcpy(defs.fmt_date, cb, date_info);
+ }
+ if(Dlg->GetText(355, datetime_info, 50) && datetime_info[0] && strcmp(datetime_info, defs.fmt_datetime)) {
+ if(defs.fmt_datetime = (char*)realloc(defs.fmt_datetime, (cb = (int)strlen(datetime_info) +2)))
+ rlp_strcpy(defs.fmt_datetime, cb, datetime_info);
+ }
+ if(Dlg->GetText(358, time_info, 50) && time_info[0] && strcmp(time_info, defs.fmt_time)) {
+ if(defs.fmt_time = (char*)realloc(defs.fmt_time, (cb = (int)strlen(time_info) +2)))
+ rlp_strcpy(defs.fmt_time, cb, time_info);
+ }
+ bRet = true;
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ return bRet;
+}
diff --git a/QT3_Spec.h b/QT3_Spec.h
index 8dec2a6..8ac0efa 100755
--- a/QT3_Spec.h
+++ b/QT3_Spec.h
@@ -1,4 +1,4 @@
-//QT_Spec.h, Copyright (c) 2001-2007 R.Lackner
+//QT_Spec.h, Copyright (c) 2001-2008 R.Lackner
//
// This file is part of RLPlot.
//
@@ -81,10 +81,11 @@ private:
class RLPserver {
public:
GraphObj *SourceGO;
+ bool bValid;
RLPserver(QObject* parent=0, GraphObj *g=0);
~RLPserver();
-
+ void CreateThread();
void SetGO(GraphObj *g);
char *GetXML();
char *GetRLP();
@@ -145,6 +146,10 @@ public slots:
void cmZoomFit(){ProcMenuEvent(CM_ZOOMFIT, this, OutputClass, BaseObj);};
void cmPaste();
void cmUndo(){if(BaseObj) BaseObj->Command(CMD_UNDO, 0L, OutputClass);};
+ void cmSave(){ProcMenuEvent(CM_SAVE, this, OutputClass, BaseObj);};
+ void cmOpen(){ProcMenuEvent(CM_OPEN, this, OutputClass, BaseObj);};
+ void cmPrint(){ProcMenuEvent(CM_PRINT, this, OutputClass, BaseObj);};
+ void cmNewInst(){ProcMenuEvent(CM_NEWINST, this, OutputClass, BaseObj);};
protected:
void paintEvent(QPaintEvent *);
@@ -170,7 +175,7 @@ public:
QPixmap *mempic;
anyOutput *OutputClass;
- DlgWidget(QWidget *par=0, const char *name=0, tag_DlgObj *d = 0);
+ DlgWidget(QWidget *par=0, const char *name=0, tag_DlgObj *d = 0, DWORD flags = 0L);
~DlgWidget();
protected:
@@ -238,13 +243,15 @@ public:
~OutputQT();
bool ActualSize(RECT *rc);
void Focus(){if(widget){widget->show(); widget->raise();}};
- void Caption(char *txt);
+ void Caption(char *txt, bool bModified);
void MouseCursor(int cid, bool force);
bool SetScroll(bool isVert, int iMin, int iMax, int iPSize, int iPos);
bool EndPage();
+ void MouseCapture(bool bgrab);
bool UpdateRect(RECT *rc, bool invert);
void ShowLine(POINT * pts, int cp, DWORD color);
- void ShowEllipse(POINT p1, POINT p2, DWORD color);
+ void ShowEllipse(POINT p1, POINT p2, DWORD color);
+ void ShowInvert(RECT *rec);
bool SetMenu(int type);
void CheckMenu(int mid, bool check);
void FileHistory();
diff --git a/QT_Spec.cpp b/QT_Spec.cpp
index 391157e..7595d5b 100755
--- a/QT_Spec.cpp
+++ b/QT_Spec.cpp
@@ -1,4 +1,4 @@
-//QT_Spec.cpp, Copyright (c) 2001-2007 R.Lackner
+//QT_Spec.cpp, Copyright (c) 2001-2008 R.Lackner
//
// This file is part of RLPlot.
//
@@ -26,6 +26,10 @@
#include "QT_Spec.h"
#endif
+#ifndef __GCC__ //GCC version >= 3 required for threads: used for clipboard only
+ #define __GCC__ 3
+#endif
+
extern tag_Units Units[];
extern GraphObj *CurrGO; //Selected Graphic Objects
extern Graph *CurrGraph;
@@ -39,11 +43,18 @@ QApplication *QAppl;
QWidget *MainWidget =0L, *CurrWidget = 0L;
POINT CurrWidgetPos = {0,0};
static int mouse_buttons_down = 0;
+static char *ShellCmd;
#if QT_VERSION >= 0x040000
static QIcon *rlp_icon = 0L;
#endif
+#if QT_VERSION < 0x040000
+ #define MK_QCOLOR(col) QColor(col&0xff,(col>>8)&0xff,(col>>16)&0xff)
+#else
+ #define MK_QCOLOR(col) QColor(col&0xff,(col>>8)&0xff,(col>>16)&0xff,255-((col>>24)&0xff))
+#endif
+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Export a QPixmap as supported by Qt
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -372,18 +383,6 @@ void Qt_Box()
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 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;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Temporary visible objects: show action
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class eph_obj {
@@ -466,7 +465,7 @@ eph_line::DoPlot(QPainter *qp)
if(next)next->DoPlot(qp);
if(!points || cp < 2) return;
- qpen.setColor(SwapRB(lcolor)); qpen.setWidth(1);
+ qpen.setColor(MK_QCOLOR(lcolor)); qpen.setWidth(1);
qpen.setStyle(Qt::SolidLine); qpen.setCapStyle(Qt::RoundCap);
qpen.setJoinStyle(Qt::RoundJoin); qp->setPen(qpen);
for (i = 1; i < cp; i++)qp->drawLine(points[i-1].x, points[i-1].y, points[i].x, points[i].y);
@@ -490,7 +489,7 @@ eph_ellipse::DoPlot(QPainter *qp)
QPen qpen;
if(next)next->DoPlot(qp);
- qpen.setColor(SwapRB(lcolor)); qpen.setWidth(1);
+ qpen.setColor(MK_QCOLOR(lcolor)); qpen.setWidth(1);
qpen.setStyle(Qt::SolidLine); qpen.setCapStyle(Qt::RoundCap);
qpen.setJoinStyle(Qt::RoundJoin); qp->setPen(qpen);
qp->drawArc(p1.x, p1.y, p2.x-p1.x, p2.y-p1.y, 0, 5760);
@@ -650,6 +649,7 @@ void ShowTextCursor(anyOutput *out, RECT *disp, DWORD color)
{
LineDEF liTxtCur = {0.0, 1.0, 0x0L, 0L};
+ if(!out || (out->OC_type&0xff) != OC_BITMAP) return;
coTxtCur = color; HideTextCursor();
oTxtCur = out; bSuspend = false;
memcpy(&rTxtCur, disp, sizeof(RECT)); ptTxtCurLine[0].x = 0;
@@ -685,6 +685,7 @@ void ShowCopyMark(anyOutput *out, RECT *mrk, int nRec)
{
int i;
+ if(!out || (out->OC_type&0xff) != OC_BITMAP) return;
HideCopyMark(); bSuspend = false;
if(!out || !mrk || !nRec || !cTxtCur) return;
if(((OutputQT*)out)->ShowAnimated) delete (eph_obj*)(((OutputQT*)oCopyMark)->ShowAnimated);
@@ -703,6 +704,7 @@ void ShowCopyMark(anyOutput *out, RECT *mrk, int nRec)
void InvalidateOutput(anyOutput *o)
{
+ if(!o || (o->OC_type&0xff) != OC_BITMAP) return;
if(!o || !cTxtCur) return;
if(o == oCopyMark) oCopyMark = 0L;
if(o == oTxtCur) {
@@ -712,6 +714,7 @@ void InvalidateOutput(anyOutput *o)
void SuspendAnimation(anyOutput *o, bool bSusp)
{
+ if(!o || (o->OC_type&0xff) != OC_BITMAP) return;
if(!o || !cTxtCur) return;
if(!bSusp) bSuspend = false;
else {
@@ -722,6 +725,7 @@ void SuspendAnimation(anyOutput *o, bool bSusp)
static void showCopyMark()
{
+ if(!oCopyMark || (oCopyMark->OC_type&0xff) != OC_BITMAP) return;
if(oCopyMark && ((OutputQT*)oCopyMark)->ShowAnimated)
((eph_obj*)(((OutputQT*)oCopyMark)->ShowAnimated))->Animate(oCopyMark);
@@ -777,6 +781,7 @@ static RLPserver *rlpsrv = 0L;
#ifdef RLP_PORT
static char *cb_owner = 0L; //user name
+#if __GCC__ >= 3
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// close remote clipboard server
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -793,17 +798,27 @@ bool CloseCB(char *msg)
memcpy(&cb_host.sin_addr, hp->h_addr, hp->h_length);
cb_host.sin_family = AF_INET; cb_host.sin_port = htons(RLP_PORT);
if(connect(sock, (sockaddr*)&cb_host, sizeof(cb_host)) >= 0) {
-// if(ioctl(sock, FIONREAD, &i) >= 0) {
-// if((cb = read(sock, &buff, 1024) > 0) && cb < 1024) {
-// if(strcmp("user:", buff) == 0) {
-// write(sock, cb_owner, strlen(cb_owner)+1);
-// ioctl(sock, BLKFLSBUF, &i);
-// }
-// }
-// }
+ if(ioctl(sock, FIONREAD, &i) >= 0 && i > 0) {
+ if((cb = read(sock, &buff, 1024) > 0) && cb < 1024) {
+ if(strcmp("user:", buff) == 0) {
+ write(sock, cb_owner, strlen(cb_owner)+1);
+ }
+ else goto CloseCBerror;
+ }
+ else goto CloseCBerror;
+ if((cb = read(sock, &buff, 1024) > 0) && cb < 1024) {
+ if(strcmp("OK", buff) != 0) goto CloseCBerror;
+ }
+ else goto CloseCBerror;
+ }
+ else goto CloseCBerror;
write(sock, msg, strlen(msg)+1);
+ for(i = 0; i < 4; i++) {
+ if(ioctl(sock, TIOCOUTQ, &cb) <= 0 || cb <= 0) break;
+ }
close(sock); return true;
}
+CloseCBerror:
close(sock); return false;
}
@@ -824,18 +839,30 @@ bool ReadCB(char *server, GraphObj *g)
memcpy(&cb_host.sin_addr, hp->h_addr, hp->h_length);
cb_host.sin_family = AF_INET; cb_host.sin_port = htons(RLP_PORT);
if(connect(sock, (sockaddr*)&cb_host, sizeof(cb_host)) >= 0) {
-// if(ioctl(sock, FIONREAD, &i) >= 0) {
-// if((cb = read(sock, &buff, 1024) > 0) && cb < 1024) {
-// if(strcmp("user:", buff) == 0) {
-// write(sock, cb_owner, strlen(cb_owner)+1);
-// ioctl(sock, BLKFLSBUF, &i);
-// }
-// }
-// }
+ if(ioctl(sock, FIONREAD, &i) >= 0 && i > 0) {
+ if((cb = read(sock, &buff, 1024) > 0) && cb < 1024) {
+ if(strcmp("user:", buff) == 0) {
+ write(sock, cb_owner, strlen(cb_owner)+1);
+ }
+ else return false;
+ }
+ else return false;
+ if((cb = read(sock, &buff, 1024) > 0) && cb < 1024) {
+ if(strcmp("OK", buff) != 0) {
+ close(sock); return false;
+ }
+ }
+ else {
+ close(sock); return false;
+ }
+ }
+ else {
+ close(sock); return false;
+ }
if(!(write(sock, "enum formats\n", 14) > 0)) {
- close(sock); return false;
+ close(sock); return false;
}
- if((cb = read(sock, &buff, 1024)) && cb < 1024) {
+ if((cb = read(sock, &buff, 1024)) >= 0 && cb < 1024) {
for(i = 0, format[0] = 0; i < cb; ) {
for (j = 0; j < 20 && i < cb; j++) {
if((line[j] = buff[i++]) < 32) break;
@@ -901,18 +928,23 @@ static void *ServerCB(void* attr)
bool bValid;
if(!parent) return 0L;
+ parent->bValid = true;
for( ; ; ) {
bValid = false;
if((msgsock = accept(parent->Socket(), (sockaddr*)&client, &clientlen)) >= 0){
-// if(write(msgsock, "user:", 6) > 0) {
-// if((cb = read(msgsock, &buff, 1024) > 0) && cb < 1024){
-// if(strcmp(buff, cb_owner) == 0) bValid = true;
-// }
-// }
-
- bValid = true; //FIXME
-
- while(bValid && (cb = read(msgsock, &buff, 1024) > 0) && cb < 1024) {
+ if(write(msgsock, "user:", 6) > 0) {
+ if((cb = read(msgsock, &buff, 1024) > 0) && cb < 1024){
+ if(strcmp(buff, cb_owner) == 0) {
+ bValid = true;
+ write(msgsock, "OK\0", 3);
+ }
+ else {
+ write(msgsock, "NO\0", 3);
+ close(msgsock);
+ }
+ }
+ }
+ while(bValid && parent && (cb = read(msgsock, &buff, 1024) > 0) && cb < 1024) {
if(strcmp(buff, "enum formats\n") == 0 && parent->SourceGO) {
if(parent->SourceGO->Id == GO_SPREADDATA) {
write(msgsock, fmts_1, strlen(fmts_1)+1);
@@ -940,7 +972,9 @@ static void *ServerCB(void* attr)
}
else if(strcmp(buff, "exit\n") == 0 || strcmp(buff, "close\n") == 0
|| strcmp(buff, "exit") == 0 || strcmp(buff, "close") == 0) {
- delete(parent); return 0L;
+ HideCopyMark(); parent->bValid = false;
+ if(parent->SourceGO) parent->SourceGO->Command(CMD_HIDEMARK, 0L, 0L);
+ return 0L;
}
else if(strcmp(buff, "exit_thread\n") == 0) {
return 0L;
@@ -957,29 +991,13 @@ static void *ServerCB(void* attr)
}
// end of thread
#endif //RLP_PORT
+#endif //__GCC__
RLPserver::RLPserver(QObject* parent, GraphObj *g)
{
+ bValid = false;
text_xml = text_rlp = text_plain = 0L;
- SetGO(g);
-#ifdef RLP_PORT
- int i;
- sockaddr_in server, client;
- socklen_t clientlen = sizeof(client);
-
- if((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) return;
- i = 1;
- setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(int));
- if(fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) & ~O_NONBLOCK) < 0);
- memset(&server, 0, sizeof(server));
- server.sin_family = AF_UNIX;
- server.sin_addr.s_addr = INADDR_ANY;
- server.sin_port = htons(RLP_PORT);
- if(bind(sock, (struct sockaddr*)&server, sizeof(server)) < 0) return;
- if(listen(sock, 5) < 0) return;
- pthread_attr_init(&thread_attr);
- pthread_create(&thread, &thread_attr, ServerCB, this);
-#endif
+ SetGO(g); CreateThread();
}
RLPserver::~RLPserver()
@@ -990,11 +1008,40 @@ RLPserver::~RLPserver()
if(text_rlp) free(text_rlp); text_rlp = 0L;
if(text_plain) free(text_plain); text_plain = 0L;
if(SourceGO) SourceGO->Command(CMD_HIDEMARK, 0L, 0L);
+#if __GCC__ >= 3
#ifdef RLP_PORT
CloseCB("exit_thread\n"); close(sock);
pthread_attr_destroy(&thread_attr);
-#endif
+#endif //RLP_PORT
+#endif //__GCC__
+}
+
+void
+RLPserver::CreateThread()
+{
+#if __GCC__ >= 3
+#ifdef RLP_PORT
+ int i;
+ sockaddr_in server, client;
+ socklen_t clientlen = sizeof(client);
+
+ if(!bValid) {
+ if((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) return;
+ i = 1;
+// setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(int));
+ if(fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) & ~O_NONBLOCK) < 0);
+ memset(&server, 0, sizeof(server));
+ server.sin_family = AF_UNIX;
+ server.sin_addr.s_addr = INADDR_ANY;
+ server.sin_port = htons(RLP_PORT);
+ if(bind(sock, (struct sockaddr*)&server, sizeof(server)) < 0) return;
+ if(listen(sock, 5) < 0) return;
+ pthread_attr_init(&thread_attr);
+ pthread_create(&thread, &thread_attr, ServerCB, this);
+ }
+#endif //RLP_PORT
+#endif //GCC
}
void
@@ -1019,6 +1066,7 @@ RLPserver::SetGO(GraphObj *g)
#endif
}
}
+ if(!bValid) CreateThread();
}
char *
@@ -1057,12 +1105,16 @@ void TestClipboard(GraphObj *g)
|| rlpsrv->SourceGO->Id == GO_ELLIPSE || rlpsrv->SourceGO->Id == GO_BEZIER
)
OpenGraph(g, 0L, (unsigned char*)rlpsrv->GetRLP(), true);
- else if(rlpsrv->SourceGO->Id == GO_SPREADDATA && g->Id == GO_SPREADDATA)
+ else if(rlpsrv->SourceGO->Id == GO_SPREADDATA && g->Id == GO_SPREADDATA){
g->Command(CMD_PASTE_XML, (void*)rlpsrv->GetXML(), 0L);
+ return;
+ }
}
+#if __GCC__ >= 3
#ifdef RLP_PORT
else if(ReadCB(0L, g)) return;
#endif
+#endif
#if QT_VERSION < 0x040000
QDragObject *mime;
@@ -1095,13 +1147,7 @@ void TestClipboard(GraphObj *g)
void CopyData(GraphObj *g)
{
QAppl->clipboard()->clear();
- if(rlpsrv) {
- if(rlpsrv->ok()) rlpsrv->SetGO(g);
- else {
- delete rlpsrv;
- rlpsrv = new RLPserver(0, g);
- }
- }
+ if(rlpsrv) rlpsrv->SetGO(g);
else rlpsrv = new RLPserver(0, g);
}
@@ -1113,19 +1159,24 @@ void CopyGraph(GraphObj *g)
void EmptyClip()
{
- if(rlpsrv) {
- delete(rlpsrv); rlpsrv = 0;
+#if __GCC__ >= 3
+#ifdef RLP_PORT
+ CloseCB("close\n");
+#endif //RLP_PORT
+#endif //GCC
+ if(rlpsrv && !rlpsrv->bValid) {
+ delete(rlpsrv); rlpsrv = 0L;
}
- else CloseCB("close\n");
HideCopyMark();
QAppl->clipboard()->clear();
}
void CopyText(char *txt, int len)
{
+
QClipboard *cb;
- HideCopyMark();
+ EmptyClip();
if(!(cb = QAppl->clipboard()) || !txt || !txt[0]) return;
cb->clear();
cb->setText(txt);
@@ -1216,18 +1267,18 @@ bool com_QStringOut(int x, int y, QString txt, TextDEF *TxtSet, QPainter *qP, an
if(TxtSet->Align & TXA_HCENTER) ix = x - (w >> 1);
else if(TxtSet->Align & TXA_HRIGHT) ix = x - w;
else ix = x;
- currPen.setColor(SwapRB(TxtSet->ColTxt));
+ currPen.setColor(MK_QCOLOR(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));
+ currPen.setColor(MK_QCOLOR(TxtSet->ColBg));
qP->setPen(currPen);
- qP->setBrush(QColor(SwapRB(TxtSet->ColBg)));
+ qP->setBrush(MK_QCOLOR(TxtSet->ColBg));
qP->drawRect(0, - iround(h*.8), w, h);
- currPen.setColor(SwapRB(TxtSet->ColTxt));
+ currPen.setColor(MK_QCOLOR(TxtSet->ColTxt));
qP->setPen(currPen);
}
if(TxtSet->Style & TXS_SUB) iy += ((TxtSet->iSize <<2)/10);
@@ -1236,11 +1287,11 @@ bool com_QStringOut(int x, int y, QString txt, TextDEF *TxtSet, QPainter *qP, an
}
else {
if(TxtSet->Mode == TXM_OPAQUE){
- currPen.setColor(SwapRB(TxtSet->ColBg));
+ currPen.setColor(MK_QCOLOR(TxtSet->ColBg));
qP->setPen(currPen);
- qP->setBrush(QColor(SwapRB(TxtSet->ColBg)));
+ qP->setBrush(MK_QCOLOR(TxtSet->ColBg));
qP->drawRect(ix, iy - iround(h*.8), w, h);
- currPen.setColor(SwapRB(TxtSet->ColTxt));
+ currPen.setColor(MK_QCOLOR(TxtSet->ColTxt));
qP->setPen(currPen);
}
if(TxtSet->Style & TXS_SUB) iy += o->un2iy(TxtSet->fSize*0.4);
@@ -1524,7 +1575,8 @@ BitMapQT::BitMapQT(GraphObj *g, QMainWindow *wi, int vr, int hr):anyOutput()
hres = (double)hr; vres = (double)vr;
image = 0L; hgo = 0L;
dlgwidget = 0L; widget = wi;
- ShowObj = ShowAnimated = 0L;
+ ShowObj = ShowAnimated = 0L; minLW = 1;
+ OC_type = OC_BITMAP;
if(wi) {
w = wi->width(); h = wi->height();
}
@@ -1553,7 +1605,8 @@ BitMapQT::BitMapQT(GraphObj *g, QWidget *wi, int vr, int hr):anyOutput()
hres = (double)hr; vres = (double)vr;
image = 0L; hgo = 0L;
dlgwidget = wi; widget = 0L;
- ShowObj = ShowAnimated = 0L;
+ ShowObj = ShowAnimated = 0L; minLW = 1;
+ OC_type = OC_BITMAP;
if(wi) {
w = wi->width(); h = wi->height();
}
@@ -1580,10 +1633,10 @@ BitMapQT::BitMapQT(int w, int h, double hr, double vr):anyOutput()
hres = hr; vres = vr;
image = 0L; hgo = 0L; widget = 0L;
w = abs(w); h = abs(h); ShowObj = ShowAnimated = 0L;
- Box1.Xmin = Box1.Ymin = 0.0;
+ Box1.Xmin = Box1.Ymin = 0.0; minLW = 1;
Box1.Xmax = w; Box1.Ymax = h;
DeskRect.right = w; DeskRect.bottom = h;
- DeskRect.left = DeskRect.top = 0;
+ DeskRect.left = DeskRect.top = 0; OC_type = OC_BITMAP;
mempic = new QPixmap(w, h);
mempic->fill(0x00ffffffL);
qPainter.begin(mempic);
@@ -1619,10 +1672,10 @@ BitMapQT::SetLine(LineDEF *lDef)
RLP.finc = 256.0/un2fix(lDef->patlength*8.0);
RLP.fp = 0.0;
if(iLine == iw && dLineCol == lDef->color) return true;
- iLine = iw;
+ iLine = iw > minLW ? iw : minLW;
dLineCol = lDef->color;
- qPen.setColor(SwapRB(dLineCol));
- qPen.setWidth(iw);
+ qPen.setColor(MK_QCOLOR(dLineCol));
+ qPen.setWidth(iLine);
qPen.setStyle(Qt::SolidLine);
qPen.setCapStyle(Qt::RoundCap);
qPen.setJoinStyle(Qt::RoundJoin);
@@ -1643,12 +1696,10 @@ BitMapQT::SetFill(FillDEF *fill)
if(hgo) hgo->SetFill(fill);
}
else {
- if(hgo) delete hgo;
- hgo = 0L;
+ if(hgo) delete hgo; hgo = 0L;
}
- qPainter.setBrush(QColor(SwapRB(fill->color)));
- dFillCol = fill->color;
- dFillCol2 = fill->color2;
+ qPainter.setBrush(MK_QCOLOR(fill->color));
+ dFillCol = fill->color; dFillCol2 = fill->color2;
return true;
}
@@ -1713,10 +1764,9 @@ BitMapQT::oGetPix(int x, int y, DWORD *col)
#else
if(!image && !(image = new QImage(mempic->toImage())))return false;
#endif
- if(x >= DeskRect.left && x < DeskRect.right &&
- y >= DeskRect.top && y < DeskRect.bottom){
- pix = SwapRB(image->pixel(x, y));
- *col = pix;
+ if(x >= DeskRect.left && x < DeskRect.right && y >= DeskRect.top && y < DeskRect.bottom){
+ pix = image->pixel(x,y); *col = pix & 0x0000ff00L;
+ *col |= (pix>>16)&0x000000ffL; *col |= (pix<<16)&0x00ff0000L;
return true;
}
return false;
@@ -1788,7 +1838,7 @@ BitMapQT::oRectangle(int x1, int y1, int x2, int y2, char *nam)
#if QT_VERSION < 0x040000
qPainter.drawRect(x1, y1, x2-x1, y2-y1);
#else
- qPainter.drawRect(x1, y1, x2-x1-1, y2-y1-1);
+ qPainter.drawRect(x1, y1, x2-x1, y2-y1);
#endif
if(hgo) hgo->oRectangle(x1, y1, x2, y2, 0L);
return true;
@@ -1863,10 +1913,10 @@ bool ProcMenuEvent(int id, QWidget *parent, anyOutput *OutputClass, GraphObj *Ba
if(BaseObj) switch(id) {
case CM_OPEN:
BaseObj->Command(CMD_OPEN, 0L, OutputClass); return true;
- case CM_SAVEDATA:
- BaseObj->Command(CMD_SAVEDATA, 0L, OutputClass); return true;
- case CM_SAVEDATAAS:
- BaseObj->Command(CMD_SAVEDATAAS, 0L, OutputClass); return true;
+ case CM_SAVE:
+ BaseObj->Command(CMD_SAVE, 0L, OutputClass); return true;
+ case CM_SAVEAS:
+ BaseObj->Command(CMD_SAVEAS, 0L, OutputClass); return true;
case CM_INSROW:
BaseObj->Command(CMD_INSROW, 0L, OutputClass); return true;
case CM_INSCOL:
@@ -1875,8 +1925,6 @@ bool ProcMenuEvent(int id, QWidget *parent, anyOutput *OutputClass, GraphObj *Ba
BaseObj->Command(CMD_DELROW, 0L, OutputClass); return true;
case CM_DELCOL:
BaseObj->Command(CMD_DELCOL, 0L, OutputClass); return true;
- case CM_SAVEGRAPHAS:
- SaveGraphAs(BaseObj); return true;
case CM_EXPORT:
if(OutputClass) {
OutputClass->HideMark(); OpenExportName(BaseObj, 0L);
@@ -1936,6 +1984,8 @@ bool ProcMenuEvent(int id, QWidget *parent, anyOutput *OutputClass, GraphObj *Ba
BaseObj->Command(CMD_CONFIG, 0L, OutputClass); return true;
case CM_REPANOV:
rep_anova(BaseObj, BaseObj->data); return true;
+ case CM_REPBDANOV:
+ rep_bdanova(BaseObj, BaseObj->data); return true;
case CM_REPKRUSKAL:
rep_kruskal(BaseObj, BaseObj->data); return true;
case CM_REPTWANR:
@@ -1978,8 +2028,10 @@ bool ProcMenuEvent(int id, QWidget *parent, anyOutput *OutputClass, GraphObj *Ba
else if(BaseObj->Id == GO_SPREADDATA) QAppl->exit(0);
}
return true;
+ case CM_NEWINST:
+ if(ShellCmd && ShellCmd[0]) system(ShellCmd);
+ return true;
case CM_COPY: case CM_CUT: case CM_COPYGRAPH:
- EmptyClip();
if(CurrGO && BaseObj->Id != GO_SPREADDATA) {
if(CurrGO->Id == GO_POLYLINE || CurrGO->Id == GO_POLYGON || CurrGO->Id == GO_RECTANGLE
|| CurrGO->Id == GO_ROUNDREC || CurrGO->Id == GO_ELLIPSE || CurrGO->Id == GO_BEZIER) {
@@ -2204,9 +2256,11 @@ OutputQT::ActualSize(RECT *rc)
}
void
-OutputQT::Caption(char *txt)
+OutputQT::Caption(char *txt, bool bModified)
{
QString cap(txt);
+
+ if(bModified) cap.append(" [modified]");
#if QT_VERSION < 0x040000
if(widget) widget->setCaption(cap);
else if(dlgwidget) dlgwidget->setCaption(cap);
@@ -2553,6 +2607,19 @@ OutputQT::EndPage()
return true;
}
+void
+OutputQT::MouseCapture(bool bgrab)
+{
+#if QT_VERSION >= 0x040000
+ if(!dlgwidget) return;
+ if(bgrab && dlgwidget->isModal()) return;
+ if(!bgrab && !dlgwidget->isModal()) return;
+ dlgwidget->hide();
+ dlgwidget->setWindowModality(bgrab ? Qt::ApplicationModal : Qt::NonModal);
+ dlgwidget->show();
+#endif
+}
+
bool
OutputQT::UpdateRect(RECT *rc, bool invert)
{
@@ -2600,7 +2667,7 @@ OutputQT::ShowLine(POINT * pts, int cp, DWORD color)
}
rec.left -= 2; rec.top -= 2; rec.bottom += 2; rec.right += 2;
if(rec.bottom < 2 && rec.top < 2) return;
- ShowObj = new eph_line((eph_line*)ShowObj, pts, cp, color);
+ if(!(ShowObj = new eph_line((eph_line*)ShowObj, pts, cp, color)))return;
#if QT_VERSION >= 0x040000
UpdateRect(&rec, false);
#else
@@ -2617,7 +2684,7 @@ OutputQT::ShowEllipse(POINT p1, POINT p2, DWORD color)
rec.left = rec.right = p1.x; rec.top = rec.bottom = p1.y;
UpdateMinMaxRect(&rec, p2.x, p2.y); IncrementMinMaxRect(&rec, 2);
if(rec.bottom < 2 && rec.top < 2) return;
- ShowObj = new eph_ellipse((eph_obj*)ShowObj, p1, p2, color);
+ if(!(ShowObj = new eph_ellipse((eph_obj*)ShowObj, p1, p2, color)))return;
#if QT_VERSION >= 0x040000
UpdateRect(&rec, false);
#else
@@ -2625,6 +2692,17 @@ OutputQT::ShowEllipse(POINT p1, POINT p2, DWORD color)
((eph_obj*)ShowObj)->DoPlot(&qp);
#endif
}
+void
+OutputQT::ShowInvert(RECT *rec)
+{
+ POINT spts[5];
+
+ spts[0].x = spts[4].x = spts[3].x = rec->left;
+ spts[0].y = spts[4].y = spts[1].y = rec->top;
+ spts[1].x = spts[2].x = rec->right;
+ spts[2].y = spts[3].y = rec->bottom;
+ ShowLine(spts, 5, 0x0);
+}
#if QT_VERSION < 0x040000
#define RLP_MITEM(menu,par,o,go,txt,id) menu->insertItem(txt,id)
@@ -2699,11 +2777,24 @@ OutputQT::SetMenu(int type)
QMenu *graph = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&Graph"));
QMenu *about = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&?"));
#endif
- RLP_MITEM(file, widget, this, BaseObj, "&Open", CM_OPEN);
- RLP_MITEM(file, widget, this, BaseObj, "&Save", CM_SAVEDATA);
- RLP_MITEM(file, widget, this, BaseObj, "Save &as", CM_SAVEDATAAS);
+#if QT_VERSION < 0x040000
+ file->insertItem("&New Instance", widget, SLOT(cmNewInst()), Qt::CTRL + Qt::Key_N);
+ file->insertSeparator();
+ file->insertItem("&Open", widget, SLOT(cmOpen()), Qt::CTRL + Qt::Key_O);
+ file->insertItem("&Save", widget, SLOT(cmSave()), Qt::CTRL + Qt::Key_S);
+#else
+ file->addAction("&New Instance", widget, SLOT(cmNewInst()), Qt::CTRL + Qt::Key_N);
+ file->addSeparator();
+ file->addAction("&Open", widget, SLOT(cmOpen()), Qt::CTRL +Qt::Key_O);
+ file->addAction("&Save", widget, SLOT(cmSave()), Qt::CTRL +Qt::Key_S);
+#endif
+ RLP_MITEM(file, widget, this, BaseObj, "Save &as", CM_SAVEAS);
RLP_MSEPARATOR(file);
- RLP_MITEM(file, widget, this, BaseObj, "&Print", CM_PRINT);
+#if QT_VERSION < 0x040000
+ file->insertItem("&Print", widget, SLOT(cmPrint()), Qt::CTRL + Qt::Key_P);
+#else
+ file->addAction("&Print", widget, SLOT(cmPrint()), Qt::CTRL + Qt::Key_P);
+#endif
RLP_MSEPARATOR(file);
RLP_MITEM(file, widget, this, BaseObj, "E&xit", CM_EXIT);
RLP_MSEPARATOR(file);
@@ -2769,6 +2860,9 @@ OutputQT::SetMenu(int type)
RLP_MITEM(corr, widget, this, BaseObj, "Correlation &Matrix", CM_CORRELM);
RLP_MITEM(corr, widget, this, BaseObj, "Tiled &Plots", CM_CORRELT);
stats->insertItem("C&orrelations", corr);
+ QPopupMenu *bdown = new QPopupMenu(widget);
+ RLP_MITEM(bdown, widget, this, BaseObj, "&One Way Anova", CM_REPBDANOV);
+ stats->insertItem("&Breakdowns", bdown);
#else
QMenu *anov = stats->addMenu("&Anova");
RLP_MITEM(anov, widget, this, BaseObj, "&One Way Anova", CM_REPANOV);
@@ -2782,6 +2876,8 @@ OutputQT::SetMenu(int type)
QMenu *corr = stats->addMenu("C&orrelations");
RLP_MITEM(corr, widget, this, BaseObj, "Correlation &Matrix", CM_CORRELM);
RLP_MITEM(corr, widget, this, BaseObj, "Tiled &Plots", CM_CORRELT);
+ QMenu *bdown = stats->addMenu("&Breakdowns");
+ RLP_MITEM(bdown, widget, this, BaseObj, "&One Way Anova", CM_REPBDANOV);
#endif
RLP_MITEM(stats, widget, this, BaseObj, "&2x2 Table", CM_REPTWOWAY);
@@ -2810,6 +2906,7 @@ OutputQT::SetMenu(int type)
QPopupMenu *displ = new QPopupMenu(widget);
QPopupMenu *plots = new QPopupMenu(widget);
QPopupMenu *about = new QPopupMenu(widget);
+ file->insertItem("&Open", widget, SLOT(cmOpen()), Qt::CTRL + Qt::Key_O);
#else
QMenu *file = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&File"));
QMenu *edit = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&Edit"));
@@ -2817,11 +2914,15 @@ OutputQT::SetMenu(int type)
MkToolMenu(((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&Tools")), widget, this, BaseObj);
QMenu *plots = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&Plots"));
QMenu *about = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&?"));
+ file->addAction("&Open", widget, SLOT(cmOpen()), Qt::CTRL + Qt::Key_O);
#endif
- RLP_MITEM(file, widget, this, BaseObj, "&Open", CM_OPEN);
- RLP_MITEM(file, widget, this, BaseObj, "Save &as", CM_SAVEGRAPHAS);
+ RLP_MITEM(file, widget, this, BaseObj, "Save &as", CM_SAVEAS);
RLP_MSEPARATOR(file);
- RLP_MITEM(file, widget, this, BaseObj, "&Print", CM_PRINT);
+#if QT_VERSION < 0x040000
+ file->insertItem("&Print", widget, SLOT(cmPrint()), Qt::CTRL + Qt::Key_P);
+#else
+ file->addAction("&Print", widget, SLOT(cmPrint()), Qt::CTRL + Qt::Key_P);
+#endif
RLP_MITEM(file, widget, this, BaseObj, "&Export", CM_EXPORT);
RLP_MSEPARATOR(file);
RLP_MITEM(file, widget, this, BaseObj, "&Close", CM_EXIT);
@@ -2871,6 +2972,7 @@ OutputQT::SetMenu(int type)
QPopupMenu *displ = new QPopupMenu(widget);
QPopupMenu *plots = new QPopupMenu(widget);
QPopupMenu *about = new QPopupMenu(widget);
+ file->insertItem("&Open", widget, SLOT(cmOpen()), Qt::CTRL + Qt::Key_O);
#else
QMenu *file = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&File"));
QMenu *edit = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&Edit"));
@@ -2878,11 +2980,15 @@ OutputQT::SetMenu(int type)
MkToolMenu(((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&Tools")), widget, this, BaseObj);
QMenu *plots = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&Plots"));
QMenu *about = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&?"));
+ file->addAction("&Open", widget, SLOT(cmOpen()), Qt::CTRL + Qt::Key_O);
#endif
- RLP_MITEM(file, widget, this, BaseObj, "&Open", CM_OPEN);
- RLP_MITEM(file, widget, this, BaseObj, "Save &as", CM_SAVEGRAPHAS);
+ RLP_MITEM(file, widget, this, BaseObj, "Save &as", CM_SAVEAS);
RLP_MSEPARATOR(file);
- RLP_MITEM(file, widget, this, BaseObj, "&Print", CM_PRINT);
+#if QT_VERSION < 0x040000
+ file->insertItem("&Print", widget, SLOT(cmPrint()), Qt::CTRL + Qt::Key_P);
+#else
+ file->addAction("&Print", widget, SLOT(cmPrint()), Qt::CTRL + Qt::Key_P);
+#endif
RLP_MITEM(file, widget, this, BaseObj, "&Export", CM_EXPORT);
RLP_MSEPARATOR(file);
RLP_MITEM(file, widget, this, BaseObj, "&Close", CM_EXIT);
@@ -2936,7 +3042,9 @@ OutputQT::SetMenu(int type)
MenuHeight = ((RLPwidget*)widget)->menu_bar->height();
widget->resize(widget->width()+8, widget->height()+8);
#endif
- if(MenuHeight< 20) MenuHeight = 24;
+ if(MenuHeight< 20) MenuHeight = 25;
+ if(MenuHeight< defs.iMenuHeight) MenuHeight = defs.iMenuHeight;
+ else defs.iMenuHeight = MenuHeight;
return true;
}
#undef RLP_MITEM
@@ -3238,6 +3346,10 @@ RLPwidget::mouseMoveEvent(QMouseEvent *e)
{
int i;
MouseEvent mev = {mouse_buttons_down, MOUSE_MOVE, e->x(), e->y()};
+
+ if(rlpsrv && !rlpsrv->bValid) {
+ delete(rlpsrv); rlpsrv = 0L;
+ }
#if QT_VERSION < 0x040000
i = e->state();
if(i & Qt::ShiftButton) mev.StateFlags |= 0x08;
@@ -3247,7 +3359,7 @@ RLPwidget::mouseMoveEvent(QMouseEvent *e)
if(i & Qt::ShiftModifier) mev.StateFlags |= 0x08;
if(i & Qt::ControlModifier) mev.StateFlags |= 0x10;
#endif
- if(((OutputQT*)OutputClass)->ShowObj) {
+ if(OutputClass && ((OutputQT*)OutputClass)->ShowObj) {
delete((eph_obj*)((OutputQT*)OutputClass)->ShowObj);
((OutputQT*)OutputClass)->ShowObj = 0L;
}
@@ -3328,6 +3440,7 @@ RLPwidget::keyPressEvent(QKeyEvent *e)
if(uc == 3) break;
else if(uc == 27 && OutputClass) {
OutputClass->HideMark();
+ EmptyClip();
ProcMenuEvent(CM_T_STANDARD, this, OutputClass, BaseObj);
}
else if(uc == 22) cmPaste();
@@ -3435,7 +3548,7 @@ PrintQT::PrintQT(GraphObj *g, char *file)
{
units = defs.cUnits;
dxf.setMatrix(0.1, 0.0, 0.0, 0.1, 0.0, 0.0);
- hgo = 0L;
+ hgo = 0L; minLW = 1;
if(file) fileName = strdup(file);
else fileName = 0L;
go = g;
@@ -3487,19 +3600,14 @@ PrintQT::SetLine(LineDEF *lDef)
if(lDef->width != LineWidth || lDef->width != LineWidth ||
lDef->pattern != dPattern || lDef->color != dLineCol) {
LineWidth = lDef->width;
- iw = iround(un2fix(lDef->width));
- dPattern = lDef->pattern;
+ 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);
+ iLine = iw > minLW ? iw : minLW; dLineCol = lDef->color;
+ qPen.setColor(MK_QCOLOR(dLineCol)); qPen.setWidth(iLine);
+ qPen.setStyle(Qt::SolidLine); qPen.setCapStyle(Qt::RoundCap);
+ qPen.setJoinStyle(Qt::RoundJoin); qPainter.setPen(qPen);
}
return true;
}
@@ -3509,16 +3617,13 @@ 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);
+ if(!hgo) hgo = new HatchOut(this); if(hgo) hgo->SetFill(fill);
}
else {
- if(hgo) delete hgo;
- hgo = 0L;
+ if(hgo) delete hgo; hgo = 0L;
}
- qPainter.setBrush(QColor(SwapRB(fill->color)));
- dFillCol = fill->color;
- dFillCol2 = fill->color2;
+ qPainter.setBrush(MK_QCOLOR(fill->color));
+ dFillCol = fill->color; dFillCol2 = fill->color2;
return true;
}
@@ -3619,7 +3724,7 @@ PrintQT::oRectangle(int x1, int y1, int x2, int y2, char *nam)
#if QT_VERSION < 0x040000
qPainter.drawRect(x1, y1, x2-x1, y2-y1);
#else
- qPainter.drawRect(x1, y1, x2-x1-1, y2-y1-1);
+ qPainter.drawRect(x1, y1, x2-x1, y2-y1);
#endif
if(hgo) hgo->oRectangle(x1, y1, x2, y2, 0L);
return true;
@@ -3680,7 +3785,8 @@ PrintQT::oPolygon(POINT *pts, int cp, char *nam)
void FindBrowser()
{
//find a suitable browser
- if(FileExist("/usr/bin/mozilla")) WWWbrowser = strdup("mozilla");
+ if(FileExist("/usr/bin/firefox")) WWWbrowser = strdup("firefox");
+ else 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");
@@ -3709,9 +3815,15 @@ int main (int argc, char **argv)
{
QApplication a(argc, argv);
DefsRW *drw;
+ int cb;
if(argc > 1 && argv[1] && argv[1][0] && FileExist(argv[1]))
LoadFile = strdup(argv[1]);
+ if(argc > 0 && argv[0] && argv[0][0]) {
+ ShellCmd = (char*)malloc(cb = strlen(argv[0]) +10);
+ cb = rlp_strcpy(ShellCmd, cb+1, argv[0]);
+ rlp_strcpy(ShellCmd + cb, 4, " &");
+ }
QAppl = &a;
InitTextCursor(true);
ShowBanner(true);
@@ -3727,14 +3839,14 @@ int main (int argc, char **argv)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Dialog box support
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-DlgWidget::DlgWidget(QWidget *par, const char *name, tag_DlgObj *d)
+DlgWidget::DlgWidget(QWidget *par, const char *name, tag_DlgObj *d, DWORD flags)
#if QT_VERSION < 0x030000 //n.a. in Qt version 2
: QWidget(par, name, Qt::WType_Dialog)
#elif QT_VERSION < 0x040000
: QWidget(par, name, 0x0000002)
#else //Qt 4.0
//: QWidget(par ? par : CurrWidget, Qt::Window)
-: QWidget(0L, Qt::Window)
+: QWidget(0L, flags & 0x00000004 ? Qt::Dialog : Qt::Window)
#endif
{
parent = par;
@@ -3763,8 +3875,10 @@ DlgWidget::paintEvent(QPaintEvent *range)
rc = range->rect();
qpainter.drawPixmap(rc.left(), rc.top(), *mempic, rc.left(), rc.top(), rc.width()+1, rc.height()+1);
#if QT_VERSION >=0x040000
- if(((OutputQT*)OutputClass)->ShowObj)((eph_obj*)(((OutputQT*)OutputClass)->ShowObj))->DoPlot(&qpainter);
- if(((OutputQT*)OutputClass)->ShowAnimated)((eph_obj*)(((OutputQT*)OutputClass)->ShowAnimated))->DoPlot(&qpainter);
+ if(OutputClass && ((OutputQT*)OutputClass)->ShowObj)
+ ((eph_obj*)(((OutputQT*)OutputClass)->ShowObj))->DoPlot(&qpainter);
+ if(OutputClass && ((OutputQT*)OutputClass)->ShowAnimated)
+ ((eph_obj*)(((OutputQT*)OutputClass)->ShowAnimated))->DoPlot(&qpainter);
#endif
}
@@ -3943,16 +4057,17 @@ void *CreateDlgWnd(char *title, int x, int y, int width, int height, tag_DlgObj
OutputQT *o;
int dw, dh;
- w = new DlgWidget(pw = QAppl->activeWindow(), 0, d);
+ w = new DlgWidget(pw = QAppl->activeWindow(), 0, d, flags);
#if QT_VERSION < 0x040000
w->setCaption(title);
#else
w->setWindowTitle(title);
+ if(d->bModal) w->setWindowModality(Qt::ApplicationModal);
#endif
if(flags & 0x2) w->setFixedSize(width, height);
else w->setFixedSize(width-6, height-16);
o = new OutputQT(w); o->units = defs.cUnits;
- o->Erase(0x00e0e0e0L); if(flags & 0x04) w->startTimer(100);
+ o->Erase(0x00e0e0e0L); if(flags & 0x08) w->startTimer(100);
if(flags & 0x1) {
GetDesktopSize(&dw, &dh);
w->move((dw>>1) - ((w->width())>>1), (dh>>1) - ((w->height())>>1));
@@ -4043,3 +4158,5 @@ bool DelBitmapClass(anyOutput *w)
return true;
}
+
+
diff --git a/QT_Spec.h b/QT_Spec.h
index 0684c1c..caae91d 100755
--- a/QT_Spec.h
+++ b/QT_Spec.h
@@ -1,4 +1,4 @@
-//QT_Spec.h, Copyright (c) 2001-2007 R.Lackner
+//QT_Spec.h, Copyright (c) 2001-2008 R.Lackner
//
// This file is part of RLPlot.
//
@@ -78,10 +78,11 @@ private:
class RLPserver {
public:
GraphObj *SourceGO;
+ bool bValid;
RLPserver(QObject* parent=0, GraphObj *g=0);
~RLPserver();
-
+ void CreateThread();
void SetGO(GraphObj *g);
char *GetXML();
char *GetRLP();
@@ -165,6 +166,10 @@ public slots:
void cmZoomFit(){ProcMenuEvent(CM_ZOOMFIT, this, OutputClass, BaseObj);};
void cmPaste();
void cmUndo(){if(BaseObj) BaseObj->Command(CMD_UNDO, 0L, OutputClass);};
+ void cmSave(){ProcMenuEvent(CM_SAVE, this, OutputClass, BaseObj);};
+ void cmOpen(){ProcMenuEvent(CM_OPEN, this, OutputClass, BaseObj);};
+ void cmPrint(){ProcMenuEvent(CM_PRINT, this, OutputClass, BaseObj);};
+ void cmNewInst(){ProcMenuEvent(CM_NEWINST, this, OutputClass, BaseObj);};
protected:
void paintEvent(QPaintEvent *);
@@ -194,7 +199,7 @@ public:
QPixmap *mempic;
anyOutput *OutputClass;
- DlgWidget(QWidget *par=0, const char *name=0, tag_DlgObj *d = 0);
+ DlgWidget(QWidget *par=0L, const char *name = 0L, tag_DlgObj *d = 0L, DWORD flags = 0L);
~DlgWidget();
protected:
@@ -239,6 +244,7 @@ public:
virtual bool StartPage() {return true;};
bool CopyBitmap(int x, int y, anyOutput* src, int sx, int sy,
int sw, int sh, bool invert);
+ virtual void MouseCapture(bool bgrab){return;};
bool oGetTextExtent(char *text, int cb, int *width, int *height);
bool oGetTextExtentW(w_char *text, int cb, int *width, int *height);
bool oGetPix(int x, int y, DWORD *col);
@@ -268,13 +274,15 @@ public:
~OutputQT();
bool ActualSize(RECT *rc);
void Focus(){if(widget){widget->show(); widget->activateWindow();widget->raise();}};
- void Caption(char *txt);
+ void Caption(char *txt, bool bModified);
void MouseCursor(int cid, bool force);
bool SetScroll(bool isVert, int iMin, int iMax, int iPSize, int iPos);
bool EndPage();
+ void MouseCapture(bool bgrab);
bool UpdateRect(RECT *rc, bool invert);
void ShowLine(POINT * pts, int cp, DWORD color);
void ShowEllipse(POINT p1, POINT p2, DWORD color);
+ void ShowInvert(RECT *rec);
bool SetMenu(int type);
void CheckMenu(int mid, bool check);
void FileHistory();
diff --git a/RLPLOT.RC b/RLPLOT.RC
new file mode 100755
index 0000000..490caac
--- /dev/null
+++ b/RLPLOT.RC
@@ -0,0 +1,307 @@
+//RLPlot.RC, (C)2000-2006 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 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"
+#include "menu.h"
+#endif
+
+MENU_1 MENU DISCARDABLE
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&Open", CM_OPEN
+ MENUITEM "&Save as", CM_SAVEAS
+ MENUITEM SEPARATOR
+ MENUITEM "&Print", CM_PRINT
+ MENUITEM "&Export", CM_EXPORT
+ MENUITEM SEPARATOR
+ MENUITEM "&Close", 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 "&New Instance" CM_NEWINST
+ MENUITEM SEPARATOR
+ MENUITEM "&Open", CM_OPEN
+ MENUITEM "&Save", CM_SAVE
+ MENUITEM "Save &as", CM_SAVEAS
+ MENUITEM SEPARATOR
+ MENUITEM "&Print", CM_PRINT
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", CM_EXIT
+ END
+ POPUP "&Edit"
+ BEGIN
+ MENUITEM "&Undo" CM_UNDO
+ MENUITEM SEPARATOR
+ MENUITEM "&Rows/Cols", CM_ADDROWCOL
+ POPUP "&Insert"
+ BEGIN
+ MENUITEM "&Rows", CM_INSROW
+ MENUITEM "&Columns", CM_INSCOL
+ END
+ POPUP "&Delete"
+ BEGIN
+ MENUITEM "&Rows", CM_DELROW
+ MENUITEM "&Columns", CM_DELCOL
+ END
+ MENUITEM SEPARATOR
+ MENUITEM "&Copy", CM_COPY
+ MENUITEM "C&ut", CM_CUT
+ MENUITEM "&Paste", CM_PASTE
+ MENUITEM SEPARATOR
+ MENUITEM "&Fill Range", CM_FILLRANGE
+ END
+ POPUP "&Statistics"
+ BEGIN
+ MENUITEM "&Sample Stats" CM_SMPLSTAT
+ MENUITEM "&Comp. Means" CM_REPCMEANS
+ POPUP "&Anova"
+ BEGIN
+ MENUITEM "&One Way Anova" CM_REPANOV
+ MENUITEM "&Kruskal Wallis" CM_REPKRUSKAL
+ MENUITEM "&Two Way Anova", CM_REPTWANOV
+ MENUITEM "&Friedman Anova", CM_REPFRIEDM
+ MENUITEM "&Two Way /w Replica" CM_REPTWANR
+ END
+ POPUP "&Regression"
+ BEGIN
+ MENUITEM "&Linear Regression" CM_REPREGR
+ MENUITEM "&Robust Line-Fit", CM_ROBUSTLINE
+ END
+ POPUP "C&orrelations"
+ BEGIN
+ MENUITEM "Correlation &Matrix" CM_CORRELM
+ MENUITEM "Tiled &Plots" CM_CORRELT
+ END
+ MENUITEM "&2x2 Table" CM_REPTWOWAY
+ 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_SAVEAS
+ MENUITEM SEPARATOR
+ MENUITEM "&Print", CM_PRINT
+ MENUITEM "&Export", CM_EXPORT
+ MENUITEM SEPARATOR
+ MENUITEM "&Close", 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_PRIOR, CM_SHPGUP, VIRTKEY, SHIFT
+ VK_NEXT, CM_SHPGDOWN, VIRTKEY, SHIFT
+ 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/TheDialog.cpp b/TheDialog.cpp
index 8350595..bc7ea4a 100755
--- a/TheDialog.cpp
+++ b/TheDialog.cpp
@@ -1,4947 +1,5027 @@
-//TheDialog.cpp, Copyright (c) 2001-2007 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 = 10;
-static unsigned long DlgBGcolor = 0x00e0e0e0L;
-static unsigned long DlgBGhigh = 0x00e8e8e8L;
-TextDEF DlgText = {0x00000000L, 0x00ffffffL, 4.0, 0.0, 0.0, 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, DataObj *d)
-{
- int i;
- RECT rc;
-
- dlg = 0L; flags = 0L; tabstops = 0L;
- DlgText.iSize = dlgtxtheight; DlgText.ColBg = DlgBGcolor;
- DlgText.fSize = defs.GetSize(SIZE_TEXT);
- type = NONE; Id = -2; cContinue = 0;
- bActive = bRedraw = false; c_go = CurrGO;
- CurrDisp = 0L; oldFocus = DialogFocus; DialogFocus = 0L;
- oldDefault = DialogDefault; oldTabStop = DialogTabStop;
- data = d; res_put = res_get = 0; hDialog = 0L;
- if(ParentOut = Undo.cdisp) ParentOut->MouseCursor(MC_WAIT, false);
- mrk_item = 0L; //if an item has a mark its this one
- 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 COLBUTT:
- dlg[i]->dialog = new ColorButton(this, &tmpl[i],rc, (DWORD *)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 RANGEINPUT:
- dlg[i]->dialog = new RangeInput(this, &tmpl[i],rc,(char*)tmpl[i].ptype, data);
- 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, data);
- 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(data) data->Command(CMD_ETRACC, 0L, 0L);
- HideTextCursor();
- 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 COLBUTT: 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 RANGEINPUT: delete((RangeInput*)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); dlg=0L;
- }
- if(tabstops) free(tabstops); tabstops = 0L;
- DialogFocus = oldFocus; DialogDefault = oldDefault;
- DialogTabStop = oldTabStop; CurrGO = c_go;
- if(Undo.cdisp)Undo.cdisp->MouseCursor(MC_ARROW, false);
-}
-
-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);
- DoPlot(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:
- if(DialogFocus && DialogFocus->type == TEXTBOX && DialogFocus->Command(cmd, tmpl, o)) return true;
- mev = (MouseEvent *) tmpl;
- switch(mev->Action) {
- case MOUSE_LBDOWN:
- bActive = true;
- case MOUSE_MOVE:
- //track mouse and display controls accordingly
- if(!(mev->StateFlags & 1))return false;
- 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:
- if(bActive)ForEach(CMD_LBUP, 0, o);
- return true;
- }
- return true;
- case CMD_ENDDIALOG:
- d = (Dialog *)tmpl;
- if(d) {
- res_q[res_put++] = d->Id; // end dialog by object
- cContinue = 0;
- }
- else if(cContinue >0) { // no end upon killing the focus
- cContinue--;
- return true;
- }
- else {
- res_q[res_put++] = 0; // end dialog with closebox or loose focus
- bRedraw = true;
- }
- res_put &= 0xff;
- 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]) || (tabstops[i]->flags & HIDDEN)) i++;
- if(!tabstops[i]) i = 0;
- switch(tabstops[i]->type) {
- case PUSHBUTTON:
- d = DialogDefault;
- DialogTabStop = DialogDefault = tabstops[i];
- if(d) d->DoPlot(o);
- DialogDefault->DoPlot(o);
- break;
- case EDTEXT: case EDVAL1: case RANGEINPUT:
- 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:
- case RANGEINPUT:
- 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: case CMD_COPY: case CMD_PASTE:
- Undo.SetDisp(CurrDisp);
- bActive = true;
- if(DialogFocus)return DialogFocus->Command(cmd, tmpl, CurrDisp);
- else return false;
- case CMD_ADDCHAR:
- if(!tmpl) return false;
- bActive = true;
- if(*((int*)tmpl) == 27) { //Esc
- HideCopyMark();
- for (i = 0; dlg[i] && i < cDlgs; i++)
- if(dlg[i]->dialog) dlg[i]->dialog->Command(cmd, tmpl, o);
- return Command(CMD_REDRAW, 0L, 0L);
- }
- 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:
- CurrDisp = 0L;
- for(i = 0; i < cDlgs; i++)
- if(dlg[i] && dlg[i]->dialog) dlg[i]->dialog->Command(CMD_UNLOCK, 0L, 0L);
- break;
- case CMD_MARKOBJ:
- if(mrk_item && mrk_item != (Dialog*)tmpl){
- i = 27;
- mrk_item->Command(CMD_ADDCHAR, &i, o);
- }
- mrk_item = (Dialog*)tmpl;
- break;
- }
- return false;
-}
-
-void
-DlgRoot::DoPlot(anyOutput *o)
-{
- int i;
-
- HideCopyMark(); mrk_item = 0L; bRedraw = false;
- HideTextCursor();
- if(tabstops) for(i = 0; i < cDlgs; tabstops[i++] = 0);
- if(o)CurrDisp = o; DialogDefault = 0L;
- 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: case RANGEINPUT:
- 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] && dlg[i]->dialog) 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 size)
-{
- int i;
-
- i = FindIndex(id);
- if(i && dlg[i]) return dlg[i]->dialog->GetText(id, txt, size);
- 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))bRedraw = true;
- else return false;
- return true;
-}
-
-bool
-DlgRoot::SetValue(int id, double val)
-{
- int i;
- char tmp_txt[80];
-
- i = FindIndex(id);
- WriteNatFloatToBuff(tmp_txt, val);
- if(i && dlg[i] && dlg[i]->dialog->Command(CMD_SETTEXT, tmp_txt+1, CurrDisp))bRedraw = true;
- 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;
-
- if(res_put != res_get) ret = res_q[res_get++];
- else ret = -1;
- res_get &= 0xff;
- if(bRedraw)DoPlot(0L);
- if(ret >= 0 && ParentOut) Undo.SetDisp(ParentOut);
- 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] && 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++) {
- if(i = FindIndex(i)) {
- dlg[next]->dialog->Command(CMD_ADDCHILD, (void*)dlg[i]->dialog, 0L);
- i = dlg[i]->next;
- }
- else{
- i=i;
- }
- }
- }
- 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] && 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] ? dlg[next]->next : 0);
- }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]){
- bRedraw = true;
- 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) && bLBstate){
- if(parent && type != CHECKBOX && type != RADIO1 && type != RADIO2) parent->Command(CMD_MARKOBJ, this, o);
- if(!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[0]) Text = (char*)memdup(text, (int)strlen(text)+1, 0);
- 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_ENDDIALOG:
- parent->Command(CMD_ENDDIALOG, (void *)this, o);
- return true;
- case CMD_ADDCHAR:
- HideCopyMark();
- 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)
-{
- lfPOINT lfp1, lfp2;
-
- TextDef.Font = FONT_COURIER; TextDef.Align = TXA_VBOTTOM | TXA_HLEFT;
-#ifdef _WINDOWS
-// TextDef.fSize unchanged
-#else
- TextDef.fSize *= .8;
-#endif
- Fill.color = 0x00ffffffL; Line.color = 0x00000000L; cont = 0L;
- lfp1.fx = rec.left; lfp1.fy = rec.top;
- lfp2.fx = rec.right; lfp2.fy = rec.bottom;
- if(cont = new TextFrame(0L, 0L, &lfp1, &lfp2, text)) cont->Command(CMD_SETTEXTDEF, &TextDef, 0L);
-}
-
-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: case CMD_MOUSE_EVENT:
- case CMD_COPY: case CMD_PASTE: case CMD_CURRUP:
- case CMD_CURRDOWN:
- if(bChecked && CurrGO && CurrGO == cont) return CurrGO->Command(cmd, tmpl, o);
- break;
- case CMD_SETTEXT:
- if(cont)return cont->Command(cmd, tmpl, o);
- return false;
- }
- return false;
-}
-
-void
-TextBox::DoPlot(anyOutput *o)
-{
- if(cont && o)cont->DoPlot(o);
-}
-
-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(CurrGO = cont) bChecked = cont->Command(CMD_SELECT, &p1, o);
- }
- return false;
-}
-
-void
-TextBox::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 && cont && parent) {
- DialogFocus = this; bChecked = true;
- parent->Command(CMD_FOCTXT, (void*)this, 0L);
- cont->Command(CMD_MOUSE_EVENT, mev, o);
- parent->Command(CMD_MARKOBJ, this, o);
- }
-}
-
-bool
-TextBox::GetText(int id, char *txt, int size)
-{
- if(cont) {
- if(!(cont->Command(CMD_ALLTEXT, TmpTxt, 0L))) return false;
- rlp_strcpy(txt, size, TmpTxt);
- return true;
- }
- 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, DWORD *color)
- :Dialog(par, desc, rec)
-{
- col = color ? *color : 0x0L;
-}
-
-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(parent && IsInRect(&cr, x, y)) {
- if((flags & OWNDIALOG) && (*(symbol))) {
- parent->Command(CMD_CONTINUE, 0L, o);
- (*symbol)->PropertyDlg();
- }
- if((flags & TOUCHEXIT))
- 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[0])Text = (char*)memdup(text, (int)strlen(text)+1, 0);
- 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 && *((char*)tmpl)) Text = (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1,0);
- 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, (int)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[0])Text = (char*)memdup(text, (int)strlen(text)+1, 0);
- 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 && *((char*)tmpl))Text = (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1, 0);
- 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, (int)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 && text[0])txt = (char*)memdup(text, (int)strlen(text)+1, 0);
- 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 && *((char*)tmpl))txt = (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1, 0);
- 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)
-{
- int i;
-
- if(WWWbrowser && WWWbrowser[0] && txt && (flags & HREF) && IsInRect(&cr, x, y)) {
- o->MouseCursor(MC_WAIT, false);
- i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE-50, WWWbrowser);
- TmpTxt[i++] = ' ';
- rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, txt);
- if(parent && (flags & TOUCHEXIT))parent->Command(CMD_ENDDIALOG, 0L, o);
- else if(parent)parent->Command(CMD_CONTINUE, 0L, o);
-#ifdef _WINDOWS
- WinExec(TmpTxt, SW_SHOWMAXIMIZED);
-#else
- strcat(TmpTxt, " &");
- system(TmpTxt);
-#endif
- o->MouseCursor(MC_ARROW, false);
- return true;
- }
- return false;
-}
-
-void
-Text::SetColor(int id, DWORD color)
-{
- TextDef.ColTxt = color;
-}
-
-void
-Text::MBtrack(MouseEvent *mev, anyOutput *o)
-{
- if((mev->StateFlags &1) && IsInRect(&hcr, mev->x, mev->y) && parent) parent->Command(CMD_MARKOBJ, this, o);
-}
-
-InputText::InputText(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text)
- :Dialog(par, desc, rec)
-{
- RECT rc;
-
- rc.left = rec.left+1; rc.top = rec.top+1;
- rc.right = rec.right-1; rc.bottom = rec.bottom-1;
- if(type == INCDECVAL1) cr.right = rc.right = cr.right - 7*xbase;
- Line.color = 0x00000000L;
- if(Text = new EditText(0L, text, -1, -1)) Text->SetRec(&rc);
- 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)){
- if(o) Undo.SetDisp(o);
- 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_UPDATE:
- if(Text && bActive && o) Text->Command(cmd, o, 0L);
- break;
- case CMD_COPY: case CMD_PASTE:
- if(Text && bActive && !(flags & NOEDIT)) return Text->Command(cmd, o, NULL);
- return false;
- case CMD_ADDCHAR:
- if(Text && bActive && !(flags & NOEDIT)){
- if(o) Undo.SetDisp(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);
- }
- if(flags & TOUCHEXIT) parent->Command(CMD_ENDDIALOG, (void *)this, o);
- }
- return false;
- case CMD_SETTEXT:
- if(Text) return Text->SetText((char*)tmpl);
- 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) {
- Text->SetText(TmpTxt+1); DoPlot(o);
- }
- }
- break;
- }
- return false;
-}
-
-void
-InputText::DoPlot(anyOutput *o)
-{
- POINT pts[5];
-
- if(!o) return;
- 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 true;
- }
- 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) {
-#ifdef USE_WIN_SECURE
- sscanf_s(Text->text, "%d", val);
-#else
- sscanf(Text->text, "%d", val);
-#endif
- return true;
- }
- return false;
-}
-
-bool
-InputText::GetText(int id, char *txt, int size)
-{
- if(Text && Text->text && Text->text[0]) {
- rlp_strcpy(txt, size, 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 && parent) {
- DialogFocus = this;
- parent->Command(CMD_FOCTXT, (void*)this, 0L);
- o->SetTextSpec(&TextDef);
- Text->Command(CMD_MOUSE_EVENT, o, (DataObj *)mev);
- parent->Command(CMD_MARKOBJ, this, o);
- }
-}
-
-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);
- }
-}
-
-RangeInput::RangeInput(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text, DataObj *d)
- :InputText(par, desc, rec, text)
-{
- data = d;
-}
-
-RangeInput::~RangeInput()
-{
- if(data) data->Command(CMD_ETRACC, 0L, 0L);
- if(Text) delete (Text); Text = 0L;
-}
-
-bool
-RangeInput::Command(int cmd, void *tmpl, anyOutput *o)
-{
- switch(cmd) {
- case CMD_SET_DATAOBJ:
- data = (DataObj*)tmpl;
- return true;
- }
- return InputText::Command(cmd, tmpl, o);
-}
-
-bool
-RangeInput::Select(int x, int y, anyOutput *o)
-{
- bool bRes;
-
- bRes = InputText::Select(x, y, o);
- if(bRes && data) {
- if(DialogFocus == this){
- data->Command(CMD_ETRACC, Text, 0L);
- if(Text) Text->Update(1, o, 0L);
- }
- else data->Command(CMD_ETRACC, 0L, 0L);
- }
- return bRes;
-}
-
-void
-RangeInput::Activate(int id, bool activate)
-{
- InputText::Activate(id, activate);
- if(activate && data) data->Command(CMD_ETRACC, Text, 0L);
-}
-
-InputValue::InputValue(tag_DlgObj *par, DlgInfo * desc, RECT rec, double *value)
- :InputText(par, desc, rec, 0L)
-{
- if(value) {
- WriteNatFloatToBuff(TmpTxt, *value);
- if(Text) Text->text = (char*)memdup(TmpTxt+1, (int)strlen(TmpTxt+1)+1, 0);
- }
- else if(Text) Text->SetText("");
-}
-
-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 = (char*)memdup(TmpTxt+1, (int)strlen(TmpTxt+1)+1, 0);
- 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[9];
-
- for(i = 0; i < 9; i++) {
- d1[i].id = i+1; d1[i].next = i+2; d1[i].first = 0;
- d1[i].flags = ISRADIO; d1[i].type = RADIO0; d1[i].ptype = 0L;
- d1[i].w = d1[i].h = 8;
- switch (i / 3) {
- case 0: d1[i].y = y1; break;
- case 1: d1[i].y = y2; break;
- case 2: d1[i].y = y3; break;
- }
- switch (i % 3) {
- case 0: d1[i].x = x1; break;
- case 1: d1[i].x = x2; break;
- case 2: d1[i].x = x3; break;
- }
- }
- d1[8].next = 0; d1[8].flags |= LASTOBJ;
- txt.ColTxt = 0x00808080L; txt.ColBg = 0x00ffffff;
- txt.fSize = defs.GetSize(SIZE_TEXT)*2.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;
- if(txt.text = (char*)malloc(20*sizeof(char))) rlp_strcpy(txt.text, 20, "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: case CMD_MARKOBJ:
- if(parent && (flags & HIDDEN) != HIDDEN) 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 == RANGEINPUT ||
- 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 && txt[0])Text = (char*)memdup(txt, (int)strlen(txt)+1, 0);
- 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, DataObj *d)
- :Group(par, desc, rec)
-{
- if(sh->text && sh->text[0])Text = (char*)memdup(sh->text, (int)strlen(sh->text)+1, 0);
- 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;
- data = d;
-}
-
-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;
- HideCopyMark();
- Line.color = 0x0L; 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);
-#ifdef _WINDOWS
- o->oTextOut(rctab.right - 6, rctab.top + 3, Text, 0);
-#else
- o->oTextOut(rctab.right - 6, rctab.top + 5, Text, 0);
- if(bChecked) {
- Line.color = 0x0L; o->SetLine(&Line);
- pts[0].y++; o->oSolidLine(pts);
- }
-#endif
- Group::DoPlot(o);
- o->UpdateRect(&cr, false);
-}
-
-bool
-TabSheet::Select(int x, int y, anyOutput *o)
-{
- if(IsInRect(&rctab, x, y)) {
- if(data)data->Command(CMD_ETRACC, 0L, 0L);
- if(parent) {
- parent->Command(CMD_RADIOBUTT, (void *)this, o);
- parent->Command(CMD_MARKOBJ, 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; i++){
- strings[i] = (char*)memdup(list[i], (int)strlen(list[i])+1, 0);
- }
- }
-}
-
-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+_SBINC));
- 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+_SBINC) - startY + hcr.top;
- mrk.right = hcr.right-2; mrk.bottom = mrk.top + (TextDef.iSize+_SBINC);
- 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+_SBINC),
- (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+_SBINC);
- if(il >= ns || il < 0){
- o->UpdateRect(&hcr, false);
- return false;
- }
- cl = il;
- mrk.left = hcr.left+2; mrk.top = (il)*(TextDef.iSize+_SBINC) - startY + hcr.top;
- mrk.right = hcr.right-2; mrk.bottom = mrk.top + (TextDef.iSize+_SBINC);
- 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+_SBINC),
- (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, int size)
-{
- if(strings && ns && cl >= 0 && cl < ns){
- rlp_strcpy(txt, size, 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+_SBINC) * 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+_SBINC);
- for(i = 0; i < ns; i++) {
- bmp->oTextOut(5, i*(TextDef.iSize+_SBINC), 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+_SBINC));
- 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+_SBINC) - startY + hcr.top;
- mrk.right = hcr.right-2; mrk.bottom = mrk.top + (TextDef.iSize+_SBINC);
- 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+_SBINC),
- (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+_SBINC);
- if(il >= ns || il < 0){
- o->UpdateRect(&hcr, false);
- return false;
- }
- cl = il;
- mrk.left = hcr.left+2; mrk.top = (il)*(TextDef.iSize+_SBINC) - startY + hcr.top;
- mrk.right = hcr.right-2; mrk.bottom = mrk.top + (TextDef.iSize+_SBINC);
- 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+_SBINC),
- (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);
- }
- }
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Common code for multiple range dialogs
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-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, TMP_TXT_SIZE) && TmpTxt[0] &&
- (*rX = new AccRange(TmpTxt))) *nx = rX[0]->CountItems();
- else if(nx) *nx = 0;
- if(Dlg->GetText(154, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0]) {
- if(rd[0][*currYR]) free(rd[0][*currYR]);
- rd[0][*currYR] = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
- }
- break;
- case 155:
- res = -1;
- *ny = 0;
- if(rX) {
- if(!(*currYR) && Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE) && 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, TMP_TXT_SIZE) && 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] = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0); //store y-ranges
- *updateYR = true;
- (*currYR)++;
- Dlg->SetText(154, rd[0][*currYR]);
- Dlg->Activate(154, true);
- break;
- case 156:
- if(Dlg->GetText(154, TmpTxt, TMP_TXT_SIZE)){
- if(rd[0][*currYR]) free(rd[0][*currYR]);
- rd[0][*currYR] = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);;
- }
- else if(*currYR == *maxYR) (*maxYR)--;
- (*currYR)--;
- Dlg->SetText(154, rd[0][*currYR]);
- *updateYR = true;
- res = -1;
- break;
- }
- return res;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Dialog meta compiler
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *std_text[] = {"OK", "Cancel", "", "x", "y", "z", "-", "Next >>", "<< Prev.",
- "%", "color", "x-value", "y-value", "z-value", TmpTxt, TmpTxt+100, TmpTxt+200,
- TmpTxt+300, TmpTxt+400, "left", "right", "top", "bottom", "x-axis", "y-axis", "z-axis"};
-
-DlgInfo *CompileDialog(char* tmpl, void **ptypes)
-{
- char **lines, **fields, **flags, error[80];
- int i, j, nlines, nfields, nflags, last_id, last_next;
- unsigned int hv;
- DlgInfo *Dlg;
-
- std_text[2] = Units[defs.cUnits].display;
- lines = split(tmpl, '\n', &nlines);
- if(!lines || nlines <1 ||(!(Dlg = (DlgInfo*)malloc(nlines*sizeof(DlgInfo))))) return 0L;
- for(i = last_id = last_next = 0; i < nlines; i++) if(lines[i] && lines[i][0]){
- if(fields = split(lines[i], ',', &nfields)) {
- if(nfields == 10) {
- Dlg[i].id = Dlg[i].next = Dlg[i].first = 0;
- if(fields[0][0]) {
- if(fields[0][0] == '.') Dlg[i].id = (last_id += 1);
- else
-#ifdef USE_WIN_SECURE
- sscanf_s(fields[0], "%d", &Dlg[i].id); last_id = Dlg[i].id;
-#else
- sscanf(fields[0], "%d", &Dlg[i].id); last_id = Dlg[i].id;
-#endif
- }
- if(fields[1][0]) {
- if(fields[1][0] == '+') Dlg[i].next = (last_id + 1);
- else if(fields[1][0] == '.') Dlg[i].next = (last_next += 1);
- else
-#ifdef USE_WIN_SECURE
- sscanf_s(fields[1], "%d", &Dlg[i].next); last_next = Dlg[i].next;
-#else
- sscanf(fields[1], "%d", &Dlg[i].next); last_next = Dlg[i].next;
-#endif
- }
-#ifdef USE_WIN_SECURE
- sscanf_s(fields[2], "%d", &Dlg[i].first);
-#else
- sscanf(fields[2], "%d", &Dlg[i].first);
-#endif
- Dlg[i].flags = 0L;
- if(flags = split(fields[3], '|', &nflags)) {
- for(j = 0; j < nflags; j++){
- hv = HashValue((unsigned char *)str_trim(flags[j]));
- switch(hv) {
- case 196904: Dlg[i].flags |= CHECKED; break;
- case 4444568: Dlg[i].flags |= TOUCHEXIT; break;
- case 284491160: Dlg[i].flags |= TOUCHSELEXIT; break;
- case 235859: Dlg[i].flags |= ISRADIO; break;
- case 942268: Dlg[i].flags |= ISPARENT; break;
- case 4220131: Dlg[i].flags |= OWNDIALOG; break;
- case 198260: Dlg[i].flags |= DEFAULT; break;
- case 54530: Dlg[i].flags |= HIDDEN; break;
- case 1011472: Dlg[i].flags |= NOSELECT; break;
- case 3546: Dlg[i].flags |= HREF; break;
- case 62296: Dlg[i].flags |= NOEDIT; break;
- case 231330: Dlg[i].flags |= LASTOBJ; break;
- case 224595: Dlg[i].flags |= EXRADIO; break;
- case 60824: Dlg[i].flags |= ODEXIT; break;
- }
- free(flags[j]);
- }
- free(flags);
- }
- hv = HashValue((unsigned char *)str_trim(fields[4]));
- switch(hv) {
- case 17108522: Dlg[i].type = PUSHBUTTON; break;
- case 3252180: Dlg[i].type = ARROWBUTT; break;
- case 206036: Dlg[i].type = COLBUTT; break;
- case 13602346: Dlg[i].type = FILLBUTTON; break;
- case 261312: Dlg[i].type = SHADE3D; break;
- case 948692: Dlg[i].type = LINEBUTT; break;
- case 282068: Dlg[i].type = SYMBUTT; break;
- case 3403091: Dlg[i].type = FILLRADIO; break;
- case 1130835: Dlg[i].type = SYMRADIO; break;
- case 787668: Dlg[i].type = CHECKBOX; break;
- case 62812: Dlg[i].type = RADIO0; break;
- case 62813: Dlg[i].type = RADIO1; break;
- case 62814: Dlg[i].type = RADIO2; break;
- case 15460: Dlg[i].type = LTEXT; break;
- case 16996: Dlg[i].type = RTEXT; break;
- case 13156: Dlg[i].type = CTEXT; break;
- case 51300: Dlg[i].type = EDTEXT; break;
- case 16235656: Dlg[i].type = RANGEINPUT; break;
- case 51281: Dlg[i].type = EDVAL1; break;
- case 14534481: Dlg[i].type = INCDECVAL1; break;
- case 229196: Dlg[i].type = HSCROLL; break;
- case 286540: Dlg[i].type = VSCROLL; break;
- case 71804: Dlg[i].type = TXTHSP; break;
- case 3418: Dlg[i].type = ICON; break;
- case 14196: Dlg[i].type = GROUP; break;
- case 909332: Dlg[i].type = GROUPBOX; break;
- case 16408: Dlg[i].type = SHEET; break;
- case 970282: Dlg[i].type = ODBUTTON; break;
- case 957537: Dlg[i].type = LISTBOX1; break;
- case 1108443: Dlg[i].type = TREEVIEW; break;
- case 237304: Dlg[i].type = LINEPAT; break;
- case 269332: Dlg[i].type = TEXTBOX; break;
- case 787858: Dlg[i].type = CHECKPIN; break;
- case 17284: Dlg[i].type = TRASH; break;
- case 51627: Dlg[i].type = CONFIG; break;
- default: Dlg[i].type = NONE; break;
- }
-#ifdef USE_WIN_SECURE
- sscanf_s(fields[5], "%d", &j);
-#else
- sscanf(fields[5], "%d", &j);
-#endif
- if(j < 0) Dlg[i].ptype = (void*)std_text[(-j)-1];
- else if(j > 0) Dlg[i].ptype = ptypes[j-1];
- else Dlg[i].ptype = (void*)0L;
-#ifdef USE_WIN_SECURE
- sscanf_s(fields[6], "%d", &Dlg[i].x); sscanf_s(fields[7], "%d", &Dlg[i].y);
- sscanf_s(fields[8], "%d", &Dlg[i].w); sscanf_s(fields[9], "%d", &Dlg[i].h);
-#else
- sscanf(fields[6], "%d", &Dlg[i].x); sscanf(fields[7], "%d", &Dlg[i].y);
- sscanf(fields[8], "%d", &Dlg[i].w); sscanf(fields[9], "%d", &Dlg[i].h);
-#endif
- }
- else {
-#ifdef USE_WIN_SECURE
- sprintf_s(error, 80, "Wrong number of arguments in template line %d", i);
-#else
- sprintf(error,"Wrong number of arguments in template line %d", i);
-#endif
- InfoBox(error);
- Dlg[i].id = Dlg[i].next = Dlg[i].first = 0;
- Dlg[i].flags = 0L; Dlg[i].type = NONE;
- Dlg[i].ptype = 0L; Dlg[i].x = Dlg[i].y = Dlg[i].w = Dlg[i].h = 0;
- }
- for(j = 0; j < nfields; j++)free(fields[j]);
- free(fields);
- }
- free(lines[i]);
- }
- free(lines);
- return Dlg;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Use marked ranges as default for dialog ranges
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-bool UseRangeMark(DataObj *d, int type, char *r0, char *r1, char *r2, char *r3,
- char *r4, char *r5, char *r6, char *r7, char *r8, char *r9, char *r10)
-{
- char *dst[] = {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10};
- char *mrk, **ra =0L;;
- int i, j, ranges=0;
- bool success = false, bErr=false;
- RECT vrc, rrc;
- AccRange *ar;
- bool bRet = true;
-
- for(i = 0; i < 11; i++) if(dst[i]) *dst[i] = 0;
- if(d && type) {
- d->ValueRec(&vrc);
- if(d->Command(CMD_GETMARK, &mrk, 0L)) {
- ra = split(mrk, ';', &ranges);
- ar = new AccRange(mrk); ar->BoundRec(&vrc); delete ar;
- }
- switch(type) {
- case 1:
- if(ranges > 1) {
- for(i = 0; i < 11; i++) if(dst[i]) {
- rlp_strcpy(dst[i], 100, i < ranges ? ra[i] : mkRangeRef(vrc.top, vrc.left, vrc.bottom, vrc.left));
- }
- success = true;
- }
- else if(vrc.top == vrc.bottom && (vrc.right - vrc.left) >2) {
- for(i = 0; i < 11; i++) if(dst[i]){
- rlp_strcpy(dst[i], 100, mkRangeRef(vrc.top+i, vrc.left, vrc.top+i, vrc.right));
- }
- success = true;
- }
- else if(vrc.right == vrc.left && (vrc.bottom - vrc.top) >2) {
- for(i = 0; i < 11; i++) if(dst[i]){
- rlp_strcpy(dst[i], 100, mkRangeRef(vrc.top, vrc.left+i, vrc.bottom, vrc.left+i));
- }
- success = true;
- }
- break;
- case 2:
- for(i = 0; i < 11; i++) if(dst[i]) *(dst[i]) = 0;
- if(ranges == 1) {
- for(i = 0, j = vrc.left; i < 11 && j <= vrc.right; i++, j++) if(dst[i]){
- rlp_strcpy(dst[i], 100, mkRangeRef(vrc.top, vrc.left+i, vrc.bottom, vrc.left+i));
- }
- }
- else if(ranges > 1) {
- ar = new AccRange(ra[0]); j = ar->CountItems();
- ar->BoundRec(&rrc); delete ar;
- if(rrc.left == rrc.right)for(i = 1; i < 11 && i < ranges && !bErr; i++){
- ar = new AccRange(ra[i]); ar->BoundRec(&rrc);
- if(rrc.left != rrc.right) bErr = true;
- delete ar;
- }
- else if(rrc.top == rrc.bottom)for(i = 1; i < 11 && i < ranges && !bErr; i++){
- ar = new AccRange(ra[i]); ar->BoundRec(&rrc);
- if(rrc.top != rrc.bottom) bErr = true;
- delete ar;
- }
- else for(i = 1; i < 11 && i < ranges && !bErr; i++){
- ar = new AccRange(ra[i]);
- if(j != ar->CountItems()) bErr = true;
- delete ar;
- }
- if(i < 12 && !bErr) for(i = 0; i < 11 && i < ranges; i++){
- if(dst[i]) rlp_strcpy(dst[i], 100, ra[i]);
- }
- }
- if(bErr) {
- InfoBox("Cannot resolve multiple ranges\nwith different sizes.\n\n"
- "Please select ranges with equal size!");
- i = 12; bRet = false;
- }
- success = true;
- }
- }
- else {
- vrc.left = vrc.top = 0; vrc.right = vrc.bottom = 9;
- }
- if(!success) for(i = 0; i < 11; i++) if(dst[i]){
- rlp_strcpy(dst[i], 100, mkRangeRef(vrc.top, vrc.left+i, vrc.bottom, vrc.left+i));
- }
- if(ra) {
- for(i = 0; i < ranges; i++) if(ra[i]) free(ra[i]);
- free(ra);
- }
- return bRet;
-}
-
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Select color out of predefined palette
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *NewColorTmpl =
- "1,2,,DEFAULT,PUSHBUTTON,-1,200,10,45,12\n"
- "2,3,,,PUSHBUTTON,-2,200,25,45,12\n"
- "3,7,4,CHECKED | ISPARENT,GROUPBOX,1,200,55,45,40\n"
- "4,5,,,LTEXT,0,210,60,45,8\n"
- "5,6,,,LTEXT,0,210,70,45,8\n"
- "6,,,,LTEXT,0,210,80,45,8\n"
- "7,,8,CHECKED | ISPARENT,GROUP,0,0,0,0,0";
-
-DWORD GetNewColor(DWORD oldColor)
-{
- void *ptypes[] = {(void*)" RGB "};
- DlgInfo *ColDlg = CompileDialog(NewColorTmpl, ptypes);
- DWORD currcol, newcol, palette[230];
- int ilevels[] = {0x0, 0x40, 0x80, 0xc0, 0xe0, 0xff};
- int i, j, ir, ig, ib, col, row, res;
- DlgRoot *Dlg;
- void *hDlg;
-
- if(!(ColDlg = (DlgInfo *)realloc(ColDlg, 230 * sizeof(DlgInfo))))return oldColor;
- for(ir=row=col=0, i=7, j=0; 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 = COLBUTT; ColDlg[i].first = 0;
- palette[j] = 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 *)&palette[j];
- 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++, j++;
- }
- j=j;
- ColDlg[i-1].next = 0;
- ColDlg[i-1].flags |= LASTOBJ;
- newcol = currcol = oldColor;
- Dlg = new DlgRoot(ColDlg, 0L);
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, 10, "R: 0x%02x", currcol & 0xff); Dlg->SetText(4, TmpTxt);
- sprintf_s(TmpTxt, 10, "G: 0x%02x", (currcol>>8) & 0xff); Dlg->SetText(5, TmpTxt);
- sprintf_s(TmpTxt, 10, "B: 0x%02x", (currcol>>16) & 0xff); Dlg->SetText(6, TmpTxt);
-#else
- 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);
-#endif
- 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;
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, 10, "R: 0x%02x", newcol & 0xff); Dlg->SetText(4, TmpTxt);
- sprintf_s(TmpTxt, 10, "G: 0x%02x", (newcol>>8) & 0xff); Dlg->SetText(5, TmpTxt);
- sprintf_s(TmpTxt, 10, "B: 0x%02x", (newcol>>16) & 0xff); Dlg->SetText(6, TmpTxt);
-#else
- 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);
-#endif
- }
- }
- break;
- }
- }while (res < 0);
- CloseDlgWnd(hDlg);
- delete Dlg;
- free(ColDlg);
- return currcol;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Configure 3D shading
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *ConfShade_DlgTmpl =
- "1,2,,DEFAULT,PUSHBUTTON,-1,95,10,45,12\n"
- "2,3,,,PUSHBUTTON,-2,95,25,45,12\n"
- "3,4,100,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
- "4,5,,ODEXIT,COLBUTT,1,60,10,15,10\n"
- "5,6,,ODEXIT,COLBUTT,2,60,37,15,10\n"
- "6,7,,ODEXIT,COLBUTT,1,60,49,15,10\n"
- "7,8,,,RTEXT,3,25,37,30,9\n"
- "8,9,,,RTEXT,4,25,49,30,9\n"
- "9,,,,SHADE3D,5,95,50,22,20\n"
- "100,101,,TOUCHEXIT,RADIO1,6,10,10,50,9\n"
- "101,,,TOUCHEXIT | LASTOBJ,RADIO1,7,10,25,60,9";
-
-void ConfShade(FillDEF *oldfill)
-{
- FillDEF newFill;
- void *dyndata[] = {(void*)&oldfill->color, (void*)&oldfill->color2, (void*)"HI-color:",
- (void*)"LO-color:", (void*)&newFill, (void*)"fixed color:", (void*)"use light sorce:"};
- DlgInfo *ShadeDlg = CompileDialog(ConfShade_DlgTmpl, dyndata);
- 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, 0L))) 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(32.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; free(ShadeDlg);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 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, FILL_HASH,
- FILL_WATER};
- 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, COLBUTT, 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, COLBUTT, 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, 0L);
- 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
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char* LayerDlg_Tmpl =
- "1,3,0,DEFAULT,PUSHBUTTON,-1,165,10,45,12\n"
- "3,20,100,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "20,550,,,CHECKPIN,0,10,0,12,8\n"
- "100,101,,TOUCHEXIT,TREEVIEW,1,10,15,100,70\n"
- "101,102,,,EDTEXT,2, 120, 25, 90, 10\n"
- "102,200,150,ISPARENT | CHECKED | HIDDEN,GROUP,0L,0,0,0,0\n"
- "150,151,,TOUCHEXIT,RADIO1,3,120,35,40,9\n"
- "151,,,TOUCHEXIT,RADIO1,4,160,35,40,9\n"
- "200,500,,,LTEXT,5,10,5,110,9\n"
- "500,501,600,ISPARENT | CHECKED | HIDDEN,GROUP,0,0,0,0,0\n"
- "501,,,HIDDEN | TOUCHEXIT,TRASH,0,125,72,15,15\n"
- "550,,,HIDDEN | TOUCHEXIT,CONFIG,0,140,72,15,15\n"
- "600,601,,TOUCHEXIT, ODBUTTON,6,125,50,15,15\n"
- "601,602,,TOUCHEXIT, ODBUTTON,6,145,50,15,15\n"
- "602,603,,TOUCHEXIT, ODBUTTON,6,165,50,15,15\n"
- "603,,,LASTOBJ | TOUCHEXIT, ODBUTTON,6,185,50,15,15";
-
-bool ShowLayers(GraphObj *root)
-{
- char curr_name[50];
- void *dyndata[] = {(void*)root, (void*)curr_name, (void*)"hidden", (void*)"visible",
- (void*)"Layers:", (void*)OD_DrawOrder};
- DlgInfo *LayerDlg;
- DlgRoot *Dlg;
- void *hDlg;
- int res, cl;
- bool bContinue = false;
- ObjTree *ot = 0L;
- GraphObj *cgo = 0L;
-
- if(!root || !(LayerDlg = CompileDialog(LayerDlg_Tmpl, dyndata))) return false;
- rlp_strcpy(curr_name, 50, "(root)");
- if(!(Dlg = new DlgRoot(LayerDlg, 0L)))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 || cgo->parent->Id == GO_PLOT3D ||
- cgo->parent->Id == GO_FUNC3D) {
- 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
- || cgo->Id == GO_GRID3D){
- 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; free(LayerDlg);
- 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;
- bool init = true;
- int res, cnt = 5;
-
- if(!show) return;
- if(!(Dlg = new DlgRoot(BannerDlg, 0L)))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);
- ShowDlgWnd(hDlg);
- do{
- LoopDlgWnd();
- res = Dlg->GetResult();
- switch (res) {
- case 0: //loose focus: get it again
- ShowDlgWnd(hDlg);
- cnt = 5; res = -1;
- break;
- case -2: //Timer event
- if(init) {
- init = false;
- FindBrowser(); SpreadMain(true);
- ShowDlgWnd(hDlg); cnt = 4;
- }
- 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-2007 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-2007 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, 0L))) {
- 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
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char * SSDlg_Tmpl =
- "1,2,,DEFAULT,PUSHBUTTON,-1,122,10,40,12\n"
- "2,3,,,PUSHBUTTON,-2,122,25,40,12\n"
- "3,,5,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
- "5,6,100,ISPARENT | CHECKED,SHEET,1,5,10,108,80\n"
- "6,,200,ISPARENT,SHEET,2,5,10,108, 80\n"
- "100,101,,,LTEXT,3,15,25,60,8\n"
- "101,102,,,EDTEXT,-16,40,37,40,10\n"
- "102,103,,,LTEXT,4,15,52,60,8\n"
- "103,,,,EDTEXT,-17,40,64,40,10\n"
- "200,201,,,RTEXT,5,10,29,40,8\n"
- "201,202,,,EDVAL1,6,52,29,25,10\n"
- "202,203,,,LTEXT,7,79,29,20,8\n"
- "203,204,,,RTEXT,8,10,44,40,8\n"
- "204,205,,,EDVAL1,9,52,44,25,10\n"
- "205,206,,,LTEXT,7,79,44,20,8\n"
- "206,207,,,RTEXT,10,10,59,40,8\n"
- "207,208,,,EDVAL1,11,52,59,25,10\n"
- "208,209,,,LTEXT,-3,79,59,20,8\n"
- "209,210,,,RTEXT,12,10,74,40,8\n"
- "210,211,,,INCDECVAL1,13,52,74,33,10\n"
- "211,,,LASTOBJ,LTEXT,-10,87,74,20,8";
-bool
-DoSpShSize(DataObj *dt, GraphObj *parent)
-{
- TabSHEET tab1 = {0, 45, 10, "Dimensions"};
- TabSHEET tab2 = {45, 108, 10, "Width and Height"};
- double fw, cw, ch, th;
- void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)"number of columns:", (void*)"number of rows:",
- (void*)"row buttons", (void*)&fw, (void*)"[digits]", (void*)"column width", (void*)&cw,
- (void*)"row height", (void*)&ch, (void*)"text size", (void*)&th};
- DlgInfo *SSDlg;
- DlgRoot *Dlg;
- void *hDlg;
- int w1, w2, h1, h2, res, celldim[3], ith;
- bool bRet = false;
- double fw1, cw1, ch1, th1;
-
- if(!dt || !dt->GetSize(&w1, &h1)) return false;
- if(!(SSDlg = CompileDialog(SSDlg_Tmpl, dyndata))) return false;
- dt->Command(CMD_GET_CELLDIMS, &celldim, 0L);
- fw1 = fw = NiceValue(((double)celldim[0])/((double)(celldim[2]-2)/2.0));
- cw1 = cw = NiceValue(((double)celldim[1])/((double)(celldim[2]-2)/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; th = th1 = defs.ss_txt*100.0;
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt+100, 40, "%d", w1); sprintf_s(TmpTxt+200, 40, "%d", h1);
-#else
- sprintf(TmpTxt+100, "%d", w1); sprintf(TmpTxt+200, "%d", h1);
-#endif
- Dlg = new DlgRoot(SSDlg, dt);
- hDlg = CreateDlgWnd("Change spread sheet settings", 50, 50, 340, 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, TmpTxt+100, 40) && Dlg->GetText(103, TmpTxt+200, 40)) {
- w2 = atol(TmpTxt+100); h2 = atol(TmpTxt+200);
- w2 = w2 > 0 ? w2: w1; h2 = h2 > 0 ? h2: h1;
- }
- else res = -1;
- break;
- }
- }while(res <0);
- if(res == 1){
- if(Dlg->GetValue(207, &ch) && Dlg->GetValue(210, &th) && ch > 0.001) {
- Undo.ValFloat(parent, &defs.ss_txt, 0L);
- defs.ss_txt = th = th >= 10.0 && th <= 100 ? th/100.0 : 1.0;
- switch(defs.cUnits) {
- case 1:
- celldim[2] = iround(ch/0.0259183673)+2; ith = iround(th * ch/0.0259183673);
- break;
- case 2:
- celldim[2] = iround(ch*98.0)+2; ith = iround(th * ch*98.0);
- break;
- default:
- celldim[2] = iround(ch/0.259183673)+2; ith = iround(th * ch/0.259183673);
- break;
- }
- bRet = dt->Command(CMD_TEXTSIZE, (void*)(& ith), 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; free(SSDlg);
- return bRet;
-}
-
-
-bool FillSsRange(DataObj *d, char **range, GraphObj *msg_go)
-{
- TabSHEET tab1 = {0, 37, 10, "fill range "};
- char *ra = range ? *range:0L;
- double startval = 1.0, stepval = 1.0;
- static char *formula = (char*)malloc(500 * sizeof(char));
- if(formula && CurrText && CurrText->isFormula()) {
- if(CurrText->GetText(TmpTxt,TMP_TXT_SIZE, false)) rlp_strcpy(formula, 500, TmpTxt);
- }
- if(formula) rlp_strcpy(formula, 500, "=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, RANGEINPUT, (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, CHECKED, 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;
- RECT rc_dest;
- anyOutput *cdisp = Undo.cdisp;
-
- if(!d || !range) return false;
- if(!(Dlg = new DlgRoot(RangeDlg, d))) 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, TMP_TXT_SIZE)) {
- InfoBox("Range not specified\nor not valid.");
- bContinue = true; res = -1;
- }
- else ra = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
- rc_dest.left = rc_dest.right = rc_dest.top = rc_dest.bottom = 0;
- 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);
- Undo.SetDisp(cdisp);
- 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)) {
- rF->BoundRec(&rc_dest);
- Undo.DataObject(msg_go, Undo.cdisp, d, &rc_dest, 0L);
- for( ; rF->GetNext(&col, &row); startval += stepval) {
- d->SetValue(row, col, startval);
- }
- delete rF; bRet = true;
- }
- }
- else if(Dlg->GetCheck(8)) {
- if((rF = new AccRange(ra)) && rF->GetFirst(&col, &row) &&
- Dlg->GetText(22, TmpTxt, TMP_TXT_SIZE) && formula){
- rlp_strcpy(formula, 500, TmpTxt);
- r1 = row; c1 = col;
- for( ; rF->GetNext(&col, &row); startval += stepval) {
- if(formula[0] == '=') {
- MoveFormula(d, formula, TmpTxt, TMP_TXT_SIZE, col-c1, row-r1, -1, -1);
- d->SetText(row, col, TmpTxt);
- }
- else d->SetText(row, col, formula);
- }
- delete rF; bRet = true;
- }
- }
- free(ra);
- }
- CloseDlgWnd(hDlg); delete Dlg;
- return bRet;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Get resolution and size for exported bitmap
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char * ResDlg_Tmpl =
- "1,2,,DEFAULT,PUSHBUTTON,-1,125,10,35,12\n"
- "2,100,,,PUSHBUTTON,-2,125,25,35,12\n"
- "100,+,,,LTEXT,1,20,10,50,9\n"
- ".,.,,,RTEXT,2,20,22,35,9\n"
- ".,.,,,EDVAL1,3,57,22,30,10\n"
- ".,.,,,LTEXT,-3,89,22,20,8\n"
- ".,.,,,RTEXT,4,20,34,35,9\n"
- ".,.,,,EDVAL1,5,57,34,30,10\n"
- ".,.,,,LTEXT,-3,89,34,20,8\n"
- ".,.,,,RTEXT,6,20,46,35,9\n"
- ".,.,,,EDVAL1,7,57,46,30,10\n"
- ".,,,LASTOBJ,LTEXT,8,89,46,20,8";
-
-bool GetBitmapRes(double *dpi, double *width, double *height, char *header)
-{
- void *dyndata[] = {(void*)"Image properties:", (void*)"width", (void*)width,
- (void*)"height", (void*)height, (void*)"resolution", (void*)dpi, (void *) "dpi"};
- DlgInfo *ResDlg;
- DlgRoot *Dlg;
- void *hDlg;
- bool bRet = false;
- int res;
-
- if(!(ResDlg = CompileDialog(ResDlg_Tmpl, dyndata))) return false;
- if(!(Dlg = new DlgRoot(ResDlg, 0L))) return false;
- if(!(hDlg = CreateDlgWnd(header, 50, 50, 340, 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);
- bRet = (res == 1);
- CloseDlgWnd(hDlg); delete Dlg; free(ResDlg);
- 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 ? COLBUTT : 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, 0L);
- }
- 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, COLBUTT, (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, 0L);
- }
- 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, COLBUTT, (void *)&ODLine.color, 42, 12, 25, 10},
- {105, 106, 0, 0x0L, RTEXT,(void*)"fill color" , 0, 24, 40, 8},
- {106, 107, 0, TOUCHEXIT | OWNDIALOG, COLBUTT, (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, 0L);
- }
- 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:
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, " %s (%.1lf x %.1lf cm)", p_formats[i].name,
- p_formats[i].mwidth/10.0, p_formats[i].mheight/10.0);
-#else
- sprintf(TmpTxt, " %s (%.1lf x %.1lf cm)", p_formats[i].name,
- p_formats[i].mwidth/10.0, p_formats[i].mheight/10.0);
-#endif
- break;
- case 2:
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, " %s (%.2lf x %.2lf inch)", p_formats[i].name,
- p_formats[i].iwidth, p_formats[i].iheight);
-#else
- sprintf(TmpTxt, " %s (%.2lf x %.2lf inch)", p_formats[i].name,
- p_formats[i].iwidth, p_formats[i].iheight);
-#endif
- break;
- default:
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, " %s (%.0lf x %.0lf mm)", p_formats[i].name,
- p_formats[i].mwidth, p_formats[i].mheight);
-#else
- sprintf(TmpTxt, " %s (%.0lf x %.0lf mm)", p_formats[i].name,
- p_formats[i].mwidth, p_formats[i].mheight);
-#endif
- break;
- }
- dispsize[i] = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
- }
- else if(dispsize[i] = (char*)malloc(15*sizeof(char)))
- rlp_strcpy(dispsize[i], 15, " 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, 0L)){
- 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, TMP_TXT_SIZE)){
- 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, 0L);
- }
- 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, TMP_TXT_SIZE)){
- 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 if(Dlg) Dlg->GetInt(110, &axisplot_sel);
- if(o) *((int*)o) = axisplot_sel;
- }
-}
+//TheDialog.cpp, Copyright (c) 2001-2008 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 = 10;
+static unsigned long DlgBGcolor = 0x00e0e0e0L;
+static unsigned long DlgBGhigh = 0x00e8e8e8L;
+TextDEF DlgText = {0x00000000L, 0x00ffffffL, 4.0, 0.0, 0.0, 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, DataObj *d)
+{
+ int i;
+ RECT rc;
+
+ dlg = 0L; flags = 0L; tabstops = 0L;
+ DlgText.iSize = dlgtxtheight; DlgText.ColBg = DlgBGcolor;
+ DlgText.fSize = defs.GetSize(SIZE_TEXT);
+ type = NONE; Id = -2; cContinue = 0;
+ bActive = bRedraw = false; c_go = CurrGO;
+ CurrDisp = 0L; oldFocus = DialogFocus; DialogFocus = 0L;
+ oldDefault = DialogDefault; oldTabStop = DialogTabStop;
+ data = d; res_put = res_get = 0; hDialog = 0L;
+ if(ParentOut = Undo.cdisp) ParentOut->MouseCursor(MC_WAIT, false);
+ mrk_item = 0L; //if an item has a mark its this one
+ bModal = true; //assume its a modal dialog
+ 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 COLBUTT:
+ dlg[i]->dialog = new ColorButton(this, &tmpl[i],rc, (DWORD *)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 RANGEINPUT:
+ dlg[i]->dialog = new RangeInput(this, &tmpl[i],rc,(char*)tmpl[i].ptype, data);
+ 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, data);
+ 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(data) data->Command(CMD_ETRACC, 0L, 0L);
+ defs.Idle(CMD_FLUSH);
+ HideTextCursor();
+ 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 COLBUTT: 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 RANGEINPUT: delete((RangeInput*)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); dlg=0L;
+ }
+ if(tabstops) free(tabstops); tabstops = 0L;
+ DialogFocus = oldFocus; DialogDefault = oldDefault;
+ DialogTabStop = oldTabStop; CurrGO = c_go;
+ if(Undo.cdisp)Undo.cdisp->MouseCursor(MC_ARROW, false);
+}
+
+bool
+DlgRoot::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ Dialog *d;
+ int i, j;
+
+ switch (cmd) {
+ case CMD_UNDO:
+ if(CurrDisp) {
+ Undo.Restore(false, CurrDisp);
+ DoPlot(CurrDisp);
+ }
+ return true;
+ case CMD_REDRAW:
+ if(CurrDisp) {
+ CurrDisp->Erase(DlgBGcolor); DoPlot(CurrDisp);
+ defs.Idle(CMD_UPDATE);
+ }
+ return true;
+ case CMD_MOUSE_EVENT:
+ if(DialogFocus && DialogFocus->type == TEXTBOX && DialogFocus->Command(cmd, tmpl, o)) return true;
+ mev = (MouseEvent *) tmpl;
+ switch(mev->Action) {
+ case MOUSE_LBDOWN:
+ bActive = true;
+ case MOUSE_MOVE:
+ //track mouse and display controls accordingly
+ if(!(mev->StateFlags & 1)) break;
+ if(bActive)ForEach(CMD_MOUSE_EVENT, 0, o);
+ break;
+ case MOUSE_LBDOUBLECLICK:
+ ForEach(CMD_MOUSE_EVENT, 0, o);
+ bActive = false; //skip next event (LB up);
+ break;
+ case MOUSE_LBUP:
+ if(bActive)ForEach(CMD_LBUP, 0, o);
+ break;
+ }
+ defs.Idle(CMD_UPDATE);
+ return true;
+ case CMD_ENDDIALOG:
+ d = (Dialog *)tmpl;
+ if(d) {
+ res_q[res_put++] = d->Id; // end dialog by object
+ cContinue = 0;
+ }
+ else if(cContinue >0) { // no end upon killing the focus
+ cContinue--;
+ return true;
+ }
+ else {
+ res_q[res_put++] = 0; // end dialog with closebox or loose focus
+ bRedraw = true;
+ }
+ res_put &= 0xff;
+ 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]) || (tabstops[i]->flags & HIDDEN)) i++;
+ if(!tabstops[i]) i = 0;
+ switch(tabstops[i]->type) {
+ case PUSHBUTTON:
+ d = DialogDefault;
+ DialogTabStop = DialogDefault = tabstops[i];
+ if(d) d->DoPlot(o);
+ DialogDefault->DoPlot(o);
+ break;
+ case EDTEXT: case EDVAL1: case RANGEINPUT:
+ 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:
+ case RANGEINPUT:
+ 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: case CMD_COPY: case CMD_PASTE:
+ Undo.SetDisp(CurrDisp);
+ bActive = true;
+ if(DialogFocus)return DialogFocus->Command(cmd, tmpl, CurrDisp);
+ else return false;
+ case CMD_ADDCHAR:
+ if(!tmpl) return false;
+ bActive = true;
+ if(*((int*)tmpl) == 27) { //Esc
+ HideCopyMark();
+ for (i = 0; dlg[i] && i < cDlgs; i++)
+ if(dlg[i]->dialog) dlg[i]->dialog->Command(cmd, tmpl, o);
+ return Command(CMD_REDRAW, 0L, 0L);
+ }
+ 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:
+ CurrDisp = 0L;
+ for(i = 0; i < cDlgs; i++)
+ if(dlg[i] && dlg[i]->dialog) dlg[i]->dialog->Command(CMD_UNLOCK, 0L, 0L);
+ break;
+ case CMD_MARKOBJ:
+ if(mrk_item && mrk_item != (Dialog*)tmpl){
+ i = 27;
+ mrk_item->Command(CMD_ADDCHAR, &i, o);
+ }
+ mrk_item = (Dialog*)tmpl;
+ break;
+ }
+ return false;
+}
+
+void
+DlgRoot::DoPlot(anyOutput *o)
+{
+ int i;
+
+ HideCopyMark(); mrk_item = 0L; bRedraw = false;
+ HideTextCursor();
+ if(tabstops) for(i = 0; i < cDlgs; tabstops[i++] = 0);
+ if(o)CurrDisp = o; DialogDefault = 0L;
+ if(CurrDisp) {
+ CurrDisp->SetTextSpec(&DlgText);
+ ForEach(CMD_DOPLOT, 0, CurrDisp);
+ }
+ defs.Idle(CMD_UPDATE);
+}
+
+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: case RANGEINPUT:
+ 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 && color && dlg[i] && dlg[i]->dialog) 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 size)
+{
+ int i;
+
+ i = FindIndex(id);
+ if(i && dlg[i]) return dlg[i]->dialog->GetText(id, txt, size);
+ 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))bRedraw = true;
+ else return false;
+ return true;
+}
+
+bool
+DlgRoot::SetValue(int id, double val)
+{
+ int i;
+ char tmp_txt[80];
+
+ i = FindIndex(id);
+ WriteNatFloatToBuff(tmp_txt, val);
+ if(i && dlg[i] && dlg[i]->dialog->Command(CMD_SETTEXT, tmp_txt+1, CurrDisp))bRedraw = true;
+ 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;
+
+ if(res_put != res_get) ret = res_q[res_get++];
+ else ret = -1;
+ res_get &= 0xff;
+ if(bRedraw)DoPlot(0L);
+ else defs.Idle(CMD_UPDATE);
+ if(ret >= 0 && ParentOut) Undo.SetDisp(ParentOut);
+ 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] && 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++) {
+ if(i = FindIndex(i)) {
+ dlg[next]->dialog->Command(CMD_ADDCHILD, (void*)dlg[i]->dialog, 0L);
+ i = dlg[i]->next;
+ }
+ else{
+ i=i;
+ }
+ }
+ }
+ 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] && 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] ? dlg[next]->next : 0);
+ }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]){
+ bRedraw = true;
+ 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) && bLBstate){
+ if(parent && type != CHECKBOX && type != RADIO1 && type != RADIO2) parent->Command(CMD_MARKOBJ, this, o);
+ if(!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[0]) Text = (char*)memdup(text, (int)strlen(text)+1, 0);
+ 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_ENDDIALOG:
+ parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ return true;
+ case CMD_ADDCHAR:
+ HideCopyMark();
+ 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-1, cr.bottom-1);
+ else {
+ o->oRectangle(cr.left, cr.top, cr.right-2, cr.bottom-2);
+ 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);
+ }
+ defs.UpdRect(o, cr.left, cr.top, cr.right, cr.bottom);
+ 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)
+{
+ lfPOINT lfp1, lfp2;
+
+ TextDef.Font = FONT_COURIER; TextDef.Align = TXA_VBOTTOM | TXA_HLEFT;
+#ifdef _WINDOWS
+// TextDef.fSize unchanged
+#else
+ TextDef.fSize *= .8;
+#endif
+ Fill.color = 0x00ffffffL; Line.color = 0x00000000L; cont = 0L;
+ lfp1.fx = rec.left; lfp1.fy = rec.top;
+ lfp2.fx = rec.right; lfp2.fy = rec.bottom;
+ if(cont = new TextFrame(0L, 0L, &lfp1, &lfp2, text)) cont->Command(CMD_SETTEXTDEF, &TextDef, 0L);
+}
+
+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: case CMD_MOUSE_EVENT:
+ case CMD_COPY: case CMD_PASTE: case CMD_CURRUP:
+ case CMD_CURRDOWN:
+ if(bChecked && CurrGO && CurrGO == cont) return CurrGO->Command(cmd, tmpl, o);
+ break;
+ case CMD_SETTEXT:
+ if(cont)return cont->Command(cmd, tmpl, o);
+ return false;
+ }
+ return false;
+}
+
+void
+TextBox::DoPlot(anyOutput *o)
+{
+ if(cont && o)cont->DoPlot(o);
+}
+
+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(CurrGO = cont) bChecked = cont->Command(CMD_SELECT, &p1, o);
+ }
+ return false;
+}
+
+void
+TextBox::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 && cont && parent) {
+ DialogFocus = this; bChecked = true;
+ parent->Command(CMD_FOCTXT, (void*)this, 0L);
+ cont->Command(CMD_MOUSE_EVENT, mev, o);
+ parent->Command(CMD_MARKOBJ, this, o);
+ }
+}
+
+bool
+TextBox::GetText(int id, char *txt, int size)
+{
+ if(cont) {
+ if(!(cont->Command(CMD_ALLTEXT, TmpTxt, 0L))) return false;
+ rlp_strcpy(txt, size, TmpTxt);
+ return true;
+ }
+ 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-1, cr.bottom-1);
+ else {
+ o->oRectangle(cr.left, cr.top, cr.right-2, cr.bottom-2);
+ 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;
+ }
+ defs.UpdRect(o, cr.left, cr.top, cr.right, cr.bottom);
+}
+
+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, DWORD *color)
+ :Dialog(par, desc, rec)
+{
+ col = color ? *color : 0x0L;
+}
+
+void
+ColorButton::DoPlot(anyOutput *o)
+{
+ POINT pts[5];
+
+ Fill.color = (col & 0x00ffffffL);
+ 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);
+ }
+ defs.UpdRect(o, cr.left, cr.top, cr.right, cr.bottom);
+}
+
+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);
+ defs.UpdRect(o, cr.left, cr.top, cr.right, cr.bottom);
+}
+
+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 & 0x00ffffff);
+ 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) & 0x00ffffffL);
+ 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 & 0x00ffffffL);
+ 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);
+ }
+ defs.UpdRect(o, cr.left, cr.top, cr.right, cr.bottom);
+}
+
+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);
+ defs.UpdRect(o, cr.left, cr.top, cr.right, cr.bottom);
+}
+
+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);
+ }
+ defs.UpdRect(o, cr.left, cr.top, cr.right, cr.bottom);
+}
+
+bool
+SymButton::Select(int x, int y, anyOutput *o)
+{
+ if(parent && IsInRect(&cr, x, y)) {
+ if((flags & OWNDIALOG) && (*(symbol))) {
+ parent->Command(CMD_CONTINUE, 0L, o);
+ (*symbol)->PropertyDlg();
+ }
+ if((flags & TOUCHEXIT))
+ 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);
+ defs.UpdRect(o, cr.left, cr.top, cr.right, cr.bottom);
+}
+
+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 & 0x00ffffff);
+ o->SetFill(&Fill);
+ o->SetLine(&Line);
+ o->oRectangle(cr.left+1, cr.top+1, cr.right-1, cr.bottom-1);
+ Sym->DoPlot(o);
+ defs.UpdRect(o, cr.left, cr.top, cr.right, cr.bottom);
+}
+
+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[0])Text = (char*)memdup(text, (int)strlen(text)+1, 0);
+ 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 && *((char*)tmpl)) Text = (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1,0);
+ 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, (int)strlen(Text));
+ }
+ defs.UpdRect(o, cr.left, cr.top, cr.right, cr.bottom);
+}
+
+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);
+ }
+ defs.UpdRect(o, cr.left, cr.top, cr.right, cr.bottom);
+}
+
+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);
+ defs.UpdRect(o, cr.left, cr.top, cr.right, cr.bottom);
+}
+
+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);
+ defs.UpdRect(o, cr.left, cr.top, cr.right, cr.bottom);
+}
+
+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[0])Text = (char*)memdup(text, (int)strlen(text)+1, 0);
+ 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 && *((char*)tmpl))Text = (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1, 0);
+ 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, (int)strlen(Text));
+ }
+ defs.UpdRect(o, cr.left, cr.top, cr.right, cr.bottom);
+}
+
+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 & 0x00ffffffL);
+}
+
+Text::Text(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text)
+ :Dialog(par, desc, rec)
+{
+ if(text && text[0])txt = (char*)memdup(text, (int)strlen(text)+1, 0);
+ 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 && *((char*)tmpl))txt = (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1, 0);
+ 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;
+ }
+ defs.UpdRect(o, cr.left, cr.top, cr.right, cr.bottom);
+ }
+}
+
+bool
+Text::Select(int x, int y, anyOutput *o)
+{
+ int i;
+
+ if(WWWbrowser && WWWbrowser[0] && txt && (flags & HREF) && IsInRect(&cr, x, y)) {
+ o->MouseCursor(MC_WAIT, false);
+ i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE-50, WWWbrowser);
+ TmpTxt[i++] = ' ';
+ rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, txt);
+ if(parent && (flags & TOUCHEXIT))parent->Command(CMD_ENDDIALOG, 0L, o);
+ else if(parent)parent->Command(CMD_CONTINUE, 0L, o);
+#ifdef _WINDOWS
+ WinExec(TmpTxt, SW_SHOWMAXIMIZED);
+#else
+ strcat(TmpTxt, " &");
+ system(TmpTxt);
+#endif
+ o->MouseCursor(MC_ARROW, false);
+ return true;
+ }
+ return false;
+}
+
+void
+Text::SetColor(int id, DWORD color)
+{
+ TextDef.ColTxt = (color & 0x00ffffffL);
+}
+
+void
+Text::MBtrack(MouseEvent *mev, anyOutput *o)
+{
+ if((mev->StateFlags &1) && IsInRect(&hcr, mev->x, mev->y) && parent) parent->Command(CMD_MARKOBJ, this, o);
+}
+
+InputText::InputText(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text)
+ :Dialog(par, desc, rec)
+{
+ RECT rc;
+
+ rc.left = rec.left+1; rc.top = rec.top+1;
+ rc.right = rec.right-1; rc.bottom = rec.bottom-1;
+ if(type == INCDECVAL1) cr.right = rc.right = cr.right - 7*xbase;
+ Line.color = 0x00000000L;
+ if(Text = new EditText(0L, text, -1, -1)) Text->SetRec(&rc);
+ Disp = 0L;
+}
+
+InputText::~InputText()
+{
+ if(Text) delete (Text); Text = 0L;
+}
+
+bool
+InputText::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ 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)){
+ if(o) Undo.SetDisp(o);
+ 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_UPDATE:
+ if(Text && bActive && o) Text->Command(cmd, o, 0L);
+ break;
+ case CMD_COPY: case CMD_PASTE:
+ if(Text && bActive && !(flags & NOEDIT)) return Text->Command(cmd, o, NULL);
+ return false;
+ case CMD_ADDCHAR:
+ if(Text && bActive && !(flags & NOEDIT)){
+ if(o) Undo.SetDisp(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);
+ }
+ if(flags & TOUCHEXIT) parent->Command(CMD_ENDDIALOG, (void *)this, o);
+ }
+ return false;
+ case CMD_SETTEXT:
+ if(Text) return Text->SetText((char*)tmpl);
+ break;
+ }
+ return false;
+}
+
+void
+InputText::DoPlot(anyOutput *o)
+{
+ POINT pts[5];
+
+ if(!o) return;
+ 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);
+ defs.UpdRect(o, cr.left, cr.top, cr.right, cr.bottom);
+ if(parent && bActive){
+ parent->Command(CMD_TABDLG, this, o);
+ if(type == RANGEINPUT)o->MouseCapture(false);
+ }
+}
+
+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 true;
+ }
+ return false;
+}
+
+bool
+InputText::GetValue(int id, double *val)
+{
+ if(Text && val) {
+ 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) {
+#ifdef USE_WIN_SECURE
+ sscanf_s(Text->text, "%d", val);
+#else
+ sscanf(Text->text, "%d", val);
+#endif
+ return true;
+ }
+ return false;
+}
+
+bool
+InputText::GetText(int id, char *txt, int size)
+{
+ if(Text && Text->text && Text->text[0]) {
+ rlp_strcpy(txt, size, 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 && parent) {
+ DialogFocus = this;
+ parent->Command(CMD_FOCTXT, (void*)this, 0L);
+ o->SetTextSpec(&TextDef);
+ Text->Command(CMD_MOUSE_EVENT, o, (DataObj *)mev);
+ parent->Command(CMD_MARKOBJ, this, o);
+ }
+}
+
+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);
+ }
+}
+
+RangeInput::RangeInput(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text, DataObj *d)
+ :InputText(par, desc, rec, text)
+{
+ data = d;
+}
+
+RangeInput::~RangeInput()
+{
+ if(data) data->Command(CMD_ETRACC, 0L, 0L);
+ if(Text) delete (Text); Text = 0L;
+}
+
+bool
+RangeInput::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ switch(cmd) {
+ case CMD_SET_DATAOBJ:
+ data = (DataObj*)tmpl;
+ return true;
+ }
+ return InputText::Command(cmd, tmpl, o);
+}
+
+bool
+RangeInput::Select(int x, int y, anyOutput *o)
+{
+ bool bRes;
+
+ bRes = InputText::Select(x, y, o);
+ if(bRes && data) {
+ if(DialogFocus == this){
+ data->Command(CMD_ETRACC, Text, 0L);
+ if(Text) Text->Update(1, o, 0L);
+ }
+ else data->Command(CMD_ETRACC, 0L, 0L);
+ }
+ return bRes;
+}
+
+void
+RangeInput::Activate(int id, bool activate)
+{
+ InputText::Activate(id, activate);
+ if(activate && data) data->Command(CMD_ETRACC, Text, 0L);
+}
+
+InputValue::InputValue(tag_DlgObj *par, DlgInfo * desc, RECT rec, double *value)
+ :InputText(par, desc, rec, 0L)
+{
+ if(value) {
+ WriteNatFloatToBuff(TmpTxt, *value);
+ if(Text) Text->text = (char*)memdup(TmpTxt+1, (int)strlen(TmpTxt+1)+1, 0);
+ }
+ else if(Text) Text->SetText("");
+}
+
+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 = (char*)memdup(TmpTxt+1, (int)strlen(TmpTxt+1)+1, 0);
+ 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);
+ hasMinMax = hasStep = false;
+ theMin = theMax = theStep = 0.0;
+}
+
+IncDecValue::~IncDecValue()
+{
+ if(Text) delete (Text);
+ if(butts[0]) delete (butts[0]);
+ if(butts[1]) delete (butts[1]);
+ Text = 0L;
+}
+
+bool
+IncDecValue::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ double tmpVal;
+
+ switch(cmd) {
+ case CMD_MINMAX:
+ if(tmpl) {
+ hasMinMax = true;
+ theMin = ((double*)tmpl)[0];
+ theMax = ((double*)tmpl)[1];
+ }
+ else hasMinMax = false;
+ return true;
+ case CMD_STEP:
+ if(tmpl) {
+ hasStep = true;
+ theStep = *((double*)tmpl);
+ }
+ else hasStep = false;
+ return true;
+ case CMD_ENDDIALOG:
+ if(GetValue(Id, &tmpVal)) {
+ if(hasStep && theStep > 0.0) {
+ tmpVal = floor(tmpVal/theStep)*theStep;
+ if(((Dialog*)tmpl)->Id == 1) tmpVal += theStep;
+ else tmpVal -= theStep;
+ }
+ else {
+ if(((Dialog*)tmpl)->Id == 1) tmpVal *= 1.2;
+ else tmpVal /= 1.2;
+ tmpVal = NiceValue(tmpVal);
+ }
+ if(hasMinMax) {
+ if(tmpVal < theMin) tmpVal = theMin;
+ if(tmpVal > theMax) tmpVal = theMax;
+ }
+ else if(!hasStep && 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) {
+ Text->SetText(TmpTxt+1); DoPlot(o);
+ }
+ }
+ return true;
+ }
+ return InputText::Command(cmd, tmpl, o);
+}
+
+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;
+}
+
+bool
+IncDecValue::GetValue(int id, double *val)
+{
+ if(Text && val) {
+ Text->Update(20, NULL, 0L); //convert string to value
+ if(Text->GetValue(val)) {
+ if(hasMinMax) {
+ if(*val < theMin) *val = theMin;
+ if(*val > theMax) *val = theMax;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+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[9];
+
+ for(i = 0; i < 9; i++) {
+ d1[i].id = i+1; d1[i].next = i+2; d1[i].first = 0;
+ d1[i].flags = ISRADIO; d1[i].type = RADIO0; d1[i].ptype = 0L;
+ d1[i].w = d1[i].h = 8;
+ switch (i / 3) {
+ case 0: d1[i].y = y1; break;
+ case 1: d1[i].y = y2; break;
+ case 2: d1[i].y = y3; break;
+ }
+ switch (i % 3) {
+ case 0: d1[i].x = x1; break;
+ case 1: d1[i].x = x2; break;
+ case 2: d1[i].x = x3; break;
+ }
+ }
+ d1[8].next = 0; d1[8].flags |= LASTOBJ;
+ txt.ColTxt = 0x00808080L; txt.ColBg = 0x00ffffff;
+ txt.fSize = defs.GetSize(SIZE_TEXT)*2.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;
+ if(txt.text = (char*)malloc(20*sizeof(char))) rlp_strcpy(txt.text, 20, "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);
+ defs.UpdRect(o, cr.left, cr.top, cr.right, cr.bottom);
+}
+
+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);
+ }
+ defs.UpdRect(o, cr.left, cr.top, cr.right, cr.bottom);
+ 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);
+ defs.UpdRect(o, cr.left, cr.top, cr.right, cr.bottom);
+}
+
+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: case CMD_MARKOBJ:
+ if(parent && (flags & HIDDEN) != HIDDEN) 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 == RANGEINPUT ||
+ 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 && txt[0])Text = (char*)memdup(txt, (int)strlen(txt)+1, 0);
+ 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);
+ defs.UpdRect(o, hcr.left, hcr.top, hcr.right, hcr.bottom);
+}
+
+TabSheet::TabSheet(tag_DlgObj *par, DlgInfo * desc, RECT rec, TabSHEET * sh, DataObj *d)
+ :Group(par, desc, rec)
+{
+ if(sh->text && sh->text[0])Text = (char*)memdup(sh->text, (int)strlen(sh->text)+1, 0);
+ 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;
+ data = d;
+}
+
+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;
+ HideCopyMark();
+ Line.color = 0x0L; 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);
+#ifdef _WINDOWS
+ o->oTextOut(rctab.right - 6, rctab.top + 3, Text, 0);
+#else
+ o->oTextOut(rctab.right - 6, rctab.top + 5, Text, 0);
+ if(bChecked) {
+ Line.color = 0x0L; o->SetLine(&Line);
+ pts[0].y++; o->oSolidLine(pts);
+ }
+#endif
+ Group::DoPlot(o);
+ defs.UpdRect(o, cr.left, cr.top, cr.right, cr.bottom);
+}
+
+bool
+TabSheet::Select(int x, int y, anyOutput *o)
+{
+ if(IsInRect(&rctab, x, y)) {
+ if(data)data->Command(CMD_ETRACC, 0L, 0L);
+ if(parent) {
+ parent->Command(CMD_RADIOBUTT, (void *)this, o);
+ parent->Command(CMD_MARKOBJ, 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; i++){
+ strings[i] = (char*)memdup(list[i], (int)strlen(list[i])+1, 0);
+ }
+ }
+}
+
+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+_SBINC));
+ 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+_SBINC) - startY + hcr.top;
+ mrk.right = hcr.right-2; mrk.bottom = mrk.top + (TextDef.iSize+_SBINC);
+ 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+_SBINC),
+ (hcr.right-hcr.left)-4, mrk.bottom-mrk.top, true);
+ }
+ defs.UpdRect(o, cr.left, cr.top, cr.right, cr.bottom);
+}
+
+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+_SBINC);
+ if(il >= ns || il < 0){
+ o->UpdateRect(&hcr, false);
+ return false;
+ }
+ cl = il;
+ mrk.left = hcr.left+2; mrk.top = (il)*(TextDef.iSize+_SBINC) - startY + hcr.top;
+ mrk.right = hcr.right-2; mrk.bottom = mrk.top + (TextDef.iSize+_SBINC);
+ 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+_SBINC),
+ (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, int size)
+{
+ if(strings && ns && cl >= 0 && cl < ns){
+ rlp_strcpy(txt, size, 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+_SBINC) * 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+_SBINC);
+ for(i = 0; i < ns; i++) {
+ bmp->oTextOut(5, i*(TextDef.iSize+_SBINC), 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+_SBINC));
+ 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+_SBINC) - startY + hcr.top;
+ mrk.right = hcr.right-2; mrk.bottom = mrk.top + (TextDef.iSize+_SBINC);
+ 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+_SBINC),
+ (hcr.right-hcr.left)-4, mrk.bottom-mrk.top, true);
+ }
+ defs.UpdRect(o, cr.left, cr.top, cr.right, cr.bottom);
+}
+
+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+_SBINC);
+ if(il >= ns || il < 0){
+ o->UpdateRect(&hcr, false);
+ return false;
+ }
+ cl = il;
+ mrk.left = hcr.left+2; mrk.top = (il)*(TextDef.iSize+_SBINC) - startY + hcr.top;
+ mrk.right = hcr.right-2; mrk.bottom = mrk.top + (TextDef.iSize+_SBINC);
+ 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+_SBINC),
+ (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;
+ defs.UpdRect(o, gr.left, gr.top, gr.right, gr.bottom);
+}
+
+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);
+ }
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Common code for multiple range dialogs
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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, TMP_TXT_SIZE) && TmpTxt[0] &&
+ (*rX = new AccRange(TmpTxt))) *nx = rX[0]->CountItems();
+ else if(nx) *nx = 0;
+ if(Dlg->GetText(154, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0]) {
+ if(rd[0][*currYR]) free(rd[0][*currYR]);
+ rd[0][*currYR] = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
+ }
+ break;
+ case 155:
+ res = -1;
+ *ny = 0;
+ if(rX) {
+ if(!(*currYR) && Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE) && 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, TMP_TXT_SIZE) && 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] = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0); //store y-ranges
+ *updateYR = true;
+ (*currYR)++;
+ Dlg->SetText(154, rd[0][*currYR]);
+ Dlg->Activate(154, true);
+ break;
+ case 156:
+ if(Dlg->GetText(154, TmpTxt, TMP_TXT_SIZE)){
+ if(rd[0][*currYR]) free(rd[0][*currYR]);
+ rd[0][*currYR] = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);;
+ }
+ else if(*currYR == *maxYR) (*maxYR)--;
+ (*currYR)--;
+ Dlg->SetText(154, rd[0][*currYR]);
+ *updateYR = true;
+ res = -1;
+ break;
+ }
+ return res;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Dialog meta compiler
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *std_text[] = {"OK", "Cancel", "", "x", "y", "z", "-", "Next >>", "<< Prev.",
+ "%", "color", "x-value", "y-value", "z-value", TmpTxt, TmpTxt+100, TmpTxt+200,
+ TmpTxt+300, TmpTxt+400, "left", "right", "top", "bottom", "x-axis", "y-axis", "z-axis",
+ "select style:"};
+
+DlgInfo *CompileDialog(char* tmpl, void **ptypes)
+{
+ char **lines, **fields, **flags, error[80];
+ int i, j, nlines, nfields, nflags, last_id, last_next;
+ unsigned int hv;
+ DlgInfo *Dlg;
+
+ std_text[2] = Units[defs.cUnits].display;
+ lines = split(tmpl, '\n', &nlines);
+ if(!lines || nlines <1 ||(!(Dlg = (DlgInfo*)malloc(nlines*sizeof(DlgInfo))))) return 0L;
+ for(i = last_id = last_next = 0; i < nlines; i++) if(lines[i] && lines[i][0]){
+ if(fields = split(lines[i], ',', &nfields)) {
+ if(nfields == 10) {
+ Dlg[i].id = Dlg[i].next = Dlg[i].first = 0;
+ if(fields[0][0]) {
+ if(fields[0][0] == '.') Dlg[i].id = (last_id += 1);
+ else
+#ifdef USE_WIN_SECURE
+ sscanf_s(fields[0], "%d", &Dlg[i].id); last_id = Dlg[i].id;
+#else
+ sscanf(fields[0], "%d", &Dlg[i].id); last_id = Dlg[i].id;
+#endif
+ }
+ if(fields[1][0]) {
+ if(fields[1][0] == '+') Dlg[i].next = (last_id + 1);
+ else if(fields[1][0] == '.') Dlg[i].next = (last_next += 1);
+ else
+#ifdef USE_WIN_SECURE
+ sscanf_s(fields[1], "%d", &Dlg[i].next); last_next = Dlg[i].next;
+#else
+ sscanf(fields[1], "%d", &Dlg[i].next); last_next = Dlg[i].next;
+#endif
+ }
+#ifdef USE_WIN_SECURE
+ sscanf_s(fields[2], "%d", &Dlg[i].first);
+#else
+ sscanf(fields[2], "%d", &Dlg[i].first);
+#endif
+ Dlg[i].flags = 0L;
+ if(flags = split(fields[3], '|', &nflags)) {
+ for(j = 0; j < nflags; j++){
+ hv = HashValue((unsigned char *)str_trim(flags[j]));
+ switch(hv) {
+ case 196904: Dlg[i].flags |= CHECKED; break;
+ case 4444568: Dlg[i].flags |= TOUCHEXIT; break;
+ case 284491160: Dlg[i].flags |= TOUCHSELEXIT; break;
+ case 235859: Dlg[i].flags |= ISRADIO; break;
+ case 942268: Dlg[i].flags |= ISPARENT; break;
+ case 4220131: Dlg[i].flags |= OWNDIALOG; break;
+ case 198260: Dlg[i].flags |= DEFAULT; break;
+ case 54530: Dlg[i].flags |= HIDDEN; break;
+ case 1011472: Dlg[i].flags |= NOSELECT; break;
+ case 3546: Dlg[i].flags |= HREF; break;
+ case 62296: Dlg[i].flags |= NOEDIT; break;
+ case 231330: Dlg[i].flags |= LASTOBJ; break;
+ case 224595: Dlg[i].flags |= EXRADIO; break;
+ case 60824: Dlg[i].flags |= ODEXIT; break;
+ }
+ free(flags[j]);
+ }
+ free(flags);
+ }
+ hv = HashValue((unsigned char *)str_trim(fields[4]));
+ switch(hv) {
+ case 17108522: Dlg[i].type = PUSHBUTTON; break;
+ case 3252180: Dlg[i].type = ARROWBUTT; break;
+ case 206036: Dlg[i].type = COLBUTT; break;
+ case 13602346: Dlg[i].type = FILLBUTTON; break;
+ case 261312: Dlg[i].type = SHADE3D; break;
+ case 948692: Dlg[i].type = LINEBUTT; break;
+ case 282068: Dlg[i].type = SYMBUTT; break;
+ case 3403091: Dlg[i].type = FILLRADIO; break;
+ case 1130835: Dlg[i].type = SYMRADIO; break;
+ case 787668: Dlg[i].type = CHECKBOX; break;
+ case 62812: Dlg[i].type = RADIO0; break;
+ case 62813: Dlg[i].type = RADIO1; break;
+ case 62814: Dlg[i].type = RADIO2; break;
+ case 15460: Dlg[i].type = LTEXT; break;
+ case 16996: Dlg[i].type = RTEXT; break;
+ case 13156: Dlg[i].type = CTEXT; break;
+ case 51300: Dlg[i].type = EDTEXT; break;
+ case 16235656: Dlg[i].type = RANGEINPUT; break;
+ case 51281: Dlg[i].type = EDVAL1; break;
+ case 14534481: Dlg[i].type = INCDECVAL1; break;
+ case 229196: Dlg[i].type = HSCROLL; break;
+ case 286540: Dlg[i].type = VSCROLL; break;
+ case 71804: Dlg[i].type = TXTHSP; break;
+ case 3418: Dlg[i].type = ICON; break;
+ case 14196: Dlg[i].type = GROUP; break;
+ case 909332: Dlg[i].type = GROUPBOX; break;
+ case 16408: Dlg[i].type = SHEET; break;
+ case 970282: Dlg[i].type = ODBUTTON; break;
+ case 957537: Dlg[i].type = LISTBOX1; break;
+ case 1108443: Dlg[i].type = TREEVIEW; break;
+ case 237304: Dlg[i].type = LINEPAT; break;
+ case 269332: Dlg[i].type = TEXTBOX; break;
+ case 787858: Dlg[i].type = CHECKPIN; break;
+ case 17284: Dlg[i].type = TRASH; break;
+ case 51627: Dlg[i].type = CONFIG; break;
+ default: Dlg[i].type = NONE; break;
+ }
+#ifdef USE_WIN_SECURE
+ sscanf_s(fields[5], "%d", &j);
+#else
+ sscanf(fields[5], "%d", &j);
+#endif
+ if(j < 0) Dlg[i].ptype = (void*)std_text[(-j)-1];
+ else if(j > 0) Dlg[i].ptype = ptypes[j-1];
+ else Dlg[i].ptype = (void*)0L;
+#ifdef USE_WIN_SECURE
+ sscanf_s(fields[6], "%d", &Dlg[i].x); sscanf_s(fields[7], "%d", &Dlg[i].y);
+ sscanf_s(fields[8], "%d", &Dlg[i].w); sscanf_s(fields[9], "%d", &Dlg[i].h);
+#else
+ sscanf(fields[6], "%d", &Dlg[i].x); sscanf(fields[7], "%d", &Dlg[i].y);
+ sscanf(fields[8], "%d", &Dlg[i].w); sscanf(fields[9], "%d", &Dlg[i].h);
+#endif
+ }
+ else {
+#ifdef USE_WIN_SECURE
+ sprintf_s(error, 80, "Wrong number of arguments in template line %d", i);
+#else
+ sprintf(error,"Wrong number of arguments in template line %d\n\"%s\"\n", i, lines[i]);
+#endif
+ InfoBox(error);
+ Dlg[i].id = Dlg[i].next = Dlg[i].first = 0;
+ Dlg[i].flags = 0L; Dlg[i].type = NONE;
+ Dlg[i].ptype = 0L; Dlg[i].x = Dlg[i].y = Dlg[i].w = Dlg[i].h = 0;
+ }
+ for(j = 0; j < nfields; j++)free(fields[j]);
+ free(fields);
+ }
+ free(lines[i]);
+ }
+ free(lines);
+ return Dlg;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Use marked ranges as default for dialog ranges
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool UseRangeMark(DataObj *d, int type, char *r0, char *r1, char *r2, char *r3,
+ char *r4, char *r5, char *r6, char *r7, char *r8, char *r9, char *r10)
+{
+ char *dst[] = {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10};
+ char *mrk, **ra =0L;;
+ int i, j, ranges=0;
+ bool success = false, bErr=false;
+ RECT vrc, rrc;
+ AccRange *ar;
+ bool bRet = true;
+
+ for(i = 0; i < 11; i++) if(dst[i]) *dst[i] = 0;
+ if(d && type) {
+ d->ValueRec(&vrc);
+ if(d->Command(CMD_GETMARK, &mrk, 0L)) {
+ ra = split(mrk, ';', &ranges);
+ ar = new AccRange(mrk); ar->BoundRec(&vrc); delete ar;
+ }
+ switch(type) {
+ case 1:
+ if(ranges > 1) {
+ for(i = 0; i < 11; i++) if(dst[i]) {
+ rlp_strcpy(dst[i], 100, i < ranges ? ra[i] : mkRangeRef(vrc.top, vrc.left, vrc.bottom, vrc.left));
+ }
+ success = true;
+ }
+ else if(vrc.top == vrc.bottom && (vrc.right - vrc.left) >2) {
+ for(i = 0; i < 11; i++) if(dst[i]){
+ rlp_strcpy(dst[i], 100, mkRangeRef(vrc.top+i, vrc.left, vrc.top+i, vrc.right));
+ }
+ success = true;
+ }
+ else if(vrc.right == vrc.left && (vrc.bottom - vrc.top) >2) {
+ for(i = 0; i < 11; i++) if(dst[i]){
+ rlp_strcpy(dst[i], 100, mkRangeRef(vrc.top, vrc.left+i, vrc.bottom, vrc.left+i));
+ }
+ success = true;
+ }
+ break;
+ case 2:
+ for(i = 0; i < 11; i++) if(dst[i]) *(dst[i]) = 0;
+ if(ranges == 1) {
+ for(i = 0, j = vrc.left; i < 11 && j <= vrc.right; i++, j++) if(dst[i]){
+ rlp_strcpy(dst[i], 100, mkRangeRef(vrc.top, vrc.left+i, vrc.bottom, vrc.left+i));
+ }
+ }
+ else if(ranges > 1) {
+ ar = new AccRange(ra[0]); j = ar->CountItems();
+ ar->BoundRec(&rrc); delete ar;
+ if(rrc.left == rrc.right)for(i = 1; i < 11 && i < ranges && !bErr; i++){
+ ar = new AccRange(ra[i]); ar->BoundRec(&rrc);
+ if(rrc.left != rrc.right) bErr = true;
+ delete ar;
+ }
+ else if(rrc.top == rrc.bottom)for(i = 1; i < 11 && i < ranges && !bErr; i++){
+ ar = new AccRange(ra[i]); ar->BoundRec(&rrc);
+ if(rrc.top != rrc.bottom) bErr = true;
+ delete ar;
+ }
+ else for(i = 1; i < 11 && i < ranges && !bErr; i++){
+ ar = new AccRange(ra[i]);
+ if(j != ar->CountItems()) bErr = true;
+ delete ar;
+ }
+ if(i < 12 && !bErr) for(i = 0; i < 11 && i < ranges; i++){
+ if(dst[i]) rlp_strcpy(dst[i], 100, ra[i]);
+ }
+ }
+ if(bErr) {
+ InfoBox("Cannot resolve multiple ranges\nwith different sizes.\n\n"
+ "Please select ranges with equal size!");
+ i = 12; bRet = false;
+ }
+ success = true;
+ }
+ }
+ else {
+ vrc.left = vrc.top = 0; vrc.right = vrc.bottom = 9;
+ }
+ if(!success) for(i = 0; i < 11; i++) if(dst[i]){
+ rlp_strcpy(dst[i], 100, mkRangeRef(vrc.top, vrc.left+i, vrc.bottom, vrc.left+i));
+ }
+ if(ra) {
+ for(i = 0; i < ranges; i++) if(ra[i]) free(ra[i]);
+ free(ra);
+ }
+ return bRet;
+}
+
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Select color out of predefined palette
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *NewColorTmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,-1,200,10,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,200,25,45,12\n"
+ "3,7,4,CHECKED | ISPARENT,GROUPBOX,1,200,55,45,40\n"
+ "4,5,,,LTEXT,0,210,60,45,9\n"
+ "5,6,,,LTEXT,0,210,70,45,9\n"
+ "6,,,,LTEXT,0,210,80,45,9\n"
+ "7,+,,,RTEXT,2,5,130,79,9\n"
+ ".,.,,,INCDECVAL1,3,85,130,33,10\n"
+ ".,.,,,LTEXT,-10,122,130,10,9\n"
+ ".,,11,CHECKED | ISPARENT,GROUP,0,0,0,0,0";
+
+DWORD GetNewColor(DWORD oldColor)
+{
+ double transp = (double)iround((double)((oldColor>>24) & 0xff)/2.55);
+ double use_step = 10.0, use_minmax[] = {0.0, 100.0};
+ void *ptypes[] = {(void*)" RGB ", (void*)"transparency", (void*)&transp};
+ DlgInfo *ColDlg = CompileDialog(NewColorTmpl, ptypes);
+ DWORD currcol, newcol, palette[230];
+ int ilevels[] = {0x0, 0x40, 0x80, 0xc0, 0xe0, 0xff};
+ int i, j, ir, ig, ib, col, row, res;
+ DlgRoot *Dlg;
+ void *hDlg;
+
+ if(!(ColDlg = (DlgInfo *)realloc(ColDlg, 240 * sizeof(DlgInfo))))return oldColor;
+ for(ir=row=col=0, i=10, j=0; 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 = COLBUTT; ColDlg[i].first = 0;
+ palette[j] = currcol = (ilevels[ib]<<16)|(ilevels[ig]<<8)|(ilevels[ir]);
+ ColDlg[i].flags = TOUCHEXIT | ISRADIO;
+ if(currcol == (oldColor & 0x00ffffff)) ColDlg[i].flags |= CHECKED;
+ ColDlg[i].ptype = (void *)&palette[j];
+ 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++, j++;
+ }
+ j=j;
+ ColDlg[i-1].next = 0;
+ ColDlg[i-1].flags |= LASTOBJ;
+ newcol = currcol = oldColor;
+ Dlg = new DlgRoot(ColDlg, 0L);
+ Dlg->ItemCmd(8, CMD_STEP, (void*)&use_step);
+ Dlg->ItemCmd(8, CMD_MINMAX, (void*)&use_minmax);
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, 10, "R: 0x%02x", currcol & 0xff); Dlg->SetText(4, TmpTxt);
+ sprintf_s(TmpTxt, 10, "G: 0x%02x", (currcol>>8) & 0xff); Dlg->SetText(5, TmpTxt);
+ sprintf_s(TmpTxt, 10, "B: 0x%02x", (currcol>>16) & 0xff); Dlg->SetText(6, TmpTxt);
+#else
+ 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);
+#endif
+ hDlg = CreateDlgWnd("Select color", 50, 50, 510, 330, Dlg, 0x4L);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 0: //close window
+ case 2: //cancel
+ currcol = oldColor;
+ break;
+ case 1: //ok
+ currcol = newcol;
+ Dlg->GetValue(8, &transp);
+ currcol &= 0x00ffffff;
+ currcol |= ((((int)(transp*2.55))<<24)&0xff000000);
+ break;
+ default:
+ if(res > 9 && res < 227) {
+ currcol = newcol;
+ if(Dlg->GetColor(res, &newcol) && currcol != newcol) {
+ res = -1;
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, 10, "R: 0x%02x", newcol & 0xff); Dlg->SetText(4, TmpTxt);
+ sprintf_s(TmpTxt, 10, "G: 0x%02x", (newcol>>8) & 0xff); Dlg->SetText(5, TmpTxt);
+ sprintf_s(TmpTxt, 10, "B: 0x%02x", (newcol>>16) & 0xff); Dlg->SetText(6, TmpTxt);
+#else
+ 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);
+#endif
+ }
+ }
+ break;
+ }
+ }while (res < 0);
+ CloseDlgWnd(hDlg); delete Dlg;
+ free(ColDlg); return currcol;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Configure 3D shading
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *ConfShade_DlgTmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,-1,95,10,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,95,25,45,12\n"
+ "3,4,100,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
+ "4,5,,ODEXIT,COLBUTT,1,60,10,15,10\n"
+ "5,6,,ODEXIT,COLBUTT,2,60,37,15,10\n"
+ "6,7,,ODEXIT,COLBUTT,1,60,49,15,10\n"
+ "7,8,,,RTEXT,3,25,37,30,9\n"
+ "8,9,,,RTEXT,4,25,49,30,9\n"
+ "9,,,,SHADE3D,5,95,50,22,20\n"
+ "100,101,,TOUCHEXIT,RADIO1,6,10,10,50,9\n"
+ "101,,,TOUCHEXIT | LASTOBJ,RADIO1,7,10,25,60,9";
+
+void ConfShade(FillDEF *oldfill)
+{
+ FillDEF newFill;
+ void *dyndata[] = {(void*)&oldfill->color, (void*)&oldfill->color2, (void*)"HI-color:",
+ (void*)"LO-color:", (void*)&newFill, (void*)"fixed color:", (void*)"use light sorce:"};
+ DlgInfo *ShadeDlg = CompileDialog(ConfShade_DlgTmpl, dyndata);
+ 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, 0L))) 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, 0x4L);
+ bRedraw = true;
+ o = Dlg->GetOutputClass(); o->LightSource(32.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; free(ShadeDlg);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Select fill pattern
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *FillDlgBase_Tmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,-1,170,10,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,170,25,45,12\n"
+ "3,100,500,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
+ "100,+,,TOUCHEXIT,FILLBUTTON,1,170,75,45,45\n"
+ ".,.,,,RTEXT,2,78,95,40,8\n"
+ ".,.,,TOUCHEXIT,INCDECVAL1,3, 119, 95, 32, 10\n"
+ ".,.,,,LTEXT,-3,152,95,15,8\n"
+ ".,.,,,RTEXT,4,5,95,30,8\n"
+ ".,.,,ODEXIT,COLBUTT,8,36,95,25,10\n"
+ ".,.,,,RTEXT,5,78,110,40,8\n"
+ ".,.,,TOUCHEXIT,INCDECVAL1,6, 119, 110, 32, 10\n"
+ ".,.,,,LTEXT,-10,152,110,8,8\n"
+ ".,.,,,RTEXT,7,5,110,30,8\n"
+ ".,,,ODEXIT,COLBUTT,9,36,110,25,10";
+
+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, FILL_HASH,
+ FILL_WATER};
+ double fscale;
+ void *dyndata[] = {(void *)&PrevFill, (void*)"line width", (void*)&PrevLine.width, (void*)"line color",
+ (void*)"pattern size", (void*)&fscale, (void*)"BG color", (void*)&PrevLine.color, (void*) &PrevFill.color};
+ DlgInfo *FillDlg;
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, j, res;
+ anyOutput *o;
+ bool bRedraw, bContinue = false;
+ double tmp, use_minmax[] = {10.0, 800.0};
+
+ 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;
+ if(!(FillDlg = CompileDialog(FillDlgBase_Tmpl, dyndata))) return;
+ if(!(FillDlg = (DlgInfo*)realloc(FillDlg, (NUM_FILLS + 15)*sizeof(DlgInfo)))) return;
+ 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;
+ Dlg = new DlgRoot(FillDlg, 0L);
+ Dlg->ItemCmd(107, CMD_MINMAX, (void*)use_minmax);
+ 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);
+ hDlg = CreateDlgWnd("Fill patterns", 50, 50, 450, 290, Dlg, 0x4L);
+ bRedraw = true;
+ o = Dlg->GetOutputClass();
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ if (res >= 0) switch (res) {
+ case 0: // focus lost
+ if(bContinue) res = -1;
+ break;
+ case -1:
+ bContinue = false;
+ break;
+ default: // test for pattern
+ i = Dlg->FindIndex(res);
+ if(FillDlg[i].type == FILLRADIO) {
+ bRedraw = bContinue = true;
+ i = *((int*)FillDlg[i].ptype);
+ if(i != PrevFill.type){ // process double click on pattern
+ PrevFill.type = i; res = -1;
+ defs.Idle(CMD_UPDATE);
+ }
+ 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
+ bContinue = true;
+ res = -1; // ...these buttons do not exit dialog
+ case 1: // but do 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
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char* LayerDlg_Tmpl =
+ "1,3,0,DEFAULT,PUSHBUTTON,-1,165,10,45,12\n"
+ "3,20,100,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "20,550,,,CHECKPIN,0,10,0,12,8\n"
+ "100,101,,TOUCHEXIT,TREEVIEW,1,10,15,100,70\n"
+ "101,102,,,EDTEXT,2, 120, 25, 90, 10\n"
+ "102,200,150,ISPARENT | CHECKED | HIDDEN,GROUP,0L,0,0,0,0\n"
+ "150,151,,TOUCHEXIT,RADIO1,3,120,35,40,9\n"
+ "151,,,TOUCHEXIT,RADIO1,4,160,35,40,9\n"
+ "200,500,,,LTEXT,5,10,5,110,9\n"
+ "500,501,600,ISPARENT | CHECKED | HIDDEN,GROUP,0,0,0,0,0\n"
+ "501,,,HIDDEN | TOUCHEXIT,TRASH,0,125,72,15,15\n"
+ "550,,,HIDDEN | TOUCHEXIT,CONFIG,0,140,72,15,15\n"
+ "600,601,,TOUCHEXIT, ODBUTTON,6,125,50,15,15\n"
+ "601,602,,TOUCHEXIT, ODBUTTON,6,145,50,15,15\n"
+ "602,603,,TOUCHEXIT, ODBUTTON,6,165,50,15,15\n"
+ "603,,,LASTOBJ | TOUCHEXIT, ODBUTTON,6,185,50,15,15";
+
+bool ShowLayers(GraphObj *root)
+{
+ char curr_name[50];
+ void *dyndata[] = {(void*)root, (void*)curr_name, (void*)"hidden", (void*)"visible",
+ (void*)"Layers:", (void*)OD_DrawOrder};
+ DlgInfo *LayerDlg;
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, cl;
+ bool bContinue = false;
+ ObjTree *ot = 0L;
+ GraphObj *cgo = 0L;
+
+ if(!root || !(LayerDlg = CompileDialog(LayerDlg_Tmpl, dyndata))) return false;
+ rlp_strcpy(curr_name, 50, "(root)");
+ if(!(Dlg = new DlgRoot(LayerDlg, 0L)))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, 0x4L);
+ 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 || cgo->parent->Id == GO_PLOT3D ||
+ cgo->parent->Id == GO_FUNC3D) {
+ 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
+ || cgo->Id == GO_GRID3D){
+ 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; free(LayerDlg);
+ 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, 112, 52},
+ {2, 3, 0, 0x0L, ICON, (void*)&icon, 10, 10, 20, 20},
+ {3, 4, 0, 0x0L, LTEXT, (void*)"RLPlot", 40, 15, 50, 20},
+ {4, 5, 0, 0x0L, LTEXT, (void*)SZ_VERSION, 13, 30, 35, 9},
+ {5, 0, 0, LASTOBJ, LTEXT, (void*)"... is loading", 50, 30, 50, 9}};
+ DlgRoot *Dlg;
+ void *hDlg;
+ bool init = true;
+ int res, cnt = 5;
+
+ if(!show) return;
+ if(!(Dlg = new DlgRoot(BannerDlg, 0L)))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, 220, 100, Dlg, 0xbL);
+ ShowDlgWnd(hDlg);
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch (res) {
+ case 0: //loose focus: get it again
+ ShowDlgWnd(hDlg);
+ cnt = 5; res = -1;
+ break;
+ case -2: //Timer event
+ if(init) {
+ init = false;
+ FindBrowser(); SpreadMain(true);
+ ShowDlgWnd(hDlg); cnt = 4;
+ }
+ 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-2007 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-2007 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, 0L))) {
+ 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, 0x4L);
+#else
+ hDlg = CreateDlgWnd("About RLPlot", 50, 50, 240, 310, Dlg, 0x4L);
+#endif // _WINDOWS
+ do{
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ if(res == 11) Qt_Box();
+ }while(res <0);
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// change spreadsheet settings
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char * SSDlg_Tmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,-1,129,10,40,12\n"
+ "2,3,,,PUSHBUTTON,-2,129,25,40,12\n"
+ "3,,5,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
+ "5,6,100,ISPARENT | CHECKED,SHEET,1,5,10,115,85\n"
+ "6,,200,ISPARENT,SHEET,2,5,10,115,85\n"
+ "100,+,,,LTEXT,3,15,25,60,8\n"
+ ".,.,,,EDTEXT,-16,50,37,40,10\n"
+ ".,.,,,LTEXT,4,15,52,60,8\n"
+ ".,,,,EDTEXT,-17,50,64,40,10\n"
+ "200,+,,,RTEXT,5,10,29,45,8\n"
+ ".,.,,,EDVAL1,6,57,29,25,10\n"
+ ".,.,,,LTEXT,7,84,29,20,8\n"
+ ".,.,,,RTEXT,8,10,41,45,8\n"
+ ".,.,,,EDVAL1,9,57,41,25,10\n"
+ ".,.,,,LTEXT,7,84,41,20,8\n"
+ ".,.,,,RTEXT,10,10,53,45,8\n"
+ ".,.,,,EDVAL1,11,57,53,25,10\n"
+ ".,.,,,LTEXT,-3,84,53,20,8\n"
+ ".,.,,,RTEXT,12,10,65,45,8\n"
+ ".,.,,,INCDECVAL1,13,57,65,33,10\n"
+ ".,.,,,LTEXT,-10,92,65,20,8\n"
+ ".,.,,,RTEXT,14,10,77,45,8\n"
+ ".,.,,,EDVAL1,15,57,77,25,10\n"
+ ".,,,LASTOBJ,LTEXT,16,84,77,20,8";
+
+bool
+DoSpShSize(DataObj *dt, GraphObj *parent)
+{
+ TabSHEET tab1 = {0, 50, 10, "Dimensions"};
+ TabSHEET tab2 = {50, 115, 10, "Width and Height"};
+ double fw, cw, ch, th, mh;
+ void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)"number of columns:", (void*)"number of rows:",
+ (void*)"row buttons", (void*)&fw, (void*)"[digits]", (void*)"column width", (void*)&cw,
+ (void*)"row height", (void*)&ch, (void*)"text size", (void*)&th, (void*)"menu height",
+ (void*)&mh, (void*)"pix"};
+ DlgInfo *SSDlg;
+ DlgRoot *Dlg;
+ void *hDlg;
+ int w1, w2, h1, h2, res, celldim[3], ith;
+ bool bRet = false;
+ double fw1, cw1, ch1, th1, mh1;
+
+ if(!dt || !dt->GetSize(&w1, &h1) || !parent) return false;
+ if(!(SSDlg = CompileDialog(SSDlg_Tmpl, dyndata))) return false;
+ dt->Command(CMD_GET_CELLDIMS, &celldim, 0L);
+ fw1 = fw = NiceValue(((double)celldim[0])/((double)(celldim[2]-2)/2.0));
+ cw1 = cw = NiceValue(((double)celldim[1])/((double)(celldim[2]-2)/2.0));
+ mh1 = mh = (double)(defs.iMenuHeight);
+ 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; th = th1 = defs.ss_txt*100.0;
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt+100, 40, "%d", w1); sprintf_s(TmpTxt+200, 40, "%d", h1);
+#else
+ sprintf(TmpTxt+100, "%d", w1); sprintf(TmpTxt+200, "%d", h1);
+#endif
+ Dlg = new DlgRoot(SSDlg, dt);
+ hDlg = CreateDlgWnd("Change spread sheet settings", 50, 50, 354, 220, Dlg, 0x4L);
+ 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, TmpTxt+100, 40) && Dlg->GetText(103, TmpTxt+200, 40)) {
+ w2 = atol(TmpTxt+100); h2 = atol(TmpTxt+200);
+ w2 = w2 > 0 ? w2: w1; h2 = h2 > 0 ? h2: h1;
+ }
+ else res = -1;
+ break;
+ }
+ }while(res <0);
+ if(res == 1){
+ if(Dlg->GetValue(207, &ch) && Dlg->GetValue(210, &th) && ch > 0.001) {
+ Undo.ValFloat(parent, &defs.ss_txt, 0L);
+ defs.ss_txt = th = th >= 10.0 && th <= 100 ? th/100.0 : 1.0;
+ switch(defs.cUnits) {
+ case 1:
+ celldim[2] = iround(ch/0.0259183673)+2; ith = iround(th * ch/0.0259183673);
+ break;
+ case 2:
+ celldim[2] = iround(ch*98.0)+2; ith = iround(th * ch*98.0);
+ break;
+ default:
+ celldim[2] = iround(ch/0.259183673)+2; ith = iround(th * ch/0.259183673);
+ break;
+ }
+ bRet = dt->Command(CMD_TEXTSIZE, (void*)(& ith), 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;
+ Dlg->GetValue(213, &mh);
+ if(mh != mh1 && mh >= 0.0 && mh < 100) {
+ defs.iMenuHeight = (int)mh;
+ parent->Command(CMD_MENUHEIGHT, 0L, 0L);
+ }
+ }
+ CloseDlgWnd(hDlg); delete Dlg; free(SSDlg);
+ return bRet;
+}
+
+
+bool FillSsRange(DataObj *d, char **range, GraphObj *msg_go)
+{
+ TabSHEET tab1 = {0, 37, 10, "fill range "};
+ char *ra = range ? *range:0L;
+ double startval = 1.0, stepval = 1.0;
+ static char *formula = (char*)malloc(500 * sizeof(char));
+ if(formula && CurrText && CurrText->isFormula()) {
+ if(CurrText->GetText(TmpTxt,TMP_TXT_SIZE, false)) rlp_strcpy(formula, 500, TmpTxt);
+ }
+ if(formula) rlp_strcpy(formula, 500, "=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, RANGEINPUT, (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, CHECKED, 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;
+ RECT rc_dest;
+ anyOutput *cdisp = Undo.cdisp;
+
+ if(!d || !range) return false;
+ if(!(Dlg = new DlgRoot(RangeDlg, d))) 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, 0x4L);
+ 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, TMP_TXT_SIZE)) {
+ InfoBox("Range not specified\nor not valid.");
+ bContinue = true; res = -1;
+ }
+ else ra = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+ rc_dest.left = rc_dest.right = rc_dest.top = rc_dest.bottom = 0;
+ 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);
+ Undo.SetDisp(cdisp);
+ 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)) {
+ rF->BoundRec(&rc_dest);
+ Undo.DataObject(msg_go, Undo.cdisp, d, &rc_dest, 0L);
+ for( ; rF->GetNext(&col, &row); startval += stepval) {
+ d->SetValue(row, col, startval);
+ }
+ delete rF; bRet = true;
+ }
+ }
+ else if(Dlg->GetCheck(8)) {
+ if((rF = new AccRange(ra)) && rF->GetFirst(&col, &row) &&
+ Dlg->GetText(22, TmpTxt, TMP_TXT_SIZE) && formula){
+ rlp_strcpy(formula, 500, TmpTxt);
+ r1 = row; c1 = col;
+ for( ; rF->GetNext(&col, &row); startval += stepval) {
+ if(formula[0] == '=') {
+ MoveFormula(d, formula, TmpTxt, TMP_TXT_SIZE, col-c1, row-r1, -1, -1);
+ d->SetText(row, col, TmpTxt);
+ }
+ else d->SetText(row, col, formula);
+ }
+ delete rF; bRet = true;
+ }
+ }
+ free(ra);
+ }
+ CloseDlgWnd(hDlg); delete Dlg;
+ return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Get resolution and size for exported bitmap
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char * ResDlg_Tmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,-1,125,10,35,12\n"
+ "2,100,,,PUSHBUTTON,-2,125,25,35,12\n"
+ "100,+,,,LTEXT,1,20,10,50,9\n"
+ ".,.,,,RTEXT,2,20,22,35,9\n"
+ ".,.,,,EDVAL1,3,57,22,30,10\n"
+ ".,.,,,LTEXT,-3,89,22,20,8\n"
+ ".,.,,,RTEXT,4,20,34,35,9\n"
+ ".,.,,,EDVAL1,5,57,34,30,10\n"
+ ".,.,,,LTEXT,-3,89,34,20,8\n"
+ ".,.,,,RTEXT,6,20,46,35,9\n"
+ ".,.,,,EDVAL1,7,57,46,30,10\n"
+ ".,,,LASTOBJ,LTEXT,8,89,46,20,8";
+
+bool GetBitmapRes(double *dpi, double *width, double *height, char *header)
+{
+ void *dyndata[] = {(void*)"Image properties:", (void*)"width", (void*)width,
+ (void*)"height", (void*)height, (void*)"resolution", (void*)dpi, (void *) "dpi"};
+ DlgInfo *ResDlg;
+ DlgRoot *Dlg;
+ void *hDlg;
+ bool bRet = false;
+ int res;
+
+ if(!(ResDlg = CompileDialog(ResDlg_Tmpl, dyndata))) return false;
+ if(!(Dlg = new DlgRoot(ResDlg, 0L))) return false;
+ if(!(hDlg = CreateDlgWnd(header, 50, 50, 340, 160, Dlg, 0x4L)))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);
+ bRet = (res == 1);
+ CloseDlgWnd(hDlg); delete Dlg; free(ResDlg);
+ 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 ? COLBUTT : 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, 0L);
+ }
+ 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, COLBUTT, (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, 0L);
+ }
+ 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, INCDECVAL1, &ODLine.width, 42, 0, 32, 10},
+ {102, 103, 0, 0x0L, LTEXT, 0L, 76, 0, 20, 8},
+ {103, 104, 0, 0x0L, RTEXT, (void*)"outline color", 0, 12, 40, 8},
+ {104, 105, 0, OWNDIALOG, COLBUTT, (void *)&ODLine.color, 42, 12, 25, 10},
+ {105, 106, 0, 0x0L, RTEXT,(void*)"fill color" , 0, 24, 40, 8},
+ {106, 107, 0, TOUCHEXIT | OWNDIALOG, COLBUTT, (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, 0L);
+ }
+ 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:
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, " %s (%.1lf x %.1lf cm)", p_formats[i].name,
+ p_formats[i].mwidth/10.0, p_formats[i].mheight/10.0);
+#else
+ sprintf(TmpTxt, " %s (%.1lf x %.1lf cm)", p_formats[i].name,
+ p_formats[i].mwidth/10.0, p_formats[i].mheight/10.0);
+#endif
+ break;
+ case 2:
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, " %s (%.2lf x %.2lf inch)", p_formats[i].name,
+ p_formats[i].iwidth, p_formats[i].iheight);
+#else
+ sprintf(TmpTxt, " %s (%.2lf x %.2lf inch)", p_formats[i].name,
+ p_formats[i].iwidth, p_formats[i].iheight);
+#endif
+ break;
+ default:
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, " %s (%.0lf x %.0lf mm)", p_formats[i].name,
+ p_formats[i].mwidth, p_formats[i].mheight);
+#else
+ sprintf(TmpTxt, " %s (%.0lf x %.0lf mm)", p_formats[i].name,
+ p_formats[i].mwidth, p_formats[i].mheight);
+#endif
+ break;
+ }
+ dispsize[i] = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+ }
+ else if(dispsize[i] = (char*)malloc(15*sizeof(char)))
+ rlp_strcpy(dispsize[i], 15, " 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, 0L)){
+ 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, TMP_TXT_SIZE)){
+ 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, 0L);
+ }
+ 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, TMP_TXT_SIZE)){
+ 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 if(Dlg) Dlg->GetInt(110, &axisplot_sel);
+ if(o) *((int*)o) = axisplot_sel;
+ }
+}
diff --git a/TheDialog.h b/TheDialog.h
index 7c88fb8..3c6f0dc 100755
--- a/TheDialog.h
+++ b/TheDialog.h
@@ -1,557 +1,563 @@
-//TheDialog.h, Copyright (c) 2001-2007 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, COLBUTT, FILLBUTTON, SHADE3D, LINEBUTT, SYMBUTT,
- FILLRADIO, SYMRADIO, CHECKBOX, RADIO0, RADIO1, RADIO2, LTEXT, RTEXT, CTEXT, EDTEXT,
- RANGEINPUT, 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
-
-#define EXRADIO TOUCHEXIT|ISRADIO
-#define ODEXIT OWNDIALOG|TOUCHEXIT
-
-//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, int size) {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; //the dialog's output class
- void *hDialog; //handle to the dialog window/widget
-
- DlgRoot(DlgInfo *tmpl, DataObj *d);
- ~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, int size);
- bool SetText(int id, char *txt);
- bool SetValue(int id, double val);
- 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 res_q[256], res_put, res_get, cDlgs, cContinue;
- anyOutput *ParentOut;
- DataObj *data;
- Dialog *oldFocus, *oldDefault, *oldTabStop;
- bool bActive, bRedraw;
- GraphObj *c_go;
- Dialog **tabstops, *mrk_item;
- 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);
- void MBtrack(MouseEvent *mev, anyOutput *o);
- bool GetText(int id, char *txt, int size);
-
-private:
- TextFrame *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, DWORD *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);
- void MBtrack(MouseEvent *mev, anyOutput *o);
-
-private:
- char *txt;
-};
-
-class InputText:public Dialog {
-public:
- EditText *Text;
-
- InputText(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text);
- ~InputText();
- virtual 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, int size);
- virtual void MBtrack(MouseEvent *mev, anyOutput *o);
- virtual void Activate(int id, bool active);
-
-private:
- anyOutput *Disp;
-};
-
-class RangeInput:public InputText {
-public:
- RangeInput(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text, DataObj *d);
- ~RangeInput();
- bool Command(int cmd, void *tmpl, anyOutput *o);
- bool Select(int x, int y, anyOutput *o);
- void Activate(int id, bool active);
-
-private:
- DataObj *data;
-};
-
-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, DataObj *d);
- ~TabSheet();
- void DoPlot(anyOutput *o);
- bool Select(int x, int y, anyOutput *o);
-
-private:
- DataObj *data;
- 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, int size);
- 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 TheDialog.cpp
-bool UseRangeMark(DataObj *d, int type, char* =0L, char* =0L, char* =0L, char* =0L,
- char* =0L, char* =0L, char* =0L, char* =0L, char* =0L, char* =0L, char* =0L);
-int com_StackDlg(int,DlgRoot*,AccRange**,int*,char***,int*,AccRange**,bool*,int*,int*,bool*);
-DlgInfo *CompileDialog(char* tmpl, void **ptypes);
-
-//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);
-void OD_NewAxisTempl3D(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id);
+//TheDialog.h, Copyright (c) 2001-2008 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
+ int x, y, w, h; //start coordinates, width, height
+} 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, COLBUTT, FILLBUTTON, SHADE3D, LINEBUTT, SYMBUTT,
+ FILLRADIO, SYMRADIO, CHECKBOX, RADIO0, RADIO1, RADIO2, LTEXT, RTEXT, CTEXT, EDTEXT,
+ RANGEINPUT, 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
+
+#define EXRADIO TOUCHEXIT|ISRADIO
+#define ODEXIT OWNDIALOG|TOUCHEXIT
+
+//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, bModal;
+
+ 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, int size) {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; //the dialog's output class
+ void *hDialog; //handle to the dialog window/widget
+
+ DlgRoot(DlgInfo *tmpl, DataObj *d);
+ ~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, int size);
+ bool SetText(int id, char *txt);
+ bool SetValue(int id, double val);
+ 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 res_q[256], res_put, res_get, cDlgs, cContinue;
+ anyOutput *ParentOut;
+ DataObj *data;
+ Dialog *oldFocus, *oldDefault, *oldTabStop;
+ bool bActive, bRedraw;
+ GraphObj *c_go;
+ Dialog **tabstops, *mrk_item;
+ 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);
+ void MBtrack(MouseEvent *mev, anyOutput *o);
+ bool GetText(int id, char *txt, int size);
+
+private:
+ TextFrame *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, DWORD *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:
+ DWORD 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);
+ void MBtrack(MouseEvent *mev, anyOutput *o);
+
+private:
+ char *txt;
+};
+
+class InputText:public Dialog {
+public:
+ EditText *Text;
+
+ InputText(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text);
+ ~InputText();
+ virtual bool Command(int cmd, void *tmpl, anyOutput *o);
+ virtual void DoPlot(anyOutput *o);
+ virtual bool Select(int x, int y, anyOutput *o);
+ virtual bool GetValue(int id, double *val);
+ bool GetInt(int id, int *val);
+ bool GetText(int id, char *txt, int size);
+ virtual void MBtrack(MouseEvent *mev, anyOutput *o);
+ virtual void Activate(int id, bool active);
+
+private:
+ anyOutput *Disp;
+};
+
+class RangeInput:public InputText {
+public:
+ RangeInput(tag_DlgObj *par, DlgInfo * desc, RECT rec, char *text, DataObj *d);
+ ~RangeInput();
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+ void Activate(int id, bool active);
+
+private:
+ DataObj *data;
+};
+
+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();
+ 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[2];
+ bool hasMinMax, hasStep;
+ double theMin, theMax, theStep;
+};
+
+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, DataObj *d);
+ ~TabSheet();
+ void DoPlot(anyOutput *o);
+ bool Select(int x, int y, anyOutput *o);
+
+private:
+ DataObj *data;
+ 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, int size);
+ 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 TheDialog.cpp
+bool UseRangeMark(DataObj *d, int type, char* =0L, char* =0L, char* =0L, char* =0L,
+ char* =0L, char* =0L, char* =0L, char* =0L, char* =0L, char* =0L, char* =0L);
+int com_StackDlg(int,DlgRoot*,AccRange**,int*,char***,int*,AccRange**,bool*,int*,int*,bool*);
+DlgInfo *CompileDialog(char* tmpl, void **ptypes);
+
+//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_PolygonStyleTempl(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id);
+void OD_LineStyleTempl(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id);
+void OD_BubbleTempl(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);
+void OD_NewAxisTempl3D(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id);
diff --git a/UtilObj.cpp b/UtilObj.cpp
index db976da..ac9c3ab 100755
--- a/UtilObj.cpp
+++ b/UtilObj.cpp
@@ -1,3997 +1,4118 @@
-//UtilObj.cpp, (c) 2000-2007 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 <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
-
-Default defs;
-
-static LineDEF ETbgnn = {0.0, 1.0, 0x00e8e8e8L, 0L};
-static LineDEF ETbgna = {0.0, 1.0, 0x00ffffffL, 0L};
-static LineDEF ETbgmn = {0.0, 1.0, 0x00cbcbcbL, 0L};
-static LineDEF ETbgma = {0.0, 1.0, 0x00ffffc0L, 0L};
-static LineDEF yLine = {0.0, 1.0, 0x0000ffffL, 0L};
-extern const LineDEF BlackLine = {0.0, 1.0, 0x00000000L, 0L};
-extern const LineDEF GrayLine = {0.0, 1.0, 0x00c0c0c0L, 0L};
-
-static FillDEF ETfbnn = {FILL_NONE, 0x00e8e8e8L, 1.0, NULL, 0x00ffffffL};
-static FillDEF ETfbna = {FILL_NONE, 0x00ffffffL, 1.0, NULL, 0x00ffffffL};
-static FillDEF ETfbmn = {FILL_NONE, 0x00e8cbcbL, 1.0, NULL, 0x00ffffffL};
-static FillDEF ETfbma = {FILL_NONE, 0x00ffffc0L, 1.0, NULL, 0x00ffffffL};
-static FillDEF yFill = {FILL_NONE, 0x0000ffffL, 1.0, NULL, 0x0000ffffL};
-
-extern char TmpTxt[500];
-extern unsigned long cObsW; //count objects written
-extern GraphObj *CurrGO, *TrackGO; //Selected Graphic Objects
-extern dragHandle *CurrHandle;
-extern UndoObj Undo;
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Process fields with user input text
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-EditText *CurrText = 0L, *scroll_et = 0;
-int scroll_dist = 0;
-
-EditText::EditText(void *par, char *msg, int r, int c)
-{
- loc.x = loc.y = crb.x = rb.x = crb.y = rb.y = 0; Value = 0.0;
- row = r; col = c; disp = 0L; text = 0L;
- CursorPos = length = Align = 0; type = ET_UNKNOWN; TextCol=0x00000000L;
- bgLine = &ETbgnn; bgFill = &ETfbnn; parent = par;
- if(msg && msg[0]) {
- SetText(msg); FindType();
- }
- else {
- Align = TXA_VCENTER | TXA_HRIGHT;
- type = ET_UNKNOWN;
- }
- m1 = m2 = -1; //cursor positions track marks
- ftext = 0L; //store formula text result here
-}
-
-EditText::~EditText()
-{
- HideCopyMark();
- if(CurrText == this) CurrText = 0L;
- if(text) free(text); text = 0L;
-// if(ftext) free(ftext); ftext = 0L;
-}
-
-bool
-EditText::AddChar(int ci, anyOutput *Out, void *data_obj)
-{
- unsigned char byte1, byte2, c, *tmp;
- POINT MyPos;
- int i;
-
- if(ci < 254 && ci > 31) c = (char)ci;
- else if(ci == 27) { //Esc
- m1 = m2 = -1; Redraw(Out, true); return true;
- }
- else return false;
- if(parent) {
- ((DataObj*)parent)->Command(CMD_MRK_DIRTY, 0L, 0L);
- ((DataObj*)parent)->Command(CMD_SAVEPOS, 0L, 0L);
- }
- Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
- bgLine = &ETbgna; bgFill = &ETfbna; TextCol = 0x00000000L;
- if(text)length = (int)strlen(text);
- else length = 0;
- if(text) tmp = (unsigned char *)realloc(text, length+2);
- else tmp = (unsigned char *)calloc(2, sizeof(unsigned char));
- if(!tmp) return false;
- text = (char*)tmp;
- byte1 = byte2 = 0;
- //replace mark by character if mark exists
- if(hasMark()) { //delete marked part of text
- if(m1 > m2) Swap(m1, m2);
- if(m2 >= (short int)strlen(text)) text[m1] = 0;
- else rlp_strcpy(text+m1, TMP_TXT_SIZE, text+m2);
- CursorPos = m1;
- m1 = m2 = -1;
- }
- byte1 = text[CursorPos];
- i = CursorPos;
- text[i++] = c;
- while(byte1) {
- byte2 = byte1; byte1 = text[i]; text[i++] = byte2;
- }
- text[i] = byte1; CursorPos++; type = ET_UNKNOWN;
- Redraw(Out, true);
- MyPos.y = ((loc.y +crb.y)>>1);
- 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);
- set_etracc();
- return true;
-}
-
-void
-EditText::Update(int select, anyOutput *Out, POINT *MousePos)
-{
- POINT MyPos;
-
- if(!parent && !disp) disp = Out;
- if(select != 1 && select != 5) m1 = m2 = -1; //no mark;
- switch(select) {
- case 0: //just redraw with current settings
- Redraw(Out, true);
- break;
- case 5: //dialog control
- if(!text)Align = TXA_VCENTER | TXA_HLEFT;
- case 1: //active spread sheet cell with cursor
- if((type & 0xff) == ET_FORMULA) Align = TXA_VCENTER | TXA_HLEFT;
- if(!text && !(text = (char *) calloc(10, sizeof(char))))return;
- if(CursorPos > (int)strlen(text)) CursorPos = (int)strlen(text);
- if(MousePos && (type & 0xff) == ET_TEXT && (text && text[0] == '\'' && (bgLine == &ETbgnn || bgLine == &ETbgmn))) {
- MousePos->x += 4;
- }
- bgLine = &ETbgna; bgFill = &ETfbna; TextCol = 0x00000000L;
- if(Out) {
- Redraw(Out, true);
- MyPos.y = ((loc.y +crb.y)>>1);
- MyPos.x = Align & TXA_HRIGHT ? crb.x - 4 : loc.x + 4;
- if(MousePos && MousePos->x && MousePos->y) {
- Out->TextCursor(text, MyPos, MousePos,&CursorPos,
- scroll_et == this ? scroll_dist : scroll_dist=0);
- }
- else if(select ==1) Out->TextCursor(text, MyPos, NULL, &CursorPos,
- scroll_et == this ? scroll_dist : (scroll_dist=0)+2);
- set_etracc();
- }
- break;
- case 2: //inactive spreadsheet cell
- if(CurrText == this) {
- FindType();
- }
- if(crb.x > rb.x) {
- crb.x = rb.x; crb.y = rb.y;
- }
- bgLine = &ETbgnn; bgFill = &ETfbnn; TextCol = 0x00000000L;
- if(Out) Redraw(Out, true);
- break;
- case 10: //value filled in by external app.
- if(text && text[0]) {
- type = ET_VALUE;
- Align = TXA_VCENTER | TXA_HRIGHT;
-#ifdef USE_WIN_SECURE
- sscanf_s(text, "%lf", &Value);
-#else
- sscanf(text, "%lf", &Value);
-#endif
- }
- break;
- case 20: //update value only
- FindType();
- break;
- }
-}
-
-bool
-EditText::Redraw(anyOutput *Out, bool display)
-{
- RECT rc;
- POINT MyPos;
- char *txt, tmptxt[500];
- int i, w, h, o_crbx;
- bool b_clip = false;
- anyOutput *opc;
- anyResult cres;
- POINT grid[3];
-
- if(!parent && disp) Out = disp;
- if((type & ET_NODRAW_EMPTY) == ET_NODRAW_EMPTY && CurrText != this){
- type &= ~ET_NODRAW;
- return true;
- }
- if(loc.x <1 || rb.x < 1 || loc.y <1 || rb.y <1) return false;
- o_crbx = crb.x; crb.x = rb.x; crb.y = rb.y;
- if (Out) {
- if (m1 >m2) Swap(m1, m2);
- if(((type & 0xff) == ET_UNKNOWN) && text && text[0] && (bgLine == &ETbgnn || bgLine == &ETbgmn)) FindType();
- Out->TxtSet.Align = Align; Out->TxtSet.ColTxt = TextCol;
- Out->TxtSet.ColBg = bgLine->color;
- if(text && text[0]) {
- Out->oGetTextExtent(text, (int)strlen(text), &w, &h);
- if(CurrText == this && parent && col >= 0) {
- for(i = col+1; (crb.x - loc.x) < (w+(h>>1)); i++) {
- crb.x += ((DataObj*)parent)->ri->GetWidth(i);
- }
- if(o_crbx > loc.x && o_crbx > crb.x && o_crbx < 4000) crb.x = o_crbx;
- }
- else if((crb.x - loc.x) < (w+(h>>1))) b_clip = true;
- }
- Out->SetFill(bgFill); Out->SetLine(bgLine);
- rc.left = loc.x; rc.right = crb.x;
- rc.top = loc.y+1; rc.bottom = crb.y-2;
- Out->oRectangle(loc.x, loc.y, crb.x-1, crb.y-1);
- if(!text || !text[0]){
- if((type & 0xff) == ET_VALUE){
-#ifdef USE_WIN_SECURE
- sprintf_s(tmptxt, 500, "%g", Value);
-#else
- sprintf(tmptxt, "%g", Value);
-#endif
- }
- else if((type & 0xff) == ET_BOOL) {
-#ifdef USE_WIN_SECURE
- sprintf_s(tmptxt, 500, Value != 0.0 ? "true" : "false");
-#else
- sprintf(tmptxt, Value != 0.0 ? "true" : "false");
-#endif
- }
- else tmptxt[0] = 0;
- if(tmptxt[0] && (text = (char*)realloc(text, strlen(tmptxt)+2))) rlp_strcpy(text, 500, tmptxt);
- CursorPos = 0;
- }
- if(ftext) free(ftext); ftext = 0L;
- if(text && text[0]){
- if(bgLine == &ETbgnn || bgLine == &ETbgmn) {
- Out->TxtSet.Align = TXA_HLEFT | TXA_VCENTER;
- GetResult(&cres, false); TranslateResult(&cres);
- Value = cres.value;
- switch (cres.type) {
- case ET_VALUE:
- Out->TxtSet.Align = TXA_HRIGHT | TXA_VCENTER;
- b_clip = false; rlp_strcpy(tmptxt, 500, cres.text);
- fit_num_rect(Out, rb.x - loc.x, tmptxt);
- Int2Nat(tmptxt); break;
- case ET_BOOL: case ET_DATE: case ET_TIME: case ET_DATETIME:
- case ET_TEXT:
- Out->TxtSet.Align = cres.type == ET_TEXT ?
- TXA_HLEFT | TXA_VCENTER : TXA_HRIGHT | TXA_VCENTER;
- i = (int)strlen(cres.text)+2;
- if(ftext = (char*)realloc(ftext, i > 20 ? i : 20))rlp_strcpy(ftext, i, cres.text);
- if(cres.text && i < sizeof(tmptxt))
- rlp_strcpy(tmptxt, 500, cres.text[0] != '\'' ? cres.text : cres.text +1);
- else if(cres.text)rlp_strcpy(tmptxt, 500, "#SIZE");
- else tmptxt[0] = 0;
- Out->oGetTextExtent(tmptxt, (int)strlen(tmptxt), &w, &h);
- b_clip = (crb.x - loc.x) < (w+(h>>1)) ? true : false;
- break;
- case ET_ERROR:
- rlp_strcpy(tmptxt, 500, "#ERROR"); break;
- default:
- rlp_strcpy(tmptxt, 500, "#VALUE"); break;
- }
- txt = tmptxt;
- }
- else txt = text;
- if(b_clip && parent && col >= 0 && row >=0) {
- Out->oGetTextExtent(txt, (int)strlen(txt), &w, &h);
- for(i = col+1; (crb.x - loc.x) < (w+(h>>1)); i++) {
- if(((DataObj*)parent)->isEmpty(row, i)) {
- crb.x += ((DataObj*)parent)->ri->GetWidth(i);
- ((DataObj*)parent)->etRows[row][i]->type |= ET_NODRAW;
- }
- else break;
- }
- if((crb.x - loc.x) >= (w+(h>>1))) b_clip = false;
- else rc.right = crb.x;
- }
- MyPos.y = (loc.y+rb.y)>>1;
- if(Out->TxtSet.Align & TXA_HRIGHT) { //right justified text
- MyPos.x = crb.x-4;
- }
- else { //left justified text
- MyPos.x = loc.x+4;
- }
- if(b_clip && (opc = NewBitmapClass(w+22, rb.y-loc.y, Out->hres, Out->vres))){
- if(scroll_et != this || parent) {
- scroll_et = this; scroll_dist = 0;
- }
- opc->Erase(bgFill->color);
- opc->SetTextSpec(&Out->TxtSet); opc->TxtSet.Align = TXA_HLEFT | TXA_VCENTER;
- opc->oTextOut(4,(rb.y-loc.y)>>1, txt, (int)strlen(txt));
- if(!parent && CursorPos) {
- Out->oGetTextExtent(txt, CursorPos, &w, &h);
- while((scroll_dist + w)>(rc.right-rc.left-10)) scroll_dist -=10;
- while((scroll_dist + w)<12) scroll_dist +=10;
- if(scroll_dist >0) scroll_dist=0;
- }
- else scroll_dist=0;
- Out->CopyBitmap(rc.left+1, rc.top+1, opc, 1-scroll_dist, 1,
- rc.right-rc.left-4, rc.bottom-rc.top-2, false);
- DelBitmapClass(opc);
- }
- else {
- if(display && hasMark() && mx1 > loc.x && mx2 < crb.x) {
- Out->SetFill(&yFill); Out->SetLine(&yLine);
- Out->oRectangle(mx1, rc.top, mx2, rc.bottom);
- Out->SetFill(bgFill); Out->SetLine(bgLine);
- }
- scroll_dist = 0;
- Out->oTextOut(MyPos.x, MyPos.y, txt, 0);
- if(display && hasMark() && mx1 > loc.x && mx2 < crb.x) {
- rc.left = mx1; rc.right = mx2;
- Out->CopyBitmap(mx1, rc.top, Out, mx1, rc.top, mx2-mx1, rc.bottom-rc.top, true);
- Out->MrkMode = MRK_NONE;
- }
- }
- }
- Out->SetLine((LineDEF*)&GrayLine);
- grid[0].x = loc.x; grid[0].y = grid[1].y = crb.y-1;
- grid[1].x = grid[2].x = crb.x-1; grid[2].y = loc.y-1;
- Out->oPolyline(grid, 3, 0L);
- if(display) {
- if(!(Out->UpdateRect(&rc, false))) return false;
- }
- return true;
- }
- return false;
-}
-
-void
-EditText::Mark(anyOutput *Out, int mark)
-{
- LineDEF *ol = bgLine;
- FillDEF *of = bgFill;
- DWORD ocol = TextCol;
-
- m1 = m2 = -1;
- if(!parent) return;
- switch (mark){
- case 0: //normal not active
- bgLine = &ETbgnn; bgFill = &ETfbnn; TextCol = 0x00000000L;
- break;
- case 1: //normal active
- bgLine = &ETbgna; bgFill = &ETfbna; TextCol = 0x00000000L;
- break;
- case 2: //mark not active
- bgLine = &ETbgmn; bgFill = &ETfbmn; TextCol = 0x00c00000L;
- break;
- case 3: //mark active
- bgLine = &ETbgma; bgFill = &ETfbma; TextCol = 0x00ff0000L;
- break;
- }
- if(!mark || mark == 2) {
- loc.y--; rb.y++;
- }
- Redraw(Out, true);
- if(!mark || mark == 2) {
- loc.y++; rb.y--;
- }
- bgLine = ol; bgFill = of; TextCol = ocol;
-}
-
-bool
-EditText::Command(int cmd, anyOutput *Out, void *data_obj)
-{
- int i, j, k, w, h;
- POINT MyPos;
- MouseEvent *mev;
- static RECT rMark;
- bool bRet;
- char *tag1, *tag2;
- unsigned char *pt;
-
- MyPos.y = ((loc.y+crb.y)>>1);
- MyPos.x = Align & TXA_HRIGHT ? crb.x - 4 : loc.x + 4;
- if(!(text)) return false;
- if(!parent && disp) Out = disp; //Dialog !
- switch(cmd) {
- case CMD_MRK_DIRTY:
- type = ET_UNKNOWN;
- if(CurrText == this) {
- Command(CMD_REDRAW, Out, data_obj);
- if(parent)((DataObj*)parent)->Command(CMD_MRK_DIRTY, Out, 0L);
- }
- else if(parent) {
- ((DataObj*)parent)->Command(CMD_REDRAW, Out, 0L);
- ((DataObj*)parent)->Command(CMD_MRK_DIRTY, Out, 0L);
- }
- else return Command(CMD_REDRAW, Out, data_obj);
- return true;
- case CMD_SETFONT:
- if (!text || !text[0]) return false;
- if(Out) Undo.SetDisp(Out);
- type = ET_TEXT;
- if(hasMark()) {
- Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
- switch (*((int*)data_obj)) {
- case FONT_HELVETICA:
- tag1 = (char*)"<face=helvetica>"; tag2 = (char*)"</face>"; break;
- case FONT_TIMES:
- tag1 = (char*)"<face=times>"; tag2 = (char*)"</face>"; break;
- case FONT_COURIER:
- tag1 = (char*)"<face=courier>"; tag2 = (char*)"</face>"; break;
- case FONT_GREEK:
- tag1 = (char*)"<face=greek>"; tag2 = (char*)"</face>"; break;
- default:
- return false;
- }
- if(m1 < m2) {
- j = m1; k = m2;
- }
- else if(m1 > m2) {
- j = m2; k = m1;
- }
- else return false; //empty mark !
- for(i = 0; i < j; i++) TmpTxt[i] = text[i];
- for(j = 0, w = i; tag1[j]; j++) TmpTxt[i++] = tag1[j];
- for( ; w < k; w++) TmpTxt[i++] = text[w];
- for(j = 0; tag2[j]; j++) TmpTxt[i++] = tag2[j];
- for( ; TmpTxt[i++] = text[w]; w++);
- m1 += (w = (int)strlen(tag1)); m2 += w; CursorPos += w;
- CleanTags(TmpTxt, &m1, &m2, &CursorPos);
- if(text = (char*)realloc(text, strlen(TmpTxt)+2)) rlp_strcpy(text, TMP_TXT_SIZE, TmpTxt);
- Command(CMD_REDRAW, Out, 0L);
- return true;
- }
- return false;
- case CMD_SETSTYLE:
- if (!text || !text[0]) return false;
- if(Out) Undo.SetDisp(Out);
- type = ET_TEXT;
- if(hasMark()) {
- Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
- switch (*((int*)data_obj)) {
- case TXS_BOLD:
- tag1 = (char*)"<b>"; tag2 = (char*)"</b>"; break;
- case ~TXS_BOLD:
- tag1 = (char*)"</b>"; tag2 = (char*)"<b>"; break;
- case TXS_ITALIC:
- tag1 = (char*)"<i>"; tag2 = (char*)"</i>"; break;
- case ~TXS_ITALIC:
- tag1 = (char*)"</i>"; tag2 = (char*)"<i>"; break;
- case TXS_UNDERLINE:
- tag1 = (char*)"<u>"; tag2 = (char*)"</u>"; break;
- case ~TXS_UNDERLINE:
- tag1 = (char*)"</u>"; tag2 = (char*)"<u>"; break;
- case TXS_SUPER:
- tag1 = (char*)"<sup>"; tag2 = (char*)"</sup>"; break;
- case ~TXS_SUPER:
- tag1 = (char*)"</sup>"; tag2 = (char*)"<sup>"; break;
- case TXS_SUB:
- tag1 = (char*)"<sub>"; tag2 = (char*)"</sub>"; break;
- case ~TXS_SUB:
- tag1 = (char*)"</sub>"; tag2 = (char*)"<sub>"; break;
- default:
- return false;
- }
- if(m1 < m2) {
- j = m1; k = m2;
- }
- else if(m1 > m2) {
- j = m2; k = m1;
- }
- else return false; //empty mark !
- for(i = 0; i < j; i++) TmpTxt[i] = text[i];
- for(j = 0, w = i; tag1[j]; j++) TmpTxt[i++] = tag1[j];
- for( ; w < k; w++) TmpTxt[i++] = text[w];
- for(j = 0; tag2[j]; j++) TmpTxt[i++] = tag2[j];
- for( ; TmpTxt[i++] = text[w]; w++);
- m1 += (w = (int)strlen(tag1)); m2 += w; CursorPos += w;
- CleanTags(TmpTxt, &m1, &m2, &CursorPos);
- if(text = (char*)realloc(text, strlen(TmpTxt)+2)) rlp_strcpy(text, TMP_TXT_SIZE, TmpTxt);
- Command(CMD_REDRAW, Out, 0L);
- return true;
- }
- return false;
- case CMD_ADDTXT:
- if((tag1 = (char*)data_obj) && *tag1 && text &&
- (type == ET_TEXT || type == ET_UNKNOWN || type == ET_FORMULA)){
- if(hasMark()) Command(CMD_DELETE, 0L, 0L);
- else Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
- if(m1 > -1 && m2 > -1) Command(CMD_DELETE, 0L, 0L);
- for(k = 0; tag1[k] && tag1[k] == text[k]; k++);
- if(tag1[k]!=';') k = 0;
- for(i = 0; i < CursorPos && text[i]; i++) TmpTxt[i] = text[i];
- j = i + rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, tag1+k);
- if(text[i]) j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, text+i);
- if(text = (char*)realloc(text, j+2 )) rlp_strcpy(text, j+2, TmpTxt);
- CursorPos += (int)strlen(tag1+k);
- Out->Focus(); Update(1, Out, 0L);
- set_etracc();
- }
- return true;
- case CMD_BACKSP:
- if(!text) return false;
- 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(!text) return false;
- if(cmd == CMD_DELETE) Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
- if(parent) {
- ((DataObj*)parent)->Command(CMD_MRK_DIRTY, 0L, 0L);
- ((DataObj*)parent)->Command(CMD_SAVEPOS, 0L, 0L);
- }
- bRet = false;
- if(!text || !text[0]) {
- type = ET_UNKNOWN; CursorPos = 0;
- }
- if(hasMark()) { //delete marked part of text
- if (!text || !text[0]) return false;
- if(m1 > m2) Swap(m1, m2);
- if(m2 >= (short int)strlen(text)) text[m1] = 0;
- else rlp_strcpy(text+m1, (int)strlen(text)+m1, text+m2);
- CursorPos = m1; m1 = m2 = -1;
- if(!text[0]) {
- type = ET_UNKNOWN; CursorPos = 0;
- }
- if(Out) Redraw(Out, (bRet = true));
- }
- else if(text[CursorPos]) {
- rlp_strcpy(text + CursorPos, (int)strlen(text + CursorPos), text + CursorPos + 1);
- if(!text || !text[0]) {
- type = ET_UNKNOWN; CursorPos = 0;
- }
- if(Out)Redraw(Out, (bRet = true));
- }
- set_etracc();
- if(Out)Out->TextCursor(text, MyPos, (POINT *) NULL, &CursorPos,
- scroll_et == this ? scroll_dist : scroll_dist=0);
- return bRet;
- case CMD_COPY:
- if(text && text[0]) {
- rMark.left = loc.x+2; rMark.right = rb.x-2;
- rMark.top = loc.y+1; rMark.bottom = rb.y-2;
- if(m1 != m2 && m1 >=0 && m2 >=0) {
- if (m1 >m2) Swap(m1, m2);
- rMark.left = mx1; rMark.right = mx2;
- if(Out) Out->UpdateRect(&rMark, false);
- CopyText(text+m1, m2-m1);
- if(Out) {
- Out->MrkMode = MRK_NONE;
- ShowCopyMark(Out, &rMark, 1);
- Out->UpdateRect(&rMark, true);
- }
- return false;
- }
- CopyText(text, (int)strlen(text));
- if(Out)Out->UpdateRect(&rMark, true);
- return false;
- }
- return false;
- case CMD_PASTE:
- if(pt = PasteText()) {
- Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
- for(i = 0; pt[i] > 0x20 && i < 81; i++) this->AddChar(pt[i], 0L, 0L);
- if(Out) Redraw(Out, true); free(pt);
- set_etracc();
- if(i) return true;
- }
- return false;
- 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;
- }
- set_etracc();
- if(text[CursorPos]) CursorPos++;
- else return false;
- case CMD_SHIFTLEFT:
- set_etracc();
- 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-4 - w;
- }
- else { //left justified text
- mx1 = loc.x +4;
- }
- 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; set_etracc();
- 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-4; MyPos.y = (rb.y+loc.y)/2;
- if(((DataObj*)data_obj)->Select(&MyPos))return true;
- MyPos.x = loc.x+4;
- ((DataObj*)data_obj)->Select(&MyPos);
- }
- return false;
- case CMD_CURRIGHT:
- m1 = m2 = -1; set_etracc();
- 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+4; MyPos.y = (rb.y+loc.y)/2; crb.x = rb.x;
- if(((DataObj*)data_obj)->Select(&MyPos)) return true;
- MyPos.x = rb.x-4;
- ((DataObj*)data_obj)->Select(&MyPos);
- }
- return false;
- case CMD_UPDATE:
- m1 = m2 = -1;
- Redraw(Out, true);
- return true;
- case CMD_POS_FIRST: case CMD_POS_LAST:
- CursorPos = (cmd == CMD_POS_LAST && text && text[0]) ? (int)strlen(text) : 0;
- m1 = m2 = -1; Redraw(Out, true);
- Out->TextCursor(text, MyPos, (POINT *) NULL, &CursorPos,
- scroll_et == this ? scroll_dist : scroll_dist=0);
- set_etracc();
- 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-4-((rb.y-loc.y-4)*((long)strlen(text)-CursorPos))/2;
- else MyPos.x = loc.x+4+((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 +4;
- if(MyPos.x > rb.x) MyPos.x = rb.x -4;
- 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;// set_etracc();
- return true;
- }
- if(mev->Action == MOUSE_LBDOUBLECLICK) {
- rMark.top = loc.y+1; rMark.bottom = rb.y-2;
- if(!Out->oGetTextExtent(text, (int)strlen(text), &w, &h)) return false;
- m1 = 0; m2 = (int)strlen(text);
- if(Align & TXA_HRIGHT) { //right justfied text
- rMark.right = crb.x -4; rMark.left = crb.x - w - 4;
- }
- else { //left justified text
- rMark.left = loc.x +4; rMark.right = rMark.left +w;
- }
- mx1 = rMark.left; mx2 = rMark.right;
- Redraw(Out, true); set_etracc();
- return true;
- }
- MyPos.x = Align & TXA_HRIGHT ? mev->x + 4 : mev->x - 4;
- 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 = (int)strlen(text)-j)){
- if(!Out->oGetTextExtent(text+j, i, &w, &h)) return false;
- w = crb.x - w - 4;
- }
- 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+4);
- }
- 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+1; rMark.bottom = rb.y-2;
- if(rMark.right < crb.x && rMark.right > loc.x &&
- rMark.left > loc.x && rMark.left < crb.x)
- Redraw(Out, true);
- }
- if(hasMark() && 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 || (type & 0xff) == ET_BOOL || (type & 0xff) == ET_DATE
- || (type & 0xff) == ET_TIME || (type & 0xff) == ET_DATETIME){
- *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 || res->type == ET_DATE || res->type == ET_TIME
- || res->type == ET_DATETIME || res->type == ET_BOOL){
- *v = Value = res->value; type &= ~ET_BUSY; return true;
- }
- }
- *v = Value = 0.0; type &= ~ET_BUSY; return false;
- }
- else type |= ET_CIRCULAR;
- *v = Value;
- return true;
- }
- return false;
-}
-
-bool
-EditText::GetText(char *tx, int size, bool bTranslate)
-{
- char *t = 0L;
- static char tmp_txt[40];
- anyResult res;
-
- if((type & 0xff) == ET_TEXT && text && text[0]) {
- if(text[0] =='\'' && text[1]) t = text + 1;
- else t = text;
- }
- else if(bTranslate) {
- GetResult(&res, false); TranslateResult(&res);
- switch (res.type) {
- case ET_VALUE:
- rlp_strcpy(tmp_txt, 40, res.text); t = tmp_txt;
- Int2Nat(tmp_txt); break;
- case ET_BOOL: case ET_DATE: case ET_TIME:
- case ET_DATETIME: case ET_TEXT:
- t = res.text; break;
- default:
- t = 0L; break;
- }
- }
- else if(text && text[0]) t = (text[0] =='\'' && text[1]) ? text+1 : text;
- if(t) {
- rlp_strcpy(tx, size, t);
- return true;
- }
- else if((type & 0xff) == ET_VALUE) {
-#ifdef USE_WIN_SECURE
- if(text = (char*)realloc(text, 20)) sprintf_s(text, 20, "%g", Value);
-#else
- if(text = (char*)realloc(text, 20)) sprintf(text, "%g", Value);
-#endif
- if(text && text[0]) return(GetText(tx, size, false));
- }
- return false;
-}
-
-bool
-EditText::GetResult(anyResult *r, bool use_last)
-{
- 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 || (type & 0xff) == ET_BOOL || (type & 0xff) == ET_DATE
- || (type & 0xff) == ET_TIME || (type & 0xff) == ET_DATETIME){
- r->text = 0L; r->value = Value; r->type = (type & 0xff);
- 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(use_last) {
- if(ftext) {
- r->text = ftext; r->value = 0.0; r->type = ET_TEXT;
- }
- else {
- r->text = 0L; r->value = Value; r->type = ET_VALUE;
- }
- return true;
- }
- if(!(type & ET_BUSY)){
- type |= ET_BUSY;
- if(res = do_formula((DataObj*)parent, text+1)) {
- if(res->type == ET_VALUE) Value = res->value;
- else if(res->type == ET_ERROR) {
- res->text = "#ERROR"; res->type = ET_TEXT;
- }
- else Value = 0.0; type &= ~ET_BUSY;
- memcpy(r, res, sizeof(anyResult));
- return true;
- }
- type &= ~ET_BUSY;
- return false;
- }
- else {
- type |= ET_CIRCULAR;
- r->text = "#CIRC."; r->value = 0.0; r->type = ET_TEXT;
- return true;
- }
- return false;
- }
- return false;
-}
-
-bool
-EditText::SetValue(double v)
-{
- if(text) text[0] = 0;
- Value = v; type = ET_VALUE;
- return true;
-}
-
-bool
-EditText::SetText(char *t)
-{
- int cb;
-
- Value = 0.0; type = ET_UNKNOWN;
- bgLine = &ETbgnn; bgFill = &ETfbnn; TextCol = 0x00000000L;
- if(t && t[0] && (text = (char*)realloc(text, cb = (int)(strlen(t)+2)))) rlp_strcpy(text, cb, t);
- else if (text) text[0] = 0;
- return false;
-}
-
-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 || type == ET_BOOL
- || type == ET_DATE || type == ET_TIME || type == ET_DATETIME);
-}
-
-bool
-EditText::isFormula()
-{
- if((type & 0xff)==ET_UNKNOWN) FindType();
- return (type == ET_FORMULA);
-}
-
-void
-EditText::FindType()
-{
- int i, c1, c2, c3, c4, c5;
-
- if(!text || !text[0]) {
- Align = TXA_VCENTER | TXA_HRIGHT;
- if ((type & 0xff) == ET_VALUE) type = ET_VALUE;
- else type = ET_UNKNOWN | ET_EMPTY;
- return;
- }
- if(text[0] == '=') {
- Align = TXA_VCENTER | TXA_HRIGHT;
- type = ET_FORMULA;
- }
- else if(text[0] > 31 && isdigit(text[0]) || ((text[0] == '-' ) || text[0] == '.'
- || text[0] == defs.DecPoint[0]) && text[1]>31 && (isdigit(text[1]))) {
- for(i = c1 = c2 = c3 = c4 = c5 = 0; text[i]; i++) {
- switch(text[i]) {
- case '.': c1++; break;
- case '-': c2++; break;
- case '/': c3++; break;
- case ':': c4++; break;
- case 'e': break;
- case 'E': break;
- default: if(isalpha(text[i])) c5++;
- }
- }
- if(c5 > 0){
- Align = TXA_VCENTER | TXA_HLEFT;
- type = ET_TEXT;
- }
- else if(c1 < 2 && c2 < 2 && !c3 && !c4 && Txt2Flt(text, &Value)) {
- Align = TXA_VCENTER | TXA_HRIGHT;
- type = ET_VALUE;
- }
- else if((c1 == 2 || c2 == 2 || c3 == 2) && date_value(text, 0L, &Value)) {
- Align = TXA_VCENTER | TXA_HRIGHT;
- type = c4 == 2 ? ET_DATETIME : ET_DATE;
- }
- else if((c4 == 1 || c4 == 2) && date_value(text, "H:M:S", &Value)) {
- Align = TXA_VCENTER | TXA_HRIGHT;
- type = ET_TIME;
- }
- else {
- Align = TXA_VCENTER | TXA_HLEFT;
- type = ET_TEXT;
- }
- }
- else {
- if(0 == strcmp(text, "true")) {
- Value = 1.0;
- Align = TXA_VCENTER | TXA_HRIGHT;
- type = ET_BOOL;
- }
- else if(0 == strcmp(text, "false")) {
- Value = 0.0;
- Align = TXA_VCENTER | TXA_HRIGHT;
- type = ET_BOOL;
- }
- else if(0 == strcmp(text, "inf")) {
- Value = HUGE_VAL;
- Align = TXA_VCENTER | TXA_HRIGHT;
- type = ET_VALUE;
- }
- else if(0 == strcmp(text, "-inf")) {
- Value = -HUGE_VAL;
- Align = TXA_VCENTER | TXA_HRIGHT;
- type = ET_VALUE;
- }
- else {
- Align = TXA_VCENTER | TXA_HLEFT;
- type = ET_TEXT;
- }
- }
-}
-
-void
-EditText::set_etracc()
-{
- int i;
- bool accept_range;
- anyResult *res;
-
- if(parent) {
- if(hasMark()) i = m1 < m2 ? m1 : m2;
- else i = CursorPos;
- accept_range = (i && text && text[0] == '=' && text[i-1]!=')'
- && text[i-1] > 31 && !(isdigit(text[i-1]) || isalpha(text[i-1])));
- if(accept_range) {
- LockData(true, true);
- res = do_formula((DataObj*)parent, text+1);
- if(res->type != ET_ERROR) accept_range = false;
- if(!accept_range) {
- if(text[i-1] == '(' || text[i-1] == ',' || text[i-1] == ';')
- accept_range = true;
- }
- ((DataObj*)parent)->Command(CMD_CLEAR_ERROR, 0L, 0L);
- LockData(false, false);
- }
- ((DataObj*)parent)->Command(CMD_ETRACC, accept_range ? this : 0L, 0L);
- }
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// output formated text - style and font changes
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-typedef struct _tag_info {
- char *tag;
- int and_style, or_style;
- int font, op;
-}tag_info;
-
-#define UC_TAG 100
-
-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},
- {"<bullet9>", 0, 0, -1, 9}, {"<bullet10>", 0, 0, -1, 10},
- {"<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()
-{
- src=0L; split_text=0L; split_text_W = 0;
- n_split = n_split_W = uc_state = 0;
- pos.x = pos.y = 0; flags =0x0;
-}
-
-fmtText::fmtText(anyOutput *o, int x, int y, char *txt)
-{
- if(txt && txt[0]) src = (char*)memdup(txt, (int)strlen(txt)+1, 0);
- else src = 0L; split_text = 0L; split_text_W = 0L;
- n_split = n_split_W = uc_state = 0; flags = 0x0;
- 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 && n < UC_TAG && SetTextDef(&td, n)) j += (int)strlen(tags[n].tag);
- if(j > idx) break;
- if(split_text[i].txt && split_text[i].txt[0]) j += (int)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=(int)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;
-}
-
-int
-fmtText::ucTag(char *txt, int cb, int *tl, int *ucc)
-{
- int i, uc=0;
-
- if(txt[cb] != '&' || txt[cb+1] != '#') return -1;
- for(i = cb+2; txt[i] && txt[i] != ';'; i++) {
- if(!isdigit(txt[i])) return -1;
- }
- if(txt[i] != ';') return -1;
- i -= cb;
-#ifdef USE_WIN_SECURE
- sscanf_s(txt+cb+2, "%d", &uc);
-#else
- sscanf(txt+cb+2, "%d", &uc);
-#endif
- if(tl) *tl = i+1; if(ucc) *ucc = uc;
- return UC_TAG;
-}
-
-int
-fmtText::ucLeft(char *txt, int cb, int *tl, int *ucc)
-{
- int i, uc = 0;
-
- for(i = 1; i < 6 && i < cb && txt[cb-i] != '#'; i++) {
- if(!isdigit(txt[cb-i])) return -1;
- }
- if(txt[cb-i] != '#' || txt[cb-i-1] != '&') return -1;
-#ifdef USE_WIN_SECURE
- sscanf_s(txt+cb-i+1, "%d", &uc);
-#else
- sscanf(txt+cb-i+1, "%d", &uc);
-#endif
- if(tl) *tl = i+1; if(ucc) *ucc = uc;
- return UC_TAG;
-}
-
-void
-fmtText::cur_right(int *pos)
-{
- int n, tl;
-
- if(!src || !pos || *pos >= (int)strlen(src) || !src[*pos]) return;
- if(src[*pos] == '<' && (n=rightTag(src, *pos)) >= 0) {
- *pos += (int)strlen(tags[n].tag);
- cur_right(pos);
- }
- else if(src[*pos] == '&' && (ucTag(src, *pos, &tl, 0L)== UC_TAG)){
- *pos += tl;
- }
- else (*pos)++;
-}
-
-void
-fmtText::cur_left(int *pos)
-{
- int n, tl;
-
- if(!src || !pos || !(*pos)) return;
- (*pos)--;
- if(*pos >= (n=(int)strlen(src))){
- *pos = n-1; return;
- }
- if(src[*pos] == ';' && (n=ucLeft(src, *pos, &tl, 0L)) == UC_TAG) {
- *pos -= tl; return;
- }
- while (src[*pos] == '>' && (n=leftTag(src, *pos)) >= 0) {
- *pos -= (int)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(!src || !src[0]) return false;
- if(!cb) cb = (int)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(split_text[i].tag == UC_TAG) {
- o->oGetTextExtentW((w_char*)(&split_text[i].uc), 1, &w1, &h1);
- w += w1; h = h1 > h ? h1 : h;
- l += split_text[i].uc_len;
- if (l >= cb) {
- *width = w; *height = h; o->SetTextSpec(&td1);
- return true;
- }
- }
- else {
- if((n=split_text[i].tag) >= 0 && SetTextDef(&td2, n)) {
- o->SetTextSpec(&td2);
- l += (int)strlen(tags[n].tag);
- }
- if(tags[n].font == -1 && tags[n].op > 0 && tags[n].op < 100) {
- w += o->un2ix(td2.fSize/2.0);
- }
- }
- if(split_text[i].txt && split_text[i].txt[0]){
- l1 = l; l += (int)strlen(split_text[i].txt);
- if (l1 >= cb) break;
- o->oGetTextExtent(split_text[i].txt, l >= cb ? cb-l1 : 0, &w1, &h1);
- w += w1; h = h1 > h ? h1 : h;
- 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(split_text_W) {
- for(i = 0; i < n_split_W; i++) {
- if(split_text_W[i].uc_txt) free((split_text_W[i].uc_txt));
- }
- free(split_text_W); split_text_W = 0L; n_split_W = 0;
- }
- if(txt && txt[0]) src = (char*)memdup(txt, (int)strlen(txt)+1, 0);
- 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, tl, uc;
- char *tmp;
-
- if((flags & 0x01) || !src || !(tmp = (char*)memdup(src, (int)strlen(src)+1, 0))) return false;
- for(i = li = uc_state = 0; src[i]; i++) {
- if(i-li == 1 && split_text) {
- if(src[li] == '<' && (n=rightTag(src, li))>=0) i--;
- else if(src[li] == '&' && (n=ucTag(src, li, &tl, &uc))>0) i--;
- }
- if(src[i] == '<' && (n=rightTag(src, i))>=0) {
- if(tags[n].font == FONT_GREEK) uc_state |= 0x02;
- if(tags[n].op) uc_state |= 0x04;
- 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 = (char*)memdup(tmp, (int)strlen((char*)tmp)+1, 0);
- i += (int)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 = (char*)memdup(tmp, (int)strlen((char*)tmp)+1, 0);
- i += (int)strlen(tags[n].tag); split_text[1].tag = n;
- n_split = 2;
- }
- li = i; i--;
- }
- else if(src[i] == '&' && (n=ucTag(src, i, &tl, &uc))>0) {
- uc_state |= 0x01;
- 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 = (char*)memdup(tmp, (int)strlen((char*)tmp)+1, 0);
- i += tl; split_text[n_split].tag = n;
- split_text[n_split].uc = uc; split_text[n_split].uc_len = tl;
- 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 = (char*)memdup(tmp, (int)strlen((char*)tmp)+1, 0);
- i += tl; split_text[1].tag = n;
- split_text[1].uc = uc; n_split = 2;
- split_text[1].uc_len = tl;
- }
- li = i;
- }
- }
- if(split_text && n_split && li < i && src[li])
- split_text[n_split-1].txt = (char*)memdup(src+li, (int)strlen((char*)src+li)+1,0);
- 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: case 9: case 10:
- if(type == 6 || type == 8 || type == 10) fd.color = ld.color;
- pts[0].x = pts[3].x = pts[4].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 if(type == 9 || type ==10) {
- pts[0].y = pts[2].y = pts[4].y = y;
- pts[1].y = y - is; pts[3].y = y + is; pts[3].x = x;
- }
- 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, type < 9 ? 4 : 5);
- break;
- }
-}
-
-static int char2uc(char*src, w_char* dest, bool isGreek)
-{
- int i;
-
- if(!src || !*src) return 0;
- for(i = 0; ; i++){
- if(isGreek && src[i] >= 'A' && src[i] <= 'Z') dest[i] = (src[i] - 'A' + 0x391);
- else if(isGreek && src[i] >= 'a' && src[i] <= 'z') dest[i] = (src[i] - 'a' + 0x3B1);
- else dest[i] = (src[i]);
- if(!dest[i]) return i;
- }
-}
-
-bool
-fmtText::DrawFormattedW(anyOutput *o)
-{
- int i, j, n, cb, x, y, x1, y1, w, h;
- double si, csi, fx, fy;
- TextDEF td1, td2;
- bool bGreek = false;
-
- if(!o || !(split_text_W = (fmt_uc_info *)calloc(n_split, sizeof(fmt_uc_info))))return false;
- memcpy(&td1, &o->TxtSet, sizeof(TextDEF)); memcpy(&td2, &o->TxtSet, sizeof(TextDEF));
- bGreek = (td1.Font == FONT_GREEK);
- for(i = n_split_W = 0; i < n_split; i++){
- if(split_text[i].tag == UC_TAG) {
- if(i) {
- j = n_split_W ? n_split_W-1 : 0;
- cb = split_text[i].txt ? (int)strlen(split_text[i].txt) : 0;
- if(split_text_W[j].uc_txt = (w_char*)realloc(split_text_W[j].uc_txt,
- (10 + cb + split_text_W[j].cb) * sizeof(w_char))) {
- split_text_W[j].uc_txt[split_text_W[j].cb++] = split_text[i].uc;
- if(cb) split_text_W[j].cb += char2uc(split_text[i].txt, split_text_W[j].uc_txt+split_text_W[j].cb, bGreek);
- split_text_W[j].uc_txt[split_text_W[j].cb] = 0;
- }
- }
- else {
- split_text_W[0].cb = 1; split_text_W[0].tag = -1;
- if(split_text_W[0].uc_txt = (w_char*)malloc(2*sizeof(w_char))) {
- split_text_W[0].uc_txt[0] = split_text[0].uc;
- split_text_W[0].uc_txt[0] = 0;
- }
- }
- }
- else if(split_text[i].tag >= 0 && tags[split_text[i].tag].font == FONT_GREEK) {
- if(!i) return false; bGreek = true;
- j = n_split_W-1; cb = split_text[i].txt ? (int)strlen(split_text[i].txt) : 0;
- if(split_text_W[j].uc_txt = (w_char*)realloc(split_text_W[j].uc_txt,
- (2 + cb + split_text_W[j].cb) * sizeof(w_char))) {
- if(cb) split_text_W[j].cb += char2uc(split_text[i].txt, split_text_W->uc_txt+split_text_W[j].cb, bGreek);
- }
- }
- else if(bGreek && split_text[i].tag >= 0 && tags[split_text[i].tag].font == -2){
- if(!i) return false; bGreek = false;
- j = n_split_W-1; cb = split_text[i].txt ? (int)strlen(split_text[i].txt) : 0;
- if(split_text_W[j].uc_txt = (w_char*)realloc(split_text_W[j].uc_txt,
- (2 + cb + split_text_W[j].cb) * sizeof(w_char))) {
- if(cb) split_text_W[j].cb += char2uc(split_text[i].txt, split_text_W->uc_txt+split_text_W[j].cb, bGreek);
- }
- }
- else {
- if((n=split_text[i].tag) >= 0) SetTextDef(&td2, n);
- bGreek = (td2.Font == FONT_GREEK);
- split_text_W[n_split_W].tag = split_text[i].tag;
- split_text_W[n_split_W].cb = split_text[i].txt ? (int)strlen(split_text[i].txt) : 0;
- if(split_text_W[n_split_W].cb && (split_text_W[n_split_W].uc_txt =
- (w_char*)malloc((1 + split_text_W[n_split_W].cb) * sizeof(w_char)))) {
- char2uc(split_text[i].txt, split_text_W[n_split_W].uc_txt, bGreek);
- }
- else split_text_W[n_split_W].uc_txt = 0L;
- n_split_W++;
- }
- }
- memcpy(&td2, &td1, 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_W; i++) {
- if((n=split_text_W[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: case 9: case 10:
- 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_W[i].uc_txt && split_text_W[i].uc_txt[0]){
- o->oTextOutW(x, y, split_text_W[i].uc_txt, 0);
- o->oGetTextExtentW(split_text_W[i].uc_txt, 0, &w, &h);
- x = iround(fx += (w*csi)); y = iround(fy -= (w*si));
- }
- }
- return true;
-}
-
-void
-fmtText::DrawFormatted(anyOutput *o)
-{
- int i, n, x, y, w, h;
- TextDEF td1, td2;
- double si, csi, fx, fy;
-
- if(!o || !split_text) return;
- if(uc_state && DrawFormattedW(o)) 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 || split_text[i].tag == UC_TAG) {
- if((n=split_text[i].tag) >= 0 && SetTextDef(&td2, n)) o->SetTextSpec(&td2);
- if(split_text[i].txt && split_text[i].txt[0]){
- 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));
- }
- }
-}
-
-void
-fmtText::EditMode(bool bEdit)
-{
- if(bEdit) flags |= 0x01;
- else flags &= ~(0x01);
-}
-#undef UC_TAG
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// assign a value to a string
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-TextValue::TextValue()
-{
- items = 0L; nitems = 0; next = inc = 1.0;
-}
-
-TextValue::TextValue(TextValItem **tvi, int ntvi)
-{
- int i;
-
- items = 0L; nitems = 0; next = inc = 1.0;
- if(ntvi && (items = (TextValItem **)malloc(ntvi*sizeof(TextValItem*)))){
- for(i = 0, nitems = ntvi; i < ntvi; i++) {
- if(items[i] = (TextValItem*)memdup(tvi[i], sizeof(TextValItem), 0)){
- if(tvi[i]->text) items[i]->text = (char*)memdup(tvi[i]->text, (int)strlen(tvi[i]->text)+1, 0);
- }
- }
- nitems = ntvi; if(items[nitems-1]) next = items[nitems-1]->val + inc;
- }
-}
-
-TextValue::~TextValue()
-{
- Reset();
-}
-
-double
-TextValue::GetValue(char *txt)
-{
- unsigned int hv1, hv2;
- int i;
-
- if(!txt || !txt[0]) return 0.0;
- hv1 = HashValue((unsigned char*)txt);
- hv2 = Hash2((unsigned char*)txt);
- if(items && nitems) for(i = 0; i < nitems; i++) {
- if(items[i] && items[i]->hv1 == hv1 && items[i]->hv2 == hv2) return items[i]->val;
- }
- else if(!items &&(items = (TextValItem **)malloc(sizeof(TextValItem*)))) {
- if(items[0] = (TextValItem*)calloc(1, sizeof(TextValItem))) {
- items[0]->hv1 = hv1; items[0]->hv2 = hv2;
- items[0]->text = (char*)memdup(txt, (int)strlen(txt)+1, 0);
- items[0]->val = next; next += inc;
- nitems = 1; return (next-inc);
- }
- return 0.0;
- }
- else return 0.0;
- if(items = (TextValItem **)realloc(items, (nitems+1)*sizeof(TextValItem*))){
- if(items[nitems] = (TextValItem*)calloc(1, sizeof(TextValItem))) {
- items[nitems]->hv1 = hv1; items[nitems]->hv2 = hv2;
- items[nitems]->text = (char*)memdup(txt, (int)strlen(txt)+1, 0);
- items[nitems]->val = next; next += inc; nitems++;
- return (next-inc);
- }
- }
- return 0.0;
-}
-
-bool
-TextValue::GetItem(int idx, char **text, double *value)
-{
- if(items && idx >=0 && idx < nitems) {
- if(text) *text = items[idx]->text;
- if(value) *value = items[idx]->val;
- return true;
- }
- return false;
-}
-
-void
-TextValue::Reset()
-{
- int i;
-
- if(items) for(i = 0; i < nitems; i++){
- if(items[i]->text) free(items[i]->text);
- free(items[i]);
- }
- if(items && nitems) free(items);
- next = inc = 1.0; items = 0L; nitems = 0;
-}
-
-TextValue *
-TextValue::Copy()
-{
- return new TextValue(items, nitems);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// manage formats and style of a spreadsheet range
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-RangeInfo::RangeInfo(int sel, int cw, int rh, int fw, RangeInfo *next)
-{
- r_type = sel; col_width = cw; row_height = rh; first_width = fw;
- ri_next = next; ar = 0L;
-}
-
-RangeInfo::RangeInfo(int sel, char *range, RangeInfo *next)
-{
- r_type = sel; ri_next = next;
- if(range && range[0]) {
- ar = new AccRange(range);
- }
- else ar = 0L;
-}
-
-RangeInfo::~RangeInfo()
-{
- if(ar) delete ar;
-}
-
-int
-RangeInfo::SetWidth(int w)
-{
- if(r_type == 0 || r_type == 1) return col_width = w;
- else if (ri_next) return ri_next->SetWidth(w);
- return w;
-}
-
-int
-RangeInfo::SetDefWidth(int w)
-{
- if(r_type == 0) return col_width = w;
- else if (ri_next) return ri_next->SetDefWidth(w);
- return w;
-}
-
-int
-RangeInfo::SetHeight(int h)
-{
- if(r_type == 0) return row_height = h;
- else if (ri_next) return ri_next->SetHeight(h);
- return h;
-}
-
-int
-RangeInfo::SetFirstWidth(int w)
-{
- if(r_type == 0) return first_width = w;
- else if (ri_next) return ri_next->SetFirstWidth(w);
- return w;
-}
-
-int
-RangeInfo::GetWidth(int col)
-{
- int r, c;
-
- if(r_type == 0) return col_width;
- else if (ar && r_type == 1){
- ar->GetFirst(&c, &r);
- while(ar->NextCol(&c)) {
- if(c == col) return col_width;
- }
- }
- if(ri_next) return ri_next->GetWidth(col);
- return 0;
-}
-
-int
-RangeInfo::GetHeight(int row)
-{
- if(r_type == 0) return row_height;
- else if (ri_next) return ri_next->GetHeight(row);
- return row_height;
-}
-
-int
-RangeInfo::GetFirstWidth()
-{
- if(r_type == 0) return first_width;
- else if (ri_next) return ri_next->GetFirstWidth();
- return first_width;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// the basic data object
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-DataObj::DataObj()
-{
- cRows = cCols = 0;
- etRows = 0L;
- ri = new RangeInfo(0, 76, 19, 32, 0L);
-}
-
-DataObj::~DataObj()
-{
- FlushData();
- delete ri;
-}
-
-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, i, j);
- }
- }
- 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, bool bTranslate)
-{
- if(row < 0 || row >= cRows || col < 0 || col >= cCols) return false;
- if(txt && etRows[row][col]) return etRows[row][col]->GetText(txt, len, bTranslate);
- 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, bool use_last)
-{
- if(row < 0 || row >= cRows || col < 0 || col >= cCols) return false;
- if(etRows[row][col]) return etRows[row][col]->GetResult(r, use_last);
- return false;
-}
-
-bool
-DataObj::GetSize(int *width, int *height)
-{
- if(width)*width = cCols; if(height)*height = cRows;
- return true;
-}
-
-bool
-DataObj::isEmpty(int row, int col)
-{
- if(row < 0 || row >= cRows || col < 0 || col >= cCols) return false;
- if(etRows[row][col]) {
- if((etRows[row][col]->type & 0xff) == ET_UNKNOWN)etRows[row][col]->Update(20, 0L, 0L);
- if((etRows[row][col]->type & ET_EMPTY) == ET_EMPTY) return true;
- }
- return false;
-}
-
-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;
-}
-
-bool
-DataObj::ValueRec(RECT *rc)
-{
- int r, c;
- double val;
-
- if(etRows && rc){
- rc->left = cCols; rc->right = 0;
- rc->bottom = 0; rc->top = cRows;
- for(r = 0; r < cRows; r++) if(etRows[r]) {
- for (c = 0; c< cCols; c++) {
- if(etRows[r][c] && etRows[r][c]->GetValue(&val)) {
- if(c < rc->left) rc->left = c;
- if(c > rc->right) rc->right = c;
- else c = rc->right;
- if(r > rc->bottom) rc->bottom = r;
- else c = rc->right;
- if(r < rc->top) rc->top = r;
- }
- }
- }
- if(rc->right < rc->left) rc->right = rc->left < cCols ? rc->left : rc->left = 0;
- if(rc->bottom < rc->top) rc->bottom = rc->top < cRows ? rc->top : rc->top = 0;
- if(!rc->bottom && !rc->top && !rc->right && !rc->left) {
- rc->right = cCols-1; rc->bottom = cRows-1;
- }
- return true;
- }
- return false;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Store Data Object as strings: less memory required than with DataObj
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-StrData::StrData(DataObj *par, RECT *rc)
-{
- int r1, c1, r2, c2, w, h;
- char **tx;
-
- pw = ph = 0; str_data = 0L;
- drc.left = drc.right = drc.top = drc.bottom = 0;
- if(!(src = par)) return;
- src->GetSize(&pw, & ph);
- if(rc) {
- if(0>(h = (rc->bottom - rc->top)) || 0>(w = (rc->right - rc->left))) return;
- if(!(str_data = (char***)calloc(h+1, sizeof(char**))))return;
- drc.left = rc->left; drc.right = rc->right;
- drc.top = rc->top; drc.bottom = rc->bottom;
- for (r1 = 0, r2 = drc.top; r1 <= h; r1++, r2++) {
- if(!(str_data[r1] = (char**)malloc((w+1) * sizeof(char*)))) break;
- for(c1 = 0, c2= drc.left; c1 <= w; c1++, c2++) {
- tx = src->GetTextPtr(r2, c2);
- if(tx && *tx && *tx[0]) {
- str_data[r1][c1] = (char*)memdup(*tx, (int)strlen(*tx)+1, 0);
- }
- else str_data[r1][c1] = 0L;
- }
- }
- }
- else {
- if(!(str_data = (char***)calloc(ph, sizeof(char**))))return;
- for (r1 = 0; r1 < ph; r1++) {
- if(!(str_data[r1] = (char**)malloc(pw * sizeof(char*)))) break;
- for(c1 = 0; c1 < pw; c1++) {
- tx = src->GetTextPtr(r1, c1);
- if(tx && *tx && *tx[0]) {
- str_data[r1][c1] = (char*)memdup(*tx, (int)strlen(*tx)+1, 0);
- }
- else str_data[r1][c1] = 0L;
- }
- }
- drc.right = pw-1; drc.bottom = ph-1;
- }
-}
-
-StrData::~StrData()
-{
- int r, c, w, h;
-
- w = drc.right-drc.left; h = drc.bottom-drc.top;
- 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 r1, c1, r2, c2;
-
- if(!dest || !str_data) return;
- for (r1 = 0, r2 = drc.top; r2 <= drc.bottom; r1++, r2++) {
- if(str_data[r1]) {
- for(c1 = 0, c2 = drc.left; c2 <= drc.right; c1++, c2++)
- dest->SetText(r2, c2, str_data[r1][c1]);
- }
- }
- return;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// The notary class handles different types of supervision and indexing
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-notary::notary()
-{
- gObs = 0L;
- goStack = 0L;
- NextPopGO = NextPushGO = NextRegGO = 0L;
-}
-
-notary::~notary()
-{
- FreeStack();
-}
-
-int
-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 i*0x2000+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 i*0x2000+j+1;
- }
- if(!gObs[i][j]) {
- gObs[i][j] = go;
- NextRegGO = ((i << 13) | j);
- return i*0x2000+j+1;
- }
- }
- if(i < 0x1fffL && !gObs[i+1])
- gObs[i+1] = (GraphObj **)calloc(0x2000L, sizeof(GraphObj *));
- if(i < 0x1fff && !gObs[i+1]) return 0;
- }
- }
- return 0;
-}
-
-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 int id, GraphObj *go)
-{
- int i, j;
-
- NextPopGO = 0L;
- if(!go) return true;
- go->Id = id;
- if(!goStack) {
- if(!(goStack = (GraphObj ***)calloc(8192, sizeof(GraphObj **))))return false;
- 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 int 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){
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "%d objects deleted\nby notary", k);
-#else
- sprintf(TmpTxt,"%d objects deleted\nby notary", k);
-#endif
- 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, l;
-
- if(asc && *asc && (l=(int)strlen(asc)) >1){
- txt = (char *)malloc(l+2);
- 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, l;
-
- RetVal = 0;
- if(txt && txt[0] && Reset()){
- l = (int)strlen(txt);
- do {
- RetVal += ((x2-x1+1)*(y2-y1+1));
- } while((curridx < l) && 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::NextRow(int *y)
-{
- if(cy <= y2) {
- *y = cy; cy++; cx = x1; return true;
- }
- else if(txt[curridx] && Parse(curridx)) return NextRow(y);
- return false;
-}
-
-bool
-AccRange::NextCol(int *x)
-{
- if(cx <= x2) {
- *x = cx; cx++; return true;
- }
- else if(txt[curridx] && Parse(curridx)) return NextCol(x);
- 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);
- }
- Reset();
- return true;
- }
- return false;
-}
-
-bool
-AccRange::Reset()
-{
- curridx = 0;
- return Parse(curridx);
-}
-
-bool
-AccRange::Parse(int start)
-{
- int i, l, step, *v;
-
- i = start;
- if(!txt) return false;
- while(txt[i] == ';' || txt[i] == ',') i++;
- if(!txt[i]) return false;
- step = x1 = y1 = x2 = y2 = 0;
- v = &x1;
- for (l=(int)strlen(txt)+1 ; i < l; 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;
-}
-
-//get a description for the current range from the data object
-char *
-AccRange::RangeDesc(void *d, int style)
-{
- anyResult res, res1;
- int cb;
- char *desc;
-
- if(!d || !txt || !Reset())return 0L;
- if(!((DataObj*)d)->GetResult(&res, y1, x1, false))return 0L;
- if(style == 3) {
- if(x1 == x2 && y1 > 0 && res.type == ET_TEXT) {
- if(((DataObj*)d)->GetResult(&res1, 0, x1, false) && res1.type == ET_TEXT)
- return (char*)memdup(res1.text, (int)strlen(res1.text)+1, 0);
- }
- if(y1 == y2 && x1 > 0 && res.type == ET_TEXT) {
- if(((DataObj*)d)->GetResult(&res1, y1, 0, false) && res1.type == ET_TEXT)
- return (char*)memdup(res1.text, (int)strlen(res1.text)+1, 0);
- }
- }
- switch(res.type) {
- case ET_TEXT:
- if(res.text && res.text[0])
- return (char*)memdup(res.text, (int)strlen(res.text)+1, 0);
- else return 0L;
- case ET_VALUE:
- if(style != 4) break;
- case ET_DATE: case ET_DATETIME: case ET_TIME:
- TranslateResult(&res);
- if(res.text && res.text[0])
- return (char*)memdup(res.text, (int)strlen(res.text)+1, 0);
- else return 0L;
- }
- if(!(desc = (char*)malloc(40*sizeof(char))))return 0L;
- if(x1 == x2) {
- if(style == 1 || style == 3) cb = rlp_strcpy(desc, 40, "Col. ");
- else if(style == 2) cb = rlp_strcpy(desc, 40, "Column ");
- else goto rdesc_err;
- rlp_strcpy(desc+cb, 40-cb, Int2ColLabel(x1, true));
- return desc;
- }
- else if(y1 == y2) {
-#ifdef USE_WIN_SECURE
- sprintf_s(desc, 40, "Row %d", y1+1);
-#else
- sprintf(desc, "Row %d", y1+1);
-#endif
- return desc;
- }
-rdesc_err:
- free(desc);
- return 0L;
-}
-
-int
-AccRange::DataTypes(void *d, int *numerical, int *strings, int *datetime)
-{
- anyResult res;
- int n, r, c, c_num, c_txt, c_dattim;
-
- if(!d || !Reset()) return 0;
- for(n = c_num = c_txt = c_dattim = 0, GetFirst(&c, &r); GetNext(&c, &r); n++) {
- if(((DataObj*)d)->GetResult(&res, r, c, false)) {
- switch(res.type) {
- case ET_VALUE: c_num++; break;
- case ET_TEXT: c_txt++; break;
- case ET_DATE: case ET_TIME: case ET_DATETIME:
- c_dattim++; break;
- }
- }
- }
- if(numerical) *numerical = c_num;
- if(strings) *strings = c_txt;
- if(datetime) *datetime = c_dattim;
- return n;
-}
-
-//---------------------------------------------------------------------------
-// Use the Delauney triangulation to create a 3D mesh of dispersed data
-//---------------------------------------------------------------------------
-void
-Triangle::SetRect()
-{
- int i, i2;
- double dy1, dy2, dx, dy;
- double m1, m2, mx1, mx2, my1, my2;
-
- //setup bounding rectangle
- rc.Xmin = rc.Xmax = pt[0].fx; rc.Ymin = rc.Ymax = pt[0].fy;
- for(i = 1; i < 3; i++) {
- if(pt[i].fx < rc.Xmin) rc.Xmin = pt[i].fx;
- if(pt[i].fx > rc.Xmax) rc.Xmax = pt[i].fx;
- if(pt[i].fy < rc.Ymin) rc.Ymin = pt[i].fy;
- if(pt[i].fy > rc.Ymax) rc.Ymax = pt[i].fy;
- }
- //get three line equations in 2D
- for(i = 0; i < 3; i++) {
- i2 = (i+1)%3;
- ld[i].fx = pt[i].fy;
- if(pt[i].fx != pt[i2].fx) {
- ld[i].fy = (pt[i2].fy - pt[i].fy) / (pt[i2].fx - pt[i].fx);
- }
- else ld[i].fy = HUGE_VAL;
- }
- //close polygon
- pt[3].fx = pt[0].fx; pt[3].fy = pt[0].fy; pt[3].fz = pt[0].fz;
- //circumcricle
- dy1 = fabs(pt[0].fy - pt[1].fy); dy2 = fabs(pt[1].fy - pt[2].fy);
- m1 = (pt[0].fx - pt[1].fx)/(pt[1].fy - pt[0].fy);
- m2 = (pt[1].fx - pt[2].fx)/(pt[2].fy - pt[1].fy);
- mx1 = (pt[0].fx + pt[1].fx)/2.0; my1 = (pt[0].fy + pt[1].fy)/2.0;
- mx2 = (pt[1].fx + pt[2].fx)/2.0; my2 = (pt[1].fy + pt[2].fy)/2.0;
- if(dy1 < 1.0e-16 && dy2 < 1.0e-16) {
- cy = (pt[0].fy + pt[1].fy + pt[2].fy)/3.0;
- cx = (pt[0].fx + pt[1].fx + pt[2].fx)/3.0;
- r2 = 0.0; return;
- }
- else if(dy1 < 1.0e-16) {
- cx = (pt[0].fx + pt[1].fx)/2.0; cy = m2 * (cx - mx2) + my2;
- }
- else if(dy2 < 1.0e-16) {
- cx = (pt[2].fx + pt[1].fx)/2.0; cy = m1 * (cx - mx1) + my1;
- }
- else {
- cx = (m1*mx1-m2*mx2+my2-my1)/(m1-m2); cy = m1*(cx - mx1) + my1;
- }
- dx = pt[1].fx - cx; dy = pt[1].fy - cy; r2 = dx * dx + dy * dy;
-}
-
-bool
-Triangle::TestVertex(double x, double y)
-{
- double dx, dy;
-
- dx = x-cx; dx = dx * dx; dy = y-cy; dy = dy * dy;
- return (dx+dy)<r2;
-}
-
-Triangulate::Triangulate(Triangle *t_list)
-{
- trl = t_list; edges = 0L;
-}
-
-bool
-Triangulate::AddEdge(fPOINT3D *p1, fPOINT3D *p2)
-{
- edge *ce, *ne;
-
- //if edge exists delete both the new and the existing edge
- for(ce = edges, ne = 0L; (ce); ) {
- if((ce->p1.fx == p1->fx && ce->p1.fy == p1->fy && ce->p1.fz == p1->fz
- && ce->p2.fx == p2->fx && ce->p2.fy == p2->fy && ce->p2.fz == p2->fz)
- || (ce->p2.fx == p1->fx && ce->p2.fy == p1->fy && ce->p2.fz == p1->fz
- && ce->p1.fx == p2->fx && ce->p1.fy == p2->fy && ce->p1.fz == p2->fz)) {
- if(ne) ne->next = ce->next;
- else edges = ce->next;
- delete ce; return true;
- }
- ne = ce; ce = ce->next;
- }
- //come here for new edge
- if(ne = new edge()) {
- ne->p1.fx = p1->fx; ne->p1.fy = p1->fy; ne->p1.fz = p1->fz;
- ne->p2.fx = p2->fx; ne->p2.fy = p2->fy; ne->p2.fz = p2->fz;
- ne->next = edges; edges = ne;
- }
- return false;
-}
-
-bool
-Triangulate::AddVertex(fPOINT3D *v)
-{
- Triangle *trc, *trn, *tr1;
- edge *ce, *ae;
-
- for(trc = trl, trn = 0L, edges = 0L; (trc);) {
- tr1 = trc->next;
- //delete triangles whose circumcircle enclose the new vertex
- if(trc->TestVertex(v->fx, v->fy)) {
- AddEdge(&trc->pt[0], &trc->pt[1]); AddEdge(&trc->pt[1], &trc->pt[2]);
- AddEdge(&trc->pt[0], &trc->pt[2]);
- if(trn) trn->next = trc->next;
- else trl = trc->next;
- if(trl == trc) trl = 0L;
- delete trc;
- }
- else trn = trc;
- trc = tr1;
- }
- //create new triangles from those edges which where found only once
- for(ce = edges; (ce); ) {
- if(trn = new Triangle()) {
- trn->pt[0].fx = ce->p1.fx; trn->pt[0].fy = ce->p1.fy; trn->pt[0].fz = ce->p1.fz;
- trn->pt[1].fx = ce->p2.fx; trn->pt[1].fy = ce->p2.fy; trn->pt[1].fz = ce->p2.fz;
- trn->pt[2].fx = v->fx; trn->pt[2].fy = v->fy; trn->pt[2].fz = v->fz;
- trn->SetRect(); trn->next = trl; trl = trn;
- ae = ce->next; delete(ce); ce = ae;
- }
- }
- return true;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Default data vault
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Default::Default()
-{
- dUnits = cUnits = 0;
- rlp_strcpy(DecPoint, 2, "."); rlp_strcpy(ColSep, 2, ",");
- 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 = .02; 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;
- ss_txt = 0.9;
- svgAttr = svgScript = currPath = IniFile = 0L;
- File1 = File2 = File3 = File4 = File5 = File6 = 0L;
- if(fmt_date = (char*)malloc(20)) rlp_strcpy(fmt_date, 20, "Z.V.Y");
- if(fmt_time = (char*)malloc(20)) rlp_strcpy(fmt_time, 20, "H:M:S");
- if(fmt_datetime = (char*)malloc(20)) rlp_strcpy(fmt_datetime, 20, "Z.V.Y H:M:S");
-}
-
-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);
- if(fmt_date) free(fmt_date); if(fmt_time) free(fmt_time);
- if(fmt_datetime) free(fmt_datetime);
-}
-
-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 = _TXH; 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 = _TXH; 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:
-#ifdef _WINDOWS
- RetVal = 4.5*ss_txt; break;
-#else
- RetVal = 4.5*ss_txt*0.7; break;
-#endif
- case SIZE_RRECT_RAD:
- return rrect_rad ? *rrect_rad : GetSize(SIZE_SYMBOL);
- case SIZE_SCALE: return 1.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, j;
-
- if(path && (tmp_path=(char*)malloc((i=(int)strlen(path))+10))){
- rlp_strcpy(tmp_path, i+1, path);
- for(j = i ; i > 0 && tmp_path[i] != '/' && tmp_path[i] != '\\'; i--);
- tmp_path[i] = 0;
- if(currPath) free(currPath);
- if(tmp_path[0]) currPath = (char*)memdup(tmp_path, i+1, 0);
- else currPath = 0L;
- rlp_strcpy(tmp_path, j+1, 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 = -1;
-#ifdef USE_WIN_SECURE
- else if(_sopen_s(&iFile, name, O_BINARY, 0x40, S_IWRITE) || iFile < 0) return false;
-#else
- else if(-1 ==(iFile = open(name, O_BINARY))) return false;
-#endif
- Cache = (unsigned char *)malloc((unsigned)(CharCacheSize + 1));
- if(Cache) return true;
- return false;
-}
-
-void
-ReadCache::Close()
-{
-#ifdef USE_WIN_SECURE
- if(iFile >= 0) _close(iFile);
-#else
- if(iFile >= 0) close(iFile);
-#endif
- if(Cache) free(Cache); Cache = 0L;
-}
-
-unsigned char
-ReadCache::Getc()
-{
- if(Cache){
- if(idx < max) return (last = Cache[idx++]);
- else {
- do {
-#ifdef USE_WIN_SECURE
- max = _read(iFile, Cache, CharCacheSize);
-#else
- max = read(iFile, Cache, CharCacheSize);
-#endif
- 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) {
-#ifdef USE_WIN_SECURE
- max = _read(iFile, Cache, CharCacheSize);
-#else
- max = read(iFile, Cache, CharCacheSize);
-#endif
- 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) {
- max = (int)strlen((char*)ptr);
- Cache = (unsigned char*) memdup(ptr, max+1, 0);
- 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; busy = false;
- 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;
-}
-
-bool
-UndoObj::isEmpty(anyOutput *o)
-{
- int i;
-
- if(!buffers) return true;
- for (i = 0; i < ndisp; i++) if(buffers[i]){
- if(o && buffers[i]->disp == o ) {
- if(buffers[i]->count > 0) return false;
- else return true;
- }
- else if(!o && buffers[i]->count > 0) return false;
- }
- return true;
-}
-
-//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;
-
- InvalidateOutput(o); //kill text cursor and animated rectangle
- if(o && buffers) {
- for(i = 0, c_buf = -1; i < ndisp; i++) {
- if(buffers[i] && buffers[i]->disp == o) {
- c_buf = i; break;
- }
- }
- if(c_buf < 0) 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[c_buf]); buffers[c_buf] = 0L;
- }
- if(ldisp && o == cdisp) SetDisp(ldisp);
- else cdisp = 0L;
-}
-
-//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(anyOutput *o)
-{
- int idx;
-
- if(o) {
- SetDisp(o);
- 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; HideCopyMark();
- 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)--;
- busy = true;
- 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];
- }
- if(((EtBuff*)buff[idx]->data)->DaO) (((EtBuff*)buff[idx]->data)->DaO)->SetText(((EtBuff*)buff[idx]->data)->row,
- ((EtBuff*)buff[idx]->data)->col, ((EtBuff*)buff[idx]->data)->txt);
- else ((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_TEXTBUF:
- if(buff[idx]->loc && buff[idx]->data) {
- target = *((TextBuff*)buff[idx]->data)->pbuff;
- target = ((TextBuff*)buff[idx]->data)->buff;
- if(*((TextBuff*)buff[idx]->data)->pbuff) free(*((TextBuff*)buff[idx]->data)->pbuff);
- *(((TextBuff*)buff[idx]->data)->pbuff) = ((TextBuff*)buff[idx]->data)->buff;
- *(((TextBuff*)buff[idx]->data)->psize) = ((TextBuff*)buff[idx]->data)->size;
- *(((TextBuff*)buff[idx]->data)->ppos) = ((TextBuff*)buff[idx]->data)->pos;
- }
- 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; if(gol) 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_POINT:
- memcpy(buff[idx]->loc, buff[idx]->data, sizeof(POINT));
- free(buff[idx]->data); break;
- case UNDO_VOIDPTR:
- *buff[idx]->loc = buff[idx]->data; break;
- case UNDO_VALINT:
- *((int*)(buff[idx]->loc)) = *((int*)(buff[idx]->data));
- free(buff[idx]->data); break;
- case UNDO_VALLONG:
- *((long*)(buff[idx]->loc)) = *((long*)(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) && buff[idx]->data)
- rlp_strcpy ((char*)(*buff[idx]->loc), 100, (char*)(buff[idx]->data));
- else if(*(buff[idx]->loc))((char*)*(buff[idx]->loc))[0] = 0;
- if(buff[idx]->data) free(buff[idx]->data);
- CurrGO = buff[idx]->owner; 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");
- }
- busy = false;
-}
-
-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;
- HideCopyMark();
- if(o){
- SetDisp(o); o->HideMark();
- }
- if(CurrGO == *go) CurrGO = 0L;
- if((*go)->Id == GO_POLYLINE || (*go)->Id == GO_POLYGON || (*go)->Id == GO_BEZIER){
- 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 = *go) {
- 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::Point(GraphObj *parent, POINT *pt, anyOutput * o, DWORD flags)
-{
- void *ptr;
-
- if(o) SetDisp(o);
- if(!(ptr = memdup(pt, sizeof(POINT), 0))) return;
- if(0 > NewItem(UNDO_POINT, flags, parent, ptr, (void**)pt)) free(ptr);
-}
-
-void
-UndoObj::VoidPtr(GraphObj *parent, void **pptr, void *ptr, anyOutput *o, DWORD flags)
-{
- if(o) SetDisp(o);
- NewItem(UNDO_VOIDPTR, flags, parent, ptr, pptr);
-}
-
-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::ValLong(GraphObj *parent, long *val, DWORD flags)
-{
- void *ptr;
-
- if(!(ptr = memdup(val, sizeof(long), 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);
-}
-
-int
-UndoObj::String(GraphObj *go, char **s, DWORD flags)
-{
- char *ptr;
- int iret;
-
- if(s && *s && *(*s)){
- iret = (int)strlen(*(s));
- ptr = (char*)memdup(*(s), iret+1, 0);
- }
- else {
- ptr = 0L; iret = 0;
- }
- if(0 > NewItem(UNDO_STRING, flags, go, ptr, (void**)s)) if(ptr) free(ptr);
- return iret;
-}
-
-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 && td->text[0]) ptr->text = (char*)memdup(td->text, (int)strlen(td->text)+1, 0);
- if(0 > NewItem(UNDO_TEXTDEF, flags, go, ptr, (void**)td)){
- if(ptr->text) free(ptr->text); 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, RECT *rc, DWORD flags)
-{
- StrData *save;
-
- if(!go || !d) return;
- if(o) SetDisp(o);
- if(!(save = new StrData(d, rc))) 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 = (char*)memdup(text, (int)strlen(text)+1, 0);
- ptr->cur = cur; ptr->m1 = m1; ptr->m2 = m2;
- ptr->vcur = *cur; ptr->vm1 = *m1; ptr->vm2 = *m2;
- ptr->row = et->row; ptr->col = et->col;
- ptr->DaO = (DataObj*)et->parent;
- if(0 > NewItem(UNDO_ET, flags, 0L, ptr, (void**)et)) {
- if(ptr->txt)free (ptr->txt); free(ptr);
- }
- }
- SetDisp(o_save);
- }
-}
-
-void
-UndoObj::TextBuffer(GraphObj *parent, int *psize, int *ppos, unsigned char **pbuff, DWORD flags, anyOutput *o)
-{
- TextBuff *ptr;
-
- if(o) SetDisp(o);
- if(!parent || !psize || !ppos || !pbuff) return;
- if(ptr = (TextBuff*)calloc(1, sizeof(TextBuff))) {
- ptr->size = *psize; ptr->psize = psize;
- ptr->pos = *ppos; ptr->ppos = ppos;
- ptr->pbuff = pbuff; ptr->buff = (unsigned char*)memdup(*pbuff, ptr->size, 0);
- if(0 > NewItem(UNDO_TEXTBUF, flags, parent, ptr, (void**)pbuff)) {
- if(ptr->buff) free(ptr->buff); free(ptr);
- }
- }
-}
-
-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);
- free((*inf)->data);
- break;
- case UNDO_TEXTBUF:
- if(((TextBuff*)((*inf)->data))->buff) free(((TextBuff*)((*inf)->data))->buff);
- free((*inf)->data);
- 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:
- case UNDO_POINT: case UNDO_VALLONG:
- 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, false);
- 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
+//UtilObj.cpp, (c) 2000-2008 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 <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
+
+Default defs;
+
+static LineDEF ETbgnn = {0.0, 1.0, 0x00e8e8e8L, 0L};
+static LineDEF ETbgna = {0.0, 1.0, 0x00ffffffL, 0L};
+static LineDEF ETbgmn = {0.0, 1.0, 0x00cbcbcbL, 0L};
+static LineDEF ETbgma = {0.0, 1.0, 0x00ffffc0L, 0L};
+static LineDEF yLine = {0.0, 1.0, 0x0000ffffL, 0L};
+extern const LineDEF BlackLine = {0.0, 1.0, 0x00000000L, 0L};
+extern const LineDEF GrayLine = {0.0, 1.0, 0x00c0c0c0L, 0L};
+
+static FillDEF ETfbnn = {FILL_NONE, 0x00e8e8e8L, 1.0, NULL, 0x00ffffffL};
+static FillDEF ETfbna = {FILL_NONE, 0x00ffffffL, 1.0, NULL, 0x00ffffffL};
+static FillDEF ETfbmn = {FILL_NONE, 0x00e8cbcbL, 1.0, NULL, 0x00ffffffL};
+static FillDEF ETfbma = {FILL_NONE, 0x00ffffc0L, 1.0, NULL, 0x00ffffffL};
+static FillDEF yFill = {FILL_NONE, 0x0000ffffL, 1.0, NULL, 0x0000ffffL};
+
+extern char TmpTxt[500];
+extern unsigned long cObsW; //count objects written
+extern GraphObj *CurrGO, *TrackGO; //Selected Graphic Objects
+extern dragHandle *CurrHandle;
+extern UndoObj Undo;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Process fields with user input text
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+EditText *CurrText = 0L, *scroll_et = 0;
+int scroll_dist = 0;
+
+EditText::EditText(void *par, char *msg, int r, int c)
+{
+ loc.x = loc.y = crb.x = rb.x = crb.y = rb.y = 0; Value = 0.0;
+ row = r; col = c; disp = 0L; text = 0L;
+ CursorPos = length = Align = 0; type = ET_UNKNOWN; TextCol=0x00000000L;
+ bgLine = &ETbgnn; bgFill = &ETfbnn; parent = par;
+ if(msg && msg[0]) {
+ SetText(msg); FindType();
+ }
+ else {
+ Align = TXA_VCENTER | TXA_HRIGHT;
+ type = ET_UNKNOWN;
+ }
+ m1 = m2 = -1; //cursor positions track marks
+ ftext = 0L; //store formula text result here
+}
+
+EditText::~EditText()
+{
+ HideCopyMark();
+ if(CurrText == this) CurrText = 0L;
+ if(text) free(text); text = 0L;
+// if(ftext) free(ftext); ftext = 0L;
+}
+
+bool
+EditText::AddChar(int ci, anyOutput *Out, void *data_obj)
+{
+ unsigned 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(parent) {
+ ((DataObj*)parent)->Command(CMD_MRK_DIRTY, 0L, 0L);
+ ((DataObj*)parent)->Command(CMD_SAVEPOS, 0L, 0L);
+ }
+ bgLine = &ETbgna; bgFill = &ETfbna; TextCol = 0x00000000L;
+ if(text)length = (int)strlen(text);
+ else length = 0;
+ if(text) tmp = (unsigned char *)realloc(text, length+2);
+ else tmp = (unsigned char *)calloc(2, sizeof(unsigned char));
+ if(!tmp) return false;
+ text = (char*)tmp;
+ byte1 = byte2 = 0;
+ //replace mark by character if mark exists
+ if(hasMark()) { //delete marked part of text
+ if(m1 > m2) Swap(m1, m2);
+ if(m2 >= (short int)strlen(text)) text[m1] = 0;
+ else rlp_strcpy(text+m1, TMP_TXT_SIZE, text+m2);
+ CursorPos = m1;
+ m1 = m2 = -1;
+ }
+ byte1 = text[CursorPos];
+ i = CursorPos;
+ text[i++] = c;
+ while(byte1) {
+ byte2 = byte1; byte1 = text[i]; text[i++] = byte2;
+ }
+ text[i] = byte1; CursorPos++; type = ET_UNKNOWN;
+ Redraw(Out, true);
+ MyPos.y = ((loc.y +crb.y)>>1);
+ 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);
+ set_etracc();
+ return true;
+}
+
+void
+EditText::Update(int select, anyOutput *Out, POINT *MousePos)
+{
+ POINT MyPos;
+
+ if(!parent && !disp) disp = Out;
+ if(select != 1 && select != 5) m1 = m2 = -1; //no mark;
+ switch(select) {
+ case 0: //just redraw with current settings
+ Redraw(Out, true);
+ break;
+ case 5: //dialog control
+ if(!text)Align = TXA_VCENTER | TXA_HLEFT;
+ case 1: //active spread sheet cell with cursor
+ if((type & 0xff) == ET_FORMULA) Align = TXA_VCENTER | TXA_HLEFT;
+ if(!text && !(text = (char *) calloc(10, sizeof(char))))return;
+ if(CursorPos > (int)strlen(text)) CursorPos = (int)strlen(text);
+ if(MousePos && (type & 0xff) == ET_TEXT && (text && text[0] == '\'' && (bgLine == &ETbgnn || bgLine == &ETbgmn))) {
+ MousePos->x += 4;
+ }
+ bgLine = &ETbgna; bgFill = &ETfbna; TextCol = 0x00000000L;
+ if(Out) {
+ Redraw(Out, true);
+ MyPos.y = ((loc.y +crb.y)>>1);
+ MyPos.x = Align & TXA_HRIGHT ? crb.x - 4 : loc.x + 4;
+ if(MousePos && MousePos->x && MousePos->y) {
+ Out->TextCursor(text, MyPos, MousePos,&CursorPos,
+ scroll_et == this ? scroll_dist : scroll_dist=0);
+ }
+ else if(select ==1) Out->TextCursor(text, MyPos, NULL, &CursorPos,
+ scroll_et == this ? scroll_dist : (scroll_dist=0)+2);
+ set_etracc();
+ }
+ break;
+ case 2: //inactive spreadsheet cell
+ if(CurrText == this) {
+ FindType();
+ }
+ if(crb.x > rb.x) {
+ crb.x = rb.x; crb.y = rb.y;
+ }
+ bgLine = &ETbgnn; bgFill = &ETfbnn; TextCol = 0x00000000L;
+ if(Out) Redraw(Out, true);
+ break;
+ case 10: //value filled in by external app.
+ if(text && text[0]) {
+ type = ET_VALUE;
+ Align = TXA_VCENTER | TXA_HRIGHT;
+#ifdef USE_WIN_SECURE
+ sscanf_s(text, "%lf", &Value);
+#else
+ sscanf(text, "%lf", &Value);
+#endif
+ }
+ break;
+ case 20: //update value only
+ FindType();
+ break;
+ }
+}
+
+bool
+EditText::Redraw(anyOutput *Out, bool display)
+{
+ RECT rc;
+ POINT MyPos;
+ char *txt, tmptxt[500];
+ int i, w, h, o_crbx;
+ bool b_clip = false;
+ anyOutput *opc;
+ anyResult cres;
+ POINT grid[3];
+
+ if(!parent && disp) Out = disp;
+ if((type & ET_NODRAW_EMPTY) == ET_NODRAW_EMPTY && CurrText != this){
+ type &= ~ET_NODRAW;
+ return true;
+ }
+ if(loc.x <1 || rb.x < 1 || loc.y <1 || rb.y <1) return false;
+ o_crbx = crb.x; crb.x = rb.x; crb.y = rb.y;
+ if (Out) {
+ if (m1 >m2) Swap(m1, m2);
+ if(((type & 0xff) == ET_UNKNOWN) && text && text[0] && (bgLine == &ETbgnn || bgLine == &ETbgmn)) FindType();
+ Out->TxtSet.Align = Align; Out->TxtSet.ColTxt = TextCol;
+ Out->TxtSet.ColBg = bgLine->color;
+ if(text && text[0]) {
+ Out->oGetTextExtent(text, (int)strlen(text), &w, &h);
+ if(CurrText == this && parent && col >= 0) {
+ for(i = col+1; (crb.x - loc.x) < (w+(h>>1)); i++) {
+ crb.x += ((DataObj*)parent)->ri->GetWidth(i);
+ }
+ if(o_crbx > loc.x && o_crbx > crb.x && o_crbx < 4000) crb.x = o_crbx;
+ }
+ else if((crb.x - loc.x) < (w+(h>>1))) b_clip = true;
+ }
+ Out->SetFill(bgFill); Out->SetLine(bgLine);
+ rc.left = loc.x; rc.right = crb.x;
+ rc.top = loc.y+1; rc.bottom = crb.y-2;
+ Out->oRectangle(loc.x, loc.y, crb.x-1, crb.y-1);
+ if(!text || !text[0]){
+ if((type & 0xff) == ET_VALUE){
+#ifdef USE_WIN_SECURE
+ sprintf_s(tmptxt, 500, "%g", Value);
+#else
+ sprintf(tmptxt, "%g", Value);
+#endif
+ }
+ else if((type & 0xff) == ET_BOOL) {
+#ifdef USE_WIN_SECURE
+ sprintf_s(tmptxt, 500, Value != 0.0 ? "true" : "false");
+#else
+ sprintf(tmptxt, Value != 0.0 ? "true" : "false");
+#endif
+ }
+ else tmptxt[0] = 0;
+ if(tmptxt[0] && (text = (char*)realloc(text, strlen(tmptxt)+2))) rlp_strcpy(text, 500, tmptxt);
+ CursorPos = 0;
+ }
+ if(ftext) free(ftext); ftext = 0L;
+ if(text && text[0]){
+ if(bgLine == &ETbgnn || bgLine == &ETbgmn) {
+ Out->TxtSet.Align = TXA_HLEFT | TXA_VCENTER;
+ GetResult(&cres, false); TranslateResult(&cres);
+ Value = cres.value;
+ switch (cres.type) {
+ case ET_VALUE:
+ Out->TxtSet.Align = TXA_HRIGHT | TXA_VCENTER;
+ b_clip = false; rlp_strcpy(tmptxt, 500, cres.text);
+ fit_num_rect(Out, rb.x - loc.x, tmptxt);
+ Int2Nat(tmptxt); break;
+ case ET_BOOL: case ET_DATE: case ET_TIME: case ET_DATETIME:
+ case ET_TEXT:
+ Out->TxtSet.Align = cres.type == ET_TEXT ?
+ TXA_HLEFT | TXA_VCENTER : TXA_HRIGHT | TXA_VCENTER;
+ i = (int)strlen(cres.text)+2;
+ if(ftext = (char*)realloc(ftext, i > 20 ? i : 20))rlp_strcpy(ftext, i, cres.text);
+ if(cres.text && i < sizeof(tmptxt))
+ rlp_strcpy(tmptxt, 500, cres.text[0] != '\'' ? cres.text : cres.text +1);
+ else if(cres.text)rlp_strcpy(tmptxt, 500, "#SIZE");
+ else tmptxt[0] = 0;
+ Out->oGetTextExtent(tmptxt, (int)strlen(tmptxt), &w, &h);
+ b_clip = (crb.x - loc.x) < (w+(h>>1)) ? true : false;
+ break;
+ case ET_ERROR:
+ rlp_strcpy(tmptxt, 500, "#ERROR"); break;
+ default:
+ rlp_strcpy(tmptxt, 500, "#VALUE"); break;
+ }
+ txt = tmptxt;
+ }
+ else txt = text;
+ if(b_clip && parent && col >= 0 && row >=0) {
+ Out->oGetTextExtent(txt, (int)strlen(txt), &w, &h);
+ for(i = col+1; (crb.x - loc.x) < (w+(h>>1)); i++) {
+ if(((DataObj*)parent)->isEmpty(row, i)) {
+ crb.x += ((DataObj*)parent)->ri->GetWidth(i);
+ ((DataObj*)parent)->etRows[row][i]->type |= ET_NODRAW;
+ }
+ else break;
+ }
+ if((crb.x - loc.x) >= (w+(h>>1))) b_clip = false;
+ else rc.right = crb.x;
+ }
+ MyPos.y = (loc.y+rb.y)>>1;
+ if(Out->TxtSet.Align & TXA_HRIGHT) { //right justified text
+ MyPos.x = crb.x-4;
+ }
+ else { //left justified text
+ MyPos.x = loc.x+4;
+ }
+ if(b_clip && (opc = NewBitmapClass(w+22, rb.y-loc.y, Out->hres, Out->vres))){
+ if(scroll_et != this || parent) {
+ scroll_et = this; scroll_dist = 0;
+ }
+ opc->Erase(bgFill->color);
+ opc->SetTextSpec(&Out->TxtSet); opc->TxtSet.Align = TXA_HLEFT | TXA_VCENTER;
+ opc->oTextOut(4,(rb.y-loc.y)>>1, txt, (int)strlen(txt));
+ if(!parent && CursorPos) {
+ Out->oGetTextExtent(txt, CursorPos, &w, &h);
+ while((scroll_dist + w)>(rc.right-rc.left-10)) scroll_dist -=10;
+ while((scroll_dist + w)<12) scroll_dist +=10;
+ if(scroll_dist >0) scroll_dist=0;
+ }
+ else scroll_dist=0;
+ Out->CopyBitmap(rc.left+1, rc.top+1, opc, 1-scroll_dist, 1,
+ rc.right-rc.left-4, rc.bottom-rc.top-2, false);
+ DelBitmapClass(opc);
+ }
+ else {
+ if(display && hasMark() && mx1 > loc.x && mx2 < crb.x) {
+ Out->SetFill(&yFill); Out->SetLine(&yLine);
+ Out->oRectangle(mx1, rc.top, mx2, rc.bottom);
+ Out->SetFill(bgFill); Out->SetLine(bgLine);
+ }
+ scroll_dist = 0;
+ Out->oTextOut(MyPos.x, MyPos.y, txt, 0);
+ if(display && hasMark() && mx1 > loc.x && mx2 < crb.x) {
+ rc.left = mx1; rc.right = mx2;
+ Out->CopyBitmap(mx1, rc.top, Out, mx1, rc.top, mx2-mx1, rc.bottom-rc.top, true);
+ Out->MrkMode = MRK_NONE;
+ }
+ }
+ }
+ Out->SetLine((LineDEF*)&GrayLine);
+ grid[0].x = loc.x; grid[0].y = grid[1].y = crb.y-1;
+ grid[1].x = grid[2].x = crb.x-1; grid[2].y = loc.y-1;
+ Out->oPolyline(grid, 3, 0L);
+ if(display) {
+ if(!(Out->UpdateRect(&rc, false))) return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+void
+EditText::Mark(anyOutput *Out, int mark)
+{
+ LineDEF *ol = bgLine;
+ FillDEF *of = bgFill;
+ DWORD ocol = TextCol;
+
+ m1 = m2 = -1;
+ if(!parent) return;
+ switch (mark){
+ case 0: //normal not active
+ bgLine = &ETbgnn; bgFill = &ETfbnn; TextCol = 0x00000000L;
+ break;
+ case 1: //normal active
+ bgLine = &ETbgna; bgFill = &ETfbna; TextCol = 0x00000000L;
+ break;
+ case 2: //mark not active
+ bgLine = &ETbgmn; bgFill = &ETfbmn; TextCol = 0x00c00000L;
+ break;
+ case 3: //mark active
+ bgLine = &ETbgma; bgFill = &ETfbma; TextCol = 0x00ff0000L;
+ break;
+ }
+ if(!mark || mark == 2) {
+ loc.y--; rb.y++;
+ }
+ Redraw(Out, true);
+ if(!mark || mark == 2) {
+ loc.y++; rb.y--;
+ }
+ bgLine = ol; bgFill = of; TextCol = ocol;
+}
+
+bool
+EditText::Command(int cmd, anyOutput *Out, void *data_obj)
+{
+ int i, j, k, w, h;
+ POINT MyPos;
+ MouseEvent *mev;
+ static RECT rMark;
+ bool bRet;
+ char *tag1, *tag2;
+ unsigned char *pt;
+
+ MyPos.y = ((loc.y+crb.y)>>1);
+ MyPos.x = Align & TXA_HRIGHT ? crb.x - 4 : loc.x + 4;
+ if(!(text)) return false;
+ if(!parent && disp) Out = disp; //Dialog !
+ switch(cmd) {
+ case CMD_MRK_DIRTY:
+ type = ET_UNKNOWN;
+ if(CurrText == this) {
+ Command(CMD_REDRAW, Out, data_obj);
+ if(parent)((DataObj*)parent)->Command(CMD_MRK_DIRTY, Out, 0L);
+ }
+ else if(parent) {
+ ((DataObj*)parent)->Command(CMD_REDRAW, Out, 0L);
+ ((DataObj*)parent)->Command(CMD_MRK_DIRTY, Out, 0L);
+ }
+ else return Command(CMD_REDRAW, Out, data_obj);
+ return true;
+ case CMD_SETFONT:
+ if (!text || !text[0]) return false;
+ if(Out) Undo.SetDisp(Out);
+ type = ET_TEXT;
+ if(hasMark()) {
+ Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
+ switch (*((int*)data_obj)) {
+ case FONT_HELVETICA:
+ tag1 = (char*)"<face=helvetica>"; tag2 = (char*)"</face>"; break;
+ case FONT_TIMES:
+ tag1 = (char*)"<face=times>"; tag2 = (char*)"</face>"; break;
+ case FONT_COURIER:
+ tag1 = (char*)"<face=courier>"; tag2 = (char*)"</face>"; break;
+ case FONT_GREEK:
+ tag1 = (char*)"<face=greek>"; tag2 = (char*)"</face>"; break;
+ default:
+ return false;
+ }
+ if(m1 < m2) {
+ j = m1; k = m2;
+ }
+ else if(m1 > m2) {
+ j = m2; k = m1;
+ }
+ else return false; //empty mark !
+ for(i = 0; i < j; i++) TmpTxt[i] = text[i];
+ for(j = 0, w = i; tag1[j]; j++) TmpTxt[i++] = tag1[j];
+ for( ; w < k; w++) TmpTxt[i++] = text[w];
+ for(j = 0; tag2[j]; j++) TmpTxt[i++] = tag2[j];
+ for( ; TmpTxt[i++] = text[w]; w++);
+ m1 += (w = (int)strlen(tag1)); m2 += w; CursorPos += w;
+ CleanTags(TmpTxt, &m1, &m2, &CursorPos);
+ if(text = (char*)realloc(text, strlen(TmpTxt)+2)) rlp_strcpy(text, TMP_TXT_SIZE, TmpTxt);
+ Command(CMD_REDRAW, Out, 0L);
+ return true;
+ }
+ return false;
+ case CMD_SETSTYLE:
+ if (!text || !text[0]) return false;
+ if(Out) Undo.SetDisp(Out);
+ type = ET_TEXT;
+ if(hasMark()) {
+ Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
+ switch (*((int*)data_obj)) {
+ case TXS_BOLD:
+ tag1 = (char*)"<b>"; tag2 = (char*)"</b>"; break;
+ case ~TXS_BOLD:
+ tag1 = (char*)"</b>"; tag2 = (char*)"<b>"; break;
+ case TXS_ITALIC:
+ tag1 = (char*)"<i>"; tag2 = (char*)"</i>"; break;
+ case ~TXS_ITALIC:
+ tag1 = (char*)"</i>"; tag2 = (char*)"<i>"; break;
+ case TXS_UNDERLINE:
+ tag1 = (char*)"<u>"; tag2 = (char*)"</u>"; break;
+ case ~TXS_UNDERLINE:
+ tag1 = (char*)"</u>"; tag2 = (char*)"<u>"; break;
+ case TXS_SUPER:
+ tag1 = (char*)"<sup>"; tag2 = (char*)"</sup>"; break;
+ case ~TXS_SUPER:
+ tag1 = (char*)"</sup>"; tag2 = (char*)"<sup>"; break;
+ case TXS_SUB:
+ tag1 = (char*)"<sub>"; tag2 = (char*)"</sub>"; break;
+ case ~TXS_SUB:
+ tag1 = (char*)"</sub>"; tag2 = (char*)"<sub>"; break;
+ default:
+ return false;
+ }
+ if(m1 < m2) {
+ j = m1; k = m2;
+ }
+ else if(m1 > m2) {
+ j = m2; k = m1;
+ }
+ else return false; //empty mark !
+ for(i = 0; i < j; i++) TmpTxt[i] = text[i];
+ for(j = 0, w = i; tag1[j]; j++) TmpTxt[i++] = tag1[j];
+ for( ; w < k; w++) TmpTxt[i++] = text[w];
+ for(j = 0; tag2[j]; j++) TmpTxt[i++] = tag2[j];
+ for( ; TmpTxt[i++] = text[w]; w++);
+ m1 += (w = (int)strlen(tag1)); m2 += w; CursorPos += w;
+ CleanTags(TmpTxt, &m1, &m2, &CursorPos);
+ if(text = (char*)realloc(text, strlen(TmpTxt)+2)) rlp_strcpy(text, TMP_TXT_SIZE, TmpTxt);
+ Command(CMD_REDRAW, Out, 0L);
+ return true;
+ }
+ return false;
+ case CMD_ADDTXT:
+ if((tag1 = (char*)data_obj) && *tag1 && text &&
+ (type == ET_TEXT || type == ET_UNKNOWN || type == ET_FORMULA)){
+ if(hasMark()) Command(CMD_DELETE, 0L, 0L);
+ else Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
+ if(m1 > -1 && m2 > -1) Command(CMD_DELETE, 0L, 0L);
+ for(k = 0; tag1[k] && tag1[k] == text[k]; k++);
+ if(tag1[k]!=';') k = 0;
+ for(i = 0; i < CursorPos && text[i]; i++) TmpTxt[i] = text[i];
+ j = i + rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, tag1+k);
+ if(text[i]) j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, text+i);
+ if(text = (char*)realloc(text, j+2 )) rlp_strcpy(text, j+2, TmpTxt);
+ CursorPos += (int)strlen(tag1+k);
+ Out->Focus(); Update(1, Out, 0L);
+ set_etracc();
+ }
+ return true;
+ case CMD_BACKSP:
+ if(!text) return false;
+ 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(!text) return false;
+ if(cmd == CMD_DELETE) Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
+ if(parent) {
+ ((DataObj*)parent)->Command(CMD_MRK_DIRTY, 0L, 0L);
+ ((DataObj*)parent)->Command(CMD_SAVEPOS, 0L, 0L);
+ }
+ bRet = false;
+ if(!text || !text[0]) {
+ type = ET_UNKNOWN; CursorPos = 0;
+ }
+ if(hasMark()) { //delete marked part of text
+ if (!text || !text[0]) return false;
+ if(m1 > m2) Swap(m1, m2);
+ if(m2 >= (short int)strlen(text)) text[m1] = 0;
+ else rlp_strcpy(text+m1, (int)strlen(text)+m1, text+m2);
+ CursorPos = m1; m1 = m2 = -1;
+ if(!text[0]) {
+ type = ET_UNKNOWN; CursorPos = 0;
+ }
+ if(Out) Redraw(Out, (bRet = true));
+ }
+ else if(text[CursorPos]) {
+ rlp_strcpy(text + CursorPos, (int)strlen(text + CursorPos), text + CursorPos + 1);
+ if(!text || !text[0]) {
+ type = ET_UNKNOWN; CursorPos = 0;
+ }
+ if(Out)Redraw(Out, (bRet = true));
+ }
+ set_etracc();
+ if(Out)Out->TextCursor(text, MyPos, (POINT *) NULL, &CursorPos,
+ scroll_et == this ? scroll_dist : scroll_dist=0);
+ return bRet;
+ case CMD_COPY:
+ if(text && text[0]) {
+ rMark.left = loc.x+2; rMark.right = rb.x-2;
+ rMark.top = loc.y+1; rMark.bottom = rb.y-2;
+ if(m1 != m2 && m1 >=0 && m2 >=0) {
+ if (m1 >m2) Swap(m1, m2);
+ rMark.left = mx1; rMark.right = mx2;
+ if(Out) Out->UpdateRect(&rMark, false);
+ CopyText(text+m1, m2-m1);
+ if(Out) {
+ Out->MrkMode = MRK_NONE;
+ ShowCopyMark(Out, &rMark, 1);
+ Out->UpdateRect(&rMark, true);
+ }
+ return false;
+ }
+ CopyText(text, (int)strlen(text));
+ if(Out)Out->UpdateRect(&rMark, true);
+ return false;
+ }
+ return false;
+ case CMD_PASTE:
+ if(pt = PasteText()) {
+ Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
+ for(i = 0; pt[i] > 0x20 && i < 81; i++) this->AddChar(pt[i], 0L, 0L);
+ if(Out) Redraw(Out, true); free(pt);
+ set_etracc();
+ if(i) return true;
+ }
+ return false;
+ 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;
+ }
+ set_etracc();
+ if(text[CursorPos]) CursorPos++;
+ else return false;
+ case CMD_SHIFTLEFT:
+ set_etracc();
+ 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-4 - w;
+ }
+ else { //left justified text
+ mx1 = loc.x +4;
+ }
+ 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; set_etracc();
+ 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-4; MyPos.y = (rb.y+loc.y)/2;
+ if(((DataObj*)data_obj)->Select(&MyPos))return true;
+ MyPos.x = loc.x+4;
+ ((DataObj*)data_obj)->Select(&MyPos);
+ }
+ return false;
+ case CMD_CURRIGHT:
+ m1 = m2 = -1; set_etracc();
+ 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+4; MyPos.y = (rb.y+loc.y)/2; crb.x = rb.x;
+ if(((DataObj*)data_obj)->Select(&MyPos)) return true;
+ MyPos.x = rb.x-4;
+ ((DataObj*)data_obj)->Select(&MyPos);
+ }
+ return false;
+ case CMD_UPDATE:
+ m1 = m2 = -1;
+ Redraw(Out, true);
+ return true;
+ case CMD_POS_FIRST: case CMD_POS_LAST:
+ CursorPos = (cmd == CMD_POS_LAST && text && text[0]) ? (int)strlen(text) : 0;
+ m1 = m2 = -1; Redraw(Out, true);
+ Out->TextCursor(text, MyPos, (POINT *) NULL, &CursorPos,
+ scroll_et == this ? scroll_dist : scroll_dist=0);
+ set_etracc();
+ 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-4-((rb.y-loc.y-4)*((long)strlen(text)-CursorPos))/2;
+ else MyPos.x = loc.x+4+((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 +4;
+ if(MyPos.x > rb.x) MyPos.x = rb.x -4;
+ 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;// set_etracc();
+ return true;
+ }
+ if(mev->Action == MOUSE_LBDOUBLECLICK) {
+ rMark.top = loc.y+1; rMark.bottom = rb.y-2;
+ if(!Out->oGetTextExtent(text, (int)strlen(text), &w, &h)) return false;
+ m1 = 0; m2 = (int)strlen(text);
+ if(Align & TXA_HRIGHT) { //right justfied text
+ rMark.right = crb.x -4; rMark.left = crb.x - w - 4;
+ }
+ else { //left justified text
+ rMark.left = loc.x +4; rMark.right = rMark.left +w;
+ }
+ mx1 = rMark.left; mx2 = rMark.right;
+ Redraw(Out, true); set_etracc();
+ return true;
+ }
+ MyPos.x = Align & TXA_HRIGHT ? mev->x + 4 : mev->x - 4;
+ 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 = (int)strlen(text)-j)){
+ if(!Out->oGetTextExtent(text+j, i, &w, &h)) return false;
+ w = crb.x - w - 4;
+ }
+ 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+4);
+ }
+ 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+1; rMark.bottom = rb.y-2;
+ if(rMark.right < crb.x && rMark.right > loc.x &&
+ rMark.left > loc.x && rMark.left < crb.x)
+ Redraw(Out, true);
+ }
+ if(hasMark() && 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 || (type & 0xff) == ET_BOOL || (type & 0xff) == ET_DATE
+ || (type & 0xff) == ET_TIME || (type & 0xff) == ET_DATETIME){
+ *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 || res->type == ET_DATE || res->type == ET_TIME
+ || res->type == ET_DATETIME || res->type == ET_BOOL){
+ *v = Value = res->value; type &= ~ET_BUSY; return true;
+ }
+ }
+ *v = Value = 0.0; type &= ~ET_BUSY; return false;
+ }
+ else type |= ET_CIRCULAR;
+ *v = Value;
+ return true;
+ }
+ return false;
+}
+
+bool
+EditText::GetText(char *tx, int size, bool bTranslate)
+{
+ char *t = 0L;
+ static char tmp_txt[40];
+ anyResult res;
+
+ if((type & 0xff) == ET_TEXT && text && text[0]) {
+ if(text[0] =='\'' && text[1]) t = text + 1;
+ else t = text;
+ }
+ else if(bTranslate) {
+ GetResult(&res, false); TranslateResult(&res);
+ switch (res.type) {
+ case ET_VALUE:
+ rlp_strcpy(tmp_txt, 40, res.text); t = tmp_txt;
+ Int2Nat(tmp_txt); break;
+ case ET_BOOL: case ET_DATE: case ET_TIME:
+ case ET_DATETIME: case ET_TEXT:
+ t = res.text; break;
+ default:
+ t = 0L; break;
+ }
+ }
+ else if(text && text[0]) t = (text[0] =='\'' && text[1]) ? text+1 : text;
+ if(t) {
+ rlp_strcpy(tx, size, t);
+ return true;
+ }
+ else if((type & 0xff) == ET_VALUE) {
+#ifdef USE_WIN_SECURE
+ if(text = (char*)realloc(text, 20)) sprintf_s(text, 20, "%g", Value);
+#else
+ if(text = (char*)realloc(text, 20)) sprintf(text, "%g", Value);
+#endif
+ if(text && text[0]) return(GetText(tx, size, false));
+ }
+ return false;
+}
+
+bool
+EditText::GetResult(anyResult *r, bool use_last)
+{
+ 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 || (type & 0xff) == ET_BOOL || (type & 0xff) == ET_DATE
+ || (type & 0xff) == ET_TIME || (type & 0xff) == ET_DATETIME){
+ r->text = 0L; r->value = Value; r->type = (type & 0xff);
+ 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(use_last) {
+ if(ftext) {
+ r->text = ftext; r->value = 0.0; r->type = ET_TEXT;
+ }
+ else {
+ r->text = 0L; r->value = Value; r->type = ET_VALUE;
+ }
+ return true;
+ }
+ if(!(type & ET_BUSY)){
+ type |= ET_BUSY;
+ if(res = do_formula((DataObj*)parent, text+1)) {
+ if(res->type == ET_VALUE) Value = res->value;
+ else if(res->type == ET_ERROR) {
+ res->text = "#ERROR"; res->type = ET_TEXT;
+ }
+ else Value = 0.0; type &= ~ET_BUSY;
+ memcpy(r, res, sizeof(anyResult));
+ return true;
+ }
+ type &= ~ET_BUSY;
+ return false;
+ }
+ else {
+ type |= ET_CIRCULAR;
+ r->text = "#CIRC."; r->value = 0.0; r->type = ET_TEXT;
+ return true;
+ }
+ return false;
+ }
+ return false;
+}
+
+bool
+EditText::SetValue(double v)
+{
+ if(text) text[0] = 0;
+ Value = v; type = ET_VALUE;
+ return true;
+}
+
+bool
+EditText::SetText(char *t)
+{
+ int cb;
+
+ Value = 0.0; type = ET_UNKNOWN;
+ bgLine = &ETbgnn; bgFill = &ETfbnn; TextCol = 0x00000000L;
+ if(t && t[0] && (text = (char*)realloc(text, cb = (int)(strlen(t)+2)))) rlp_strcpy(text, cb, t);
+ else if (text) text[0] = 0;
+ return false;
+}
+
+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 || type == ET_BOOL
+ || type == ET_DATE || type == ET_TIME || type == ET_DATETIME);
+}
+
+bool
+EditText::isFormula()
+{
+ if((type & 0xff)==ET_UNKNOWN) FindType();
+ return (type == ET_FORMULA);
+}
+
+void
+EditText::FindType()
+{
+ int i, c1, c2, c3, c4, c5;
+
+ if(!text || !text[0]) {
+ Align = TXA_VCENTER | TXA_HRIGHT;
+ if ((type & 0xff) == ET_VALUE) type = ET_VALUE;
+ else type = ET_UNKNOWN | ET_EMPTY;
+ return;
+ }
+ if(text[0] == '=') {
+ Align = TXA_VCENTER | TXA_HRIGHT;
+ type = ET_FORMULA;
+ }
+ else if(text[0] > 31 && isdigit(text[0]) || ((text[0] == '-' ) || text[0] == '.'
+ || text[0] == defs.DecPoint[0]) && text[1]>31 && (isdigit(text[1]))) {
+ for(i = c1 = c2 = c3 = c4 = c5 = 0; text[i]; i++) {
+ switch(text[i]) {
+ case '.': c1++; break;
+ case '-': c2++; break;
+ case '/': c3++; break;
+ case ':': c4++; break;
+ case 'e': break;
+ case 'E': break;
+ default: if(isalpha(text[i])) c5++;
+ }
+ }
+ if(c5 > 0){
+ Align = TXA_VCENTER | TXA_HLEFT;
+ type = ET_TEXT;
+ }
+ else if(c1 < 2 && c2 < 2 && !c3 && !c4 && Txt2Flt(text, &Value)) {
+ Align = TXA_VCENTER | TXA_HRIGHT;
+ type = ET_VALUE;
+ }
+ else if((c1 == 2 || c2 == 2 || c3 == 2) && date_value(text, 0L, &Value)) {
+ Align = TXA_VCENTER | TXA_HRIGHT;
+ type = c4 == 2 ? ET_DATETIME : ET_DATE;
+ }
+ else if((c4 == 1 || c4 == 2) && date_value(text, "H:M:S", &Value)) {
+ Align = TXA_VCENTER | TXA_HRIGHT;
+ type = ET_TIME;
+ }
+ else {
+ Align = TXA_VCENTER | TXA_HLEFT;
+ type = ET_TEXT;
+ }
+ }
+ else {
+ if(0 == strcmp(text, "true")) {
+ Value = 1.0;
+ Align = TXA_VCENTER | TXA_HRIGHT;
+ type = ET_BOOL;
+ }
+ else if(0 == strcmp(text, "false")) {
+ Value = 0.0;
+ Align = TXA_VCENTER | TXA_HRIGHT;
+ type = ET_BOOL;
+ }
+ else if(0 == strcmp(text, "inf")) {
+ Value = HUGE_VAL;
+ Align = TXA_VCENTER | TXA_HRIGHT;
+ type = ET_VALUE;
+ }
+ else if(0 == strcmp(text, "-inf")) {
+ Value = -HUGE_VAL;
+ Align = TXA_VCENTER | TXA_HRIGHT;
+ type = ET_VALUE;
+ }
+ else {
+ Align = TXA_VCENTER | TXA_HLEFT;
+ type = ET_TEXT;
+ }
+ }
+}
+
+void
+EditText::set_etracc()
+{
+ int i;
+ bool accept_range;
+ anyResult *res;
+
+ if(parent) {
+ if(hasMark()) i = m1 < m2 ? m1 : m2;
+ else i = CursorPos;
+ accept_range = (i && text && text[0] == '=' && text[i-1]!=')'
+ && text[i-1] > 31 && !(isdigit(text[i-1]) || isalpha(text[i-1])));
+ if(accept_range) {
+ LockData(true, true);
+ res = do_formula((DataObj*)parent, text+1);
+ if(res->type != ET_ERROR) accept_range = false;
+ if(!accept_range) {
+ if(text[i-1] == '(' || text[i-1] == ',' || text[i-1] == ';')
+ accept_range = true;
+ }
+ ((DataObj*)parent)->Command(CMD_CLEAR_ERROR, 0L, 0L);
+ LockData(false, false);
+ }
+ ((DataObj*)parent)->Command(CMD_ETRACC, accept_range ? this : 0L, 0L);
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// output formated text - style and font changes
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+typedef struct _tag_info {
+ char *tag;
+ int and_style, or_style;
+ int font, op;
+}tag_info;
+
+#define UC_TAG 100
+
+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},
+ {"<bullet9>", 0, 0, -1, 9}, {"<bullet10>", 0, 0, -1, 10},
+ {"<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()
+{
+ src=0L; split_text=0L; split_text_W = 0;
+ n_split = n_split_W = uc_state = 0;
+ pos.x = pos.y = 0; flags =0x0;
+}
+
+fmtText::fmtText(anyOutput *o, int x, int y, char *txt)
+{
+ if(txt && txt[0]) src = (char*)memdup(txt, (int)strlen(txt)+1, 0);
+ else src = 0L; split_text = 0L; split_text_W = 0L;
+ n_split = n_split_W = uc_state = 0; flags = 0x0;
+ 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 && n < UC_TAG && SetTextDef(&td, n)) j += (int)strlen(tags[n].tag);
+ if(j > idx) break;
+ if(split_text[i].txt && split_text[i].txt[0]) j += (int)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=(int)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;
+}
+
+int
+fmtText::ucTag(char *txt, int cb, int *tl, int *ucc)
+{
+ int i, uc=0;
+
+ if(txt[cb] != '&' || txt[cb+1] != '#') return -1;
+ for(i = cb+2; txt[i] && txt[i] != ';'; i++) {
+ if(!isdigit(txt[i])) return -1;
+ }
+ if(txt[i] != ';') return -1;
+ i -= cb;
+#ifdef USE_WIN_SECURE
+ sscanf_s(txt+cb+2, "%d", &uc);
+#else
+ sscanf(txt+cb+2, "%d", &uc);
+#endif
+ if(tl) *tl = i+1; if(ucc) *ucc = uc;
+ return UC_TAG;
+}
+
+int
+fmtText::ucLeft(char *txt, int cb, int *tl, int *ucc)
+{
+ int i, uc = 0;
+
+ for(i = 1; i < 6 && i < cb && txt[cb-i] != '#'; i++) {
+ if(!isdigit(txt[cb-i])) return -1;
+ }
+ if(txt[cb-i] != '#' || txt[cb-i-1] != '&') return -1;
+#ifdef USE_WIN_SECURE
+ sscanf_s(txt+cb-i+1, "%d", &uc);
+#else
+ sscanf(txt+cb-i+1, "%d", &uc);
+#endif
+ if(tl) *tl = i+1; if(ucc) *ucc = uc;
+ return UC_TAG;
+}
+
+void
+fmtText::cur_right(int *pos)
+{
+ int n, tl;
+
+ if(!src || !pos || *pos >= (int)strlen(src) || !src[*pos]) return;
+ if(src[*pos] == '<' && (n=rightTag(src, *pos)) >= 0) {
+ *pos += (int)strlen(tags[n].tag);
+ cur_right(pos);
+ }
+ else if(src[*pos] == '&' && (ucTag(src, *pos, &tl, 0L)== UC_TAG)){
+ *pos += tl;
+ }
+ else (*pos)++;
+}
+
+void
+fmtText::cur_left(int *pos)
+{
+ int n, tl;
+
+ if(!src || !pos || !(*pos)) return;
+ (*pos)--;
+ if(*pos >= (n=(int)strlen(src))){
+ *pos = n-1; return;
+ }
+ if(src[*pos] == ';' && (n=ucLeft(src, *pos, &tl, 0L)) == UC_TAG) {
+ *pos -= tl; return;
+ }
+ while (src[*pos] == '>' && (n=leftTag(src, *pos)) >= 0) {
+ *pos -= (int)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(!src || !src[0]) return false;
+ if(!cb) cb = (int)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(split_text[i].tag == UC_TAG) {
+ o->oGetTextExtentW((w_char*)(&split_text[i].uc), 1, &w1, &h1);
+ w += w1; h = h1 > h ? h1 : h;
+ l += split_text[i].uc_len;
+ if (l >= cb) {
+ *width = w; *height = h; o->SetTextSpec(&td1);
+ return true;
+ }
+ }
+ else {
+ if((n=split_text[i].tag) >= 0 && SetTextDef(&td2, n)) {
+ o->SetTextSpec(&td2);
+ l += (int)strlen(tags[n].tag);
+ }
+ if(tags[n].font == -1 && tags[n].op > 0 && tags[n].op < 100) {
+ w += o->un2ix(td2.fSize/2.0);
+ }
+ }
+ if(split_text[i].txt && split_text[i].txt[0]){
+ l1 = l; l += (int)strlen(split_text[i].txt);
+ if (l1 >= cb) break;
+ o->oGetTextExtent(split_text[i].txt, l >= cb ? cb-l1 : 0, &w1, &h1);
+ w += w1; h = h1 > h ? h1 : h;
+ 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(split_text_W) {
+ for(i = 0; i < n_split_W; i++) {
+ if(split_text_W[i].uc_txt) free((split_text_W[i].uc_txt));
+ }
+ free(split_text_W); split_text_W = 0L; n_split_W = 0;
+ }
+ if(txt && txt[0]) src = (char*)memdup(txt, (int)strlen(txt)+1, 0);
+ 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, tl, uc;
+ char *tmp;
+
+ if((flags & 0x01) || !src || !(tmp = (char*)memdup(src, (int)strlen(src)+1, 0))) return false;
+ for(i = li = uc_state = 0; src[i]; i++) {
+ if(i-li == 1 && split_text) {
+ if(src[li] == '<' && (n=rightTag(src, li))>=0) i--;
+ else if(src[li] == '&' && (n=ucTag(src, li, &tl, &uc))>0) i--;
+ }
+ if(src[i] == '<' && (n=rightTag(src, i))>=0) {
+ if(tags[n].font == FONT_GREEK) uc_state |= 0x02;
+ if(tags[n].op) uc_state |= 0x04;
+ 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 = (char*)memdup(tmp, (int)strlen((char*)tmp)+1, 0);
+ i += (int)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 = (char*)memdup(tmp, (int)strlen((char*)tmp)+1, 0);
+ i += (int)strlen(tags[n].tag); split_text[1].tag = n;
+ n_split = 2;
+ }
+ li = i; i--;
+ }
+ else if(src[i] == '&' && (n=ucTag(src, i, &tl, &uc))>0) {
+ uc_state |= 0x01;
+ 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 = (char*)memdup(tmp, (int)strlen((char*)tmp)+1, 0);
+ i += tl; split_text[n_split].tag = n;
+ split_text[n_split].uc = uc; split_text[n_split].uc_len = tl;
+ 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 = (char*)memdup(tmp, (int)strlen((char*)tmp)+1, 0);
+ i += tl; split_text[1].tag = n;
+ split_text[1].uc = uc; n_split = 2;
+ split_text[1].uc_len = tl;
+ }
+ li = i;
+ }
+ }
+ if(split_text && n_split && li < i && src[li])
+ split_text[n_split-1].txt = (char*)memdup(src+li, (int)strlen((char*)src+li)+1,0);
+ 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: case 9: case 10:
+ if(type == 6 || type == 8 || type == 10) fd.color = ld.color;
+ pts[0].x = pts[3].x = pts[4].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 if(type == 9 || type ==10) {
+ pts[0].y = pts[2].y = pts[4].y = y;
+ pts[1].y = y - is; pts[3].y = y + is; pts[3].x = x;
+ }
+ 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, type < 9 ? 4 : 5);
+ break;
+ }
+}
+
+static int char2uc(char*src, w_char* dest, bool isGreek)
+{
+ int i;
+
+ if(!src || !*src) return 0;
+ for(i = 0; ; i++){
+ if(isGreek && src[i] >= 'A' && src[i] <= 'Z') dest[i] = (src[i] - 'A' + 0x391);
+ else if(isGreek && src[i] >= 'a' && src[i] <= 'z') dest[i] = (src[i] - 'a' + 0x3B1);
+ else dest[i] = (src[i]);
+ if(!dest[i]) return i;
+ }
+}
+
+bool
+fmtText::DrawFormattedW(anyOutput *o)
+{
+ int i, j, n, cb, x, y, x1, y1, w, h;
+ double si, csi, fx, fy;
+ TextDEF td1, td2;
+ bool bGreek = false;
+
+ if(!o || !(split_text_W = (fmt_uc_info *)calloc(n_split, sizeof(fmt_uc_info))))return false;
+ memcpy(&td1, &o->TxtSet, sizeof(TextDEF)); memcpy(&td2, &o->TxtSet, sizeof(TextDEF));
+ bGreek = (td1.Font == FONT_GREEK);
+ for(i = n_split_W = 0; i < n_split; i++){
+ if(split_text[i].tag == UC_TAG) {
+ if(i) {
+ j = n_split_W ? n_split_W-1 : 0;
+ cb = split_text[i].txt ? (int)strlen(split_text[i].txt) : 0;
+ if(split_text_W[j].uc_txt = (w_char*)realloc(split_text_W[j].uc_txt,
+ (10 + cb + split_text_W[j].cb) * sizeof(w_char))) {
+ split_text_W[j].uc_txt[split_text_W[j].cb++] = split_text[i].uc;
+ if(cb) split_text_W[j].cb += char2uc(split_text[i].txt, split_text_W[j].uc_txt+split_text_W[j].cb, bGreek);
+ split_text_W[j].uc_txt[split_text_W[j].cb] = 0;
+ }
+ }
+ else {
+ split_text_W[0].cb = 1; split_text_W[0].tag = -1;
+ if(split_text_W[0].uc_txt = (w_char*)malloc(2*sizeof(w_char))) {
+ split_text_W[0].uc_txt[0] = split_text[0].uc;
+ split_text_W[0].uc_txt[0] = 0;
+ }
+ }
+ }
+ else if(split_text[i].tag >= 0 && tags[split_text[i].tag].font == FONT_GREEK) {
+ if(!i) return false; bGreek = true;
+ j = n_split_W-1; cb = split_text[i].txt ? (int)strlen(split_text[i].txt) : 0;
+ if(split_text_W[j].uc_txt = (w_char*)realloc(split_text_W[j].uc_txt,
+ (2 + cb + split_text_W[j].cb) * sizeof(w_char))) {
+ if(cb) split_text_W[j].cb += char2uc(split_text[i].txt, split_text_W->uc_txt+split_text_W[j].cb, bGreek);
+ }
+ }
+ else if(bGreek && split_text[i].tag >= 0 && tags[split_text[i].tag].font == -2){
+ if(!i) return false; bGreek = false;
+ j = n_split_W-1; cb = split_text[i].txt ? (int)strlen(split_text[i].txt) : 0;
+ if(split_text_W[j].uc_txt = (w_char*)realloc(split_text_W[j].uc_txt,
+ (2 + cb + split_text_W[j].cb) * sizeof(w_char))) {
+ if(cb) split_text_W[j].cb += char2uc(split_text[i].txt, split_text_W->uc_txt+split_text_W[j].cb, bGreek);
+ }
+ }
+ else {
+ if((n=split_text[i].tag) >= 0) SetTextDef(&td2, n);
+ bGreek = (td2.Font == FONT_GREEK);
+ split_text_W[n_split_W].tag = split_text[i].tag;
+ split_text_W[n_split_W].cb = split_text[i].txt ? (int)strlen(split_text[i].txt) : 0;
+ if(split_text_W[n_split_W].cb && (split_text_W[n_split_W].uc_txt =
+ (w_char*)malloc((1 + split_text_W[n_split_W].cb) * sizeof(w_char)))) {
+ char2uc(split_text[i].txt, split_text_W[n_split_W].uc_txt, bGreek);
+ }
+ else split_text_W[n_split_W].uc_txt = 0L;
+ n_split_W++;
+ }
+ }
+ memcpy(&td2, &td1, 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_W; i++) {
+ if((n=split_text_W[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: case 9: case 10:
+ 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_W[i].uc_txt && split_text_W[i].uc_txt[0]){
+ o->oTextOutW(x, y, split_text_W[i].uc_txt, 0);
+ o->oGetTextExtentW(split_text_W[i].uc_txt, 0, &w, &h);
+ x = iround(fx += (w*csi)); y = iround(fy -= (w*si));
+ }
+ }
+ return true;
+}
+
+void
+fmtText::DrawFormatted(anyOutput *o)
+{
+ int i, n, x, y, w, h;
+ TextDEF td1, td2;
+ double si, csi, fx, fy;
+
+ if(!o || !split_text) return;
+ if(uc_state && DrawFormattedW(o)) 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 || split_text[i].tag == UC_TAG) {
+ if((n=split_text[i].tag) >= 0 && SetTextDef(&td2, n)) o->SetTextSpec(&td2);
+ if(split_text[i].txt && split_text[i].txt[0]){
+ 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));
+ }
+ }
+}
+
+void
+fmtText::EditMode(bool bEdit)
+{
+ if(bEdit) flags |= 0x01;
+ else flags &= ~(0x01);
+}
+#undef UC_TAG
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// assign a value to a string
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+TextValue::TextValue()
+{
+ items = 0L; nitems = 0; next = inc = 1.0;
+}
+
+TextValue::TextValue(TextValItem **tvi, int ntvi)
+{
+ int i;
+
+ items = 0L; nitems = 0; next = inc = 1.0;
+ if(ntvi && (items = (TextValItem **)malloc(ntvi*sizeof(TextValItem*)))){
+ for(i = 0, nitems = ntvi; i < ntvi; i++) {
+ if(items[i] = (TextValItem*)memdup(tvi[i], sizeof(TextValItem), 0)){
+ if(tvi[i]->text) items[i]->text = (char*)memdup(tvi[i]->text, (int)strlen(tvi[i]->text)+1, 0);
+ }
+ }
+ nitems = ntvi; if(items[nitems-1]) next = items[nitems-1]->val + inc;
+ }
+}
+
+TextValue::~TextValue()
+{
+ Reset();
+}
+
+double
+TextValue::GetValue(char *txt)
+{
+ unsigned int hv1, hv2;
+ int i;
+
+ if(!txt || !txt[0]) return 0.0;
+ hv1 = HashValue((unsigned char*)txt);
+ hv2 = Hash2((unsigned char*)txt);
+ if(items && nitems) for(i = 0; i < nitems; i++) {
+ if(items[i] && items[i]->hv1 == hv1 && items[i]->hv2 == hv2) return items[i]->val;
+ }
+ else if(!items &&(items = (TextValItem **)malloc(sizeof(TextValItem*)))) {
+ if(items[0] = (TextValItem*)calloc(1, sizeof(TextValItem))) {
+ items[0]->hv1 = hv1; items[0]->hv2 = hv2;
+ items[0]->text = (char*)memdup(txt, (int)strlen(txt)+1, 0);
+ items[0]->val = next; next += inc;
+ nitems = 1; return (next-inc);
+ }
+ return 0.0;
+ }
+ else return 0.0;
+ if(items = (TextValItem **)realloc(items, (nitems+1)*sizeof(TextValItem*))){
+ if(items[nitems] = (TextValItem*)calloc(1, sizeof(TextValItem))) {
+ items[nitems]->hv1 = hv1; items[nitems]->hv2 = hv2;
+ items[nitems]->text = (char*)memdup(txt, (int)strlen(txt)+1, 0);
+ items[nitems]->val = next; next += inc; nitems++;
+ return (next-inc);
+ }
+ }
+ return 0.0;
+}
+
+bool
+TextValue::GetItem(int idx, char **text, double *value)
+{
+ if(items && idx >=0 && idx < nitems) {
+ if(text) *text = items[idx]->text;
+ if(value) *value = items[idx]->val;
+ return true;
+ }
+ return false;
+}
+
+void
+TextValue::Reset()
+{
+ int i;
+
+ if(items) for(i = 0; i < nitems; i++){
+ if(items[i]->text) free(items[i]->text);
+ free(items[i]);
+ }
+ if(items && nitems) free(items);
+ next = inc = 1.0; items = 0L; nitems = 0;
+}
+
+TextValue *
+TextValue::Copy()
+{
+ return new TextValue(items, nitems);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// manage formats and style of a spreadsheet range
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+RangeInfo::RangeInfo(int sel, int cw, int rh, int fw, RangeInfo *next)
+{
+ r_type = sel; col_width = cw; row_height = rh; first_width = fw;
+ ri_next = next; ar = 0L;
+}
+
+RangeInfo::RangeInfo(int sel, char *range, RangeInfo *next)
+{
+ r_type = sel; ri_next = next;
+ if(range && range[0]) {
+ ar = new AccRange(range);
+ }
+ else ar = 0L;
+}
+
+RangeInfo::~RangeInfo()
+{
+ if(ar) delete ar;
+}
+
+int
+RangeInfo::SetWidth(int w)
+{
+ if(r_type == 0 || r_type == 1) return col_width = w;
+ else if (ri_next) return ri_next->SetWidth(w);
+ return w;
+}
+
+int
+RangeInfo::SetDefWidth(int w)
+{
+ if(r_type == 0) return col_width = w;
+ else if (ri_next) return ri_next->SetDefWidth(w);
+ return w;
+}
+
+int
+RangeInfo::SetHeight(int h)
+{
+ if(r_type == 0) return row_height = h;
+ else if (ri_next) return ri_next->SetHeight(h);
+ return h;
+}
+
+int
+RangeInfo::SetFirstWidth(int w)
+{
+ if(r_type == 0) return first_width = w;
+ else if (ri_next) return ri_next->SetFirstWidth(w);
+ return w;
+}
+
+int
+RangeInfo::GetWidth(int col)
+{
+ int r, c;
+
+ if(r_type == 0) return col_width;
+ else if (ar && r_type == 1){
+ ar->GetFirst(&c, &r);
+ while(ar->NextCol(&c)) {
+ if(c == col) return col_width;
+ }
+ }
+ if(ri_next) return ri_next->GetWidth(col);
+ return 0;
+}
+
+int
+RangeInfo::GetHeight(int row)
+{
+ if(r_type == 0) return row_height;
+ else if (ri_next) return ri_next->GetHeight(row);
+ return row_height;
+}
+
+int
+RangeInfo::GetFirstWidth()
+{
+ if(r_type == 0) return first_width;
+ else if (ri_next) return ri_next->GetFirstWidth();
+ return first_width;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// the basic data object
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+DataObj::DataObj()
+{
+ cRows = cCols = 0;
+ etRows = 0L;
+ ri = new RangeInfo(0, 76, 19, 32, 0L);
+}
+
+DataObj::~DataObj()
+{
+ FlushData();
+ delete ri;
+}
+
+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, i, j);
+ }
+ }
+ 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, bool bTranslate)
+{
+ if(row < 0 || row >= cRows || col < 0 || col >= cCols) return false;
+ if(txt && etRows[row][col]) return etRows[row][col]->GetText(txt, len, bTranslate);
+ 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, bool use_last)
+{
+ if(row < 0 || row >= cRows || col < 0 || col >= cCols) return false;
+ if(etRows[row][col]) return etRows[row][col]->GetResult(r, use_last);
+ return false;
+}
+
+bool
+DataObj::GetSize(int *width, int *height)
+{
+ if(width)*width = cCols; if(height)*height = cRows;
+ return true;
+}
+
+bool
+DataObj::isEmpty(int row, int col)
+{
+ if(row < 0 || row >= cRows || col < 0 || col >= cCols) return false;
+ if(etRows[row][col]) {
+ if((etRows[row][col]->type & 0xff) == ET_UNKNOWN)etRows[row][col]->Update(20, 0L, 0L);
+ if((etRows[row][col]->type & ET_EMPTY) == ET_EMPTY) return true;
+ }
+ return false;
+}
+
+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;
+}
+
+bool
+DataObj::ValueRec(RECT *rc)
+{
+ int r, c;
+ double val;
+
+ if(etRows && rc){
+ rc->left = cCols; rc->right = 0;
+ rc->bottom = 0; rc->top = cRows;
+ for(r = 0; r < cRows; r++) if(etRows[r]) {
+ for (c = 0; c< cCols; c++) {
+ if(etRows[r][c] && etRows[r][c]->GetValue(&val)) {
+ if(c < rc->left) rc->left = c;
+ if(c > rc->right) rc->right = c;
+ else c = rc->right;
+ if(r > rc->bottom) rc->bottom = r;
+ else c = rc->right;
+ if(r < rc->top) rc->top = r;
+ }
+ }
+ }
+ if(rc->right < rc->left) rc->right = rc->left < cCols ? rc->left : rc->left = 0;
+ if(rc->bottom < rc->top) rc->bottom = rc->top < cRows ? rc->top : rc->top = 0;
+ if(!rc->bottom && !rc->top && !rc->right && !rc->left) {
+ rc->right = cCols-1; rc->bottom = cRows-1;
+ }
+ return true;
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Store Data Object as strings: less memory required than with DataObj
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+StrData::StrData(DataObj *par, RECT *rc)
+{
+ int r1, c1, r2, c2, w, h;
+ char **tx;
+
+ pw = ph = 0; str_data = 0L;
+ drc.left = drc.right = drc.top = drc.bottom = 0;
+ if(!(src = par)) return;
+ src->GetSize(&pw, & ph);
+ if(rc) {
+ if(0>(h = (rc->bottom - rc->top)) || 0>(w = (rc->right - rc->left))) return;
+ if(!(str_data = (char***)calloc(h+1, sizeof(char**))))return;
+ drc.left = rc->left; drc.right = rc->right;
+ drc.top = rc->top; drc.bottom = rc->bottom;
+ for (r1 = 0, r2 = drc.top; r1 <= h; r1++, r2++) {
+ if(!(str_data[r1] = (char**)malloc((w+1) * sizeof(char*)))) break;
+ for(c1 = 0, c2= drc.left; c1 <= w; c1++, c2++) {
+ tx = src->GetTextPtr(r2, c2);
+ if(tx && *tx && *tx[0]) {
+ str_data[r1][c1] = (char*)memdup(*tx, (int)strlen(*tx)+1, 0);
+ }
+ else str_data[r1][c1] = 0L;
+ }
+ }
+ }
+ else {
+ if(!(str_data = (char***)calloc(ph, sizeof(char**))))return;
+ for (r1 = 0; r1 < ph; r1++) {
+ if(!(str_data[r1] = (char**)malloc(pw * sizeof(char*)))) break;
+ for(c1 = 0; c1 < pw; c1++) {
+ tx = src->GetTextPtr(r1, c1);
+ if(tx && *tx && *tx[0]) {
+ str_data[r1][c1] = (char*)memdup(*tx, (int)strlen(*tx)+1, 0);
+ }
+ else str_data[r1][c1] = 0L;
+ }
+ }
+ drc.right = pw-1; drc.bottom = ph-1;
+ }
+}
+
+StrData::~StrData()
+{
+ int r, c, w, h;
+
+ w = drc.right-drc.left; h = drc.bottom-drc.top;
+ 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 r1, c1, r2, c2;
+
+ if(!dest || !str_data) return;
+ for (r1 = 0, r2 = drc.top; r2 <= drc.bottom; r1++, r2++) {
+ if(str_data[r1]) {
+ for(c1 = 0, c2 = drc.left; c2 <= drc.right; c1++, c2++)
+ dest->SetText(r2, c2, str_data[r1][c1]);
+ }
+ }
+ return;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// The notary class handles different types of supervision and indexing
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+notary::notary()
+{
+ gObs = 0L;
+ goStack = 0L;
+ NextPopGO = NextPushGO = NextRegGO = 0L;
+}
+
+notary::~notary()
+{
+ FreeStack();
+}
+
+int
+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 i*0x2000+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 i*0x2000+j+1;
+ }
+ if(!gObs[i][j]) {
+ gObs[i][j] = go;
+ NextRegGO = ((i << 13) | j);
+ return i*0x2000+j+1;
+ }
+ }
+ if(i < 0x1fffL && !gObs[i+1])
+ gObs[i+1] = (GraphObj **)calloc(0x2000L, sizeof(GraphObj *));
+ if(i < 0x1fff && !gObs[i+1]) return 0;
+ }
+ }
+ return 0;
+}
+
+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 int id, GraphObj *go)
+{
+ int i, j;
+
+ NextPopGO = 0L;
+ if(!go) return true;
+ go->Id = id;
+ if(!goStack) {
+ if(!(goStack = (GraphObj ***)calloc(8192, sizeof(GraphObj **))))return false;
+ 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 int 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 = k = 0; goStack[i] && i <8192; i++){
+ for(j = 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){
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "%d objects deleted\nby notary", k);
+#else
+ sprintf(TmpTxt,"%d objects deleted\nby notary", k);
+#endif
+ 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, l;
+
+ if(asc && *asc && (l=(int)strlen(asc)) >1){
+ txt = (char *)malloc(l+2);
+ 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, l;
+
+ RetVal = 0;
+ if(txt && txt[0] && Reset()){
+ l = (int)strlen(txt);
+ do {
+ RetVal += ((x2-x1+1)*(y2-y1+1));
+ } while((curridx < l) && 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::NextRow(int *y)
+{
+ if(cy <= y2) {
+ *y = cy; cy++; cx = x1; return true;
+ }
+ else if(txt[curridx] && Parse(curridx)) return NextRow(y);
+ return false;
+}
+
+bool
+AccRange::NextCol(int *x)
+{
+ if(cx <= x2) {
+ *x = cx; cx++; return true;
+ }
+ else if(txt[curridx] && Parse(curridx)) return NextCol(x);
+ 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);
+ }
+ Reset();
+ return true;
+ }
+ return false;
+}
+
+bool
+AccRange::Reset()
+{
+ curridx = 0;
+ return Parse(curridx);
+}
+
+bool
+AccRange::Parse(int start)
+{
+ int i, l, step, *v;
+
+ i = start;
+ if(!txt) return false;
+ while(txt[i] == ';' || txt[i] == ',') i++;
+ if(!txt[i]) return false;
+ step = x1 = y1 = x2 = y2 = 0;
+ v = &x1;
+ for (l=(int)strlen(txt)+1 ; i < l; 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;
+}
+
+//get a description for the current range from the data object
+char *
+AccRange::RangeDesc(void *d, int style)
+{
+ anyResult res, res1;
+ int cb;
+ char *desc;
+
+ if(!d || !txt || !Reset())return 0L;
+ if(!((DataObj*)d)->GetResult(&res, y1, x1, false))return 0L;
+ if(style == 3) {
+ if(x1 == x2 && y1 > 0 && res.type == ET_TEXT) {
+ if(((DataObj*)d)->GetResult(&res1, 0, x1, false) && res1.type == ET_TEXT)
+ return (char*)memdup(res1.text, (int)strlen(res1.text)+1, 0);
+ }
+ if(y1 == y2 && x1 > 0 && res.type == ET_TEXT) {
+ if(((DataObj*)d)->GetResult(&res1, y1, 0, false) && res1.type == ET_TEXT)
+ return (char*)memdup(res1.text, (int)strlen(res1.text)+1, 0);
+ }
+ }
+ switch(res.type) {
+ case ET_TEXT:
+ if(res.text && res.text[0])
+ return (char*)memdup(res.text, (int)strlen(res.text)+1, 0);
+ else return 0L;
+ case ET_VALUE:
+ if(style != 4) break;
+ case ET_DATE: case ET_DATETIME: case ET_TIME:
+ TranslateResult(&res);
+ if(res.text && res.text[0])
+ return (char*)memdup(res.text, (int)strlen(res.text)+1, 0);
+ else return 0L;
+ }
+ if(!(desc = (char*)malloc(40*sizeof(char))))return 0L;
+ if(x1 == x2) {
+ if(style == 1 || style == 3) cb = rlp_strcpy(desc, 40, "Col. ");
+ else if(style == 2) cb = rlp_strcpy(desc, 40, "Column ");
+ else goto rdesc_err;
+ rlp_strcpy(desc+cb, 40-cb, Int2ColLabel(x1, true));
+ return desc;
+ }
+ else if(y1 == y2) {
+#ifdef USE_WIN_SECURE
+ sprintf_s(desc, 40, "Row %d", y1+1);
+#else
+ sprintf(desc, "Row %d", y1+1);
+#endif
+ return desc;
+ }
+rdesc_err:
+ free(desc);
+ return 0L;
+}
+
+int
+AccRange::DataTypes(void *d, int *numerical, int *strings, int *datetime)
+{
+ anyResult res;
+ int n, r, c, c_num, c_txt, c_dattim;
+
+ if(!d || !Reset()) return 0;
+ for(n = c_num = c_txt = c_dattim = 0, GetFirst(&c, &r); GetNext(&c, &r); n++) {
+ if(((DataObj*)d)->GetResult(&res, r, c, false)) {
+ switch(res.type) {
+ case ET_VALUE: c_num++; break;
+ case ET_TEXT: c_txt++; break;
+ case ET_DATE: case ET_TIME: case ET_DATETIME:
+ c_dattim++; break;
+ }
+ }
+ }
+ if(numerical) *numerical = c_num;
+ if(strings) *strings = c_txt;
+ if(datetime) *datetime = c_dattim;
+ return n;
+}
+
+//---------------------------------------------------------------------------
+// Use the Delauney triangulation to create a 3D mesh of dispersed data
+//---------------------------------------------------------------------------
+Triangle::Triangle()
+{
+ bSorted = false;
+}
+
+void
+Triangle::SetRect()
+{
+ int i, i2;
+ double dy1, dy2, dx, dy;
+ double m1, m2, mx1, mx2, my1, my2;
+
+ //setup bounding rectangle
+ rc.Xmin = rc.Xmax = pt[0].fx; rc.Ymin = rc.Ymax = pt[0].fy;
+ for(i = 1; i < 3; i++) {
+ if(pt[i].fx < rc.Xmin) rc.Xmin = pt[i].fx;
+ if(pt[i].fx > rc.Xmax) rc.Xmax = pt[i].fx;
+ if(pt[i].fy < rc.Ymin) rc.Ymin = pt[i].fy;
+ if(pt[i].fy > rc.Ymax) rc.Ymax = pt[i].fy;
+ }
+ //get three line equations in 2D
+ for(i = 0; i < 3; i++) {
+ i2 = (i+1)%3;
+ ld[i].fx = pt[i].fy;
+ if(pt[i].fx != pt[i2].fx) {
+ ld[i].fy = (pt[i2].fy - pt[i].fy) / (pt[i2].fx - pt[i].fx);
+ }
+ else ld[i].fy = HUGE_VAL;
+ }
+ //close polygon
+ pt[3].fx = pt[0].fx; pt[3].fy = pt[0].fy; pt[3].fz = pt[0].fz;
+ //circumcricle
+ dy1 = fabs(pt[0].fy - pt[1].fy); dy2 = fabs(pt[1].fy - pt[2].fy);
+ m1 = (pt[0].fx - pt[1].fx)/(pt[1].fy - pt[0].fy);
+ m2 = (pt[1].fx - pt[2].fx)/(pt[2].fy - pt[1].fy);
+ mx1 = (pt[0].fx + pt[1].fx)/2.0; my1 = (pt[0].fy + pt[1].fy)/2.0;
+ mx2 = (pt[1].fx + pt[2].fx)/2.0; my2 = (pt[1].fy + pt[2].fy)/2.0;
+ if(dy1 < 1.0e-16 && dy2 < 1.0e-16) {
+ cy = (pt[0].fy + pt[1].fy + pt[2].fy)/3.0;
+ cx = (pt[0].fx + pt[1].fx + pt[2].fx)/3.0;
+ r2 = 0.0; return;
+ }
+ else if(dy1 < 1.0e-16) {
+ cx = (pt[0].fx + pt[1].fx)/2.0; cy = m2 * (cx - mx2) + my2;
+ }
+ else if(dy2 < 1.0e-16) {
+ cx = (pt[2].fx + pt[1].fx)/2.0; cy = m1 * (cx - mx1) + my1;
+ }
+ else {
+ cx = (m1*mx1-m2*mx2+my2-my1)/(m1-m2); cy = m1*(cx - mx1) + my1;
+ }
+ dx = pt[1].fx - cx; dy = pt[1].fy - cy; r2 = dx * dx + dy * dy;
+}
+
+bool
+Triangle::TestVertex(double x, double y)
+{
+ double dx, dy;
+
+ dx = x-cx; dx = dx * dx; dy = y-cy; dy = dy * dy;
+ return (dx+dy)<r2;
+}
+
+bool
+Triangle::Sort()
+{
+ if(pt[0].fz <= pt[1].fz) {
+ if(pt[1].fz <= pt[2].fz) {
+ order[0] = 0; order[1] = 1; order[2] = 2;
+ }
+ else if(pt[0].fz <= pt[2].fz) {
+ order[0] = 0; order[1] = 2; order[2] = 1;
+ }
+ else {
+ order[0] = 1; order[1] = 2; order[2] = 0;
+ }
+ }
+ else {
+ if(pt[1].fz >= pt[2].fz) {
+ order[0] = 2; order[1] = 1; order[2] = 0;
+ }
+ else if(pt[0].fz >= pt[2].fz) {
+ order[0] = 2; order[1] = 0; order[2] = 1;
+ }
+ else {
+ order[0] = 1; order[1] = 0; order[2] = 2;
+ }
+ }
+ return (bSorted = true);
+}
+
+void
+Triangle::LinePoint(int i1, int i2, double z, lfPOINT *res)
+{
+ double dx, dy, dz, l, f;
+
+ dx = pt[i2].fx - pt[i1].fx; dy = pt[i2].fy - pt[i1].fy;
+ dz = f = pt[i2].fz - pt[i1].fz;
+ l = sqrt(dx * dx + dy * dy + dz * dz);
+ dx /= l; dy /= l; dz /= l;
+ f = (z-pt[i1].fz) / dz;
+ res->fx = pt[i1].fx + dx * f;
+ res->fy = pt[i1].fy + dy * f;
+}
+
+bool
+Triangle::IsoLine(double z, void *dest)
+{
+ lfPOINT li[2];
+
+ if(!bSorted && !Sort())return false;
+ if(z < pt[order[0]].fz) return false; //below lowest point
+ if(z == pt[order[0]].fz) {
+ if(pt[order[1]].fz > z) return true; //crossing single lowest point
+ li[0].fx = pt[order[0]].fx; li[0].fy = pt[order[0]].fy;
+ li[1].fx = pt[order[1]].fx; li[1].fy = pt[order[1]].fy;
+ return ((GraphObj*)dest)->Command(CMD_ADDTOLINE, &li, 0L);
+ }
+ if(z < pt[order[1]].fz) {
+ LinePoint(order[0], order[1], z, &li[0]);
+ LinePoint(order[0], order[2], z, &li[1]);
+ return ((GraphObj*)dest)->Command(CMD_ADDTOLINE, &li, 0L);
+ }
+ if(z == pt[order[1]].fz && pt[order[1]].fz < pt[order[2]].fz) {
+ li[0].fx = pt[order[1]].fx; li[0].fy = pt[order[1]].fy;
+ LinePoint(order[0], order[2], z, &li[1]);
+ return ((GraphObj*)dest)->Command(CMD_ADDTOLINE, &li, 0L);
+ }
+ if(z < pt[order[2]].fz) {
+ LinePoint(order[1], order[2], z, &li[0]);
+ LinePoint(order[0], order[2], z, &li[1]);
+ return ((GraphObj*)dest)->Command(CMD_ADDTOLINE, &li, 0L);
+ }
+ if(z == pt[order[1]].fz && z == pt[order[2]].fz) {
+ li[0].fx = pt[order[1]].fx; li[0].fy = pt[order[1]].fy;
+ li[1].fx = pt[order[2]].fx; li[1].fy = pt[order[2]].fy;
+ return ((GraphObj*)dest)->Command(CMD_ADDTOLINE, &li, 0L);
+ }
+ return false;
+}
+
+Triangulate::Triangulate(Triangle *t_list)
+{
+ trl = t_list; edges = 0L;
+}
+
+bool
+Triangulate::AddEdge(fPOINT3D *p1, fPOINT3D *p2)
+{
+ edge *ce, *ne;
+
+ //if edge exists delete both the new and the existing edge
+ for(ce = edges, ne = 0L; (ce); ) {
+ if((ce->p1.fx == p1->fx && ce->p1.fy == p1->fy && ce->p1.fz == p1->fz
+ && ce->p2.fx == p2->fx && ce->p2.fy == p2->fy && ce->p2.fz == p2->fz)
+ || (ce->p2.fx == p1->fx && ce->p2.fy == p1->fy && ce->p2.fz == p1->fz
+ && ce->p1.fx == p2->fx && ce->p1.fy == p2->fy && ce->p1.fz == p2->fz)) {
+ if(ne) ne->next = ce->next;
+ else edges = ce->next;
+ delete ce; return true;
+ }
+ ne = ce; ce = ce->next;
+ }
+ //come here for new edge
+ if(ne = new edge()) {
+ ne->p1.fx = p1->fx; ne->p1.fy = p1->fy; ne->p1.fz = p1->fz;
+ ne->p2.fx = p2->fx; ne->p2.fy = p2->fy; ne->p2.fz = p2->fz;
+ ne->next = edges; edges = ne;
+ }
+ return false;
+}
+
+bool
+Triangulate::AddVertex(fPOINT3D *v)
+{
+ Triangle *trc, *trn, *tr1;
+ edge *ce, *ae;
+
+ for(trc = trl, trn = 0L, edges = 0L; (trc);) {
+ tr1 = trc->next;
+ //delete triangles whose circumcircle enclose the new vertex
+ if(trc->TestVertex(v->fx, v->fy)) {
+ AddEdge(&trc->pt[0], &trc->pt[1]); AddEdge(&trc->pt[1], &trc->pt[2]);
+ AddEdge(&trc->pt[0], &trc->pt[2]);
+ if(trn) trn->next = trc->next;
+ else trl = trc->next;
+ if(trl == trc) trl = 0L;
+ delete trc;
+ }
+ else trn = trc;
+ trc = tr1;
+ }
+ //create new triangles from those edges which where found only once
+ for(ce = edges; (ce); ) {
+ if(trn = new Triangle()) {
+ trn->pt[0].fx = ce->p1.fx; trn->pt[0].fy = ce->p1.fy; trn->pt[0].fz = ce->p1.fz;
+ trn->pt[1].fx = ce->p2.fx; trn->pt[1].fy = ce->p2.fy; trn->pt[1].fz = ce->p2.fz;
+ trn->pt[2].fx = v->fx; trn->pt[2].fy = v->fy; trn->pt[2].fz = v->fz;
+ trn->SetRect(); trn->next = trl; trl = trn;
+ ae = ce->next; delete(ce); ce = ae;
+ }
+ }
+ return true;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Default data vault
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Default::Default()
+{
+ dUnits = cUnits = 0;
+ rlp_strcpy(DecPoint, 2, "."); rlp_strcpy(ColSep, 2, ",");
+ 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 = .02; 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;
+ ss_txt = 0.9; out_upd = 0L; can_upd = false;
+#ifdef _WINDOWS
+ iMenuHeight = 0;
+#else
+ iMenuHeight = 25;
+#endif
+ svgAttr = svgScript = currPath = IniFile = 0L;
+ File1 = File2 = File3 = File4 = File5 = File6 = 0L;
+ if(fmt_date = (char*)malloc(20)) rlp_strcpy(fmt_date, 20, "Z.V.Y");
+ if(fmt_time = (char*)malloc(20)) rlp_strcpy(fmt_time, 20, "H:M:S");
+ if(fmt_datetime = (char*)malloc(20)) rlp_strcpy(fmt_datetime, 20, "Z.V.Y H:M:S");
+}
+
+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);
+ if(fmt_date) free(fmt_date); if(fmt_time) free(fmt_time);
+ if(fmt_datetime) free(fmt_datetime);
+}
+
+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 = _TXH; 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 = _TXH; 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:
+#ifdef _WINDOWS
+ RetVal = 4.5*ss_txt; break;
+#else
+ RetVal = 4.5*ss_txt*0.7; break;
+#endif
+ case SIZE_RRECT_RAD:
+ return rrect_rad ? *rrect_rad : GetSize(SIZE_SYMBOL);
+ case SIZE_SCALE: return 1.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, j;
+
+ if(path && (tmp_path=(char*)malloc((i=(int)strlen(path))+10))){
+ rlp_strcpy(tmp_path, i+1, path);
+ for(j = i ; i > 0 && tmp_path[i] != '/' && tmp_path[i] != '\\'; i--);
+ tmp_path[i] = 0;
+ if(currPath) free(currPath);
+ if(tmp_path[0]) currPath = (char*)memdup(tmp_path, i+1, 0);
+ else currPath = 0L;
+ rlp_strcpy(tmp_path, j+1, 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);
+}
+
+void
+Default::Idle(int cmd)
+{
+ if(cmd == CMD_UPDATE && can_upd && out_upd) {
+ IncrementMinMaxRect(&rec_upd, 6);
+ if(rec_upd.left < 0) rec_upd.left = 0;
+ if(rec_upd.top < 0) rec_upd.top = 0;
+ out_upd->UpdateRect(&rec_upd, false);
+ }
+ if(cmd == CMD_FLUSH) {
+ }
+ out_upd = 0L; can_upd = false;
+}
+
+void
+Default::UpdRect(anyOutput *o, int x1, int y1, int x2, int y2)
+{
+ if(out_upd && o != out_upd) Idle(CMD_UPDATE);
+ out_upd = o;
+ if(can_upd){
+ UpdAdd(o, x1, y1); UpdAdd(o, x2, y2);
+ }
+ else SetMinMaxRect(&rec_upd, x1, y1, x2, y2);
+ can_upd = true;
+}
+
+void
+Default::UpdAdd(anyOutput * o, int x, int y)
+{
+ if(o == out_upd && can_upd)
+ UpdateMinMaxRect(&rec_upd, x, y);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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 = -1;
+#ifdef USE_WIN_SECURE
+ else if(_sopen_s(&iFile, name, O_BINARY, 0x40, S_IWRITE) || iFile < 0) return false;
+#else
+ else if(-1 ==(iFile = open(name, O_BINARY))) return false;
+#endif
+ Cache = (unsigned char *)malloc((unsigned)(CharCacheSize + 1));
+ if(Cache) return true;
+ return false;
+}
+
+void
+ReadCache::Close()
+{
+#ifdef USE_WIN_SECURE
+ if(iFile >= 0) _close(iFile);
+#else
+ if(iFile >= 0) close(iFile);
+#endif
+ if(Cache) free(Cache); Cache = 0L;
+}
+
+unsigned char
+ReadCache::Getc()
+{
+ if(Cache){
+ if(idx < max) return (last = Cache[idx++]);
+ else {
+ do {
+#ifdef USE_WIN_SECURE
+ max = _read(iFile, Cache, CharCacheSize);
+#else
+ max = read(iFile, Cache, CharCacheSize);
+#endif
+ 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) {
+#ifdef USE_WIN_SECURE
+ max = _read(iFile, Cache, CharCacheSize);
+#else
+ max = read(iFile, Cache, CharCacheSize);
+#endif
+ 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) {
+ max = (int)strlen((char*)ptr);
+ Cache = (unsigned char*) memdup(ptr, max+1, 0);
+ 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; busy = false;
+ 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;
+}
+
+bool
+UndoObj::isEmpty(anyOutput *o)
+{
+ int i;
+
+ if(!buffers) return true;
+ for (i = 0; i < ndisp; i++) if(buffers[i]){
+ if(o && buffers[i]->disp == o ) {
+ if(buffers[i]->count > 0) return false;
+ else return true;
+ }
+ else if(!o && buffers[i]->count > 0) return false;
+ }
+ return true;
+}
+
+//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;
+
+ InvalidateOutput(o); //kill text cursor and animated rectangle
+ if(o && buffers) {
+ for(i = 0, c_buf = -1; i < ndisp; i++) {
+ if(buffers[i] && buffers[i]->disp == o) {
+ c_buf = i; break;
+ }
+ }
+ if(c_buf < 0) 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[c_buf]); buffers[c_buf] = 0L;
+ }
+ if(ldisp && o == cdisp) SetDisp(ldisp);
+ else cdisp = 0L;
+}
+
+//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(anyOutput *o)
+{
+ int idx;
+
+ if(o) {
+ SetDisp(o);
+ 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; HideCopyMark();
+ 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)--;
+ busy = true;
+ 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];
+ }
+ if(((EtBuff*)buff[idx]->data)->DaO) (((EtBuff*)buff[idx]->data)->DaO)->SetText(((EtBuff*)buff[idx]->data)->row,
+ ((EtBuff*)buff[idx]->data)->col, ((EtBuff*)buff[idx]->data)->txt);
+ else ((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_TEXTBUF:
+ if(buff[idx]->loc && buff[idx]->data) {
+ target = *((TextBuff*)buff[idx]->data)->pbuff;
+ target = ((TextBuff*)buff[idx]->data)->buff;
+ if(*((TextBuff*)buff[idx]->data)->pbuff) free(*((TextBuff*)buff[idx]->data)->pbuff);
+ *(((TextBuff*)buff[idx]->data)->pbuff) = ((TextBuff*)buff[idx]->data)->buff;
+ *(((TextBuff*)buff[idx]->data)->psize) = ((TextBuff*)buff[idx]->data)->size;
+ *(((TextBuff*)buff[idx]->data)->ppos) = ((TextBuff*)buff[idx]->data)->pos;
+ }
+ 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; if(gol) 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_POINT:
+ memcpy(buff[idx]->loc, buff[idx]->data, sizeof(POINT));
+ free(buff[idx]->data); break;
+ case UNDO_VOIDPTR:
+ *buff[idx]->loc = buff[idx]->data; break;
+ case UNDO_VALINT:
+ *((int*)(buff[idx]->loc)) = *((int*)(buff[idx]->data));
+ free(buff[idx]->data); break;
+ case UNDO_VALLONG:
+ *((long*)(buff[idx]->loc)) = *((long*)(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) && buff[idx]->data)
+ rlp_strcpy ((char*)(*buff[idx]->loc), 100, (char*)(buff[idx]->data));
+ else if(*(buff[idx]->loc))((char*)*(buff[idx]->loc))[0] = 0;
+ if(buff[idx]->data) free(buff[idx]->data);
+ CurrGO = buff[idx]->owner; 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");
+ }
+ busy = false;
+}
+
+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;
+ HideCopyMark();
+ if(o){
+ SetDisp(o); o->HideMark();
+ }
+ if(CurrGO == *go) CurrGO = 0L;
+ if((*go)->Id == GO_POLYLINE || (*go)->Id == GO_POLYGON || (*go)->Id == GO_BEZIER){
+ 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 = *go) {
+ 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::Point(GraphObj *parent, POINT *pt, anyOutput * o, DWORD flags)
+{
+ void *ptr;
+
+ if(o) SetDisp(o);
+ if(!(ptr = memdup(pt, sizeof(POINT), 0))) return;
+ if(0 > NewItem(UNDO_POINT, flags, parent, ptr, (void**)pt)) free(ptr);
+}
+
+void
+UndoObj::VoidPtr(GraphObj *parent, void **pptr, void *ptr, anyOutput *o, DWORD flags)
+{
+ if(o) SetDisp(o);
+ NewItem(UNDO_VOIDPTR, flags, parent, ptr, pptr);
+}
+
+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::ValLong(GraphObj *parent, long *val, DWORD flags)
+{
+ void *ptr;
+
+ if(!(ptr = memdup(val, sizeof(long), 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);
+}
+
+int
+UndoObj::String(GraphObj *go, char **s, DWORD flags)
+{
+ char *ptr;
+ int iret;
+
+ if(s && *s && *(*s)){
+ iret = (int)strlen(*(s));
+ ptr = (char*)memdup(*(s), iret+1, 0);
+ }
+ else {
+ ptr = 0L; iret = 0;
+ }
+ if(0 > NewItem(UNDO_STRING, flags, go, ptr, (void**)s)) if(ptr) free(ptr);
+ return iret;
+}
+
+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 && td->text[0]) ptr->text = (char*)memdup(td->text, (int)strlen(td->text)+1, 0);
+ if(0 > NewItem(UNDO_TEXTDEF, flags, go, ptr, (void**)td)){
+ if(ptr->text) free(ptr->text); 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, RECT *rc, DWORD flags)
+{
+ StrData *save;
+
+ if(!go || !d) return;
+ if(o) SetDisp(o);
+ if(!(save = new StrData(d, rc))) 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 = (char*)memdup(text, (int)strlen(text)+1, 0);
+ ptr->cur = cur; ptr->m1 = m1; ptr->m2 = m2;
+ ptr->vcur = *cur; ptr->vm1 = *m1; ptr->vm2 = *m2;
+ ptr->row = et->row; ptr->col = et->col;
+ ptr->DaO = (DataObj*)et->parent;
+ if(0 > NewItem(UNDO_ET, flags, 0L, ptr, (void**)et)) {
+ if(ptr->txt)free (ptr->txt); free(ptr);
+ }
+ }
+ SetDisp(o_save);
+ }
+}
+
+void
+UndoObj::TextBuffer(GraphObj *parent, int *psize, int *ppos, unsigned char **pbuff, DWORD flags, anyOutput *o)
+{
+ TextBuff *ptr;
+
+ if(o) SetDisp(o);
+ if(!parent || !psize || !ppos || !pbuff) return;
+ if(ptr = (TextBuff*)calloc(1, sizeof(TextBuff))) {
+ ptr->size = *psize; ptr->psize = psize;
+ ptr->pos = *ppos; ptr->ppos = ppos;
+ ptr->pbuff = pbuff; ptr->buff = (unsigned char*)memdup(*pbuff, ptr->size, 0);
+ if(0 > NewItem(UNDO_TEXTBUF, flags, parent, ptr, (void**)pbuff)) {
+ if(ptr->buff) free(ptr->buff); free(ptr);
+ }
+ }
+}
+
+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);
+ free((*inf)->data);
+ break;
+ case UNDO_TEXTBUF:
+ if(((TextBuff*)((*inf)->data))->buff) free(((TextBuff*)((*inf)->data))->buff);
+ free((*inf)->data);
+ 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:
+ case UNDO_POINT: case UNDO_VALLONG:
+ 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, false);
+ 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
index ca15ccd..f83236a 100755
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -1,2494 +1,2528 @@
-//Utils.cpp, Copyright (c) 2000-2007 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 <errno.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;
- if(logStep > 0.8) Step = 10.0;
- else if(logStep > 0.5) Step = 5.0;
- else if(logStep > 0.2) Step = 2.0;
- else Step = 1.0;
- Step *= pow(10.0, Magn); HiVal = LoVal = Step * floor(axis->min/Step);
- axis->max += (diff * 0.05);
- while(HiVal < axis->max) HiVal += Step;
- if((axis->flags & AXIS_LOG) == AXIS_LOG) {
- if (LoVal > defs.min4log) axis->min = LoVal;
- if ((LoVal + Step) > defs.min4log && (LoVal + Step) < axis->min) axis->min = LoVal+Step;
- }
- else axis->min = LoVal;
- axis->max = HiVal; axis->Start = axis->min; axis->Step = Step;
-}
-
-void NiceStep(AxisDEF *axis, int nTick)
-{
- double diff, d, logStep, Step, Magn;
- int i;
-
- diff = axis->max - axis->min; d = axis->Step != 0.0 ? diff/axis->Step : HUGE_VAL;
- if((d - floor(d)) < 0.1 && axis->Step != 0.0 && diff/axis->Step < 12.0)return;
- 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;
- if(logStep > 0.8) Step = 10.0;
- else if(logStep > 0.5) Step = 5.0;
- else if(logStep > 0.2) Step = 2.0;
- else Step = 1.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;
- }
- lv = axis->min > defs.min4log ? axis->min : defs.min4log;
- 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
-//----------------------------------------------------------------------------
-//remove leading/trailing whitespace
-char *str_ltrim(char *str) {
- int i, j;
-
- if(!str || !str[0]) return str;
- for(i = 0; str[i] && str[i] <= ' '; i++);
- for(j = 0; str[i]; str[j++] = str[i++]);
- str[j++] = '\0'; return str;
- }
-
-char *str_rtrim(char *str) {
- size_t i;
-
- i = strlen(str);
- while(i > 0 && str[i-1] <= ' ') str[--i] = '\0';
- return str;
-}
-
-char *str_trim(char *str) {
- str = str_ltrim(str); return str_rtrim(str);
-}
-
-//remove leading and tailing quotatation
-void rmquot(char *str)
-{
- size_t i, len;
- char c;
-
- if(str && str[0] && (*str == '"' || *str == '\'')) {
- len = strlen(str); c = *str;
- if(str[len-1] == c) {
- str[len-1] = 0;
- for(i = 1; i < len; str[i-1] = str[i++]);
- }
- }
-}
-
-int strpos(char *needle, char *haystack)
-{
- int i, j;
-
- if(!needle || !needle[0] || !haystack || !haystack[0]) return -1;
- for(i = j = 0; haystack[i]; i++, j=0) {
- if(haystack[i] == needle[0]) for (j = 1; haystack[i+j]; j++) {
- if(needle[j] != haystack[i+j]) break;
- }
- if(j && !needle[j]) return i;
- }
- return -1;
-}
-
-char *strreplace(char *needle, char *replace, char *haystack)
-{
- static char *result = 0L;
- static size_t reslen = 0;
- size_t i, j, k, l;
-
- if(!needle || !needle[0] || !haystack || !haystack[0]) return result;
- if(!result) result = (char*)malloc(reslen = 100);
- result[0] = 0; l = strlen(needle);
- for(i = j = k = 0; haystack[i]; i++, j=0) {
- if(haystack[i] == needle[0]) for (j = 1; haystack[i+j]; j++) {
- if(needle[j] != haystack[i+j]) break;
- }
- if(j && !needle[j]) {
- if(replace && replace[0]) {
- if(reslen < (i + (int)strlen(replace) + 10)) {
- result = (char*)realloc(result, reslen += 100);
- }
- for(j = 0; replace[j]; j++) result[k++] = replace[j];
- }
- i += (l-1);
- }
- else result[k++] = haystack[i];
- }
- result[k++] = 0;
- return result;
-}
-
-char *substr(char *text, int pos1, int pos2)
-{
- static char *result = 0L;
- static size_t reslen = 0;
- int i, j;
- size_t l;
-
- if(!text || !text[0]) return 0L;
- l = strlen(text);
- if(pos1 < 0) pos1 = 0; if(pos2 < pos1) pos2 = (int)(l+1);
- if(!result) result = (char*)malloc(reslen = 100);
- while (reslen < l) result = (char*) realloc(result, reslen += 100);
- for(i = 0; i < pos1 && text[i]; i++);
- for(j = 0; i <= pos2 && text[i]; result[j++] = text[i++]);
- result[j] = 0;
- return result;
-}
-
-//copy string in src to dest, returning the stringlength of src
-// seek better solution for long strings
-int rlp_strcpy(char*dest, int size, char*src)
-{
- int i;
-
- if(dest && src) {
- for(i = 0; i < size; i++) {
- if(!(dest[i] = src[i])) return i;
- }
- dest[i-1] = 0;
- return i-1;
- }
- return 0;
-}
-
-// restyle formula
-void ReshapeFormula(char **text)
-{
- int i, j, l;
-
- if(!text || !*text || !**text) return;
- l = (int)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(j && j <= l && TmpTxt[0]) {
- rlp_strcpy(*text, l+1, TmpTxt);
- }
-}
-
-//translate anyResult to output format
-void TranslateResult(anyResult *res)
-{
- static char tr_text[80];
-
- switch (res->type) {
- case ET_VALUE:
- if(res->value == HUGE_VAL) rlp_strcpy(tr_text, 80, "inf");
- else if(res->value == -HUGE_VAL) rlp_strcpy(tr_text, 80, "-inf");
-#ifdef USE_WIN_SECURE
- else sprintf_s(tr_text, 80, "%g", res->value);
-#else
- else sprintf(tr_text, "%g", res->value);
-#endif
- res->text = tr_text; return;
- case ET_BOOL:
- rlp_strcpy(tr_text, 80, ((int)res->value) ? (char*)"true" : (char*)"false");
- res->text = tr_text; return;
- case ET_DATE:
- rlp_strcpy(tr_text, 80, value_date(res->value, defs.fmt_date));
- res->text = tr_text; return;
- case ET_TIME:
- rlp_strcpy(tr_text, 80, value_date(res->value, defs.fmt_time));
- res->text = tr_text; return;
- case ET_DATETIME:
- rlp_strcpy(tr_text, 80, value_date(res->value, defs.fmt_datetime));
- res->text = tr_text; return;
- case ET_TEXT:
- if(res->text && res->text[0]) return;
- }
- if(!(res->text)) res->text="";
-}
-
-//remove invalid tag combinations from string
-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=(int)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)
-{
-#ifdef USE_WIN_SECURE
- sprintf_s(buff, 20, " %g", val);
-#else
- sprintf(buff, " %g", val);
-#endif
- 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 = (char*)memdup(txt, (int)strlen(txt)+1, 0))){
- Nat2Int(tmp);
- //the return value of sscanf only roughly identifies a number
-#ifdef USE_WIN_SECURE
- if(!sscanf_s(tmp,"%lf", val)){
-#else
- if(!sscanf(tmp,"%lf", val)){
-#endif
- free(tmp);
- return false;
- }
- free(tmp);
- return true;
- }
- }
- return false;
-}
-
-void RmTrail(char *txt)
-{
- int i;
-
- i = (int)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 *NiceTime(double val)
-{
- rlp_datetime dt;
-
- parse_datevalue(&dt, val);
- if(dt.year > 1905) {
- if(dt.hours) return date2text(&dt, defs.fmt_datetime);
- else return date2text(&dt, defs.fmt_date);
- }
- else return date2text(&dt, defs.fmt_time);
-}
-
-char *Int2ColLabel(int nr1, bool uc)
-{
- static char RetTxt[12];
- int i, j, nr = nr1;
- char base = uc ? 'A' : 'a';
-
-#ifdef USE_WIN_SECURE
- sprintf_s(RetTxt+8, 4, "%c\0", base + (nr %26));
-#else
- sprintf(RetTxt+8, "%c\0", base + (nr %26));
-#endif
- 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;
-}
-
-char *mkCellRef(int row, int col)
-{
- static char RetTxt[20];
-
-#ifdef USE_WIN_SECURE
- sprintf_s(RetTxt, 20, "%s%d", Int2ColLabel(col, false), row+1);
-#else
- sprintf(RetTxt, "%s%d", Int2ColLabel(col, false), row+1);
-#endif
- return RetTxt;
-}
-
-char *mkRangeRef(int r1, int c1, int r2, int c2)
-{
- static char RetTxt[40];
- int cb;
-
- cb = rlp_strcpy(RetTxt, 20, mkCellRef(r1, c1));
- RetTxt[cb++] = ':';
- rlp_strcpy(RetTxt+cb, 40-cb, mkCellRef(r2, c2));
- return RetTxt;
-}
-//convert strings to XML specifications
-//this offers a limited support for special characters
-char *str2xml(char *str, bool bGreek)
-{
- int i, j;
- wchar_t wc;
-
- if(!str) return 0L;
- for(i = j = 0; str[i] && j < 4090; i++) {
- switch(str[i]) {
- case '"':
- j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, """);
- break;
- case '&':
- j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, "&");
- break;
- case '<':
- j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, "<");
- break;
- case '>':
- j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, ">");
- break;
- default:
-#ifdef USE_WIN_SECURE
- if(bGreek && str[i] >= 'A' && str[i] <= 'Z') j += sprintf_s(TmpTxt+j, 20, "&#%d;", str[i] - 'A' + 0x391);
- else if(bGreek && str[i] >= 'a' && str[i] <= 'z') j += sprintf_s(TmpTxt+j, 20, "&#%d;", str[i] - 'a' + 0x3B1);
-#else
- if(bGreek && str[i] >= 'A' && str[i] <= 'Z') j += sprintf(TmpTxt+j, "&#%d;", str[i] - 'A' + 0x391);
- else if(bGreek && str[i] >= 'a' && str[i] <= 'z') j += sprintf(TmpTxt+j, "&#%d;", str[i] - 'a' + 0x3B1);
-#endif
- else if((unsigned char)str[i] <= 127) TmpTxt[j++]=str[i];
- else {
- if(mbtowc(&wc, str+i, 1) >0)
-#ifdef USE_WIN_SECURE
- j += sprintf_s(TmpTxt+j, TMP_TXT_SIZE-j, "&#%d;", ((unsigned short)wc));
-#else
- j += sprintf(TmpTxt+j, "&#%d;", ((unsigned short)wc));
-#endif
- }
- }
- }
- TmpTxt[j] = 0;
- return(TmpTxt);
-}
-
-// split string str into array of strings using sep as separator
-// return number of lines created in nl
-static char *split_buf = 0L;
-static int split_buf_size, split_buf_pos;
-char **split(char *str, char sep, int *nl)
-{
- int i, j, l, ns;
- char **ptr;
-
- if(!str || !str[0] || !sep) return 0L;
- split_buf_pos = 0;
- add_to_buff(&split_buf, &split_buf_pos, &split_buf_size, str, 0);
- if(!split_buf || !split_buf_pos) return 0L;
- for(i = ns = 0; i < split_buf_pos; i++) if(split_buf[i] == sep) ns++;
- if(!(ptr = (char**)calloc(ns+2, sizeof(char*)))) return 0L;
- for(i = j = l = 0; i < split_buf_pos; i++) {
- if(split_buf[i] == sep) {
- split_buf[i] = 0;
- ptr[l++] = (char*)memdup(split_buf+j, (int)strlen(split_buf+j)+1, 0);
- j = i+1;
- }
- }
- ptr[l++] = (char*)memdup(split_buf+j, (int)strlen(split_buf+j)+1, 0);
- if(nl) *nl = l;
- return ptr;
-}
-
-char *fit_num_rect(anyOutput *o, int max_width, char *num_str)
-{
- int i, j, k, w, h, slen;
- char mant[30], expo[30], fmt[20];
- double num;
-
- o->oGetTextExtent(num_str, slen = (int)strlen(num_str), &w, &h);
- if(w < (max_width-5)) return num_str;
- //first try to remove leading zero from exponent
- for(i = 0; i < slen; i++) if(num_str[i] == 'e') break;
- if(num_str[i] == 'e') while (num_str[i+2] == '0') {
- for(j = i+2; num_str[j]; j++) num_str[j] = num_str[j+1];
- o->oGetTextExtent(num_str, slen = (int)strlen(num_str), &w, &h);
- if(w < (max_width-5)) return num_str;
- }
- //no success: reduce the number of digit by rounding
- for(i = k = 0; i <= slen; i++){
- if(num_str[i] == '.') k = i;
- if((mant[i] = num_str[i]) == 'e' || mant[i] == 0) break;
- }
- if(num_str[i] =='e') mant[i] = 0; k = i - k-1;
- for(j = 0; num_str[i]; j++, i++) expo[j] = num_str[i]; expo[j] = 0;
-#ifdef USE_WIN_SECURE
- sscanf_s(mant, "%lf", &num);
-#else
- sscanf(mant, "%lf", &num);
-#endif
- if(k >0) do {
-#ifdef USE_WIN_SECURE
- sprintf_s(fmt, 20, "%%.%dlf%s", k, expo);
- slen = sprintf_s(num_str, 60, fmt, num); //num_str is much longer than 60
-#else
- sprintf(fmt, "%%.%dlf%s", k, expo);
- slen = sprintf(num_str, fmt, num);
-#endif
- k--;
- o->oGetTextExtent(num_str, slen, &w, &h);
- if(w < (max_width-5)) return num_str;
- }while (k >= 0);
- //cannot fit: return hash marks instead
- for(i = w = 0; w < (max_width-5) && i < 11; i++) {
- rlp_strcpy(num_str, i+2, "##########");
- o->oGetTextExtent(num_str, i+1, &w, &h);
- }
- num_str[i-1] = 0; return num_str;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// utilities to add a line or number to a text buffer: memory file
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-void add_to_buff(char** dest, int *pos, int *csize, char *txt, int len)
-{
- if(!len)len = (int)strlen(txt);
- if(!len) return;
- if((*pos+len+1)>= *csize) {
- *csize += 1000;
- while(*csize < (*pos+len+1)) *csize += 1000;
- *dest = (char*)realloc(*dest, *csize);
- }
- if(*dest) {
- *pos += rlp_strcpy(*dest+*pos, len+1, txt);
- }
-}
-
-void add_int_to_buff(char** dest, int *pos, int *csize, int value, bool lsp, int ndig)
-{
- int len;
- char txt[40];
-
-#ifdef USE_WIN_SECURE
- len = sprintf_s(txt, 40, lsp ? " %d" : "%d", value);
-#else
- len = sprintf(txt, lsp ? " %d" : "%d", value);
-#endif
- add_to_buff(dest, pos, csize, txt, len);
-}
-
-void add_dbl_to_buff(char** dest, int *pos, int *csize, double value, bool lsp)
-{
- int len;
- char txt[40];
-
-#ifdef USE_WIN_SECURE
- len = sprintf_s(txt, 40, lsp ? " %g" : "%g", value);
-#else
- len = sprintf(txt, lsp ? " %g" : "%g", value);
-#endif
- add_to_buff(dest, pos, csize, txt, len);
-}
-
-void add_hex_to_buff(char** dest, int *pos, int *csize, DWORD value, bool lsp)
-{
- int len;
- char txt[40];
-
- if(value) {
-#ifdef USE_WIN_SECURE
- len = sprintf_s(txt, 40, lsp ? " 0x%08x" : "0x%08x", value);
-#else
- len = sprintf(txt, lsp ? " 0x%08x" : "0x%08x", value);
-#endif
- add_to_buff(dest, pos, csize, txt, len);
- }
- else if(lsp) add_to_buff(dest, pos, csize, " 0x0", 4);
- else add_to_buff(dest, pos, csize, "0x0", 3);
-}
-
-//----------------------------------------------------------------------------
-// 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 Bezier polygon
-void DrawBezier(long *cp, POINT *pts, POINT p0, POINT p1, POINT p2, POINT p3, int depth)
-{
-#define MIN_SEG 11
-#define MAX_DEPTH 5
- int i;
- POINT np, p01, p12, p23, p012, p123, p0123;
- POINT *ap[] = {&p0, &p1, &p2, &p3};
-
- depth ++;
- if(depth > MAX_DEPTH) {
- for(i= 0; i < 4; i++) {
- np.x = (*ap[i]).x >> 2; np.y = (*ap[i]).y >> 2;
- AddToPolygon(cp, pts, &np);
- }
- return;
- }
- else if(depth == 1) for(i=0; i < 4; i++) {
- (*ap[i]).x <<= 2; (*ap[i]).y <<= 2;
- }
- p01.x = (p0.x + p1.x) >> 1; p01.y = (p0.y + p1.y) >> 1;
- p12.x = (p1.x + p2.x) >> 1; p12.y = (p1.y + p2.y) >> 1;
- p23.x = (p2.x + p3.x) >> 1; p23.y = (p2.y + p3.y) >> 1;
- p012.x = (p01.x + p12.x) >> 1; p012.y = (p01.y + p12.y) >> 1;
- p123.x = (p12.x + p23.x) >> 1; p123.y = (p12.y + p23.y) >> 1;
- p0123.x = (p012.x + p123.x) >> 1; p0123.y = (p012.y + p123.y) >> 1;
- if(abs(p0.x - p0123.x)> MIN_SEG || abs(p0.y - p0123.y)> MIN_SEG) {
- DrawBezier(cp, pts, p0, p01, p012, p0123, depth); //recursion: refine
- }
- else {
- DrawBezier(cp, pts, p0, p01, p012, p0123, MAX_DEPTH); //recursion: store data
- }
- if(abs(p3.x - p0123.x)> MIN_SEG || abs(p3.y - p0123.y)> MIN_SEG) {
- DrawBezier(cp, pts, p0123, p123, p23, p3, depth); //recursion: refine
- }
- else {
- DrawBezier(cp, pts, p0123, p123, p23, p3, MAX_DEPTH); //recursion: store data
- }
-#undef MAX_DEPTH
-#undef MIN_SEG
-}
-
-//----------------------------------------------------------------------------
-// create a Bezier spline through data points
-static void ipol_curve(lfPOINT *p1, lfPOINT *p2, lfPOINT *p3, lfPOINT *cp1, lfPOINT *cp2)
-{
- double dx, dy, l;
- lfPOINT tHat;
-
- tHat.fx = p3->fx - p1->fx; tHat.fy = p3->fy - p1->fy;
- l = sqrt(tHat.fx * tHat.fx + tHat.fy * tHat.fy);
- tHat.fx /= l; tHat.fy /= l;
- cp1->fx = cp2->fx = p2->fx; cp1->fy = cp2->fy = p2->fy;
- dx = p3->fx - p2->fx; dy = p3->fy - p2->fy; l = sqrt(dx*dx + dy*dy)/3.0;
- cp2->fx += (tHat.fx * l); cp2->fy += (tHat.fy *l);
- dx = p2->fx - p1->fx; dy = p2->fy - p1->fy; l = sqrt(dx*dx + dy*dy)/3.0;
- cp1->fx -= (tHat.fx * l); cp1->fy -= (tHat.fy *l);
-}
-
-static void mirr_vecvec(lfPOINT *a0, lfPOINT *a1, lfPOINT *v1)
-{
- double dx, dy, as, ac, vs, vc, s, c, l;
- lfPOINT sol1, sol2;
-
- //mirror vector a0 -> v1 by rotation around vector a0 -> a1
- dx = a1->fx - a0->fx; dy = a1->fy - a0->fy;
- l = sqrt(dx*dx + dy*dy); as = dy/l; ac = dx/l;
- dx = v1->fx - a0->fx; dy = v1->fy - a0->fy;
- l = sqrt(dx*dx + dy*dy); vs = dy/l; vc = dx/l;
- //calculate cw and ccw solution
- s = sin((asin(as)-asin(vs))*2.0); c = cos((acos(ac)-acos(vc))*2.0);
- sol1.fx = dx * c + dy * s + a0->fx; sol1.fy = dy * c - dx * s + a0->fy;
- s = sin((asin(as)-asin(-vs))*2.0); c = cos((acos(ac)-acos(-vc))*2.0);
- sol2.fx = dx * c + dy * s + a0->fx; sol2.fy = dy * c - dx * s + a0->fy;
- //get better solution
- dx = sol1.fx - a1->fx; dy = sol1.fy - a1->fy;
- l = sqrt(dx*dx + dy*dy);
- dx = sol2.fx - a1->fx; dy = sol2.fy - a1->fy;
- if( l < sqrt(dx*dx + dy*dy)) {
- v1->fx = sol1.fx; v1->fy = sol1.fy;
- }
- else {
- v1->fx = sol2.fx; v1->fy = sol2.fy;
- }
-}
-
-int mkCurve(lfPOINT *src, int n1, lfPOINT **dst, bool bClosed)
-{
- int i, j, iret;
-
- if(!src || n1 < 3) return 0;
- if(!(*dst = (lfPOINT*)malloc((n1*3+2) * sizeof(lfPOINT))))return 0;
- for(i = j = iret = 0; i < n1; i++, j += 3) {
- (*dst)[j].fx = src[i].fx; (*dst)[j].fy = src[i].fy;
- if(i && i < (n1-1)){
- ipol_curve(&src[i-1], &src[i], &src[i+1], *dst+j-1, *dst+j+1);
- }
- else if(i) {
- iret = j+1; break;
- }
- }
- if(bClosed && iret >2) {
- if((*dst)[j].fx != (*dst)[0].fx || (*dst)[j].fy != (*dst)[0].fy) {
- j += 3; iret += 3;
- (*dst)[j].fx = (*dst)[0].fx; (*dst)[j].fy = (*dst)[0].fy;
- }
- if(j < 6) {
- free(*dst); *dst = 0L; return 0;
- }
- ipol_curve(*dst+j-3, *dst+j, *dst+3, *dst+j-1, *dst+1);
- ipol_curve(*dst+j-6, *dst+j-3, *dst+j, *dst+j-4, *dst+j-2);
- }
- else if(!bClosed && iret>3) {
- (*dst)[1].fx = (*dst)[0].fx + (*dst)[3].fx - (*dst)[2].fx;
- (*dst)[1].fy = (*dst)[0].fy + (*dst)[3].fy - (*dst)[2].fy;
- mirr_vecvec(*dst, *dst+3, *dst+1);
- (*dst)[j-1].fx = (*dst)[j].fx + (*dst)[j-3].fx - (*dst)[j-2].fx;
- (*dst)[j-1].fy = (*dst)[j].fy + (*dst)[j-3].fy - (*dst)[j-2].fy;
- mirr_vecvec(*dst+j, *dst+j-3, *dst+j-1);
- }
- else {
- free(*dst); *dst = 0L; return 0;
- }
- return iret;
-}
-
-//----------------------------------------------------------------------------
-// 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+4))) 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)
-{
- int i;
- LineDEF OldLine;
-
- memcpy(&OldLine, Line, sizeof(LineDEF));
- if(OldLine.width <= 0.0001) OldLine.width = 0.0001;
- for(i = 0; o->un2fiy(OldLine.width) < 1.0 && i < 50; i++) OldLine.width *= 2.0;
- OldLine.color = mark ? Line->color : 0x00ffffffL;
- 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;
- case GO_FUNC3D: delete((Func3D*)go); break;
- case GO_XYSTAT: delete((xyStat*)go); break;
- case GO_FITFUNC3D: delete((FitFunc3D*)go); break;
- case GO_BEZIER: delete((Bezier*)go); break;
- case GO_TEXTFRAME: delete((TextFrame*)go); break;
- case GO_NORMQUANT: delete((NormQuant*)go); break;
- default:
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "Cannot delete Object\nwith Id %ld", go->Id);
-#else
- sprintf(TmpTxt, "Cannot delete Object\nwith Id %ld", go->Id);
-#endif
- ErrorBox(TmpTxt);
- //we do not delete the object, probably we recover
- }
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//Delete a graphic object from a list
-bool DeleteGOL(GraphObj ***gol, long n, GraphObj *go, anyOutput *o)
-{
- long i;
- int c;
- GraphObj **g, *p;
-
- if(!gol || !(*gol) || !go || !n) return false;
- for (i = 0, c = 0, g = *gol; i < n; i++, g++) {
- if(*g) {
- c++;
- if(*g == go) {
- p = (*g)->parent;
- if(o) o->HideMark();
- Undo.DeleteGO(g, 0L, o);
- if(c == 1) {
- for (g++, i++ ;i < n; i++, g++) {
- if(*g) return true;
- }
- if(p) Undo.DropMemory(p, (void**) gol, UNDO_CONTINUE);
- }
- return true;
- }
- }
- }
- return false;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//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;
- rlp_strcpy(Name, 512,FileName);
- i = (int)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 {
-#ifdef USE_WIN_SECURE
- sprintf_s(ext, 6, ".%03d", i);
- sprintf_s(TmpFileName, 512, "%s%s", Name, ext);
- if(!(fopen_s(&TheFile, TmpFileName, "r"))) {
- fclose(TheFile);
- }
- else break;
-#else
- sprintf(ext, ".%03d", i);
- sprintf(TmpFileName, "%s%s", Name, ext);
- if((TheFile = fopen(TmpFileName, "r"))) fclose(TheFile);
-#endif
- 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;
-
-#ifdef USE_WIN_SECURE
- if(fopen_s(&TheFile, FileName, "r")) return false;
-#else
- if(0L ==(TheFile = fopen(FileName, "r"))) return false;
-#endif
- 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;
-
-#ifdef USE_WIN_SECURE
- if(fopen_s(&TheFile, FileName, "r")) return false;
-#else
- if(0L ==(TheFile = fopen(FileName, "r"))) return false;
-#endif
- 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;
-
-#ifdef USE_WIN_SECURE
- if(ENOENT == fopen_s(&TheFile, FileName, "r")) return false;
-#else
- if(0L ==(TheFile = fopen(FileName, "r"))) {
- if(errno == ENOENT) return false;
- return true;
- }
-#endif
- fclose(TheFile);
- return true;
-}
-
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//check Object for certain properties
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-bool IsPlot3D(GraphObj *g)
-{
- if(g && (g->Id == GO_PLOT3D || g->Id == GO_FUNC3D || g->Id == GO_FITFUNC3D)) return true;
- return false;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//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
-//Ref: Corman T.H., Leiserson C.E. & Rivest R.L. (1990) Hash Functions.
-// in: Introduction to Algorithms (MIT Press & McGraw-Hill)
-// ISBN 0-262-03141-8 and ISBN 0-07-013143-0, pp. 226ff
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-unsigned int HashValue(unsigned char *str)
-{
- unsigned int i = 0, ret = 0;
-
- if(!str || !str[0]) return 0;
- do {
- if(str[i] > 32) ret = ((str[i]-32) + (ret <<2));
- i++;
- }while(str[i]);
- return ret;
-}
-
-unsigned int Hash2(unsigned char * str)
-{
- unsigned int i = 0, ret = 0, c;
-
- if(!str) return 0;
- do {
- c = str[i++];
- ret = ((ret * c)<<2) | c;
- }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;
-}
-
-DWORD CheckNewString(char **loc, char *s_old, char *s_new, GraphObj *par, DWORD flags)
-{
- int ocb, ncb, cb;
-
- if(s_old && s_new) {
- if(!strcmp(s_old, s_new)) return flags;
- ocb = (int)strlen(s_old); ncb = (int)strlen(s_new);
- cb = ncb > ocb ? ncb : ocb;
- if(cb > ocb) {
- *loc = (char*)realloc(*loc, cb * sizeof(char)+1);
- }
- Undo.String(par, loc, flags); flags |= UNDO_CONTINUE;
- if(*loc) rlp_strcpy(*loc, cb+1, s_new);
- }
- else if(!s_old && s_new && s_new[0]) {
- Undo.String(par, loc, flags); flags |= UNDO_CONTINUE;
- *loc = (char *)memdup(s_new, (int)strlen(s_new) +1, 0);
- }
- else if(s_old && s_old[0] && !s_new) {
- Undo.String(par, loc, flags); flags |= UNDO_CONTINUE;
- if(*loc) *loc[0] = 0;
- }
- 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
-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
-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;
-}
+//Utils.cpp, Copyright (c) 2000-2008 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 <errno.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;
+ if(logStep > 0.8) Step = 10.0;
+ else if(logStep > 0.5) Step = 5.0;
+ else if(logStep > 0.2) Step = 2.0;
+ else Step = 1.0;
+ Step *= pow(10.0, Magn); HiVal = LoVal = Step * floor(axis->min/Step);
+ axis->max += (diff * 0.05);
+ while(HiVal < axis->max) HiVal += Step;
+ if((axis->flags & AXIS_LOG) == AXIS_LOG) {
+ if (LoVal > defs.min4log) axis->min = LoVal;
+ if ((LoVal + Step) > defs.min4log && (LoVal + Step) < axis->min) axis->min = LoVal+Step;
+ }
+ else axis->min = LoVal;
+ axis->max = HiVal; axis->Start = axis->min; axis->Step = Step;
+}
+
+void NiceStep(AxisDEF *axis, int nTick)
+{
+ double diff, d, logStep, Step, Magn;
+ int i;
+
+ diff = axis->max - axis->min; d = axis->Step != 0.0 ? diff/axis->Step : HUGE_VAL;
+ if((d - floor(d)) < 0.1 && axis->Step != 0.0 && diff/axis->Step < 12.0)return;
+ 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;
+ if(logStep > 0.8) Step = 10.0;
+ else if(logStep > 0.5) Step = 5.0;
+ else if(logStep > 0.2) Step = 2.0;
+ else Step = 1.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;
+ }
+ lv = axis->min > defs.min4log ? axis->min : defs.min4log;
+ 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
+//----------------------------------------------------------------------------
+//remove leading/trailing whitespace
+char *str_ltrim(char *str) {
+ int i, j;
+
+ if(!str || !str[0]) return str;
+ for(i = 0; str[i] && str[i] <= ' '; i++);
+ for(j = 0; str[i]; str[j++] = str[i++]);
+ str[j++] = '\0'; return str;
+ }
+
+char *str_rtrim(char *str) {
+ size_t i;
+
+ i = strlen(str);
+ while(i > 0 && str[i-1] <= ' ') str[--i] = '\0';
+ return str;
+}
+
+char *str_trim(char *str) {
+ str = str_ltrim(str); return str_rtrim(str);
+}
+
+//remove leading and tailing quotatation
+void rmquot(char *str)
+{
+ size_t i, len;
+ char c;
+
+ if(str && str[0] && (*str == '"' || *str == '\'')) {
+ len = strlen(str); c = *str;
+ if(str[len-1] == c) {
+ str[len-1] = 0;
+ for(i = 1; i < len; str[i-1] = str[i++]);
+ }
+ }
+}
+
+int strpos(char *needle, char *haystack)
+{
+ int i, j;
+
+ if(!needle || !needle[0] || !haystack || !haystack[0]) return -1;
+ for(i = j = 0; haystack[i]; i++, j=0) {
+ if(haystack[i] == needle[0]) for (j = 1; haystack[i+j]; j++) {
+ if(needle[j] != haystack[i+j]) break;
+ }
+ if(j && !needle[j]) return i;
+ }
+ return -1;
+}
+
+char *strreplace(char *needle, char *replace, char *haystack)
+{
+ static char *result = 0L;
+ static size_t reslen = 0;
+ size_t i, j, k, l;
+
+ if(!needle || !needle[0] || !haystack || !haystack[0]) return result;
+ if(!result) result = (char*)malloc(reslen = 100);
+ result[0] = 0; l = strlen(needle);
+ for(i = j = k = 0; haystack[i]; i++, j=0) {
+ if(haystack[i] == needle[0]) for (j = 1; haystack[i+j]; j++) {
+ if(needle[j] != haystack[i+j]) break;
+ }
+ if(j && !needle[j]) {
+ if(replace && replace[0]) {
+ if(reslen < (i + (int)strlen(replace) + 10)) {
+ result = (char*)realloc(result, reslen += 100);
+ }
+ for(j = 0; replace[j]; j++) result[k++] = replace[j];
+ }
+ i += (l-1);
+ }
+ else result[k++] = haystack[i];
+ }
+ result[k++] = 0;
+ return result;
+}
+
+char *substr(char *text, int pos1, int pos2)
+{
+ static char *result = 0L;
+ static size_t reslen = 0;
+ int i, j;
+ size_t l;
+
+ if(!text || !text[0]) return 0L;
+ l = strlen(text);
+ if(pos1 < 0) pos1 = 0; if(pos2 < pos1) pos2 = (int)(l+1);
+ if(!result) result = (char*)malloc(reslen = 100);
+ while (reslen < l) result = (char*) realloc(result, reslen += 100);
+ for(i = 0; i < pos1 && text[i]; i++);
+ for(j = 0; i <= pos2 && text[i]; result[j++] = text[i++]);
+ result[j] = 0;
+ return result;
+}
+
+//copy string in src to dest, returning the stringlength of src
+// seek better solution for long strings
+int rlp_strcpy(char*dest, int size, char*src)
+{
+ int i;
+
+ if(dest && src) {
+ for(i = 0; i < size; i++) {
+ if(!(dest[i] = src[i])) return i;
+ }
+ dest[i-1] = 0;
+ return i-1;
+ }
+ return 0;
+}
+
+// restyle formula
+void ReshapeFormula(char **text)
+{
+ int i, j, l;
+
+ if(!text || !*text || !**text) return;
+ l = (int)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(j && j <= l && TmpTxt[0]) {
+ rlp_strcpy(*text, l+1, TmpTxt);
+ }
+}
+
+//translate anyResult to output format
+void TranslateResult(anyResult *res)
+{
+ static char tr_text[80];
+
+ switch (res->type) {
+ case ET_VALUE:
+ if(res->value == HUGE_VAL) rlp_strcpy(tr_text, 80, "inf");
+ else if(res->value == -HUGE_VAL) rlp_strcpy(tr_text, 80, "-inf");
+#ifdef USE_WIN_SECURE
+ else sprintf_s(tr_text, 80, "%g", res->value);
+#else
+ else sprintf(tr_text, "%g", res->value);
+#endif
+ res->text = tr_text; return;
+ case ET_BOOL:
+ rlp_strcpy(tr_text, 80, ((int)res->value) ? (char*)"true" : (char*)"false");
+ res->text = tr_text; return;
+ case ET_DATE:
+ rlp_strcpy(tr_text, 80, value_date(res->value, defs.fmt_date));
+ res->text = tr_text; return;
+ case ET_TIME:
+ rlp_strcpy(tr_text, 80, value_date(res->value, defs.fmt_time));
+ res->text = tr_text; return;
+ case ET_DATETIME:
+ rlp_strcpy(tr_text, 80, value_date(res->value, defs.fmt_datetime));
+ res->text = tr_text; return;
+ case ET_TEXT:
+ if(res->text && res->text[0]) return;
+ }
+ if(!(res->text)) res->text="";
+}
+
+//remove invalid tag combinations from string
+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=(int)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)
+{
+#ifdef USE_WIN_SECURE
+ sprintf_s(buff, 20, " %g", val);
+#else
+ sprintf(buff, " %g", val);
+#endif
+ 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 = (char*)memdup(txt, (int)strlen(txt)+1, 0))){
+ Nat2Int(tmp);
+ //the return value of sscanf only roughly identifies a number
+#ifdef USE_WIN_SECURE
+ if(!sscanf_s(tmp,"%lf", val)){
+#else
+ if(!sscanf(tmp,"%lf", val)){
+#endif
+ free(tmp);
+ return false;
+ }
+ free(tmp);
+ return true;
+ }
+ }
+ return false;
+}
+
+void RmTrail(char *txt)
+{
+ int i;
+
+ i = (int)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 *NiceTime(double val)
+{
+ rlp_datetime dt;
+
+ parse_datevalue(&dt, val);
+ if(dt.year > 1905) {
+ if(dt.hours) return date2text(&dt, defs.fmt_datetime);
+ else return date2text(&dt, defs.fmt_date);
+ }
+ else return date2text(&dt, defs.fmt_time);
+}
+
+char *Int2ColLabel(int nr1, bool uc)
+{
+ static char RetTxt[12];
+ int i, j, nr = nr1;
+ char base = uc ? 'A' : 'a';
+
+#ifdef USE_WIN_SECURE
+ sprintf_s(RetTxt+8, 4, "%c\0", base + (nr %26));
+#else
+ sprintf(RetTxt+8, "%c\0", base + (nr %26));
+#endif
+ 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;
+}
+
+char *mkCellRef(int row, int col)
+{
+ static char RetTxt[20];
+
+#ifdef USE_WIN_SECURE
+ sprintf_s(RetTxt, 20, "%s%d", Int2ColLabel(col, false), row+1);
+#else
+ sprintf(RetTxt, "%s%d", Int2ColLabel(col, false), row+1);
+#endif
+ return RetTxt;
+}
+
+char *mkRangeRef(int r1, int c1, int r2, int c2)
+{
+ static char RetTxt[40];
+ int cb;
+
+ cb = rlp_strcpy(RetTxt, 20, mkCellRef(r1, c1));
+ RetTxt[cb++] = ':';
+ rlp_strcpy(RetTxt+cb, 40-cb, mkCellRef(r2, c2));
+ return RetTxt;
+}
+//convert strings to XML specifications
+//this offers a limited support for special characters
+char *str2xml(char *str, bool bGreek)
+{
+ int i, j;
+ wchar_t wc;
+
+ if(!str) return 0L;
+ for(i = j = 0; str[i] && j < 4090; i++) {
+ switch(str[i]) {
+ case '"':
+ j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, """);
+ break;
+ case '&':
+ j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, "&");
+ break;
+ case '<':
+ j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, "<");
+ break;
+ case '>':
+ j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, ">");
+ break;
+ default:
+#ifdef USE_WIN_SECURE
+ if(bGreek && str[i] >= 'A' && str[i] <= 'Z') j += sprintf_s(TmpTxt+j, 20, "&#%d;", str[i] - 'A' + 0x391);
+ else if(bGreek && str[i] >= 'a' && str[i] <= 'z') j += sprintf_s(TmpTxt+j, 20, "&#%d;", str[i] - 'a' + 0x3B1);
+#else
+ if(bGreek && str[i] >= 'A' && str[i] <= 'Z') j += sprintf(TmpTxt+j, "&#%d;", str[i] - 'A' + 0x391);
+ else if(bGreek && str[i] >= 'a' && str[i] <= 'z') j += sprintf(TmpTxt+j, "&#%d;", str[i] - 'a' + 0x3B1);
+#endif
+ else if((unsigned char)str[i] <= 127) TmpTxt[j++]=str[i];
+ else {
+ if(mbtowc(&wc, str+i, 1) >0)
+#ifdef USE_WIN_SECURE
+ j += sprintf_s(TmpTxt+j, TMP_TXT_SIZE-j, "&#%d;", ((unsigned short)wc));
+#else
+ j += sprintf(TmpTxt+j, "&#%d;", ((unsigned short)wc));
+#endif
+ }
+ }
+ }
+ TmpTxt[j] = 0;
+ return(TmpTxt);
+}
+
+// split string str into array of strings using sep as separator
+// return number of lines created in nl
+static char *split_buf = 0L;
+static int split_buf_size, split_buf_pos;
+char **split(char *str, char sep, int *nl)
+{
+ int i, j, l, ns;
+ char **ptr;
+
+ if(!str || !str[0] || !sep) return 0L;
+ split_buf_pos = 0;
+ add_to_buff(&split_buf, &split_buf_pos, &split_buf_size, str, 0);
+ if(!split_buf || !split_buf_pos) return 0L;
+ for(i = ns = 0; i < split_buf_pos; i++) if(split_buf[i] == sep) ns++;
+ if(!(ptr = (char**)calloc(ns+2, sizeof(char*)))) return 0L;
+ for(i = j = l = 0; i < split_buf_pos; i++) {
+ if(split_buf[i] == sep) {
+ split_buf[i] = 0;
+ ptr[l++] = (char*)memdup(split_buf+j, (int)strlen(split_buf+j)+1, 0);
+ j = i+1;
+ }
+ }
+ ptr[l++] = (char*)memdup(split_buf+j, (int)strlen(split_buf+j)+1, 0);
+ if(nl) *nl = l;
+ return ptr;
+}
+
+char *fit_num_rect(anyOutput *o, int max_width, char *num_str)
+{
+ int i, j, k, w, h, slen;
+ char mant[30], expo[30], fmt[20];
+ double num;
+
+ o->oGetTextExtent(num_str, slen = (int)strlen(num_str), &w, &h);
+ if(w < (max_width-5)) return num_str;
+ //first try to remove leading zero from exponent
+ for(i = 0; i < slen; i++) if(num_str[i] == 'e') break;
+ if(num_str[i] == 'e') while (num_str[i+2] == '0') {
+ for(j = i+2; num_str[j]; j++) num_str[j] = num_str[j+1];
+ o->oGetTextExtent(num_str, slen = (int)strlen(num_str), &w, &h);
+ if(w < (max_width-5)) return num_str;
+ }
+ //no success: reduce the number of digit by rounding
+ for(i = k = 0; i <= slen; i++){
+ if(num_str[i] == '.') k = i;
+ if((mant[i] = num_str[i]) == 'e' || mant[i] == 0) break;
+ }
+ if(num_str[i] =='e') mant[i] = 0; k = i - k-1;
+ for(j = 0; num_str[i]; j++, i++) expo[j] = num_str[i]; expo[j] = 0;
+#ifdef USE_WIN_SECURE
+ sscanf_s(mant, "%lf", &num);
+#else
+ sscanf(mant, "%lf", &num);
+#endif
+ if(k >0) do {
+#ifdef USE_WIN_SECURE
+ sprintf_s(fmt, 20, "%%.%dlf%s", k, expo);
+ slen = sprintf_s(num_str, 60, fmt, num); //num_str is much longer than 60
+#else
+ sprintf(fmt, "%%.%dlf%s", k, expo);
+ slen = sprintf(num_str, fmt, num);
+#endif
+ k--;
+ o->oGetTextExtent(num_str, slen, &w, &h);
+ if(w < (max_width-5)) return num_str;
+ }while (k >= 0);
+ //cannot fit: return hash marks instead
+ for(i = w = 0; w < (max_width-5) && i < 11; i++) {
+ rlp_strcpy(num_str, i+2, "##########");
+ o->oGetTextExtent(num_str, i+1, &w, &h);
+ }
+ num_str[i-1] = 0; return num_str;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// utilities to add a line or number to a text buffer: memory file
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void add_to_buff(char** dest, int *pos, int *csize, char *txt, int len)
+{
+ if(!len)len = (int)strlen(txt);
+ if(!len) return;
+ if((*pos+len+1)>= *csize) {
+ *csize += 1000;
+ while(*csize < (*pos+len+1)) *csize += 1000;
+ *dest = (char*)realloc(*dest, *csize);
+ }
+ if(*dest) {
+ *pos += rlp_strcpy(*dest+*pos, len+1, txt);
+ }
+}
+
+void add_int_to_buff(char** dest, int *pos, int *csize, int value, bool lsp, int ndig)
+{
+ int len;
+ char txt[40];
+
+#ifdef USE_WIN_SECURE
+ len = sprintf_s(txt, 40, lsp ? " %d" : "%d", value);
+#else
+ len = sprintf(txt, lsp ? " %d" : "%d", value);
+#endif
+ add_to_buff(dest, pos, csize, txt, len);
+}
+
+void add_dbl_to_buff(char** dest, int *pos, int *csize, double value, bool lsp)
+{
+ int len;
+ char txt[40];
+
+#ifdef USE_WIN_SECURE
+ len = sprintf_s(txt, 40, lsp ? " %g" : "%g", value);
+#else
+ len = sprintf(txt, lsp ? " %g" : "%g", value);
+#endif
+ add_to_buff(dest, pos, csize, txt, len);
+}
+
+void add_hex_to_buff(char** dest, int *pos, int *csize, DWORD value, bool lsp)
+{
+ int len;
+ char txt[40];
+
+ if(value) {
+#ifdef USE_WIN_SECURE
+ len = sprintf_s(txt, 40, lsp ? " 0x%08x" : "0x%08x", value);
+#else
+ len = sprintf(txt, lsp ? " 0x%08x" : "0x%08x", value);
+#endif
+ add_to_buff(dest, pos, csize, txt, len);
+ }
+ else if(lsp) add_to_buff(dest, pos, csize, " 0x0", 4);
+ else add_to_buff(dest, pos, csize, "0x0", 3);
+}
+
+//----------------------------------------------------------------------------
+// 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 segments 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 Bezier polygon
+#define MIN_SEG 11
+#define MAX_DEPTH 5
+void DrawBezier(long *cp, POINT *pts, POINT p0, POINT p1, POINT p2, POINT p3, int depth)
+{
+ int i;
+ POINT np, p01, p12, p23, p012, p123, p0123;
+ POINT *ap[] = {&p0, &p1, &p2, &p3};
+
+ depth ++;
+ if(depth > MAX_DEPTH) {
+ for(i= 0; i < 4; i++) {
+ np.x = (*ap[i]).x >> 2; np.y = (*ap[i]).y >> 2;
+ AddToPolygon(cp, pts, &np);
+ }
+ return;
+ }
+ else if(depth == 1) for(i=0; i < 4; i++) {
+ (*ap[i]).x <<= 2; (*ap[i]).y <<= 2;
+ }
+ p01.x = (p0.x + p1.x) >> 1; p01.y = (p0.y + p1.y) >> 1;
+ p12.x = (p1.x + p2.x) >> 1; p12.y = (p1.y + p2.y) >> 1;
+ p23.x = (p2.x + p3.x) >> 1; p23.y = (p2.y + p3.y) >> 1;
+ p012.x = (p01.x + p12.x) >> 1; p012.y = (p01.y + p12.y) >> 1;
+ p123.x = (p12.x + p23.x) >> 1; p123.y = (p12.y + p23.y) >> 1;
+ p0123.x = (p012.x + p123.x) >> 1; p0123.y = (p012.y + p123.y) >> 1;
+ if(abs(p0.x - p0123.x)> MIN_SEG || abs(p0.y - p0123.y)> MIN_SEG) {
+ DrawBezier(cp, pts, p0, p01, p012, p0123, depth); //recursion: refine
+ }
+ else {
+ DrawBezier(cp, pts, p0, p01, p012, p0123, MAX_DEPTH); //recursion: store data
+ }
+ if(abs(p3.x - p0123.x)> MIN_SEG || abs(p3.y - p0123.y)> MIN_SEG) {
+ DrawBezier(cp, pts, p0123, p123, p23, p3, depth); //recursion: refine
+ }
+ else {
+ DrawBezier(cp, pts, p0123, p123, p23, p3, MAX_DEPTH); //recursion: store data
+ }
+}
+#undef MAX_DEPTH
+#undef MIN_SEG
+
+// create a Bezier polygon clipped to rectangle
+static RECT BezClipRec;
+#define MIN_SEGCLP 5
+#define MAX_DEPTHCLP 6
+static void DrawBezierClip(long *cp, POINT *pts, POINT p0, POINT p1, POINT p2, POINT p3, int depth)
+{
+ int i;
+ POINT np, p01, p12, p23, p012, p123, p0123;
+ POINT *ap[] = {&p0, &p1, &p2, &p3};
+
+ depth++;
+ if(depth > MAX_DEPTHCLP) {
+ for(i= 0; i < 4; i++) {
+ np.x = (*ap[i]).x >> 2; np.y = (*ap[i]).y >> 2;
+ if(np.x < BezClipRec.left) np.x = BezClipRec.left;
+ if(np.x > BezClipRec.right) np.x = BezClipRec.right;
+ if(np.y < BezClipRec.top) np.y = BezClipRec.top;
+ if(np.y > BezClipRec.bottom) np.y = BezClipRec.bottom;
+ AddToPolygon(cp, pts, &np);
+ }
+ return;
+ }
+ else if(depth == 1) for(i=0; i < 4; i++) {
+ (*ap[i]).x <<= 2; (*ap[i]).y <<= 2;
+ }
+ p01.x = (p0.x + p1.x) >> 1; p01.y = (p0.y + p1.y) >> 1;
+ p12.x = (p1.x + p2.x) >> 1; p12.y = (p1.y + p2.y) >> 1;
+ p23.x = (p2.x + p3.x) >> 1; p23.y = (p2.y + p3.y) >> 1;
+ p012.x = (p01.x + p12.x) >> 1; p012.y = (p01.y + p12.y) >> 1;
+ p123.x = (p12.x + p23.x) >> 1; p123.y = (p12.y + p23.y) >> 1;
+ p0123.x = (p012.x + p123.x) >> 1; p0123.y = (p012.y + p123.y) >> 1;
+ if((abs(p0.x - p0123.x)> MIN_SEGCLP || abs(p0.y - p0123.y)> MIN_SEGCLP)) {
+ DrawBezierClip(cp, pts, p0, p01, p012, p0123, depth); //recursion: refine
+ }
+ else {
+ DrawBezierClip(cp, pts, p0, p01, p012, p0123, MAX_DEPTHCLP); //store data
+ }
+ if((abs(p3.x - p0123.x)> MIN_SEGCLP || abs(p3.y - p0123.y)> MIN_SEGCLP)) {
+ DrawBezierClip(cp, pts, p0123, p123, p23, p3, depth); //recursion: refine
+ }
+ else {
+ DrawBezierClip(cp, pts, p0123, p123, p23, p3, MAX_DEPTHCLP); //store data
+ }
+}
+
+void ClipBezier(long *cp, POINT *pts, POINT p0, POINT p1, POINT p2, POINT p3, POINT *clp1, POINT *clp2)
+{
+ if(clp1 && clp2){
+ SetMinMaxRect(&BezClipRec, clp1->x, clp1->y, clp2->x, clp2->y);
+ }
+ if(cp && pts) DrawBezierClip(cp, pts, p0, p1, p2, p3, 0);
+}
+#undef MIN_SEGCLP
+#undef MAX_DEPTHCLP
+
+//----------------------------------------------------------------------------
+// create a Bezier spline through data points
+static void ipol_curve(lfPOINT *p1, lfPOINT *p2, lfPOINT *p3, lfPOINT *cp1, lfPOINT *cp2)
+{
+ double dx, dy, l;
+ lfPOINT tHat;
+
+ tHat.fx = p3->fx - p1->fx; tHat.fy = p3->fy - p1->fy;
+ l = sqrt(tHat.fx * tHat.fx + tHat.fy * tHat.fy);
+ tHat.fx /= l; tHat.fy /= l;
+ cp1->fx = cp2->fx = p2->fx; cp1->fy = cp2->fy = p2->fy;
+ dx = p3->fx - p2->fx; dy = p3->fy - p2->fy; l = sqrt(dx*dx + dy*dy)/3.0;
+ cp2->fx += (tHat.fx * l); cp2->fy += (tHat.fy *l);
+ dx = p2->fx - p1->fx; dy = p2->fy - p1->fy; l = sqrt(dx*dx + dy*dy)/3.0;
+ cp1->fx -= (tHat.fx * l); cp1->fy -= (tHat.fy *l);
+}
+
+static void mirr_vecvec(lfPOINT *a0, lfPOINT *a1, lfPOINT *v1)
+{
+ double dx, dy, as, ac, vs, vc, s, c, l;
+ lfPOINT sol1, sol2;
+
+ //mirror vector a0 -> v1 by rotation around vector a0 -> a1
+ dx = a1->fx - a0->fx; dy = a1->fy - a0->fy;
+ l = sqrt(dx*dx + dy*dy); as = dy/l; ac = dx/l;
+ dx = v1->fx - a0->fx; dy = v1->fy - a0->fy;
+ l = sqrt(dx*dx + dy*dy); vs = dy/l; vc = dx/l;
+ //calculate cw and ccw solution
+ s = sin((asin(as)-asin(vs))*2.0); c = cos((acos(ac)-acos(vc))*2.0);
+ sol1.fx = dx * c + dy * s + a0->fx; sol1.fy = dy * c - dx * s + a0->fy;
+ s = sin((asin(as)-asin(-vs))*2.0); c = cos((acos(ac)-acos(-vc))*2.0);
+ sol2.fx = dx * c + dy * s + a0->fx; sol2.fy = dy * c - dx * s + a0->fy;
+ //get better solution
+ dx = sol1.fx - a1->fx; dy = sol1.fy - a1->fy;
+ l = sqrt(dx*dx + dy*dy);
+ dx = sol2.fx - a1->fx; dy = sol2.fy - a1->fy;
+ if( l < sqrt(dx*dx + dy*dy)) {
+ v1->fx = sol1.fx; v1->fy = sol1.fy;
+ }
+ else {
+ v1->fx = sol2.fx; v1->fy = sol2.fy;
+ }
+}
+
+int mkCurve(lfPOINT *src, int n1, lfPOINT **dst, bool bClosed)
+{
+ int i, j, iret;
+
+ if(!src || n1 < 3) return 0;
+ if(!(*dst = (lfPOINT*)malloc((n1*3+2) * sizeof(lfPOINT))))return 0;
+ for(i = j = iret = 0; i < n1; i++, j += 3) {
+ (*dst)[j].fx = src[i].fx; (*dst)[j].fy = src[i].fy;
+ if(i && i < (n1-1)){
+ ipol_curve(&src[i-1], &src[i], &src[i+1], *dst+j-1, *dst+j+1);
+ }
+ else if(i) {
+ iret = j+1; break;
+ }
+ }
+ if(bClosed && iret >2) {
+ if((*dst)[j].fx != (*dst)[0].fx || (*dst)[j].fy != (*dst)[0].fy) {
+ j += 3; iret += 3;
+ (*dst)[j].fx = (*dst)[0].fx; (*dst)[j].fy = (*dst)[0].fy;
+ }
+ if(j < 6) {
+ free(*dst); *dst = 0L; return 0;
+ }
+ ipol_curve(*dst+j-3, *dst+j, *dst+3, *dst+j-1, *dst+1);
+ ipol_curve(*dst+j-6, *dst+j-3, *dst+j, *dst+j-4, *dst+j-2);
+ }
+ else if(!bClosed && iret>3) {
+ (*dst)[1].fx = (*dst)[0].fx + (*dst)[3].fx - (*dst)[2].fx;
+ (*dst)[1].fy = (*dst)[0].fy + (*dst)[3].fy - (*dst)[2].fy;
+ mirr_vecvec(*dst, *dst+3, *dst+1);
+ (*dst)[j-1].fx = (*dst)[j].fx + (*dst)[j-3].fx - (*dst)[j-2].fx;
+ (*dst)[j-1].fy = (*dst)[j].fy + (*dst)[j-3].fy - (*dst)[j-2].fy;
+ mirr_vecvec(*dst+j, *dst+j-3, *dst+j-1);
+ }
+ else {
+ free(*dst); *dst = 0L; return 0;
+ }
+ return iret;
+}
+
+//----------------------------------------------------------------------------
+// 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+4))) return rpts;
+ return pts;
+}
+
+//----------------------------------------------------------------------------
+// display a marked line using complement colors
+//----------------------------------------------------------------------------
+void InvertLine(POINT *pts, int nPts, LineDEF *Line, RECT *rc,
+ anyOutput *o, bool mark)
+{
+ int i;
+ LineDEF OldLine;
+
+ memcpy(&OldLine, Line, sizeof(LineDEF));
+ if(OldLine.width <= 0.0001) OldLine.width = 0.0001;
+ for(i = 0; o->un2fiy(OldLine.width) < 1.0 && i < 50; i++) OldLine.width *= 2.0;
+ OldLine.color = mark ? (Line->color & 0x00ffffffL) : 0x00ffffffL;
+ OldLine.width *= 3.0; o->SetLine(&OldLine);
+ o->oPolyline(pts, nPts); OldLine.width = Line->width;
+ OldLine.color = mark ? (Line->color & 0x00ffffffL) ^ 0x00ffffffL : (Line->color & 0x00ffffff);
+ 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 < 4; i++) {
+ c1 = iround(fabs((((col1 & 0xff000000)>>24) & 0xff) * fact));
+ c1 += iround(fabs((((col2 & 0xff000000)>>24) & 0xff) *(1.0-fact)));
+ col3 |= c1 < 0xff ? c1 : 0xff;
+ col1 <<= 8; col2 <<= 8;
+ if(i < 3) 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;
+ case GO_FUNC3D: delete((Func3D*)go); break;
+ case GO_XYSTAT: delete((xyStat*)go); break;
+ case GO_FITFUNC3D: delete((FitFunc3D*)go); break;
+ case GO_BEZIER: delete((Bezier*)go); break;
+ case GO_TEXTFRAME: delete((TextFrame*)go); break;
+ case GO_NORMQUANT: delete((NormQuant*)go); break;
+ case GO_CONTOUR: delete((ContourPlot*)go); break;
+ default:
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "Cannot delete Object\nwith Id %ld", go->Id);
+#else
+ sprintf(TmpTxt, "Cannot delete Object\nwith Id %ld", go->Id);
+#endif
+ ErrorBox(TmpTxt);
+ //we do not delete the object, probably we recover
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//Delete a graphic object from a list
+bool DeleteGOL(GraphObj ***gol, long n, GraphObj *go, anyOutput *o)
+{
+ long i;
+ int c;
+ GraphObj **g, *p;
+
+ if(!gol || !(*gol) || !go || !n) return false;
+ for (i = 0, c = 0, g = *gol; i < n; i++, g++) {
+ if(*g) {
+ c++;
+ if(*g == go) {
+ p = (*g)->parent;
+ if(o) o->HideMark();
+ Undo.DeleteGO(g, 0L, o);
+ if(c == 1) {
+ for (g++, i++ ;i < n; i++, g++) {
+ if(*g) return true;
+ }
+ if(p) Undo.DropMemory(p, (void**) gol, UNDO_CONTINUE);
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//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;
+ rlp_strcpy(Name, 512,FileName);
+ i = (int)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 {
+#ifdef USE_WIN_SECURE
+ sprintf_s(ext, 6, ".%03d", i);
+ sprintf_s(TmpFileName, 512, "%s%s", Name, ext);
+ if(!(fopen_s(&TheFile, TmpFileName, "r"))) {
+ fclose(TheFile);
+ }
+ else break;
+#else
+ sprintf(ext, ".%03d", i);
+ sprintf(TmpFileName, "%s%s", Name, ext);
+ if((TheFile = fopen(TmpFileName, "r"))) fclose(TheFile);
+#endif
+ 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;
+
+#ifdef USE_WIN_SECURE
+ if(fopen_s(&TheFile, FileName, "r")) return false;
+#else
+ if(0L ==(TheFile = fopen(FileName, "r"))) return false;
+#endif
+ 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;
+
+#ifdef USE_WIN_SECURE
+ if(fopen_s(&TheFile, FileName, "r")) return false;
+#else
+ if(0L ==(TheFile = fopen(FileName, "r"))) return false;
+#endif
+ 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;
+
+#ifdef USE_WIN_SECURE
+ if(ENOENT == fopen_s(&TheFile, FileName, "r")) return false;
+#else
+ if(0L ==(TheFile = fopen(FileName, "r"))) {
+ if(errno == ENOENT) return false;
+ return true;
+ }
+#endif
+ fclose(TheFile);
+ return true;
+}
+
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//check Object for certain properties
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool IsPlot3D(GraphObj *g)
+{
+ if(g && (g->Id == GO_PLOT3D || g->Id == GO_FUNC3D || g->Id == GO_FITFUNC3D)) return true;
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//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
+//Ref: Corman T.H., Leiserson C.E. & Rivest R.L. (1990) Hash Functions.
+// in: Introduction to Algorithms (MIT Press & McGraw-Hill)
+// ISBN 0-262-03141-8 and ISBN 0-07-013143-0, pp. 226ff
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+unsigned int HashValue(unsigned char *str)
+{
+ unsigned int i = 0, ret = 0;
+
+ if(!str || !str[0]) return 0;
+ do {
+ if(str[i] > 32) ret = ((str[i]-32) + (ret <<2));
+ i++;
+ }while(str[i]);
+ return ret;
+}
+
+unsigned int Hash2(unsigned char * str)
+{
+ unsigned int i = 0, ret = 0, c;
+
+ if(!str) return 0;
+ do {
+ c = str[i++];
+ ret = ((ret * c)<<2) | c;
+ }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;
+}
+
+DWORD CheckNewString(char **loc, char *s_old, char *s_new, GraphObj *par, DWORD flags)
+{
+ int ocb, ncb, cb;
+
+ if(s_old && s_new) {
+ if(!strcmp(s_old, s_new)) return flags;
+ ocb = (int)strlen(s_old); ncb = (int)strlen(s_new);
+ cb = ncb > ocb ? ncb : ocb;
+ if(cb > ocb) {
+ *loc = (char*)realloc(*loc, cb * sizeof(char)+1);
+ }
+ Undo.String(par, loc, flags); flags |= UNDO_CONTINUE;
+ if(*loc) rlp_strcpy(*loc, cb+1, s_new);
+ }
+ else if(!s_old && s_new && s_new[0]) {
+ Undo.String(par, loc, flags); flags |= UNDO_CONTINUE;
+ *loc = (char *)memdup(s_new, (int)strlen(s_new) +1, 0);
+ }
+ else if(s_old && s_old[0] && !s_new) {
+ Undo.String(par, loc, flags); flags |= UNDO_CONTINUE;
+ if(*loc) *loc[0] = 0;
+ }
+ 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
+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
+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 segment 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) 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) 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]);
+ if(ppg_par) 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
+ }
+ }
+ if(ppg_par) ppg_par->Command(CMD_ADDTOLINE, &nep, 0L);
+ }
+ else {
+ //point is inside by one algorithm but outside with another
+ //try without this point
+ }
+ }
+ }
+ if(ppg_par && (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 vis1, POINT3D *pnt, POINT3D *last)
+{
+ static POINT3D np, lp;
+ long d, d1;
+ int vis = vis1;
+ 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 !
+ if(ppg_par && (vis1 == 3 || ppg_vis == 3)) ppg_par->Command(CMD_SIGNAL_POL, pnt, 0L);
+ 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) { //on line: visible
+ vis = 1;
+ }
+ 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;
+ if(ppg_par) 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(vis1 == 3 && ppg_par) ppg_par->Command(CMD_SIGNAL_POL, pnt, 0L);
+ if(vis && ppg_par) ppg_par->Command(CMD_ADDTOLINE, pnt, 0L);
+ else if(ppg_par) 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_par) ppg_par->Command(CMD_SIGNAL_POL, pnt, 0L);
+ if(ppg_vis == 3) ppg_vis = 1;
+ if(ppg_firstvis == 1 && ppg_vis == 1) {
+ //from below surface to below surface
+ if(!(spg_valid = AddShadowPolygon(last, &ppg_first, -2)))
+ if(ppg_par) spg_valid = ppg_par->Command(CMD_ADDTOLINE, pnt, 0L);
+ }
+ else if(ppg_firstvis == 1 && ppg_vis == 2) {
+ //from below surface enter inside surface
+ if(CuttingEdge(last, &np)){
+ if(ppg_par)ppg_par->Command(CMD_ADDTOLINE, &np, 0L);
+ spg_valid = AddShadowPolygon(&np, &ppg_first, seg_x_seg);
+ }
+ else if(!(spg_valid = AddShadowPolygon(last, &ppg_first, seg_x_seg)))
+ if(ppg_par) spg_valid = ppg_par->Command(CMD_ADDTOLINE, pnt, 0L);
+ }
+ else if(ppg_firstvis == 2 && ppg_vis == 1 && ppg_par) {
+ //from inside surface to below surface
+ if(CuttingEdge(&ppg_first, &np)){
+ if(!(spg_valid = AddShadowPolygon(last, &np, seg_x_seg)))
+ spg_valid = ppg_par->Command(CMD_REQ_POINT, &ppg_first, 0L);
+ ppg_par->Command(CMD_ADDTOLINE, &np, 0L);
+ }
+ else if(!(spg_valid = AddShadowPolygon(last, &ppg_first, seg_x_seg)))
+ spg_valid = ppg_par->Command(CMD_ADDTOLINE, pnt, 0L);
+ }
+ 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_par = par;
+ 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;
+ 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
index 5b444bb..23a4b3b 100755
--- a/Version.h
+++ b/Version.h
@@ -1,4 +1,4 @@
-//RLPlot.h, Copyright (c) 2000-2007 R.Lackner
+//RLPlot.h, Copyright (c) 2000-2008 R.Lackner
//
// This file is part of RLPlot.
//
@@ -16,4 +16,4 @@
// 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 "1.4"
+#define SZ_VERSION "1.5"
diff --git a/WinSpec.cpp b/WinSpec.cpp
index 1b1bcb3..a9724bf 100755
--- a/WinSpec.cpp
+++ b/WinSpec.cpp
@@ -1,4 +1,4 @@
-//WinSpec.cpp, Copyright (c) 2000-2007 R.Lackner
+//WinSpec.cpp, Copyright (c) 2000-2008 R.Lackner
//the entire code of this module is highly specific to Windows!
//
// This file is part of RLPlot.
@@ -46,6 +46,7 @@ const char name[] = "RLPLOT1";
static unsigned int cf_rlpobj = RegisterClipboardFormat("rlp_obj");
static unsigned int cf_rlpxml = RegisterClipboardFormat("rlp_xml");
+static char *ShellCmd;
long FAR PASCAL WndProc(HWND, UINT, UINT, LONG);
PrintWin *Printer = 0L;
@@ -327,6 +328,7 @@ void ShowTextCursor(anyOutput *out, RECT *disp, DWORD color)
{
HWND wnd = GetFocus();
+ if(!out || (out->OC_type & 0xff) != OC_BITMAP) return;
cTxtCur = color; HideTextCursor();
oTxtCur = out; bSuspend = false;
iTxtCurCount = -2;
@@ -354,6 +356,7 @@ void ShowCopyMark(anyOutput *out, RECT *mrk, int nRec)
{
int i;
+ if(!out || (out->OC_type & 0xff) != OC_BITMAP) return;
HideCopyMark(); bSuspend = false;
if(!out || !mrk || !nRec) return;
oCopyMark = out;
@@ -369,7 +372,7 @@ void ShowCopyMark(anyOutput *out, RECT *mrk, int nRec)
void InvalidateOutput(anyOutput *o)
{
- if(!o) return;
+ if(!o || (o->OC_type & 0xff) != OC_BITMAP) return;
if(o == oCopyMark) {
oCopyMark = 0L;
if(bmCopyMark) delete bmCopyMark;
@@ -382,7 +385,7 @@ void InvalidateOutput(anyOutput *o)
void SuspendAnimation(anyOutput *o, bool bSusp)
{
- if(!o) return;
+ if(!o || (o->OC_type & 0xff) != OC_BITMAP) return;
if(!bSusp) bSuspend = false;
else {
if(o == oCopyMark) bSuspend = bSusp;
@@ -401,7 +404,7 @@ LRESULT FAR PASCAL TimerWndProc(HWND hwnd, UINT message, UINT wParam, LONG lPara
switch(message) {
case WM_TIMER:
if(bSuspend) return 0;
- if(bmCopyMark && oCopyMark) {
+ if(bmCopyMark && oCopyMark && (oCopyMark->OC_type & 0xff) == OC_BITMAP) {
bmCopyMark->CopyBitmap(0, 0, oCopyMark, rCopyMark.left, rCopyMark.top,
rCopyMark.right - rCopyMark.left, rCopyMark.bottom - rCopyMark.top, false);
bmCopyMark->SetLine(&liCopyMark1);
@@ -602,16 +605,52 @@ bool com_oTextOutW(int x, int y, w_char *txt, int cb, HFONT *hFont, HDC *dc,
TextDEF *td, anyOutput *o)
{
XFORM xf;
- int ix, iy, w, h, dtflags;
+ int ix, iy, w, h, dtflags, rx, ry;
+ double si, csi;
RECT dtrc;
+ fRECT rc;
+ TextDEF ttd;
if(!*hFont || !txt || !txt[0]) return false;
if(cb < 1) cb = (int)wcslen(txt);
- SelectObject(*dc, *hFont); SetTextColor(*dc, td->ColTxt);
- SetBkColor(*dc, td->ColBg); SetBkMode(*dc, td->Mode ? TRANSPARENT : OPAQUE);
- ix = iy = 0; SetTextAlign(*dc, TA_LEFT | TA_TOP);
- if(o->OC_type == OC_HIMETRIC) {
+ //test for transparency
+ if(((td->ColTxt & 0xff000000L) || (td->ColBg & 0xff000000L)) && (o->OC_type & 0xff) == OC_BITMAP) {
+ o->oGetTextExtentW(txt, cb, &rx, &ry);
+ rx += 4; rc.Xmin = -2.0; rc.Ymin = 0.0; rc.Xmax = rx; rc.Ymax = ry;
+ si = sin(td->RotBL *0.01745329252); csi = cos(td->RotBL *0.01745329252);
+ if(td->Align & TXA_HCENTER) {
+ rc.Xmin -= rx/2.0-1.0; rc.Xmax -= rx/2.0-1.0;
+ }
+ else if(td->Align & TXA_HRIGHT) {
+ rc.Xmin -= rx-2.0; rc.Xmax -= rx-2.0;
+ }
+ if(td->Align & TXA_VCENTER) {
+ rc.Ymin -= ry/2.0; rc.Ymax -= ry/2.0;
+ }
+ else if(td->Align & TXA_VBOTTOM) {
+ rc.Ymin -= ry; rc.Ymax -= ry;
+ }
+ SetMinMaxRect(&((BitMapWin*)o)->tr_rec, iround(rc.Xmin*csi + rc.Ymin*si)+x, iround(rc.Ymin*csi - rc.Xmin*si)+y,
+ iround(rc.Xmax*csi + rc.Ymin*si)+x, iround(rc.Ymin*csi - rc.Xmax*si)+y);
+ UpdateMinMaxRect(&((BitMapWin*)o)->tr_rec, iround(rc.Xmax*csi + rc.Ymax*si)+x, iround(rc.Ymax*csi - rc.Xmax*si)+y);
+ UpdateMinMaxRect(&((BitMapWin*)o)->tr_rec, iround(rc.Xmin*csi + rc.Ymax*si)+x, iround(rc.Ymax*csi - rc.Xmin*si)+y);
+ IncrementMinMaxRect(&((BitMapWin*)o)->tr_rec, (td->iSize>>1) +6);
+ ((BitMapWin*)o)->tr_out = GetRectBitmap(&((BitMapWin*)o)->tr_rec, o);
+ ((BitMapWin*)o)->tr_out->hres = ((BitMapWin*)o)->hres;
+ ((BitMapWin*)o)->tr_out->vres = ((BitMapWin*)o)->vres;
+ memcpy(&ttd, td, sizeof(TextDEF));
+ ttd.ColTxt = td->ColTxt & 0x00ffffffL; ttd.ColBg = td->ColBg & 0x00ffffffL;
+ ((BitMapWin*)o)->tr_out->SetTextSpec(&ttd);
+ ((BitMapWin*)o)->tr_out->oTextOutW(x-((BitMapWin*)o)->tr_rec.left, y-((BitMapWin*)o)->tr_rec.top,
+ txt, cb);
+ ((BitMapWin*)o)->DoTransparency(td->ColTxt);
+ return true;
+ }
+ SelectObject(*dc, *hFont); SetTextColor(*dc, (td->ColTxt)&0x00ffffffL);
+ SetBkColor(*dc, (td->ColBg)&0x00ffffffL); SetBkMode(*dc, td->Mode ? TRANSPARENT : OPAQUE);
+ ix = iy = 0; SetTextAlign(*dc, TA_LEFT | TA_TOP);
+ if((o->OC_type & 0xff) == OC_HIMETRIC) {
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);
@@ -657,7 +696,7 @@ bool com_oTextOutW(int x, int y, w_char *txt, int cb, HFONT *hFont, HDC *dc,
dtrc.top = iy + y; dtrc.right = dtrc.left+w; dtrc.bottom = dtrc.top+h;
if(fabs(td->RotBL) >.01 || fabs(td->RotCHAR) >.01) {
SetGraphicsMode(*dc, GM_ADVANCED);
- if(o->OC_type == OC_HIMETRIC) {
+ if((o->OC_type &0xff) == OC_HIMETRIC) {
if((td->Align & TXA_VBOTTOM) == TXA_VBOTTOM) iy -= (td->iSize<<1);
else if((td->Align & TXA_VCENTER) == TXA_VCENTER) iy -= (td->iSize);
xf.eM11 = (float)cos(td->RotBL *0.01745329252);
@@ -714,7 +753,7 @@ bool com_SetTextSpec(TextDEF *set, anyOutput *o, HFONT *hFont, TextDEF *TxtSet,
LOGFONT FontRec;
HFONT newFont;
- if(!set->iSize && set->fSize > 0.001f) set->iSize = o->un2iy(set->fSize);
+ if(!set->iSize && set->fSize > 0.001) 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 ||
@@ -815,11 +854,10 @@ BitMapWin::BitMapWin(GraphObj *g, HWND hw):anyOutput()
Box1.Ymin = DeskRect.top; Box1.Ymax = DeskRect.bottom;
scr = CreateCompatibleBitmap(dc, DeskRect.right, DeskRect.bottom);
memDC = CreateCompatibleDC(NULL);
- SelectObject(memDC, scr);
- ReleaseDC(hwndDesk, dc);
+ SelectObject(memDC, scr); ReleaseDC(hwndDesk, dc);
hPen = CreatePen(PS_SOLID, 1, dLineCol = 0x00ffffffL);
hBrush = CreateSolidBrush(dFillCol =dBgCol = 0x00ffffffL);
- dPattern = 0L;
+ dPattern = 0L; minLW = 1;
if(memDC) {
oldPen = (HPEN)SelectObject(memDC, hPen);
oldBrush = (HBRUSH)SelectObject(memDC, hBrush);
@@ -828,7 +866,7 @@ BitMapWin::BitMapWin(GraphObj *g, HWND hw):anyOutput()
oldBrush = 0L;
oldPen = 0L;
}
- hFont = 0L;
+ hFont = 0L; OC_type = OC_BITMAP;
}
BitMapWin::BitMapWin(int w, int h, double hr, double vr)
@@ -837,7 +875,7 @@ BitMapWin::BitMapWin(int w, int h, double hr, double vr)
HWND hwndDesk;
memDC = 0L; hgo = 0L; go = 0L;
- hres = hr; vres = vr;
+ hres = hr; vres = vr; minLW = 1;
units = defs.cUnits;
DeskRect.right = w; DeskRect.bottom = h;
DeskRect.left = DeskRect.top = 0;
@@ -854,7 +892,7 @@ BitMapWin::BitMapWin(int w, int h, double hr, double vr)
SelectObject(memDC, hPen);
SelectObject(memDC, hBrush);
}
- hFont = 0L;
+ hFont = 0L; OC_type = OC_BITMAP;
}
BitMapWin::BitMapWin(GraphObj *g):anyOutput()
@@ -864,8 +902,7 @@ BitMapWin::BitMapWin(GraphObj *g):anyOutput()
memDC = 0L; hgo = 0L; go = g;
dc = GetDC(hwndDesk = GetDesktopWindow());
- hres = vres = 300.0;
- units = defs.cUnits;
+ hres = vres = 300.0; units = defs.cUnits; minLW = 1;
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;
@@ -882,19 +919,15 @@ BitMapWin::BitMapWin(GraphObj *g):anyOutput()
SelectObject(memDC, hPen);
SelectObject(memDC, hBrush);
}
- hFont = 0L;
+ hFont = 0L; OC_type = OC_BITMAP;
}
BitMapWin::~BitMapWin()
{
- 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);
+ 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;
@@ -936,7 +969,7 @@ BitMapWin::SetFill(FillDEF *fill)
}
else {
if(hgo) delete hgo;
- hgo = NULL;
+ hgo = 0L;
}
if(dFillCol != fill->color) {
newBrush = CreateSolidBrush(dFillCol = fill->color);
@@ -968,10 +1001,8 @@ BitMapWin::Erase(DWORD Color)
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);
+ SelectObject(memDC, hOldBrush); SelectObject(memDC, hOldPen);
+ DeleteObject(hBGbrush); DeleteObject(hBGpen);
return true;
}
if(hBGpen) DeleteObject(hBGpen);
@@ -1042,44 +1073,117 @@ bool
BitMapWin::oCircle(int x1, int y1, int x2, int y2, char *nam)
{
BOOL RetVal;
+ FillDEF tr_fill = {FILL_NONE, 0x0, 1.0, 0L, 0x0};
+ LineDEF tr_line = {0.0, 1.0, 0x0, 0x0};
+ bool bTrans = false;
+ HPEN newPen;
- RetVal = Ellipse(memDC, x1, y1, x2, y2);
- if(RetVal && hgo) return hgo->oCircle(x1, y1, x2, y2);
- else if(RetVal) return true;
- return false;
+
+ if(dFillCol & 0xff000000) {
+ bTrans = true;
+ tr_fill.color = tr_fill.color2 = tr_line.color = (dFillCol & 0x00ffffffL);
+ SetMinMaxRect(&tr_rec, x1, y1, x2, y2);
+ IncrementMinMaxRect(&tr_rec, 6);
+ tr_out = GetRectBitmap(&tr_rec, this);
+ tr_out->hres = hres; tr_out->vres = vres;
+ tr_out->SetLine(&tr_line); tr_out->SetFill(&tr_fill);
+ RetVal = tr_out->oCircle(x1-tr_rec.left, y1-tr_rec.top, x2-tr_rec.left, y2-tr_rec.top, nam);
+ DoTransparency(dFillCol);
+ if(!(dLineCol & 0xff000000)) Arc(memDC, x1, y1, x2, y2, 0, 0, 0, 0);
+ }
+ if(dLineCol & 0xff000000) {
+ if(!bTrans) {
+ newPen = CreatePen(PS_SOLID, 1, dFillCol);
+ SelectObject(memDC, newPen); Ellipse(memDC, x1, y1, x2, y2);
+ if(hPen) {
+ SelectObject(memDC, hPen); DeleteObject(newPen);
+ }
+ }
+ bTrans = true;
+ tr_line.color = (dLineCol & 0x00ffffffL);
+ tr_line.width = LineWidth;
+ tr_line.pattern = dPattern;
+ SetMinMaxRect(&tr_rec, x1, y1, x2, y2);
+ IncrementMinMaxRect(&tr_rec, 6 + un2ix(LineWidth*2.0));
+ tr_out = GetRectBitmap(&tr_rec, this);
+ tr_out->hres = hres; tr_out->vres = vres;
+ tr_out->SetLine(&tr_line);
+ Arc(((BitMapWin*)tr_out)->memDC, x1-tr_rec.left, y1-tr_rec.top,
+ x2-tr_rec.left, y2-tr_rec.top, 0, 0, 0, 0);
+ DoTransparency(dLineCol);
+ }
+ if(!bTrans) {
+ RetVal = Ellipse(memDC, x1, y1, x2, y2);
+ if(RetVal && hgo) return hgo->oCircle(x1, y1, x2, y2);
+ else if(RetVal) return true;
+ }
+ return true;
}
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;
+ BOOL RetVal;
+ POINT *newpts;
+ LineDEF tr_line = {0.0, 1.0, 0x0, 0x0};
+
+ if(!pts || cp < 1) return false;
+ if((dLineCol & 0xff000000) && (newpts = (POINT*)malloc(cp * sizeof(POINT)))) {
+ tr_line.color = (dLineCol & 0x00ffffffL);
+ tr_line.width = LineWidth;
+ tr_line.pattern = dPattern;
+ SetMinMaxRect(&tr_rec, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+ for(i = 2; i < cp; i++) {
+ UpdateMinMaxRect(&tr_rec, pts[i].x, pts[i].y);
+ }
+ IncrementMinMaxRect(&tr_rec, 6 + un2ix(LineWidth*2.0));
+ tr_out = GetRectBitmap(&tr_rec, this);
+ tr_out->RLP.finc = RLP.finc; tr_out->RLP.fp = RLP.fp;
+ tr_out->hres = hres; tr_out->vres = vres;
+ for(i = 0; i < cp; i++) {
+ newpts[i].x = pts[i].x - tr_rec.left;
+ newpts[i].y = pts[i].y - tr_rec.top;
+ }
+ tr_out->SetLine(&tr_line);
+ RetVal = tr_out->oPolyline(newpts, cp, 0L);
+ RLP.finc = tr_out->RLP.finc; RLP.fp = tr_out->RLP.fp;
+ DoTransparency(dLineCol); free(newpts);
+ return (RetVal != 0);
}
else {
- if(Polyline(memDC, pts, cp))return true;
- else return false;
+ if (dPattern) {
+ for (i = 1; i < cp; i++) PatLine(pts[i-1], pts[i]);
+ return true;
+ }
+ else RetVal = Polyline(memDC, pts, cp);
}
+ return false;
}
bool
-BitMapWin::oRectangle(int x1, int y1, int x2, int y2, char *name)
+BitMapWin::oRectangle(int x1, int y1, int x2, int y2, char *nam)
{
- BOOL RetVal;
+ POINT pts[5];
- 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;
+ pts[0].x = pts[3].x = pts[4].x = x1; pts[0].y = pts[1].y = pts[4].y = y1;
+ pts[1].x = pts[2].x = x2; pts[2].y = pts[3].y = y2;
+ return oPolygon(pts, 5, nam);
}
bool
BitMapWin::oSolidLine(POINT *p)
{
- if(Polyline(memDC, p, 2)) return true;
+ DWORD dPat;
+
+ if(dLineCol & 0xff000000L) {
+ dPat = dPattern; dPattern = 0L;
+ oPolyline(p, 2, 0L); dPattern = dPat;
+ return true;
+ }
+ else {
+ if(Polyline(memDC, p, 2)) return true;
+ }
return false;
}
@@ -1098,12 +1202,93 @@ BitMapWin::oTextOutW(int x, int y, w_char *txt, int cb)
bool
BitMapWin::oPolygon(POINT *pts, int cp, char *nam)
{
+ int i;
BOOL RetVal;
+ POINT *newpts;
+ FillDEF tr_fill = {FILL_NONE, 0x0, 1.0, 0L, 0x0};
+ LineDEF tr_line = {0.0, 1.0, 0x0, 0x0};
+ HPEN newPen;
- RetVal = Polygon(memDC, pts, cp);
+ if(!pts || cp < 2) return false;
+ if((dFillCol & 0xff000000) && (newpts = (POINT*)malloc(cp * sizeof(POINT)))) {
+ tr_fill.color = tr_fill.color2 = tr_line.color = (dFillCol & 0x00ffffffL);
+ SetMinMaxRect(&tr_rec, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
+ for(i = 2; i < cp; i++) {
+ UpdateMinMaxRect(&tr_rec, pts[i].x, pts[i].y);
+ }
+ IncrementMinMaxRect(&tr_rec, 6);
+ tr_out = GetRectBitmap(&tr_rec, this);
+ tr_out->hres = hres; tr_out->vres = vres;
+ for(i = 0; i < cp; i++) {
+ newpts[i].x = pts[i].x - tr_rec.left;
+ newpts[i].y = pts[i].y - tr_rec.top;
+ }
+ tr_out->SetLine(&tr_line); tr_out->SetFill(&tr_fill);
+ RetVal = tr_out->oPolygon(newpts, cp, 0L);
+ DoTransparency(dFillCol); free(newpts);
+ oPolyline(pts, cp, nam);
+ }
+ else if((dLineCol & 0xff000000) && (newpts = (POINT*)malloc(cp * sizeof(POINT)))) {
+ newPen = CreatePen(PS_SOLID, 1, dFillCol);
+ SelectObject(memDC, newPen);
+ RetVal = Polygon(memDC, pts, cp);
+ if(hPen) {
+ SelectObject(memDC, hPen); oPolyline(pts, cp, nam);
+ DeleteObject(newPen);
+ }
+ }
+ else {
+ RetVal = Polygon(memDC, pts, cp);
+ }
if(RetVal && hgo) return hgo->oPolygon(pts, cp);
- else if (RetVal) return true;
- return false;
+ return RetVal != 0;
+}
+
+// The following code does alpha blending for transparent colors.
+// The Windows AlphaBlend function requires msimg32.dll. To include
+// this library add MSIMG32.LIB to the Project/Settings.../Link/Library_Moduls list.
+// The code executed with USE_MSIMG32 undefined is very slow because of the GetPixel
+// and SetPixel functions.
+//
+#define USE_MSIMG32
+void
+BitMapWin::DoTransparency(DWORD color)
+{
+#ifdef USE_MSIMG32
+ BLENDFUNCTION bf = {AC_SRC_OVER, 0, 127, 0};
+
+ bf.SourceConstantAlpha = (unsigned char)(255 - ((color >> 24) & 0xff));
+ AlphaBlend(memDC, tr_rec.left, tr_rec.top, tr_rec.right - tr_rec.left, tr_rec.bottom - tr_rec.top,
+ ((BitMapWin*)tr_out)->memDC, 0, 0, tr_rec.right - tr_rec.left, tr_rec.bottom - tr_rec.top, bf);
+#else
+ int x1, y1, x2, y2, c, c1, c2;
+ DWORD col1, col2, col;
+ double f, f1;
+
+ if(!tr_out) return;
+ f = ((color & 0xff000000L) >>24)/255.0; f1 = 1.0 - f;
+ for(y1 = tr_rec.top, y2 = 0; y1 < tr_rec.bottom; y1++, y2++) {
+ for(x1 = tr_rec.left, x2 = 0; x1 < tr_rec.right; x1++, x2++) {
+ col1 = GetPixel(memDC, x1, y1);
+ col2 = GetPixel(((BitMapWin*)tr_out)->memDC, x2, y2);
+ if(col1 != col2) {
+ col = 0x0;
+ c1 = (col1 & 0x000000ffL); c = c2 = (col2 & 0x000000ffL);
+ if(c1 != c2) c = (int)(c2 * f1 + c1 * f);
+ col |= (c < 256 ? c : 0xff);
+ c1 = ((col1 & 0x0000ff00L)>>8); c = c2 = ((col2 & 0x0000ff00L)>>8);
+ if(c1 != c2) c = (int)(c2 * f1 + c1 * f);
+ col |= (c < 256 ? (c<<8) : 0x00ff00);
+ c1 = ((col1 & 0x00ff0000L)>>16); c = c2 = ((col2 & 0x00ff0000L)>>16);
+ if(c1 != c2) c = (int)(c2 * f1 + c1 * f);
+ col |= (c < 256 ? (c<<16) : 0xff0000);
+ SetPixel(memDC, x1, y1, col);
+ }
+ }
+ }
+#endif //USE_MSIMG32
+ DelBitmapClass(tr_out); tr_out = 0L;
+ OC_type |= OC_TRANSPARENT;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1111,7 +1296,7 @@ BitMapWin::oPolygon(POINT *pts, int cp, char *nam)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OutputWin::OutputWin(GraphObj *g, HWND hw):BitMapWin(g, hw)
{
- hdc = 0L;
+ hdc = 0L; minLW = 1;
if(g) {
if(!hw) CreateNewWindow(g);
else hWnd = hw;
@@ -1138,9 +1323,14 @@ OutputWin::ActualSize(RECT *rc)
}
void
-OutputWin::Caption(char *txt)
+OutputWin::Caption(char *txt, bool bModified)
{
- SetWindowText(hWnd, txt);
+ char txt1[200];
+ int cb;
+
+ cb = rlp_strcpy(txt1, 180, txt);
+ if(bModified)rlp_strcpy(txt1+cb, 20, " [modified]");
+ SetWindowText(hWnd, txt1);
}
const static unsigned char hand_bits[] = { //hand cursor bitmap
@@ -1531,7 +1721,7 @@ WinCopyWMF::WinCopyWMF(GraphObj *g, char *file_wmf, char *file_emf)
hPen = CreatePen(PS_SOLID, 1, dLineCol = 0x00ff0000L);
hBrush = CreateSolidBrush(dFillCol =dBgCol = 0x00ffffffL);
dPattern = 0L; go = g; hgo = 0L; bott_y = 0;
- dc = GetDC(hwndDesk = GetDesktopWindow());
+ dc = GetDC(hwndDesk = GetDesktopWindow()); minLW = 1;
hres = (double)GetDeviceCaps(dc, LOGPIXELSX); vres = (double)GetDeviceCaps(dc, LOGPIXELSY);
ReleaseDC(hwndDesk, dc); wmf_file = file_wmf; emf_file = file_emf;
}
@@ -1771,7 +1961,7 @@ PrintWin::PrintWin()
PrintDriver = PrintDevice = PrintPort = 0L;
hPen = 0L; hBrush = 0L; hFont = 0L; hDC = 0L;
- hgo = 0L; units = defs.cUnits; i = j = 0;
+ hgo = 0L; units = defs.cUnits; i = j = 0; minLW = 1;
GetProfileString("windows", "device", "", TmpTxt, 4096);
while(TmpTxt[i] && TmpTxt[i] != ',') i++;
TmpTxt[i] = 0;
@@ -1928,6 +2118,16 @@ PrintWin::Eject()
}
bool
+PrintWin::CopyBitmap(int x, int y, anyOutput* sr, int sx, int sy,
+ int sw, int sh, bool invert)
+{
+ BitMapWin *src = (BitMapWin*)sr;
+
+ return(0 != BitBlt(hDC, x, y, sw, sh, src->memDC, sx, sy,
+ invert ? DSTINVERT : SRCCOPY));
+}
+
+bool
PrintWin::oCircle(int x1, int y1, int x2, int y2, char* nam)
{
BOOL RetVal;
@@ -1955,14 +2155,13 @@ PrintWin::oPolyline(POINT * pts, int cp, char *nam)
}
bool
-PrintWin::oRectangle(int x1, int y1, int x2, int y2, char *name)
+PrintWin::oRectangle(int x1, int y1, int x2, int y2, char *nam)
{
- BOOL RetVal;
+ POINT pts[5];
- 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;
+ pts[0].x = pts[3].x = pts[4].x = x1; pts[0].y = pts[1].y = pts[4].y = y1;
+ pts[1].x = pts[2].x = x2; pts[2].y = pts[3].y = y2;
+ return oPolygon(pts, 5, nam);
}
bool
@@ -2082,6 +2281,7 @@ int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInstance,
rmquot(TmpTxt);
if(TmpTxt[0]) LoadFile= _strdup(TmpTxt);
}
+ ShellCmd = GetCommandLine();
hInstance = hInst;
wndclass.style = CS_BYTEALIGNWINDOW | CS_DBLCLKS;
wndclass.lpfnWndProc = WndProc;
@@ -2251,6 +2451,7 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
MouseEvent mev;
HDC dc;
int cc;
+ RECT rec;
g = (GraphObj *) reflptr(GetWindowLong(hwnd, 0));
w = (OutputWin *) reflptr(GetWindowLong(hwnd, GWL_USERDATA));
@@ -2394,6 +2595,9 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
DestroyWindow(hwnd);
}
return 0;
+ case CM_NEWINST:
+ if(ShellCmd && ShellCmd[0])WinExec(ShellCmd, SW_SHOW);
+ return 0;
case CM_PASTE:
w->MouseCursor(MC_WAIT, true);
if(g->Id == GO_SPREADDATA) TestClipboard(g);
@@ -2423,7 +2627,7 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
SetClipboardData(cf_rlpxml, NULL);
}
else if(g->Id == GO_PAGE) {
- SetClipboardData(CF_ENHMETAFILE, NULL);
+ if(!g->hasTransp()) SetClipboardData(CF_ENHMETAFILE, NULL);
SetClipboardData(CF_BITMAP, NULL);
if(CurrGraph) {
CopyGraph(CurrGraph, cf_rlpobj, w); copy_obj = CurrGraph;
@@ -2431,12 +2635,12 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
}
else if (wParam == CM_CUT)return 0;
else if(CurrGraph && CurrGraph->Id == GO_GRAPH){
- SetClipboardData(CF_ENHMETAFILE, NULL);
+ if(!g->hasTransp()) SetClipboardData(CF_ENHMETAFILE, NULL);
SetClipboardData(CF_BITMAP, NULL);
CopyGraph(CurrGraph, cf_rlpobj, w); copy_obj = CurrGraph;
}
else if(g->Id == GO_GRAPH){
- SetClipboardData(CF_ENHMETAFILE, NULL);
+ if(!g->hasTransp()) SetClipboardData(CF_ENHMETAFILE, NULL);
SetClipboardData(CF_BITMAP, NULL);
CopyGraph(g, cf_rlpobj, w); copy_obj = g;
}
@@ -2499,11 +2703,11 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
case CM_DELGRAPH:
g->Command(CMD_DELGRAPH, 0L, w);
return 0;
- case CM_SAVEDATA:
- g->Command(CMD_SAVEDATA, 0L, w);
+ case CM_SAVE:
+ g->Command(CMD_SAVE, 0L, w);
return 0;
- case CM_SAVEDATAAS:
- g->Command(CMD_SAVEDATAAS, 0L, w);
+ case CM_SAVEAS:
+ g->Command(CMD_SAVEAS, 0L, w);
return 0;
case CM_REDRAW:
if(w->Erase(defs.Color(COL_BG))) g->DoPlot(w);
@@ -2516,9 +2720,6 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
}
else if(!CurrGO) InfoBox("No object selected!");
return 0;
- case CM_SAVEGRAPHAS:
- SaveGraphAs(g);
- return 0;
case CM_EXPORT:
OpenExportName(g, 0L);
g->DoPlot(w);
@@ -2530,8 +2731,26 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
}
if(Printer && Printer->StartPage()) {
SetCursor(LoadCursor(0L, IDC_WAIT));
- g->DoPlot(Printer);
- Printer->EndPage();
+ rec.left = Printer->un2ix(g->GetSize(SIZE_GRECT_LEFT));
+ rec.right = Printer->un2ix(g->GetSize(SIZE_GRECT_RIGHT));
+ rec.top = Printer->un2iy(g->GetSize(SIZE_GRECT_TOP));
+ rec.bottom = Printer->un2iy(g->GetSize(SIZE_GRECT_BOTTOM));
+ if(g->hasTransp()) {
+ if((CopyBMP = new BitMapWin(rec.right-rec.left, rec.bottom-rec.top,
+ Printer->hres, Printer->vres)) && CopyBMP->StartPage()) {
+ CopyBMP->VPorg.fy = -Printer->co2fiy(g->GetSize(SIZE_GRECT_TOP));
+ CopyBMP->VPorg.fx = -Printer->co2fix(g->GetSize(SIZE_GRECT_LEFT));
+ g->DoPlot(CopyBMP); CopyBMP->EndPage();
+ Printer->CopyBitmap(rec.left, rec.top, CopyBMP, 0, 0, CopyBMP->DeskRect.right,
+ CopyBMP->DeskRect.bottom, false);
+ delete CopyBMP; CopyBMP = NULL;
+ Printer->EndPage();
+ }
+ }
+ else {
+ g->DoPlot(Printer);
+ Printer->EndPage();
+ }
w->Erase(defs.Color(COL_BG));
g->DoPlot(w);
SetCursor(LoadCursor(0L, IDC_ARROW));
@@ -2633,6 +2852,9 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
case CM_REPANOV:
if(g->data) rep_anova(g, g->data);
return 0;
+ case CM_REPBDANOV:
+ if(g->data) rep_bdanova(g, g->data);
+ return 0;
case CM_REPTWANR:
if(g->data) rep_twoway_anova(g, g->data);
return 0;
@@ -2827,7 +3049,7 @@ void *CreateDlgWnd(char *title, int x, int y, int width, int height, tag_DlgObj
(BoxRec.bottom- BoxRec.top)/2, BoxRec.right - BoxRec.left,
BoxRec.bottom - BoxRec.top, 0);
}
- if(flags & 0x04) SetTimer(hDlg, 1, 100, 0L);
+ if(flags & 0x08) SetTimer(hDlg, 1, 100, 0L);
UpdateWindow(hDlg); d->DoPlot(w);
ShowWindow(hDlg, SW_SHOW);
}
diff --git a/WinSpec.h b/WinSpec.h
index aaa60b8..fa83f1f 100755
--- a/WinSpec.h
+++ b/WinSpec.h
@@ -1,4 +1,4 @@
-//WinSpec.h, Copyright (c) 2000-2006 R.Lackner
+//WinSpec.h, Copyright (c) 2000-2008 R.Lackner
//
// This file is part of RLPlot.
//
@@ -25,6 +25,8 @@ public:
HBRUSH hBrush, oldBrush;
HFONT hFont;
HatchOut *hgo;
+ RECT tr_rec; //rectangle for transparency
+ anyOutput *tr_out; //transparency source class
BitMapWin(GraphObj *g, HWND hw);
BitMapWin(int w, int h, double hr, double vr);
@@ -48,6 +50,7 @@ public:
bool oTextOut(int x, int y, char *txt, int cb);
bool oTextOutW(int x, int y, w_char *txt, int cb);
bool oPolygon(POINT *pts, int cp, char *nam = 0L);
+ void DoTransparency(DWORD color);
};
class OutputWin:public BitMapWin{
@@ -59,7 +62,7 @@ public:
~OutputWin();
bool ActualSize(RECT *rc);
void Focus(){if(hWnd) SetFocus(hWnd);};
- void Caption(char *txt);
+ void Caption(char *txt, bool bModified);
void MouseCursor(int cid, bool force);
bool SetScroll(bool isVert, int iMin, int iMax, int iPSize, int iPos);
bool Erase(DWORD Color);
@@ -119,6 +122,8 @@ public:
bool oGetTextExtentW(w_char *text, int cb, int *width, int *height);
bool StartPage();
bool EndPage();
+ bool CopyBitmap(int x, int y, anyOutput* src, int sx, int sy,
+ int sw, int sh, bool invert);
bool Eject();
bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L);
bool oPolyline(POINT * pts, int cp, char *nam = 0L);
diff --git a/exprlp.cpp b/exprlp.cpp
index 4b0a5e5..8da75b0 100755
--- a/exprlp.cpp
+++ b/exprlp.cpp
@@ -1,235 +1,253 @@
-//exprlp.cpp, Copyright (c) 2002-2006 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
-char *name1, *name2; //the filenames
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 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;
-}
-
-int YesNoCancelBox(char *Msg)
-{
- return 0;
-}
-
-void HideCopyMark()
-{
-}
-
-void ShowCopyMark(anyOutput *out, RECT *mrk, int nRec)
-{
-}
-
-void CopyText(char *txt, int len)
-{
-}
-
-unsigned char* PasteText()
-{
- return 0L;
-}
-
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 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:
- 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, false);
- 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;
- case FF_RLP:
- SaveGraphAs(go);
- 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-2005 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 'r': case 'R':
- file_fmt = FF_RLP;
- 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;
- else if(0==strcmp(".rlp", szFile2+i-4)) file_fmt = FF_RLP;
- }
- 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;
-}
+//exprlp.cpp, Copyright (c) 2002-2008 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
+//
+// A console application to process *.rlp files
+
+#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
+char *name1, *name2; //the filenames
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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;
+}
+
+int YesNoCancelBox(char *Msg)
+{
+ return 0;
+}
+
+void HideCopyMark()
+{
+}
+
+void ShowCopyMark(anyOutput *out, RECT *mrk, int nRec)
+{
+}
+
+void CopyText(char *txt, int len)
+{
+}
+
+unsigned char* PasteText()
+{
+ return 0L;
+}
+
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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:
+ 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, false);
+ 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;
+ case FF_RLP:
+ SaveGraphAs(go);
+ 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-2005 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 'r': case 'R':
+ file_fmt = FF_RLP;
+ 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;
+ else if(0==strcmp(".rlp", szFile2+i-4)) file_fmt = FF_RLP;
+ }
+ 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);
+ }
+ 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/menu.h b/menu.h
index 00a49ed..88e8777 100755
--- a/menu.h
+++ b/menu.h
@@ -1,106 +1,107 @@
-//menu.h, (C) 2006, 2007 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
-//
-// menu declarations
-//
-
-#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_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_INSROW 541
-#define CM_INSCOL 542
-#define CM_DELROW 543
-#define CM_DELCOL 544
-#define CM_SAVEDATA 545
-
-#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 CM_SHPGUP 615
-#define CM_SHPGDOWN 616
-
-#define CM_SMPLSTAT 650
-#define CM_REPCMEANS 651
-#define CM_REPANOV 652
-#define CM_REPTWANOV 653
-#define CM_REPFRIEDM 654
-#define CM_REPTWANR 655
-#define CM_REPKRUSKAL 656
-#define CM_REPREGR 657
-#define CM_ROBUSTLINE 658
-#define CM_CORRELM 659
-#define CM_CORRELT 660
-#define CM_REPTWOWAY 661
+//menu.h, (C) 2006-2008 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
+//
+// menu declarations
+//
+
+#define CM_OPEN 500
+#define CM_SAVE 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_REDRAW 510
+#define CM_ZOOM25 511
+#define CM_ZOOM50 512
+#define CM_ZOOM100 513
+#define CM_ZOOM200 514
+#define CM_ZOOM400 515
+#define CM_PRINT 516
+#define CM_EXPORT 517
+#define CM_DELOBJ 518
+#define CM_DEFAULTS 519
+#define CM_COPY 520
+#define CM_PASTE 521
+#define CM_UPDATE 522
+#define CM_ADDAXIS 523
+#define CM_UNDO 524
+#define CM_ZOOMIN 525
+#define CM_ZOOMOUT 526
+#define CM_ZOOMFIT 527
+#define CM_FILE1 528
+#define CM_FILE2 529
+#define CM_FILE3 530
+#define CM_FILE4 531
+#define CM_FILE5 532
+#define CM_FILE6 533
+#define CM_FILLRANGE 534
+#define CM_CUT 535
+#define CM_LEGEND 536
+#define CM_LAYERS 537
+#define CM_INSROW 538
+#define CM_INSCOL 539
+#define CM_DELROW 540
+#define CM_DELCOL 541
+#define CM_SAVEAS 542
+#define CM_NEWINST 543
+
+#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 CM_SHPGUP 615
+#define CM_SHPGDOWN 616
+
+#define CM_SMPLSTAT 650
+#define CM_REPCMEANS 651
+#define CM_REPANOV 652
+#define CM_REPTWANOV 653
+#define CM_REPFRIEDM 654
+#define CM_REPTWANR 655
+#define CM_REPKRUSKAL 656
+#define CM_REPREGR 657
+#define CM_ROBUSTLINE 658
+#define CM_CORRELM 659
+#define CM_CORRELT 660
+#define CM_REPTWOWAY 661
+#define CM_REPBDANOV 662
diff --git a/mfcalc.cpp b/mfcalc.cpp
index 3b55224..a1cf5de 100755
--- a/mfcalc.cpp
+++ b/mfcalc.cpp
@@ -66,7 +66,7 @@
/*
- mfcalc.y, mfcalc.cpp, Copyright (c) 2004-2006 R.Lackner
+ mfcalc.y, mfcalc.cpp, Copyright (c) 2004-2008 R.Lackner
parse string and simple math: based on the bison 'mfcalc' example
This file is part of RLPlot.
@@ -142,6 +142,7 @@ static int block_res; //result of eval()
static symrec *putsym (unsigned int h_name, unsigned int h2_name, int sym_type);
static symrec *getsym (unsigned int h_name, unsigned int h2_name, char *sym_name = 0L);
static int push(YYSTYPE *res, YYSTYPE *val);
+static void yyCompare(YYSTYPE *res, YYSTYPE *arg1, YYSTYPE *arg2, int op);
static void store_res(YYSTYPE *res);
static char *PushString(char *text);
static double *PushArray(double *arr);
@@ -157,7 +158,7 @@ static void yyerror(char *s);
static void make_time(YYSTYPE *dst, double h, double m, double s);
static int yylex(void);
static double nop() {return 0.0;};
-static double for_loop(char *block1, char *block2);
+static int for_loop(char *block1, char *block2);
static char res_txt[1000];
static anyResult line_res = {ET_UNKNOWN, 0.0, res_txt, 0L, 0};
@@ -168,7 +169,7 @@ static char *last_err_desc = 0L; //short error description
static char *buffer = 0L; //the current command buffer
static int buff_pos = 0;
static bool bRecent = false; //rearrange functions
-static bool bNoWrite, bNoExec; //while editing ...
+static bool bNoWrite, bNoExec, bNoSS; //while editing ...
static int parse_level = 0; //count reentrances into parser
#define MAX_PARSE 50 //maximum number of recursive reentances
#include <stdio.h>
@@ -181,23 +182,23 @@ static int parse_level = 0; //count reentrances into parser
-#define YYFINAL 243
+#define YYFINAL 221
#define YYFLAG -32768
#define YYNTBASE 77
-#define YYTRANSLATE(x) ((unsigned)(x) <= 315 ? yytranslate[x] : 86)
+#define YYTRANSLATE(x) ((unsigned)(x) <= 315 ? yytranslate[x] : 87)
static const char yytranslate[] = { 0,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 70,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 72,
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, 73,
- 74, 60, 59, 72, 58, 2, 61, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 76, 71, 2,
+ 74, 60, 59, 71, 58, 2, 61, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 76, 70, 2,
40, 2, 49, 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,
- 62, 2, 75, 63, 2, 2, 2, 2, 2, 2,
+ 63, 2, 75, 62, 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,
@@ -224,88 +225,79 @@ static const char yytranslate[] = { 0,
#if YYDEBUG != 0
static const short yyprhs[] = { 0,
- 0, 1, 4, 6, 8, 10, 13, 16, 19, 22,
- 25, 29, 35, 39, 43, 46, 48, 51, 53, 57,
- 61, 65, 70, 77, 84, 91, 98, 100, 102, 104,
- 108, 112, 114, 118, 120, 125, 127, 129, 133, 137,
- 141, 145, 149, 153, 157, 161, 163, 165, 167, 169,
- 171, 173, 175, 177, 179, 181, 183, 185, 187, 191,
- 195, 199, 203, 207, 211, 216, 221, 228, 237, 242,
- 247, 254, 261, 268, 275, 282, 289, 296, 303, 314,
- 321, 328, 332, 337, 344, 349, 358, 365, 369, 373,
- 377, 381, 384, 387, 390, 393, 397, 400, 404, 410,
- 415, 422, 429, 436, 443, 450, 456, 460, 466, 472,
- 478
+ 0, 1, 4, 6, 8, 10, 12, 14, 17, 20,
+ 23, 26, 30, 36, 40, 44, 47, 49, 52, 54,
+ 58, 62, 66, 71, 78, 80, 82, 84, 88, 92,
+ 94, 98, 100, 105, 107, 109, 113, 117, 121, 125,
+ 129, 133, 137, 141, 143, 145, 147, 149, 151, 153,
+ 155, 157, 159, 161, 163, 165, 167, 171, 175, 179,
+ 183, 187, 191, 196, 201, 208, 217, 222, 227, 234,
+ 245, 252, 259, 263, 268, 275, 280, 289, 296, 300,
+ 304, 308, 312, 315, 318, 321, 324, 328, 331, 335,
+ 341, 346, 353, 360, 367, 374, 381, 387, 391, 397,
+ 403, 409
};
static const short yyrhs[] = { -1,
- 77, 78, 0, 70, 0, 71, 0, 72, 0, 85,
- 70, 0, 85, 71, 0, 85, 72, 0, 79, 70,
- 0, 79, 71, 0, 14, 8, 83, 0, 14, 8,
- 83, 15, 83, 0, 23, 8, 83, 0, 22, 8,
- 83, 0, 26, 9, 0, 27, 0, 1, 70, 0,
- 5, 0, 79, 59, 85, 0, 85, 59, 79, 0,
- 79, 59, 79, 0, 35, 73, 85, 74, 0, 35,
- 73, 85, 13, 79, 74, 0, 35, 73, 85, 13,
- 85, 74, 0, 35, 73, 85, 72, 79, 74, 0,
- 35, 73, 85, 72, 85, 74, 0, 79, 0, 6,
- 0, 85, 0, 81, 45, 81, 0, 81, 46, 85,
- 0, 80, 0, 3, 47, 3, 0, 4, 0, 30,
- 73, 85, 74, 0, 16, 0, 17, 0, 85, 50,
- 85, 0, 85, 51, 85, 0, 85, 52, 85, 0,
- 85, 53, 85, 0, 85, 54, 85, 0, 85, 55,
- 85, 0, 85, 56, 85, 0, 85, 57, 85, 0,
- 7, 0, 9, 0, 85, 0, 79, 0, 3, 0,
- 25, 0, 82, 0, 34, 0, 12, 0, 10, 0,
- 11, 0, 28, 0, 83, 0, 28, 40, 85, 0,
- 28, 40, 79, 0, 28, 41, 85, 0, 28, 42,
- 85, 0, 28, 43, 85, 0, 28, 44, 85, 0,
- 29, 73, 85, 74, 0, 31, 73, 81, 74, 0,
- 31, 73, 85, 13, 81, 74, 0, 31, 73, 85,
- 13, 85, 13, 85, 74, 0, 32, 73, 79, 74,
- 0, 32, 73, 85, 74, 0, 32, 73, 79, 13,
- 79, 74, 0, 32, 73, 85, 13, 79, 74, 0,
- 32, 73, 85, 13, 85, 74, 0, 32, 73, 79,
- 13, 85, 74, 0, 32, 73, 79, 72, 79, 74,
- 0, 32, 73, 85, 72, 79, 74, 0, 32, 73,
- 79, 72, 85, 74, 0, 32, 73, 85, 72, 85,
- 74, 0, 37, 73, 85, 13, 85, 13, 81, 13,
- 80, 74, 0, 33, 73, 81, 13, 80, 74, 0,
- 33, 73, 81, 13, 25, 74, 0, 36, 73, 74,
- 0, 36, 73, 81, 74, 0, 38, 73, 84, 13,
- 84, 74, 0, 38, 73, 84, 74, 0, 39, 73,
- 84, 13, 84, 13, 84, 74, 0, 39, 73, 84,
- 13, 84, 74, 0, 85, 59, 85, 0, 85, 58,
- 85, 0, 85, 60, 85, 0, 85, 61, 85, 0,
- 28, 65, 0, 28, 66, 0, 65, 28, 0, 66,
- 28, 0, 85, 63, 85, 0, 58, 85, 0, 73,
- 84, 74, 0, 21, 28, 62, 85, 75, 0, 85,
- 62, 85, 75, 0, 85, 62, 85, 75, 40, 85,
- 0, 85, 62, 85, 75, 41, 85, 0, 85, 62,
- 85, 75, 42, 85, 0, 85, 62, 85, 75, 43,
- 85, 0, 85, 62, 85, 75, 44, 85, 0, 3,
- 76, 3, 76, 3, 0, 3, 76, 3, 0, 85,
- 49, 85, 48, 85, 0, 85, 49, 5, 48, 5,
- 0, 85, 49, 5, 48, 85, 0, 85, 49, 85,
- 48, 5, 0
+ 77, 79, 0, 70, 0, 71, 0, 72, 0, 70,
+ 0, 71, 0, 86, 72, 0, 86, 78, 0, 80,
+ 72, 0, 80, 70, 0, 14, 8, 84, 0, 14,
+ 8, 84, 15, 84, 0, 23, 8, 84, 0, 22,
+ 8, 84, 0, 26, 9, 0, 27, 0, 1, 72,
+ 0, 5, 0, 80, 59, 86, 0, 86, 59, 80,
+ 0, 80, 59, 80, 0, 35, 73, 86, 74, 0,
+ 35, 73, 86, 78, 80, 74, 0, 80, 0, 6,
+ 0, 86, 0, 82, 45, 82, 0, 82, 46, 86,
+ 0, 81, 0, 3, 47, 3, 0, 4, 0, 30,
+ 73, 86, 74, 0, 16, 0, 17, 0, 86, 50,
+ 86, 0, 86, 51, 86, 0, 86, 52, 86, 0,
+ 86, 53, 86, 0, 86, 54, 86, 0, 86, 55,
+ 86, 0, 86, 56, 86, 0, 86, 57, 86, 0,
+ 7, 0, 9, 0, 86, 0, 80, 0, 3, 0,
+ 25, 0, 83, 0, 34, 0, 12, 0, 10, 0,
+ 11, 0, 28, 0, 84, 0, 28, 40, 86, 0,
+ 28, 40, 80, 0, 28, 41, 86, 0, 28, 42,
+ 86, 0, 28, 43, 86, 0, 28, 44, 86, 0,
+ 29, 73, 86, 74, 0, 31, 73, 82, 74, 0,
+ 31, 73, 86, 13, 82, 74, 0, 31, 73, 86,
+ 13, 86, 13, 86, 74, 0, 32, 73, 80, 74,
+ 0, 32, 73, 86, 74, 0, 32, 73, 85, 78,
+ 85, 74, 0, 37, 73, 86, 13, 86, 13, 82,
+ 13, 81, 74, 0, 33, 73, 82, 13, 81, 74,
+ 0, 33, 73, 82, 13, 25, 74, 0, 36, 73,
+ 74, 0, 36, 73, 82, 74, 0, 38, 73, 85,
+ 13, 85, 74, 0, 38, 73, 85, 74, 0, 39,
+ 73, 85, 13, 85, 13, 85, 74, 0, 39, 73,
+ 85, 13, 85, 74, 0, 86, 59, 86, 0, 86,
+ 58, 86, 0, 86, 60, 86, 0, 86, 61, 86,
+ 0, 28, 65, 0, 28, 66, 0, 65, 28, 0,
+ 66, 28, 0, 86, 62, 86, 0, 58, 86, 0,
+ 73, 85, 74, 0, 21, 28, 63, 86, 75, 0,
+ 86, 63, 86, 75, 0, 86, 63, 86, 75, 40,
+ 86, 0, 86, 63, 86, 75, 41, 86, 0, 86,
+ 63, 86, 75, 42, 86, 0, 86, 63, 86, 75,
+ 43, 86, 0, 86, 63, 86, 75, 44, 86, 0,
+ 3, 76, 3, 76, 3, 0, 3, 76, 3, 0,
+ 86, 49, 86, 48, 86, 0, 86, 49, 5, 48,
+ 5, 0, 86, 49, 5, 48, 86, 0, 86, 49,
+ 86, 48, 5, 0
};
#endif
#if YYDEBUG != 0
static const short yyrline[] = { 0,
- 136, 137, 140, 140, 140, 141, 142, 143, 144, 145,
- 146, 148, 151, 152, 154, 155, 156, 159, 161, 162,
- 163, 164, 165, 166, 167, 168, 171, 175, 176, 177,
- 178, 179, 180, 184, 185, 186, 187, 188, 189, 190,
- 191, 192, 193, 194, 195, 198, 198, 200, 200, 202,
- 203, 204, 205, 206, 207, 208, 209, 210, 211, 212,
- 213, 214, 215, 216, 218, 219, 220, 222, 225, 226,
- 227, 228, 229, 230, 231, 232, 233, 234, 235, 236,
- 237, 238, 239, 240, 241, 242, 243, 244, 248, 252,
- 253, 255, 256, 257, 258, 259, 260, 261, 262, 264,
- 266, 270, 274, 278, 282, 287, 288, 289, 290, 291,
- 292
+ 137, 138, 141, 141, 143, 143, 143, 144, 145, 146,
+ 147, 148, 150, 153, 154, 156, 157, 158, 161, 163,
+ 164, 165, 166, 167, 170, 174, 175, 176, 177, 178,
+ 179, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+ 192, 193, 194, 197, 197, 199, 199, 201, 202, 203,
+ 204, 205, 206, 207, 208, 209, 210, 211, 212, 213,
+ 214, 215, 217, 218, 219, 221, 224, 225, 226, 227,
+ 228, 229, 230, 231, 232, 233, 234, 235, 236, 240,
+ 244, 245, 247, 248, 249, 250, 251, 252, 253, 254,
+ 256, 258, 262, 266, 270, 274, 279, 280, 281, 282,
+ 283, 284
};
#endif
@@ -318,340 +310,296 @@ static const char * const yytname[] = { "$","error","$undefined.","NUM","BOOLV
"RETURN","BREAK","VAR","FNCT","BFNCT","AFNCT","SFNCT","FUNC1","TXT","SRFUNC",
"YYFNC","FUNC4","YYFNC2","YYFNC3","'='","ADDEQ","SUBEQ","MULEQ","DIVEQ","LSEP",
"CLAUSE","SER","COLC","'?'","AND","OR","EQ","NE","GT","GE","LT","LE","'-'","'+'",
-"'*'","'/'","'['","'^'","NEG","INC","DEC","PINC","PDEC","PDIM","'\\n'","';'",
-"','","'('","')'","']'","':'","input","line","str_exp","range","arr","bool",
+"'*'","'/'","'^'","'['","NEG","INC","DEC","PINC","PDEC","PDIM","';'","','","'\\n'",
+"'('","')'","']'","':'","input","anysep","line","str_exp","range","arr","bool",
"block","anyarg","exp", NULL
};
#endif
static const short yyr1[] = { 0,
- 77, 77, 78, 78, 78, 78, 78, 78, 78, 78,
- 78, 78, 78, 78, 78, 78, 78, 79, 79, 79,
- 79, 79, 79, 79, 79, 79, 80, 81, 81, 81,
- 81, 81, 81, 82, 82, 82, 82, 82, 82, 82,
- 82, 82, 82, 82, 82, 83, 83, 84, 84, 85,
- 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
- 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
- 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
- 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
- 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
- 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
- 85
+ 77, 77, 78, 78, 79, 79, 79, 79, 79, 79,
+ 79, 79, 79, 79, 79, 79, 79, 79, 80, 80,
+ 80, 80, 80, 80, 81, 82, 82, 82, 82, 82,
+ 82, 83, 83, 83, 83, 83, 83, 83, 83, 83,
+ 83, 83, 83, 84, 84, 85, 85, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86
};
static const short yyr2[] = { 0,
- 0, 2, 1, 1, 1, 2, 2, 2, 2, 2,
- 3, 5, 3, 3, 2, 1, 2, 1, 3, 3,
- 3, 4, 6, 6, 6, 6, 1, 1, 1, 3,
- 3, 1, 3, 1, 4, 1, 1, 3, 3, 3,
- 3, 3, 3, 3, 3, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 3, 3,
- 3, 3, 3, 3, 4, 4, 6, 8, 4, 4,
- 6, 6, 6, 6, 6, 6, 6, 6, 10, 6,
- 6, 3, 4, 6, 4, 8, 6, 3, 3, 3,
- 3, 2, 2, 2, 2, 3, 2, 3, 5, 4,
- 6, 6, 6, 6, 6, 5, 3, 5, 5, 5,
- 5
+ 0, 2, 1, 1, 1, 1, 1, 2, 2, 2,
+ 2, 3, 5, 3, 3, 2, 1, 2, 1, 3,
+ 3, 3, 4, 6, 1, 1, 1, 3, 3, 1,
+ 3, 1, 4, 1, 1, 3, 3, 3, 3, 3,
+ 3, 3, 3, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 3, 3, 3, 3,
+ 3, 3, 4, 4, 6, 8, 4, 4, 6, 10,
+ 6, 6, 3, 4, 6, 4, 8, 6, 3, 3,
+ 3, 3, 2, 2, 2, 2, 3, 2, 3, 5,
+ 4, 6, 6, 6, 6, 6, 5, 3, 5, 5,
+ 5, 5
};
static const short yydefact[] = { 1,
- 0, 0, 50, 34, 18, 46, 47, 55, 56, 54,
- 0, 36, 37, 0, 0, 0, 51, 0, 16, 57,
- 0, 0, 0, 0, 0, 53, 0, 0, 0, 0,
- 0, 0, 0, 0, 3, 4, 5, 0, 2, 0,
- 52, 58, 0, 17, 0, 0, 0, 0, 0, 15,
- 0, 0, 0, 0, 0, 92, 93, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 97, 94, 95,
- 49, 0, 48, 0, 9, 10, 0, 0, 0, 0,
+ 0, 0, 48, 32, 19, 44, 45, 53, 54, 52,
+ 0, 34, 35, 0, 0, 0, 49, 0, 17, 55,
+ 0, 0, 0, 0, 0, 51, 0, 0, 0, 0,
+ 0, 0, 0, 0, 6, 7, 5, 0, 2, 0,
+ 50, 56, 0, 18, 0, 0, 0, 0, 0, 16,
+ 0, 0, 0, 0, 0, 83, 84, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 88, 85, 86,
+ 47, 0, 46, 0, 11, 10, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 6, 7, 8, 107, 11, 0, 14, 13, 60,
- 59, 61, 62, 63, 64, 0, 0, 50, 28, 27,
- 32, 0, 29, 0, 0, 0, 29, 0, 82, 0,
- 0, 0, 0, 0, 98, 21, 19, 0, 0, 38,
- 39, 40, 41, 42, 43, 44, 45, 89, 20, 88,
- 90, 91, 0, 96, 0, 0, 0, 65, 35, 0,
- 0, 0, 66, 0, 0, 0, 69, 0, 0, 70,
- 0, 0, 0, 22, 83, 0, 0, 85, 0, 88,
- 0, 0, 100, 106, 12, 99, 33, 30, 31, 0,
- 29, 0, 0, 0, 0, 0, 0, 0, 0, 51,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 109,
- 110, 111, 108, 0, 0, 0, 0, 0, 67, 0,
- 71, 74, 75, 77, 72, 73, 76, 78, 81, 80,
- 23, 24, 25, 26, 0, 84, 0, 87, 101, 102,
- 103, 104, 105, 0, 0, 0, 68, 0, 86, 0,
- 79, 0, 0
+ 0, 3, 4, 8, 9, 98, 12, 0, 15, 14,
+ 58, 57, 59, 60, 61, 62, 0, 0, 48, 26,
+ 25, 30, 0, 27, 47, 0, 46, 0, 27, 0,
+ 73, 0, 0, 0, 0, 0, 89, 22, 20, 0,
+ 0, 36, 37, 38, 39, 40, 41, 42, 43, 80,
+ 21, 79, 81, 82, 87, 0, 0, 0, 0, 63,
+ 33, 0, 0, 0, 64, 0, 67, 0, 68, 0,
+ 23, 0, 74, 0, 0, 76, 0, 79, 0, 0,
+ 91, 97, 13, 90, 31, 28, 29, 0, 27, 0,
+ 49, 0, 0, 0, 0, 0, 0, 100, 101, 102,
+ 99, 0, 0, 0, 0, 0, 65, 0, 69, 72,
+ 71, 24, 0, 75, 0, 78, 92, 93, 94, 95,
+ 96, 0, 0, 0, 66, 0, 77, 0, 70, 0,
+ 0
};
static const short yydefgoto[] = { 1,
- 39, 110, 111, 112, 41, 42, 72, 73
+ 95, 39, 111, 112, 113, 41, 42, 72, 73
};
static const short yypact[] = {-32768,
- 218, -41, -44,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
- 27,-32768,-32768, 8, 34, 40,-32768, 58,-32768, 59,
- 1, 2, 24, 25, 37,-32768, 38, 48, 49, 53,
- 54, 746, 15, 44,-32768,-32768,-32768, 426,-32768, 35,
--32768,-32768, 1008,-32768, 104, 21, 46, 21, 21,-32768,
- 426, 746, 746, 746, 746,-32768,-32768, 746, 746, 361,
- 426, 361, 746, 289, 746, 426, 426,-32768,-32768,-32768,
- 69, 39, 1048, 426,-32768,-32768, 556, 746, 746, 746,
- 746, 746, 746, 746, 746, 746, 426, 746, 746, 746,
- 746,-32768,-32768,-32768, 68, 130, 746,-32768,-32768, 69,
- 1048, 1063, 1063, 1063, 1063, 680, 740, -20,-32768, 69,
--32768, -30, 80, -4, 773, -12, 1048, 800,-32768, -27,
- 419, -5, 134, 746,-32768,-32768, 137, 100, 1033, 131,
- 131, 57, 57, 57, 57, 57, 57, 137,-32768, 137,
- 3, 3, 353,-32768, 146, 21, 613,-32768,-32768, 149,
- 361, 746,-32768, 361, 426, 426,-32768, 426, 426,-32768,
- 491, 426, 426,-32768,-32768, 746, 426,-32768, 426, 137,
- 621, 686, 136,-32768,-32768,-32768,-32768, 110, 1063, -25,
- 484, -57, 826, -37, 852, -36, 878, -35, 904, 89,
- 90, 1048, -34, 930, -33, 956, 549, 93, -3,-32768,
- 1063,-32768, 1063, 746, 746, 746, 746, 746,-32768, 746,
--32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
--32768,-32768,-32768,-32768, 361,-32768, 426,-32768, 1063, 1063,
- 1063, 1063, 1063, 982, 0, 94,-32768, 426,-32768, 99,
--32768, 181,-32768
+ 235, -46, -48,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+ 22,-32768,-32768, 4, 29, 33,-32768, 35,-32768, 145,
+ 1, 2, 18, 20, 21,-32768, 23, 34, 36, 37,
+ 39, 763, 42, 44,-32768,-32768,-32768, 443,-32768, -30,
+-32768,-32768, 814,-32768, 43, 13, 50, 13, 13,-32768,
+ 443, 763, 763, 763, 763,-32768,-32768, 763, 763, 378,
+ 443, 378, 763, 306, 763, 443, 443,-32768,-32768,-32768,
+ 6, 40, 854, 443,-32768,-32768, 573, 763, 763, 763,
+ 763, 763, 763, 763, 763, 763, 443, 763, 763, 763,
+ 763,-32768,-32768,-32768,-32768, 46, 108, 763,-32768,-32768,
+ 6, 854, 869, 869, 869, 869, 631, 697, -20,-32768,
+ 6,-32768, -31, 121, -36, -22, 756, -12, 854, 566,
+-32768, -29, 228, -8, 111, 763,-32768,-32768, 56, 78,
+ 839, 170, 170, 77, 77, 77, 77, 77, 77, 56,
+-32768, 56, 5, 5, 64, 298, 126, 13, 370,-32768,
+-32768, 127, 378, 763,-32768, 378,-32768, 443,-32768, 508,
+-32768, 443,-32768, 763, 443,-32768, 443, 56, 638, 703,
+ 60,-32768,-32768,-32768,-32768, 85, 869, -27, 436, 58,
+ 59, 68, 854, -35, 501, 69, -3,-32768, 869,-32768,
+ 869, 763, 763, 763, 763, 763,-32768, 763,-32768,-32768,
+-32768,-32768, 378,-32768, 443,-32768, 869, 869, 869, 869,
+ 869, 788, -10, 70,-32768, 443,-32768, 73,-32768, 148,
+-32768
};
static const short yypgoto[] = {-32768,
--32768, 108, -147, -59,-32768, -42, -55, -1
+ -95,-32768, 54, -147, -58,-32768, -37, -59, -1
};
-#define YYLAST 1126
+#define YYLAST 932
static const short yytable[] = { 43,
- 161, 74, 116, 96, 120, 98, 99, 167, 155, 227,
- 122, 123, 238, 191, 151, 152, 211, 151, 152, 151,
- 152, 74, 74, 74, 74, 74, 150, 6, 44, 7,
- 68, 45, 151, 152, 46, 47, 213, 215, 217, 221,
- 223, 48, 69, 153, 151, 152, 165, 49, 209, 101,
- 102, 103, 104, 105, 74, 45, 106, 107, 113, 115,
- 117, 118, 117, 121, 90, 91, 50, 156, 168, 157,
- 228, 70, 127, 58, 59, 129, 130, 131, 132, 133,
- 134, 135, 136, 137, 138, 140, 141, 142, 143, 144,
- 240, 178, 154, 74, 180, 147, 60, 61, 51, 52,
- 53, 54, 55, 175, 75, 76, 95, 97, 40, 62,
- 63, 198, 125, 199, 86, 124, 88, 89, 90, 91,
- 64, 65, 170, 56, 57, 66, 67, 74, 77, 78,
- 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
- 89, 90, 91, 145, 146, 71, 169, 171, 174, 117,
- 179, 177, 181, 183, 185, 152, 187, 189, 100, 192,
- 194, 196, 219, 220, 197, 235, 226, 239, 114, 201,
- 203, 236, 241, 71, 71, 204, 205, 206, 207, 208,
- 243, 126, 80, 81, 82, 83, 84, 85, 86, 124,
- 88, 89, 90, 91, 139, 0, 88, 89, 90, 91,
- 0, 0, 229, 230, 231, 232, 233, 0, 234, 0,
- 0, 0, 0, 0, 0, 0, 0, 242, 2, 0,
- 3, 4, 5, 117, 6, 0, 7, 8, 9, 10,
- 0, 11, 0, 12, 13, 0, 192, 0, 14, 15,
- 16, 0, 17, 18, 19, 20, 21, 22, 23, 24,
- 25, 26, 27, 28, 29, 30, 31, 0, 0, 0,
- 0, 0, 182, 184, 0, 186, 188, 0, 0, 193,
- 195, 0, 0, 0, 71, 32, 71, 0, 0, 0,
- 0, 0, 33, 34, 0, 0, 0, 35, 36, 37,
- 38, 108, 4, 5, 109, 6, 0, 7, 8, 9,
- 10, 0, 0, 0, 12, 13, 0, 0, 0, 14,
- 0, 0, 0, 17, 0, 0, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31, 0, 0,
- 0, 0, 0, 0, 71, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 32, 0, 0, 0,
- 0, 0, 0, 33, 34, 0, 0, 0, 0, 0,
- 0, 38, 119, 108, 4, 5, 109, 6, 0, 7,
- 8, 9, 10, 0, 0, 0, 12, 13, 0, 0,
- 0, 14, 0, 0, 0, 17, 0, 0, 20, 21,
- 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 0, 77, 78, 79, 80, 81, 82, 83, 84, 85,
- 86, 124, 88, 89, 90, 91, 0, 0, 32, 0,
- 0, 0, 0, 0, 0, 33, 34, 173, 3, 4,
- 5, 166, 6, 38, 7, 8, 9, 10, 0, 0,
+ 160, 116, 216, 118, 165, 122, 124, 125, 97, 205,
+ 99, 100, 182, 153, 154, 153, 154, 153, 154, 6,
+ 158, 7, 74, 74, 162, 44, 152, 45, 74, 46,
+ 68, 47, 153, 154, 153, 154, 48, 157, 202, 75,
+ 49, 76, 155, 50, 163, 96, 197, 92, 93, 102,
+ 103, 104, 105, 106, 40, 45, 107, 108, 114, 117,
+ 119, 120, 119, 123, 74, 166, 90, 91, 218, 69,
+ 206, 70, 129, 58, 59, 131, 132, 133, 134, 135,
+ 136, 137, 138, 139, 140, 142, 143, 144, 145, 146,
+ 60, 71, 61, 62, 176, 63, 149, 178, 180, 192,
+ 193, 194, 195, 196, 101, 186, 64, 187, 65, 66,
+ 173, 67, 98, 127, 115, 88, 89, 90, 91, 71,
+ 71, 147, 148, 167, 168, 169, 91, 128, 172, 175,
+ 154, 199, 200, 156, 86, 126, 88, 89, 90, 91,
+ 141, 201, 204, 217, 213, 214, 219, 221, 0, 0,
+ 0, 119, 177, 0, 179, 0, 0, 0, 183, 0,
+ 183, 0, 185, 0, 0, 0, 0, 189, 191, 77,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 51, 52, 53, 54, 55, 0,
+ 207, 208, 209, 210, 211, 0, 212, 0, 0, 0,
+ 0, 119, 0, 0, 0, 0, 0, 0, 0, 56,
+ 57, 71, 0, 0, 183, 184, 0, 0, 71, 0,
+ 71, 80, 81, 82, 83, 84, 85, 86, 126, 88,
+ 89, 90, 91, 0, 220, 2, 0, 3, 4, 5,
+ 164, 6, 0, 7, 8, 9, 10, 0, 11, 0,
+ 12, 13, 0, 0, 0, 14, 15, 16, 71, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 31, 0, 0, 77, 78, 79, 80,
+ 81, 82, 83, 84, 85, 86, 126, 88, 89, 90,
+ 91, 0, 32, 0, 0, 0, 0, 0, 0, 33,
+ 34, 0, 0, 0, 35, 36, 37, 38, 109, 4,
+ 5, 110, 6, 0, 7, 8, 9, 10, 0, 0,
0, 12, 13, 0, 0, 0, 14, 0, 0, 0,
17, 0, 0, 20, 21, 22, 23, 24, 25, 26,
- 27, 28, 29, 30, 31, 0, 0, 77, 78, 79,
- 80, 81, 82, 83, 84, 85, 86, 124, 88, 89,
- 90, 91, 0, 32, 0, 0, 0, 0, 0, 0,
- 33, 34, 0, 3, 4, 5, 210, 6, 38, 7,
- 8, 9, 10, 0, 0, 0, 12, 13, 0, 0,
- 0, 14, 0, 0, 0, 190, 0, 0, 20, 21,
- 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 0, 0, 77, 78, 79, 80, 81, 82, 83, 84,
- 85, 86, 87, 88, 89, 90, 91, 0, 32, 0,
- 0, 0, 0, 0, 0, 33, 34, 0, 3, 4,
- 128, 225, 6, 38, 7, 8, 9, 10, 0, 0,
- 0, 12, 13, 0, 0, 0, 14, 0, 0, 0,
- 17, 0, 0, 20, 21, 22, 23, 24, 25, 26,
- 0, 28, 29, 30, 31, 0, 0, 77, 78, 79,
- 80, 81, 82, 83, 84, 85, 86, 124, 88, 89,
- 90, 91, 0, 32, 0, 0, 0, 0, 0, 0,
- 33, 34, 0, 3, 4, 200, 0, 6, 38, 7,
- 8, 9, 10, 0, 0, 0, 12, 13, 0, 0,
- 0, 14, 0, 0, 0, 17, 0, 0, 20, 21,
- 22, 23, 24, 25, 26, 0, 28, 29, 30, 31,
- 0, 77, 78, 79, 80, 81, 82, 83, 84, 85,
- 86, 124, 88, 89, 90, 91, 0, 0, 32, 0,
- 0, 0, 0, 0, 0, 33, 34, 176, 3, 4,
- 202, 0, 6, 38, 7, 8, 9, 10, 0, 0,
- 0, 12, 13, 0, 0, 0, 14, 0, 0, 0,
- 17, 0, 0, 20, 21, 22, 23, 24, 25, 26,
- 0, 28, 29, 30, 31, 0, 0, 0, 77, 78,
- 79, 80, 81, 82, 83, 84, 85, 86, 124, 88,
- 89, 90, 91, 32, 0, 0, 0, 0, 3, 4,
- 33, 34, 6, 148, 7, 8, 9, 10, 38, 0,
- 0, 12, 13, 0, 0, 0, 14, 0, 0, 0,
- 17, 0, 0, 20, 21, 22, 23, 24, 25, 26,
- 0, 28, 29, 30, 31, 158, 0, 0, 77, 78,
- 79, 80, 81, 82, 83, 84, 85, 86, 124, 88,
- 89, 90, 91, 32, 0, 0, 0, 0, 0, 0,
- 33, 34, 162, 149, 0, 0, 0, 0, 38, 0,
- 0, 77, 78, 79, 80, 81, 82, 83, 84, 85,
- 86, 87, 88, 89, 90, 91, 0, 0, 0, 0,
- 0, 0, 0, 0, 159, 0, 160, 0, 77, 78,
- 79, 80, 81, 82, 83, 84, 85, 86, 124, 88,
- 89, 90, 91, 0, 0, 0, 0, 0, 0, 0,
- 0, 163, 0, 164, 77, 78, 79, 80, 81, 82,
+ 27, 28, 29, 30, 31, 0, 77, 78, 79, 80,
+ 81, 82, 83, 84, 85, 86, 126, 88, 89, 90,
+ 91, 0, 0, 32, 0, 0, 0, 0, 0, 0,
+ 33, 34, 171, 0, 0, 0, 0, 0, 38, 121,
+ 109, 4, 5, 110, 6, 0, 7, 8, 9, 10,
+ 0, 0, 0, 12, 13, 0, 0, 0, 14, 0,
+ 0, 0, 17, 0, 0, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 0, 77, 78,
+ 79, 80, 81, 82, 83, 84, 85, 86, 126, 88,
+ 89, 90, 91, 0, 0, 32, 0, 0, 0, 0,
+ 0, 0, 33, 34, 174, 3, 4, 5, 198, 6,
+ 38, 7, 8, 9, 10, 0, 0, 0, 12, 13,
+ 0, 0, 0, 14, 0, 0, 0, 17, 0, 0,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 0, 0, 77, 78, 79, 80, 81, 82,
+ 83, 84, 85, 86, 87, 88, 89, 90, 91, 0,
+ 32, 0, 0, 0, 0, 0, 0, 33, 34, 0,
+ 3, 4, 5, 203, 6, 38, 7, 8, 9, 10,
+ 0, 0, 0, 12, 13, 0, 0, 0, 14, 0,
+ 0, 0, 181, 0, 0, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 0, 0, 77,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 126,
+ 88, 89, 90, 91, 0, 32, 0, 0, 0, 0,
+ 0, 0, 33, 34, 0, 3, 4, 130, 0, 6,
+ 38, 7, 8, 9, 10, 0, 0, 0, 12, 13,
+ 0, 0, 0, 14, 0, 0, 0, 17, 0, 0,
+ 20, 21, 22, 23, 24, 25, 26, 0, 28, 29,
+ 30, 31, 0, 0, 77, 78, 79, 80, 81, 82,
+ 83, 84, 85, 86, 126, 88, 89, 90, 91, 0,
+ 32, 0, 0, 0, 0, 92, 93, 33, 34, 161,
+ 3, 4, 188, 0, 6, 38, 7, 8, 9, 10,
+ 0, 0, 0, 12, 13, 0, 0, 0, 14, 0,
+ 0, 0, 17, 0, 0, 20, 21, 22, 23, 24,
+ 25, 26, 0, 28, 29, 30, 31, 0, 0, 77,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 126,
+ 88, 89, 90, 91, 0, 32, 0, 0, 0, 0,
+ 0, 0, 33, 34, 150, 3, 4, 190, 0, 6,
+ 38, 7, 8, 9, 10, 0, 0, 0, 12, 13,
+ 0, 0, 0, 14, 0, 0, 0, 17, 0, 0,
+ 20, 21, 22, 23, 24, 25, 26, 0, 28, 29,
+ 30, 31, 0, 0, 0, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 126, 88, 89, 90, 91,
+ 32, 0, 0, 0, 0, 3, 4, 33, 34, 6,
+ 151, 7, 8, 9, 10, 38, 0, 0, 12, 13,
+ 0, 0, 0, 14, 0, 0, 0, 17, 0, 0,
+ 20, 21, 22, 23, 24, 25, 26, 0, 28, 29,
+ 30, 31, 0, 0, 77, 78, 79, 80, 81, 82,
83, 84, 85, 86, 87, 88, 89, 90, 91, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 212,
- 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
- 87, 88, 89, 90, 91, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 214, 77, 78, 79, 80,
- 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
+ 32, 0, 0, 0, 0, 0, 0, 33, 34, 159,
+ 0, 0, 0, 0, 0, 38, 77, 78, 79, 80,
+ 81, 82, 83, 84, 85, 86, 126, 88, 89, 90,
91, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 216, 77, 78, 79, 80, 81, 82, 83, 84,
+ 0, 215, 77, 78, 79, 80, 81, 82, 83, 84,
85, 86, 87, 88, 89, 90, 91, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 218, 77, 78,
- 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
- 89, 90, 91, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 222, 77, 78, 79, 80, 81, 82,
- 83, 84, 85, 86, 87, 88, 89, 90, 91, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 224,
- 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
- 124, 88, 89, 90, 91, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 237, 77, 78, 79, 80,
- 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
- 91, 0, 0, 0, 0, 0, 0, 92, 93, 94,
- 172, 77, 78, 79, 80, 81, 82, 83, 84, 85,
- 86, 124, 88, 89, 90, 91, 77, 78, 79, 80,
- 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
- 91, 77, 78, 79, 80, 81, 82, 83, 84, 85,
- 86, 124, 88, 89, 90, 91
+ 0, 0, 0, 92, 93, 94, 170, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 126, 88, 89,
+ 90, 91, 77, 78, 79, 80, 81, 82, 83, 84,
+ 85, 86, 87, 88, 89, 90, 91, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 126, 88, 89,
+ 90, 91
};
static const short yycheck[] = { 1,
- 13, 59, 62, 46, 64, 48, 49, 13, 13, 13,
- 66, 67, 13, 161, 45, 46, 74, 45, 46, 45,
- 46, 59, 59, 59, 59, 59, 47, 7, 70, 9,
- 32, 76, 45, 46, 8, 28, 74, 74, 74, 74,
- 74, 8, 28, 74, 45, 46, 74, 8, 74, 51,
- 52, 53, 54, 55, 59, 76, 58, 59, 60, 61,
- 62, 63, 64, 65, 62, 63, 9, 72, 74, 74,
+ 13, 61, 13, 62, 13, 64, 66, 67, 46, 13,
+ 48, 49, 160, 45, 46, 45, 46, 45, 46, 7,
+ 116, 9, 59, 59, 120, 72, 47, 76, 59, 8,
+ 32, 28, 45, 46, 45, 46, 8, 74, 74, 70,
+ 8, 72, 74, 9, 74, 3, 74, 70, 71, 51,
+ 52, 53, 54, 55, 1, 76, 58, 59, 60, 61,
+ 62, 63, 64, 65, 59, 74, 62, 63, 216, 28,
74, 28, 74, 73, 73, 77, 78, 79, 80, 81,
82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
- 238, 151, 13, 59, 154, 97, 73, 73, 40, 41,
- 42, 43, 44, 146, 70, 71, 3, 62, 1, 73,
- 73, 167, 74, 169, 58, 59, 60, 61, 62, 63,
- 73, 73, 124, 65, 66, 73, 73, 59, 49, 50,
- 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
- 61, 62, 63, 76, 15, 38, 13, 48, 3, 151,
- 152, 3, 154, 155, 156, 46, 158, 159, 51, 161,
- 162, 163, 74, 74, 166, 225, 74, 74, 61, 171,
- 172, 227, 74, 66, 67, 40, 41, 42, 43, 44,
- 0, 74, 52, 53, 54, 55, 56, 57, 58, 59,
- 60, 61, 62, 63, 87, -1, 60, 61, 62, 63,
- -1, -1, 204, 205, 206, 207, 208, -1, 210, -1,
- -1, -1, -1, -1, -1, -1, -1, 0, 1, -1,
- 3, 4, 5, 225, 7, -1, 9, 10, 11, 12,
- -1, 14, -1, 16, 17, -1, 238, -1, 21, 22,
- 23, -1, 25, 26, 27, 28, 29, 30, 31, 32,
- 33, 34, 35, 36, 37, 38, 39, -1, -1, -1,
- -1, -1, 155, 156, -1, 158, 159, -1, -1, 162,
- 163, -1, -1, -1, 167, 58, 169, -1, -1, -1,
- -1, -1, 65, 66, -1, -1, -1, 70, 71, 72,
- 73, 3, 4, 5, 6, 7, -1, 9, 10, 11,
- 12, -1, -1, -1, 16, 17, -1, -1, -1, 21,
- -1, -1, -1, 25, -1, -1, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, -1, -1,
- -1, -1, -1, -1, 227, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, 58, -1, -1, -1,
- -1, -1, -1, 65, 66, -1, -1, -1, -1, -1,
- -1, 73, 74, 3, 4, 5, 6, 7, -1, 9,
- 10, 11, 12, -1, -1, -1, 16, 17, -1, -1,
- -1, 21, -1, -1, -1, 25, -1, -1, 28, 29,
- 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
- -1, 49, 50, 51, 52, 53, 54, 55, 56, 57,
- 58, 59, 60, 61, 62, 63, -1, -1, 58, -1,
- -1, -1, -1, -1, -1, 65, 66, 75, 3, 4,
- 5, 13, 7, 73, 9, 10, 11, 12, -1, -1,
- -1, 16, 17, -1, -1, -1, 21, -1, -1, -1,
- 25, -1, -1, 28, 29, 30, 31, 32, 33, 34,
- 35, 36, 37, 38, 39, -1, -1, 49, 50, 51,
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
- 62, 63, -1, 58, -1, -1, -1, -1, -1, -1,
- 65, 66, -1, 3, 4, 5, 13, 7, 73, 9,
- 10, 11, 12, -1, -1, -1, 16, 17, -1, -1,
- -1, 21, -1, -1, -1, 25, -1, -1, 28, 29,
- 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
- -1, -1, 49, 50, 51, 52, 53, 54, 55, 56,
- 57, 58, 59, 60, 61, 62, 63, -1, 58, -1,
- -1, -1, -1, -1, -1, 65, 66, -1, 3, 4,
- 5, 13, 7, 73, 9, 10, 11, 12, -1, -1,
- -1, 16, 17, -1, -1, -1, 21, -1, -1, -1,
- 25, -1, -1, 28, 29, 30, 31, 32, 33, 34,
- -1, 36, 37, 38, 39, -1, -1, 49, 50, 51,
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
- 62, 63, -1, 58, -1, -1, -1, -1, -1, -1,
- 65, 66, -1, 3, 4, 5, -1, 7, 73, 9,
- 10, 11, 12, -1, -1, -1, 16, 17, -1, -1,
- -1, 21, -1, -1, -1, 25, -1, -1, 28, 29,
- 30, 31, 32, 33, 34, -1, 36, 37, 38, 39,
- -1, 49, 50, 51, 52, 53, 54, 55, 56, 57,
- 58, 59, 60, 61, 62, 63, -1, -1, 58, -1,
- -1, -1, -1, -1, -1, 65, 66, 75, 3, 4,
- 5, -1, 7, 73, 9, 10, 11, 12, -1, -1,
- -1, 16, 17, -1, -1, -1, 21, -1, -1, -1,
- 25, -1, -1, 28, 29, 30, 31, 32, 33, 34,
- -1, 36, 37, 38, 39, -1, -1, -1, 49, 50,
- 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
- 61, 62, 63, 58, -1, -1, -1, -1, 3, 4,
- 65, 66, 7, 74, 9, 10, 11, 12, 73, -1,
+ 73, 38, 73, 73, 153, 73, 98, 156, 158, 40,
+ 41, 42, 43, 44, 51, 165, 73, 167, 73, 73,
+ 148, 73, 63, 74, 61, 60, 61, 62, 63, 66,
+ 67, 76, 15, 13, 126, 48, 63, 74, 3, 3,
+ 46, 74, 74, 13, 58, 59, 60, 61, 62, 63,
+ 87, 74, 74, 74, 203, 205, 74, 0, -1, -1,
+ -1, 153, 154, -1, 156, -1, -1, -1, 160, -1,
+ 162, -1, 164, -1, -1, -1, -1, 169, 170, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 40, 41, 42, 43, 44, -1,
+ 192, 193, 194, 195, 196, -1, 198, -1, -1, -1,
+ -1, 203, -1, -1, -1, -1, -1, -1, -1, 65,
+ 66, 158, -1, -1, 216, 162, -1, -1, 165, -1,
+ 167, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+ 61, 62, 63, -1, 0, 1, -1, 3, 4, 5,
+ 13, 7, -1, 9, 10, 11, 12, -1, 14, -1,
+ 16, 17, -1, -1, -1, 21, 22, 23, 205, 25,
+ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, -1, -1, 49, 50, 51, 52,
+ 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
+ 63, -1, 58, -1, -1, -1, -1, -1, -1, 65,
+ 66, -1, -1, -1, 70, 71, 72, 73, 3, 4,
+ 5, 6, 7, -1, 9, 10, 11, 12, -1, -1,
-1, 16, 17, -1, -1, -1, 21, -1, -1, -1,
25, -1, -1, 28, 29, 30, 31, 32, 33, 34,
- -1, 36, 37, 38, 39, 13, -1, -1, 49, 50,
- 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
- 61, 62, 63, 58, -1, -1, -1, -1, -1, -1,
- 65, 66, 13, 74, -1, -1, -1, -1, 73, -1,
- -1, 49, 50, 51, 52, 53, 54, 55, 56, 57,
- 58, 59, 60, 61, 62, 63, -1, -1, -1, -1,
- -1, -1, -1, -1, 72, -1, 74, -1, 49, 50,
+ 35, 36, 37, 38, 39, -1, 49, 50, 51, 52,
+ 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
+ 63, -1, -1, 58, -1, -1, -1, -1, -1, -1,
+ 65, 66, 75, -1, -1, -1, -1, -1, 73, 74,
+ 3, 4, 5, 6, 7, -1, 9, 10, 11, 12,
+ -1, -1, -1, 16, 17, -1, -1, -1, 21, -1,
+ -1, -1, 25, -1, -1, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, -1, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
- 61, 62, 63, -1, -1, -1, -1, -1, -1, -1,
- -1, 72, -1, 74, 49, 50, 51, 52, 53, 54,
+ 61, 62, 63, -1, -1, 58, -1, -1, -1, -1,
+ -1, -1, 65, 66, 75, 3, 4, 5, 13, 7,
+ 73, 9, 10, 11, 12, -1, -1, -1, 16, 17,
+ -1, -1, -1, 21, -1, -1, -1, 25, -1, -1,
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, -1, -1, 49, 50, 51, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, 62, 63, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 74,
- 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
- 59, 60, 61, 62, 63, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 74, 49, 50, 51, 52,
+ 58, -1, -1, -1, -1, -1, -1, 65, 66, -1,
+ 3, 4, 5, 13, 7, 73, 9, 10, 11, 12,
+ -1, -1, -1, 16, 17, -1, -1, -1, 21, -1,
+ -1, -1, 25, -1, -1, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, -1, -1, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, -1, 58, -1, -1, -1, -1,
+ -1, -1, 65, 66, -1, 3, 4, 5, -1, 7,
+ 73, 9, 10, 11, 12, -1, -1, -1, 16, 17,
+ -1, -1, -1, 21, -1, -1, -1, 25, -1, -1,
+ 28, 29, 30, 31, 32, 33, 34, -1, 36, 37,
+ 38, 39, -1, -1, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, -1,
+ 58, -1, -1, -1, -1, 70, 71, 65, 66, 74,
+ 3, 4, 5, -1, 7, 73, 9, 10, 11, 12,
+ -1, -1, -1, 16, 17, -1, -1, -1, 21, -1,
+ -1, -1, 25, -1, -1, 28, 29, 30, 31, 32,
+ 33, 34, -1, 36, 37, 38, 39, -1, -1, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, -1, 58, -1, -1, -1, -1,
+ -1, -1, 65, 66, 74, 3, 4, 5, -1, 7,
+ 73, 9, 10, 11, 12, -1, -1, -1, 16, 17,
+ -1, -1, -1, 21, -1, -1, -1, 25, -1, -1,
+ 28, 29, 30, 31, 32, 33, 34, -1, 36, 37,
+ 38, 39, -1, -1, -1, 49, 50, 51, 52, 53,
+ 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 58, -1, -1, -1, -1, 3, 4, 65, 66, 7,
+ 74, 9, 10, 11, 12, 73, -1, -1, 16, 17,
+ -1, -1, -1, 21, -1, -1, -1, 25, -1, -1,
+ 28, 29, 30, 31, 32, 33, 34, -1, 36, 37,
+ 38, 39, -1, -1, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, -1,
+ 58, -1, -1, -1, -1, -1, -1, 65, 66, 74,
+ -1, -1, -1, -1, -1, 73, 49, 50, 51, 52,
53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
63, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 74, 49, 50, 51, 52, 53, 54, 55, 56,
57, 58, 59, 60, 61, 62, 63, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 74, 49, 50,
- 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
- 61, 62, 63, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 74, 49, 50, 51, 52, 53, 54,
- 55, 56, 57, 58, 59, 60, 61, 62, 63, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 74,
- 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
- 59, 60, 61, 62, 63, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 74, 49, 50, 51, 52,
- 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
- 63, -1, -1, -1, -1, -1, -1, 70, 71, 72,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
- 58, 59, 60, 61, 62, 63, 49, 50, 51, 52,
- 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
- 63, 49, 50, 51, 52, 53, 54, 55, 56, 57,
- 58, 59, 60, 61, 62, 63
+ -1, -1, -1, 70, 71, 72, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+ 62, 63, 49, 50, 51, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, 62, 63, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+ 62, 63
};
/* -*-C-*- Note some compilers choke on comments on `#line' lines. */
@@ -1196,12 +1144,6 @@ yyreduce:
switch (yyn) {
-case 6:
-{store_res(&yyvsp[-1]); return 0;;
- break;}
-case 7:
-{store_res(&yyvsp[-1]); return 0;;
- break;}
case 8:
{store_res(&yyvsp[-1]); return 0;;
break;}
@@ -1212,322 +1154,295 @@ case 10:
{store_res(&yyvsp[-1]); return 0;;
break;}
case 11:
+{store_res(&yyvsp[-1]); return 0;;
+ break;}
+case 12:
{if(block_res = eval(&yyval, &yyvsp[-1]))return block_res;
if(yyval.val != 0.0) if(block_res = eval(&yyval, &yyvsp[0]))return block_res;;
break;}
-case 12:
+case 13:
{if(block_res = eval(&yyval, &yyvsp[-3])) return block_res;
if(yyval.val != 0.0) {if(block_res = eval(&yyval, &yyvsp[-2])) return block_res;}
else if(block_res = eval(&yyval, &yyvsp[0])) return block_res;;
break;}
-case 13:
-{for_loop(yyvsp[-1].text, yyvsp[0].text);;
- break;}
case 14:
-{for(int i=0; i< yy_maxiter; i++){ if(block_res = eval(&yyval, &yyvsp[-1]))return block_res;
- if(yyval.val != 0.0){if(block_res = eval(&yyval, &yyvsp[0]))return block_res;} else break;};
+{block_res = for_loop(yyvsp[-1].text, yyvsp[0].text); if(block_res == 1 || block_res == 2) return block_res;;
break;}
case 15:
-{if(block_res = eval(&yyval, &yyvsp[0]) == 1) return 1; else return 2;;
+{for(int i=0; i< yy_maxiter; i++){ if(block_res = eval(&yyval, &yyvsp[-1]))return block_res;
+ if(yyval.val != 0.0){if(block_res = eval(&yyval, &yyvsp[0]))return block_res;} else break;};
break;}
case 16:
-{return 3;;
+{if(block_res = eval(&yyval, &yyvsp[0]) == 1) return 1; else return 2;;
break;}
case 17:
-{yyerrok;;
+{return 3;;
break;}
case 18:
-{;;
+{yyerrok;;
break;}
case 19:
-{yyval.text=add_strings(yyvsp[-2].text, string_value(&yyvsp[0])); yyval.type = STR;;
+{;;
break;}
case 20:
-{yyval.text=add_strings(string_value(&yyvsp[-2]), yyvsp[0].text); yyval.type = STR;;
+{yyval.text=add_strings(yyvsp[-2].text, string_value(&yyvsp[0])); yyval.type = STR;;
break;}
case 21:
-{yyval.text=add_strings(yyvsp[-2].text, yyvsp[0].text); yyval.type = STR;;
+{yyval.text=add_strings(string_value(&yyvsp[-2]), yyvsp[0].text); yyval.type = STR;;
break;}
case 22:
-{if(yyvsp[-3].tptr->fnctptr)((yyvsp[-3].tptr->fnctptr)(&yyval, &yyvsp[-1], 0L)); yyval.type = STR;;
+{yyval.text=add_strings(yyvsp[-2].text, yyvsp[0].text); yyval.type = STR;;
break;}
case 23:
-{if(yyvsp[-5].tptr->fnctptr)((yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;;
+{if(yyvsp[-3].tptr->fnctptr)((yyvsp[-3].tptr->fnctptr)(&yyval, &yyvsp[-1], 0L)); yyval.type = STR;;
break;}
case 24:
{if(yyvsp[-5].tptr->fnctptr)((yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;;
break;}
case 25:
-{if(yyvsp[-5].tptr->fnctptr)((yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;;
- break;}
-case 26:
-{if(yyvsp[-5].tptr->fnctptr)((yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;;
- break;}
-case 27:
{;;
break;}
-case 28:
+case 26:
{;;
break;}
-case 29:
+case 27:
{if(!yyval.a_data) {yyval.a_data = PushArray((double*)malloc(sizeof(double))); yyval.a_count = 1; yyval.a_data[0] = yyval.val;};
break;}
-case 30:
+case 28:
{push(&yyval, &yyvsp[0]);yyval.type = ARR;;
break;}
-case 31:
+case 29:
{exec_clause(&yyval);;
break;}
-case 32:
+case 30:
{range_array(&yyval, yyvsp[0].text);;
break;}
-case 33:
+case 31:
{if(yyvsp[-2].val < yyvsp[0].val && (yyval.a_data = PushArray((double*)malloc((int)(yyvsp[0].val-yyvsp[-2].val+2)*sizeof(double)))))
for(yyval.a_count=0; yyvsp[-2].val<=yyvsp[0].val; yyval.a_data[yyval.a_count++] = yyvsp[-2].val, yyvsp[-2].val += 1.0 ); yyval.type = ARR;;
break;}
-case 35:
+case 33:
{yyval.val = yyvsp[-3].tptr->fnctptr ? ((yyvsp[-3].tptr->fnctptr)(yyvsp[-1].val)): 0.0; yyval.type = BOOLVAL;;
break;}
-case 36:
+case 34:
{yyval.val = 1.0; yyval.type = BOOLVAL;;
break;}
-case 37:
+case 35:
{yyval.val = 0.0; yyval.type = BOOLVAL;;
break;}
+case 36:
+{yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], AND);;
+ break;}
+case 37:
+{yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], OR);;
+ break;}
case 38:
-{yyval.val = ((yyvsp[-2].val != 0) && (yyvsp[0].val != 0))? 1 : 0; yyval.type = BOOLVAL;;
+{yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], EQ);;
break;}
case 39:
-{yyval.val = ((yyvsp[-2].val != 0) || (yyvsp[0].val != 0))? 1 : 0; yyval.type = BOOLVAL;;
+{yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], NE);;
break;}
case 40:
-{yyval.val = (yyvsp[-2].val == yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
+{yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], GT);;
break;}
case 41:
-{yyval.val = (yyvsp[-2].val != yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
+{yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], GE);;
break;}
case 42:
-{yyval.val = (yyvsp[-2].val > yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
+{yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], LT);;
break;}
case 43:
-{yyval.val = (yyvsp[-2].val >= yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
+{yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], LE);;
break;}
-case 44:
-{yyval.val = (yyvsp[-2].val < yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
- break;}
-case 45:
-{yyval.val = (yyvsp[-2].val <= yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
- break;}
-case 50:
+case 48:
{yyval.val = yyvsp[0].val; yyval.type = NUM;;
break;}
-case 52:
+case 50:
{yyval.val = yyvsp[0].val; yyval.type = BOOLVAL;;
break;}
-case 53:
+case 51:
{yyval.val = 0.0;;
break;}
-case 54:
+case 52:
{yyval.val = syntax_level ? syntax_level->clval : 0.0; yyval.type = NUM;;
break;}
-case 55:
+case 53:
{yyval.val = _PI; yyval.type = NUM;;
break;}
-case 56:
+case 54:
{yyval.val = 2.71828182845905; yyval.type = NUM;;
break;}
-case 57:
+case 55:
{if(yyvsp[0].tptr)yyvsp[0].tptr->GetValue(&yyval);;
break;}
-case 58:
+case 56:
{if(block_res = eval(&yyval, &yyvsp[0]))return block_res;;
break;}
-case 59:
+case 57:
{if(yyvsp[-2].tptr)yyvsp[-2].tptr->SetValue(&yyval, &yyvsp[0]);;
break;}
-case 60:
+case 58:
{if(yyvsp[-2].tptr)yyvsp[-2].tptr->SetValue(&yyval, &yyvsp[0]);;
break;}
-case 61:
+case 59:
{if(yyvsp[-2].tptr){yyvsp[-2].tptr->GetValue(&yyval); yyvsp[-2].tptr->SetValue(yyval.val + yyvsp[0].val);};
break;}
-case 62:
+case 60:
{if(yyvsp[-2].tptr){yyvsp[-2].tptr->GetValue(&yyval); yyvsp[-2].tptr->SetValue(yyval.val - yyvsp[0].val);};
break;}
-case 63:
+case 61:
{if(yyvsp[-2].tptr){yyvsp[-2].tptr->GetValue(&yyval); yyvsp[-2].tptr->SetValue(yyval.val * yyvsp[0].val);};
break;}
-case 64:
+case 62:
{if(yyvsp[-2].tptr){yyvsp[-2].tptr->GetValue(&yyval); yyvsp[-2].tptr->SetValue(yyvsp[0].val != 0.0 ? yyval.val / yyvsp[0].val :
(getsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv")))->GetValue());};
break;}
-case 65:
+case 63:
{yyval.val = yyvsp[-3].tptr->fnctptr ? ((yyvsp[-3].tptr->fnctptr)(yyvsp[-1].val)): 0.0; yyval.type = NUM;;
break;}
-case 66:
+case 64:
{yyval.val = yyvsp[-3].tptr->fnctptr ? ((yyvsp[-3].tptr->fnctptr)(proc_clause(&yyvsp[-1]))) : 0.0; yyval.type = NUM; yyval.a_data = 0L; yyval.a_count = 0; yyval.text = 0L;;
break;}
-case 67:
+case 65:
{ if(!yyval.a_data){yyval.a_data=PushArray((double*)malloc(sizeof(double)));yyval.a_data[0]=yyvsp[-3].val;yyval.a_count=1;}
push(&yyval, &yyvsp[-1]);yyval.val = yyvsp[-5].tptr->fnctptr ?((yyvsp[-5].tptr->fnctptr)(&yyval)):0.0; yyval.type = NUM;;
break;}
-case 68:
+case 66:
{ yyval.a_data = PushArray((double*)malloc(3*sizeof(double)));
yyval.a_count = 3; yyval.a_data[0] = yyvsp[-5].val; yyval.a_data[1] = yyvsp[-3].val; yyval.a_data[2] = yyvsp[-1].val;
yyval.val = yyvsp[-7].tptr->fnctptr ? ((yyvsp[-7].tptr->fnctptr)(&yyval)) : 0.0; yyval.type = NUM;;
break;}
-case 69:
+case 67:
{yyval.type = NUM; yyval.val = yyvsp[-3].tptr->fnctptr ? ((yyvsp[-3].tptr->fnctptr)(&yyvsp[-1], &yyval, 0L)) : 0.0;;
break;}
-case 70:
+case 68:
{yyval.type = NUM; yyvsp[-1].text = string_value(&yyvsp[-1]); yyval.val = yyvsp[-3].tptr->fnctptr ? ((yyvsp[-3].tptr->fnctptr)(&yyvsp[-1], &yyval, 0L)) : 0.0;;
break;}
-case 71:
-{yyval.val = yyvsp[-5].tptr->fnctptr ? ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;;
- break;}
-case 72:
-{yyval.val = yyvsp[-5].tptr->fnctptr ?((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;;
- break;}
-case 73:
-{yyval.val = yyvsp[-5].tptr->fnctptr ? ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;;
- break;}
-case 74:
-{yyval.val = yyvsp[-5].tptr->fnctptr ? ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;;
- break;}
-case 75:
-{yyval.val = yyvsp[-5].tptr->fnctptr ? ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;;
- break;}
-case 76:
-{yyval.val = yyvsp[-5].tptr->fnctptr ? ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;;
- break;}
-case 77:
-{yyval.val = yyvsp[-5].tptr->fnctptr ? ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;;
- break;}
-case 78:
+case 69:
{yyval.val = yyvsp[-5].tptr->fnctptr ? ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;;
break;}
-case 79:
+case 70:
{proc_clause(&yyvsp[-3]); yyval.val=yyvsp[-9].tptr->fnctptr ? (*yyvsp[-9].tptr->fnctptr)(yyvsp[-7].val, yyvsp[-5].val, &yyvsp[-3], &yyvsp[-1]) : 0.0; yyval.type = NUM;;
break;}
-case 80:
+case 71:
{yyval.val = yyvsp[-5].tptr->fnctptr ? ((*yyvsp[-5].tptr->fnctptr)(proc_clause(&yyvsp[-3]), yyvsp[-1].text)) : 0.0; yyval.type = NUM;;
break;}
-case 81:
+case 72:
{yyval.val = yyvsp[-5].tptr->fnctptr ? ((*yyvsp[-5].tptr->fnctptr)(proc_clause(&yyvsp[-3]), yyvsp[-1].text)) : 0.0; yyval.type = NUM;;
break;}
-case 82:
+case 73:
{if(yyvsp[-2].tptr->fnctptr)(*yyvsp[-2].tptr->fnctptr)(&yyval, 0L);;
break;}
-case 83:
+case 74:
{if(yyvsp[-3].tptr->fnctptr)(*yyvsp[-3].tptr->fnctptr)(&yyval, &yyvsp[-1]);;
break;}
-case 84:
+case 75:
{if(yyvsp[-5].tptr->fnctptr)(*yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);;
break;}
-case 85:
+case 76:
{if(yyvsp[-3].tptr->fnctptr)(*yyvsp[-3].tptr->fnctptr)(&yyval, &yyvsp[-1], 0L);;
break;}
-case 86:
+case 77:
{if(yyvsp[-7].tptr->fnctptr)(*yyvsp[-7].tptr->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);;
break;}
-case 87:
+case 78:
{if(yyvsp[-5].tptr->fnctptr)(*yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1], 0L);;
break;}
-case 88:
+case 79:
{yyval.val = yyvsp[-2].val + yyvsp[0].val; yyval.type = NUM;
if(yyvsp[0].type == DATE1 || yyvsp[-2].type == DATE1) yyval.type = DATE1;
else if(yyvsp[0].type == TIME1 || yyvsp[-2].type == TIME1) yyval.type = TIME1;
else if(yyvsp[0].type == DATETIME1 || yyvsp[-2].type == DATETIME1) yyval.type = DATETIME1;;
break;}
-case 89:
+case 80:
{yyval.val = yyvsp[-2].val - yyvsp[0].val; yyval.type = NUM;
if(yyvsp[0].type == DATE1 || yyvsp[-2].type == DATE1) yyval.type = DATE1;
else if(yyvsp[0].type == TIME1 || yyvsp[-2].type == TIME1) yyval.type = TIME1;
else if(yyvsp[0].type == DATETIME1 || yyvsp[-2].type == DATETIME1) yyval.type = DATETIME1;;
break;}
-case 90:
+case 81:
{yyval.val = yyvsp[-2].val * yyvsp[0].val; yyval.type = NUM;;
break;}
-case 91:
+case 82:
{yyval.type = NUM; if(yyvsp[0].val != 0.0) yyval.val = yyvsp[-2].val / yyvsp[0].val;
else yyval.val = (getsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv")))->GetValue(); ;
break;}
-case 92:
+case 83:
{yyval.val=yyvsp[-1].tptr->GetValue(); yyvsp[-1].tptr->SetValue(yyval.val+1.0); yyval.val -= 1.0; yyval.type = NUM;;
break;}
-case 93:
+case 84:
{yyval.val=yyvsp[-1].tptr->GetValue(); yyvsp[-1].tptr->SetValue(yyval.val-1.0); yyval.val += 1.0; yyval.type = NUM;;
break;}
-case 94:
+case 85:
{yyval.val=yyvsp[0].tptr->GetValue(); yyvsp[0].tptr->SetValue(yyval.val+1.0); yyval.type = NUM;;
break;}
-case 95:
+case 86:
{yyval.val=yyvsp[0].tptr->GetValue(); yyvsp[0].tptr->SetValue(yyval.val-1.0); yyval.type = NUM;;
break;}
-case 96:
+case 87:
{yyval.val = (yyvsp[0].val >0 && yyvsp[0].val/2.0 == floor(yyvsp[0].val/2.0)) ? fabs(pow(yyvsp[-2].val,yyvsp[0].val) ): pow(yyvsp[-2].val, yyvsp[0].val); yyval.type = NUM;;
break;}
-case 97:
+case 88:
{yyval.val = -yyvsp[0].val; yyval.type = NUM;;
break;}
-case 98:
+case 89:
{memcpy(&yyval, &yyvsp[-1], sizeof(YYSTYPE)); yyvsp[-1].a_data = 0L; yyvsp[-1].a_count = 0;;
break;}
-case 99:
+case 90:
{yyval.a_data = PushArray((double*)calloc((int)yyvsp[-1].val, sizeof(double))); yyval.a_count=(int)(yyvsp[-1].val);
yyval.type = ARR; yyvsp[-3].tptr->SetValue(&yyval,&yyval);;
break;}
-case 100:
+case 91:
{if(yyvsp[-3].a_data && yyvsp[-1].val >= 0.0 && yyvsp[-1].val < yyvsp[-3].a_count) yyval.val = yyvsp[-3].a_data[(int)yyvsp[-1].val];
- else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
+ else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.a_data = 0L; yyval.a_count = 0; yyval.type = NUM;;
break;}
-case 101:
+case 92:
{if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count)
{yyval.val = yyvsp[-5].a_data[(int)yyvsp[-3].val] = yyvsp[0].val;
if(yyvsp[-5].tptr && yyvsp[-5].tptr->type == VAR)yyvsp[-5].tptr->SetValue(0L, &yyvsp[-5]);}
else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
break;}
-case 102:
+case 93:
{if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count)
{yyval.val = yyvsp[-5].a_data[(int)yyvsp[-3].val] += yyvsp[0].val;
if(yyvsp[-5].tptr && yyvsp[-5].tptr->type == VAR)yyvsp[-5].tptr->SetValue(0L, &yyvsp[-5]);}
else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
break;}
-case 103:
+case 94:
{if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count)
{yyval.val = yyvsp[-5].a_data[(int)yyvsp[-3].val] -= yyvsp[0].val;
if(yyvsp[-5].tptr && yyvsp[-5].tptr->type == VAR)yyvsp[-5].tptr->SetValue(0L, &yyvsp[-5]);}
else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
break;}
-case 104:
+case 95:
{if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count)
{yyval.val = yyvsp[-5].a_data[(int)yyvsp[-3].val] *= yyvsp[0].val;
if(yyvsp[-5].tptr && yyvsp[-5].tptr->type == VAR)yyvsp[-5].tptr->SetValue(0L, &yyvsp[-5]);}
else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
break;}
-case 105:
+case 96:
{if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count){
if(yyvsp[0].val != 0.0) {yyval.val = yyvsp[-5].a_data[(int)yyvsp[-3].val] /= yyvsp[0].val;
if(yyvsp[-5].tptr && yyvsp[-5].tptr->type == VAR)yyvsp[-5].tptr->SetValue(0L, &yyvsp[-5]);}
else {yyval.val = (getsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv")))->GetValue();}}
else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
break;}
-case 106:
+case 97:
{make_time(&yyval, yyvsp[-4].val, yyvsp[-2].val, yyvsp[0].val+1.0e-10);;
break;}
-case 107:
+case 98:
{make_time(&yyval, yyvsp[-2].val, yyvsp[0].val, 1.0e-10);;
break;}
-case 108:
+case 99:
{memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
break;}
-case 109:
+case 100:
{memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
break;}
-case 110:
+case 101:
{memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
break;}
-case 111:
+case 102:
{memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
break;}
}
@@ -2044,7 +1959,7 @@ symrec::GetValue()
{
anyResult ares;
- if(isSSval) {
+ if(isSSval && !bNoSS) {
if(row < 0 && col < 0) InitSS();
//GetResult( , , ,true) inhibits reentrance into parser !
if(curr_data->GetResult(&ares, row, col, parse_level > MAX_PARSE)){
@@ -2062,9 +1977,10 @@ symrec::GetValue(void *re)
{
anyResult ares;
YYSTYPE *res = (YYSTYPE*)re;
+ int i;
if(!res) return;
- if(isSSval) {
+ if(isSSval && !bNoSS) {
if(row < 0 && col < 0) InitSS();
res->a_data = 0L; res->a_count = 0;
//GetResult( , , ,true) inhibits reentrance into parser !
@@ -2088,9 +2004,21 @@ symrec::GetValue(void *re)
res->type = DATETIME1; res->val = ares.value;
res->text = 0L; break;
case ET_TEXT:
- res->type = STR; res->val = 0.0;
- if(ares.text) res->text = PushString(text = (char*)memdup(ares.text, (int)strlen(ares.text)+1, 0));
- else res->text = 0L; break;
+ i = 0; res->val = 0.0;
+ if(ares.text) for( ; ares.text && ares.text[i] != ':'; i++);
+ if(i > 1 && ares.text[i]
+ && (isalpha(ares.text[0]) || ares.text[0] =='$')
+ && (isalpha(ares.text[i+1]) || ares.text[i+1] =='$')
+ && isdigit(ares.text[i-1])) {
+ RangeData.GetData(ares.text, &res->a_data, &res->a_count, &res->text);
+ res->type = RANGEARR;
+ }
+ else {
+ res->type = STR;
+ if(ares.text) res->text = PushString(text = (char*)memdup(ares.text, (int)strlen(ares.text)+1, 0));
+ else res->text = 0L;
+ }
+ break;
default:
res->type = NUM; res->val = var;
res->text = 0L; break;
@@ -2210,6 +2138,7 @@ void LockData(bool lockExec, bool lockWrite)
RangeData.Clear();
bNoWrite = lockWrite;
bNoExec = lockExec;
+ bNoSS = false;
}
static void yyerror(char *s)
@@ -2287,6 +2216,69 @@ char *yywarn(char *txt, bool bNew)
else return 0L;
}
+static void yyCompare(YYSTYPE *res, YYSTYPE *arg1, YYSTYPE *arg2, int op)
+{
+ int cmp;
+
+ if(!res || !arg1 || !arg2) return;
+ if(arg1->type == STR && arg2->type == STR) {
+ if (arg1->text && arg1->text[0] && arg2->text
+ && arg2->text[0]) cmp = strcmp(arg1->text, arg2->text);
+ else if(arg1->text && arg1->text[0]) cmp = 1;
+ else if(arg2->text && arg2->text[0]) cmp = -1;
+ else cmp = 0;
+ switch(op) {
+ case AND:
+ res->val = (arg1->text && arg1->text[0] && arg2->text
+ && arg2->text[0]) ? 1.0 : 0.0; break;
+ case OR:
+ res->val = ((arg1->text && arg1->text[0]) || (arg2->text
+ && arg2->text[0])) ? 1.0 : 0.0; break;
+ case EQ:
+ res->val = cmp ? 0.0 : 1.0; break;
+ case NE:
+ res->val = cmp ? 1.0 : 0.0; break;
+ case GT:
+ res->val = cmp > 0 ? 1.0 : 0.0; break;
+ case GE:
+ res->val = cmp >= 0 ? 1.0 : 0.0; break;
+ case LT:
+ res->val = cmp < 0 ? 1.0 : 0.0; break;
+ case LE:
+ res->val = cmp <= 0 ? 1.0 : 0.0; break;
+ }
+ }
+ else {
+ switch(op) {
+ case AND:
+ res->val = (arg1->val != 0.0 && arg2->val != 0.0)
+ ? 1.0 : 0.0; break;
+ case OR:
+ res->val = (arg1->val != 0.0 || arg2->val != 0.0)
+ ? 1.0 : 0.0; break;
+ case EQ:
+ res->val = (arg1->val == arg2->val) ? 1.0 : 0.0;
+ break;
+ case NE:
+ res->val = (arg1->val != arg2->val) ? 1.0 : 0.0;
+ break;
+ case GT:
+ res->val = (arg1->val > arg2->val) ? 1.0 : 0.0;
+ break;
+ case GE:
+ res->val = (arg1->val >= arg2->val) ? 1.0 : 0.0;
+ break;
+ case LT:
+ res->val = (arg1->val < arg2->val) ? 1.0 : 0.0;
+ break;
+ case LE:
+ res->val = (arg1->val <= arg2->val) ? 1.0 : 0.0;
+ break;
+ }
+ }
+ res->type = BOOLVAL;
+}
+
static void store_res(YYSTYPE *res)
{
if(last_err_desc) {
@@ -2332,7 +2324,8 @@ static void store_res(YYSTYPE *res)
line_res.value = 0.0;
line_res.a_data = res->a_data;
line_res.a_count = res->a_count;
- rlp_strcpy(res_txt, 1000, "#ARRAY");
+ if(res->text) rlp_strcpy(res_txt, 1000, res->text);
+ else rlp_strcpy(res_txt, 1000, "#ARRAY");
}
else if(res->tptr && res->tptr->type == TXT) {
line_res.type = ET_TEXT;
@@ -2482,6 +2475,14 @@ static double srand(double v)
return v;
}
+static double maxiter(YYSTYPE *dst, YYSTYPE *src)
+{
+ if(!dst) return 0.0;
+ if(src) yy_maxiter = (int)src->val;
+ dst->type = NUM;
+ return(dst->val = (double)yy_maxiter);
+}
+
static double factorial(double v)
{
return factrl((int)v);
@@ -3025,6 +3026,50 @@ static double weibinv(YYSTYPE *sr)
return sr->val;
}
+static double geomfreq(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ sr->val = 0.0;
+ if(sr->a_data && sr->a_count == 2){
+ sr->val = geom_freq(sr->a_data[0], sr->a_data[1]);
+ }
+ else yyargcnterr("geomfreq(x, p)");
+ return sr->val;
+}
+
+static double geomdist(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ sr->val = 0.0;
+ if(sr->a_data && sr->a_count == 2){
+ sr->val = geom_dist(sr->a_data[0], sr->a_data[1]);
+ }
+ else yyargcnterr("geomdist(x, p)");
+ return sr->val;
+}
+
+static double hyperfreq(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ sr->val = 0.0;
+ if(sr->a_data && sr->a_count == 4){
+ sr->val = hyper_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2], sr->a_data[3]);
+ }
+ else yyargcnterr("hyperfreq(k, N, m, n)");
+ return sr->val;
+}
+
+static double hyperdist(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ sr->val = 0.0;
+ if(sr->a_data && sr->a_count == 4){
+ sr->val = hyper_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2], sr->a_data[3]);
+ }
+ else yyargcnterr("hyperdist(k, N, m, n)");
+ return sr->val;
+}
+
static double cauchydist(YYSTYPE *sr)
{
if(!sr) return 0.0;
@@ -3869,7 +3914,9 @@ void InitArithFuncs(DataObj *d)
double (*fnct)(double);
};
fdef fncts[] = {
- INIT_SYM(YYFNC3, "mkarr", mkarr),
+ INIT_SYM(AFNCT, "geomfreq", geomfreq), INIT_SYM(AFNCT, "geomdist", geomdist),
+ INIT_SYM(AFNCT, "hyperfreq", hyperfreq), INIT_SYM(AFNCT, "hyperdist", hyperdist),
+ INIT_SYM(YYFNC3, "mkarr", mkarr), INIT_SYM(YYFNC, "maxiter", maxiter),
INIT_SYM(YYFNC, "randarr", _randarr), INIT_SYM(YYFNC, "resample", _resample),
INIT_SYM(AFNCT, "weibdist", weibdist), INIT_SYM(AFNCT, "weibfreq", weibfreq),
INIT_SYM(AFNCT, "weibinv", weibinv), INIT_SYM(AFNCT, "cauchydist", cauchydist),
@@ -4313,17 +4360,17 @@ static char *copy_block()
}
static symrec *curr_sym;
-static double for_loop(char *block1, char *block2)
+static int for_loop(char *block1, char *block2)
{
char *last_buffer, *bb1, *bb2, *bb3;
- int i, a_count, last_buff_pos, cb1;
+ int i, a_count, last_buff_pos, cb1, bres;
double *a_data;
YYSTYPE yyres, yysrc;
symrec *var;
- if(!block1 || !block1[0] || bNoExec) return 0.0;
+ if(!block1 || !block1[0] || bNoExec) return 0;
bb1 = bb2 = bb3 = 0L; parse_level++;
- cb1 = (int)strlen(block1);
+ cb1 = (int)strlen(block1); bres = 0;
last_buffer = buffer; last_buff_pos = buff_pos;
buffer = block1; buff_pos = 0;
//test for syntax 1
@@ -4331,21 +4378,21 @@ static double for_loop(char *block1, char *block2)
if(buff_pos < cb1) bb2 = copy_block();
if(buff_pos < cb1) bb3 = copy_block();
if(bb1 && bb2 && bb3) { //syntax 1 found !
- yysrc.text = bb1; if(bb1[0]) eval(&yyres, &yysrc);
- for(i = 0; i < yy_maxiter; i++) {
+ yysrc.text = bb1; if(bb1[0]) bres = eval(&yyres, &yysrc);
+ for(i = 0; !bres && i < yy_maxiter; i++) {
yysrc.text = bb2;
if(bb2[0]) {
- eval(&yyres, &yysrc);
+ bres = eval(&yyres, &yysrc);
if(yyres.type != NUM && yyres.type != BOOLVAL) yyres.val = 0.0;
}
else yyres.val = 1.0;
if(yyres.val != 0.0) {
if(block2 && block2[0]) {
yysrc.text = block2;
- eval(&yyres, &yysrc);
+ bres = eval(&yyres, &yysrc);
}
yysrc.text = bb3;
- eval(&yyres, &yysrc);
+ bres = eval(&yyres, &yysrc);
}
else break;
}
@@ -4356,14 +4403,14 @@ static double for_loop(char *block1, char *block2)
buff_pos = 0;
if (VAR == yylex() && (var = curr_sym) && INARR == yylex() && buffer[buff_pos]){
yysrc.text = buffer + buff_pos;
- eval(&yyres, &yysrc);
+ bres = eval(&yyres, &yysrc);
a_count = yyres.a_count;
a_data = yyres.a_data;
- for(i = 0; i < a_count && i < yy_maxiter; i++) {
+ for(i = 0; !bres && i < a_count && i < yy_maxiter; i++) {
var->SetValue(a_data[i]);
if(block2 && block2[0]) {
yysrc.text = block2;
- eval(&yyres, &yysrc);
+ bres = eval(&yyres, &yysrc);
}
}
last_error = 0;
@@ -4374,7 +4421,7 @@ static double for_loop(char *block1, char *block2)
if(bb1) free(bb1); if(bb2) free(bb2); if(bb3) free(bb3);
buffer = last_buffer; buff_pos = last_buff_pos;
parse_level--;
- return 0.0;
+ return bres;
}
static int yylex()
@@ -4447,7 +4494,7 @@ static int yylex()
tmp_txt[i] = 0;
RangeData.GetData(tmp_txt, &yylval.a_data, &yylval.a_count, &yylval.text);
yylval.val = 0.0;
- return yylval.type = RANGEARR;
+ return yylval.type = (yylval.a_data && yylval.a_count) ? RANGEARR : STR;
}
tmp_txt[i] = 0;
h_nam = HashValue((unsigned char*)tmp_txt);
@@ -4722,7 +4769,7 @@ bool MoveFormula(DataObj *d, char *of, char *nf, int nfsize, int dx, int dy, int
char *res, desc1[2], desc2[2];
if(d) curr_data = d;
- if(!curr_data || !of || !nf) return false;
+ if(!curr_data || !of || !of[0] || !nf) return false;
push_parser(); //make code reentrant
init_table(); length = (int)strlen(of);
if(!(buffer = (char*)malloc(length+2))){
@@ -4873,10 +4920,12 @@ bool MoveFormula(DataObj *d, char *of, char *nf, int nfsize, int dx, int dy, int
pos += rlp_strcpy(res+pos, length2-pos, " break");
break;
case RANGEARR:
- for(i = 0; yylval.text[i]; i++) if(yylval.text[i] == ':') {
- yylval.text[i] = ';'; break;
+ if(yylval.text && yylval.text[0]) {
+ for(i = 0; yylval.text[i]; i++) if(yylval.text[i] == ':') {
+ yylval.text[i] = ';'; break;
+ }
+ MoveFormula(d, yylval.text, res+pos, nfsize-pos-2, dx, dy, r0, c0);
}
- MoveFormula(d, yylval.text, res+pos, nfsize-pos-2, dx, dy, r0, c0);
while(res[pos]) {
pos++; if(res[pos] == ';') res[pos] = ':';
}
@@ -4925,7 +4974,7 @@ static void fcurve(double x, double z, double **a, double *y, double dyda[], int
}
//calc result
symx->SetValue(x); symz->SetValue(z);
- buffer = txt_formula;
+ buffer = txt_formula; bNoSS = true;
buff_pos = 0; length = (int)strlen(txt_formula);
while(!(parse_res = yyparse()) && buff_pos < length);
if(sy = getsym(hn_y, h2_y)) *y = sy->GetValue();
@@ -4955,6 +5004,7 @@ static void fcurve(double x, double z, double **a, double *y, double dyda[], int
if(a != parval) for(i = 0; i < ma; i++) {
tmp = *parval[i]; *parval[i] = *a[i]; *a[i] = tmp;
}
+ bNoSS = false;
}
int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr, double conv, int maxiter, double *chi_2)
@@ -5049,6 +5099,7 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
mrqmin(x, y, z, ndata, parval, nparam, lista, nparam, covar, alpha, &chisq, fcurve, &alamda);
Check_MRQerror();
}
+ bNoSS = true;
for(i = nparam-1, j = k = l = 0; i >= 0; l = 0, i--) {
if(k > 20) {
if(tmp_txt[j-1] == ' ') j--;
@@ -5085,8 +5136,7 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
d->Command(CMD_CLEAR_ERROR, 0L, 0L);
d->Command(CMD_REDRAW, 0L, 0L);
}
+ bNoSS = false;
return itst < maxiter ? itst+1 : maxiter;
}
-
-
diff --git a/mfcalc.y b/mfcalc.y
index 69a4162..5fb3fd0 100755
--- a/mfcalc.y
+++ b/mfcalc.y
@@ -1,6 +1,6 @@
%{
/*
- mfcalc.y, mfcalc.cpp, Copyright (c) 2004-2006 R.Lackner
+ mfcalc.y, mfcalc.cpp, Copyright (c) 2004-2008 R.Lackner
parse string and simple math: based on the bison 'mfcalc' example
This file is part of RLPlot.
@@ -76,6 +76,7 @@ static int block_res; //result of eval()
static symrec *putsym (unsigned int h_name, unsigned int h2_name, int sym_type);
static symrec *getsym (unsigned int h_name, unsigned int h2_name, char *sym_name = 0L);
static int push(YYSTYPE *res, YYSTYPE *val);
+static void yyCompare(YYSTYPE *res, YYSTYPE *arg1, YYSTYPE *arg2, int op);
static void store_res(YYSTYPE *res);
static char *PushString(char *text);
static double *PushArray(double *arr);
@@ -91,7 +92,7 @@ static void yyerror(char *s);
static void make_time(YYSTYPE *dst, double h, double m, double s);
static int yylex(void);
static double nop() {return 0.0;};
-static double for_loop(char *block1, char *block2);
+static int for_loop(char *block1, char *block2);
static char res_txt[1000];
static anyResult line_res = {ET_UNKNOWN, 0.0, res_txt, 0L, 0};
@@ -102,7 +103,7 @@ static char *last_err_desc = 0L; //short error description
static char *buffer = 0L; //the current command buffer
static int buff_pos = 0;
static bool bRecent = false; //rearrange functions
-static bool bNoWrite, bNoExec; //while editing ...
+static bool bNoWrite, bNoExec, bNoSS; //while editing ...
static int parse_level = 0; //count reentrances into parser
#define MAX_PARSE 50 //maximum number of recursive reentances
%}
@@ -124,8 +125,8 @@ static int parse_level = 0; //count reentrances into parser
%left EQ NE GT GE LT LE
%left '-' '+'
%left '*' '/'
-%left '['
%left '^' /* exponentiation */
+%left '['
%left NEG /* negation-unary minus */
%left INC DEC /* increment, decrement */
%left PINC PDEC /* pre- increment, decrement */
@@ -137,10 +138,11 @@ input: /* empty string */
| input line
;
+anysep: ';' | ',';
+
line: '\n' | ';' | ','
| exp '\n' {store_res(&yyvsp[-1]); return 0;}
- | exp ';' {store_res(&yyvsp[-1]); return 0;}
- | exp ',' {store_res(&yyvsp[-1]); return 0;}
+ | exp anysep {store_res(&yyvsp[-1]); return 0;}
| str_exp '\n' {store_res(&yyvsp[-1]); return 0;}
| str_exp ';' {store_res(&yyvsp[-1]); return 0;}
| IF PBLOCK block {if(block_res = eval(&yyval, &yyvsp[-1]))return block_res;
@@ -148,7 +150,7 @@ line: '\n' | ';' | ','
| IF PBLOCK block ELSE block {if(block_res = eval(&yyval, &yyvsp[-3])) return block_res;
if(yyval.val != 0.0) {if(block_res = eval(&yyval, &yyvsp[-2])) return block_res;}
else if(block_res = eval(&yyval, &yyvsp[0])) return block_res;}
- | FOR PBLOCK block {for_loop(yyvsp[-1].text, yyvsp[0].text);}
+ | FOR PBLOCK block {block_res = for_loop(yyvsp[-1].text, yyvsp[0].text); if(block_res == 1 || block_res == 2) return block_res;}
| WHILE PBLOCK block {for(int i=0; i< yy_maxiter; i++){ if(block_res = eval(&yyval, &yyvsp[-1]))return block_res;
if(yyval.val != 0.0){if(block_res = eval(&yyval, &yyvsp[0]))return block_res;} else break;}}
| RETURN IBLOCK {if(block_res = eval(&yyval, &yyvsp[0]) == 1) return 1; else return 2;}
@@ -162,10 +164,7 @@ str_exp:
|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;}
|SRFUNC '(' exp ')' {if($1->fnctptr)(($1->fnctptr)(&yyval, &yyvsp[-1], 0L)); yyval.type = STR;}
- |SRFUNC '(' exp PSEP str_exp ')' {if($1->fnctptr)(($1->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;}
- |SRFUNC '(' exp PSEP exp ')' {if($1->fnctptr)(($1->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;}
- |SRFUNC '(' exp ',' str_exp ')' {if($1->fnctptr)(($1->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;}
- |SRFUNC '(' exp ',' exp ')' {if($1->fnctptr)(($1->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;}
+ |SRFUNC '(' exp anysep str_exp ')' {if($1->fnctptr)(($1->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;}
;
range:
@@ -185,14 +184,14 @@ bool: BOOLVAL
|BFNCT '(' exp ')' {$$ = $1->fnctptr ? (($1->fnctptr)($3)): 0.0; yyval.type = BOOLVAL;}
|BTRUE {$$ = 1.0; yyval.type = BOOLVAL;}
|BFALSE {$$ = 0.0; yyval.type = BOOLVAL;}
- |exp AND exp {$$ = (($1 != 0) && ($3 != 0))? 1 : 0; yyval.type = BOOLVAL;}
- |exp OR exp {$$ = (($1 != 0) || ($3 != 0))? 1 : 0; yyval.type = BOOLVAL;}
- |exp EQ exp {$$ = ($1 == $3) ? 1 : 0; yyval.type = BOOLVAL;}
- |exp NE exp {$$ = ($1 != $3) ? 1 : 0; yyval.type = BOOLVAL;}
- |exp GT exp {$$ = ($1 > $3) ? 1 : 0; yyval.type = BOOLVAL;}
- |exp GE exp {$$ = ($1 >= $3) ? 1 : 0; yyval.type = BOOLVAL;}
- |exp LT exp {$$ = ($1 < $3) ? 1 : 0; yyval.type = BOOLVAL;}
- |exp LE exp {$$ = ($1 <= $3) ? 1 : 0; yyval.type = BOOLVAL;}
+ |exp AND exp {yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], AND);}
+ |exp OR exp {yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], OR);}
+ |exp EQ exp {yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], EQ);}
+ |exp NE exp {yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], NE);}
+ |exp GT exp {yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], GT);}
+ |exp GE exp {yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], GE);}
+ |exp LT exp {yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], LT);}
+ |exp LE exp {yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], LE);}
;
block: BLOCK | IBLOCK;
@@ -224,14 +223,7 @@ exp: NUM {$$ = $1; yyval.type = NUM;}
$$ = $1->fnctptr ? (($1->fnctptr)(&yyval)) : 0.0; yyval.type = NUM;}
|SFNCT '(' str_exp ')' {yyval.type = NUM; $$ = $1->fnctptr ? (($1->fnctptr)(&yyvsp[-1], &yyval, 0L)) : 0.0;}
|SFNCT '(' exp ')' {yyval.type = NUM; yyvsp[-1].text = string_value(&yyvsp[-1]); $$ = $1->fnctptr ? (($1->fnctptr)(&yyvsp[-1], &yyval, 0L)) : 0.0;}
- |SFNCT '(' str_exp PSEP str_exp ')' {$$ = $1->fnctptr ? (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
- |SFNCT '(' exp PSEP str_exp ')' {$$ = $1->fnctptr ?(($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
- |SFNCT '(' exp PSEP exp ')' {$$ = $1->fnctptr ? (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
- |SFNCT '(' str_exp PSEP exp ')' {$$ = $1->fnctptr ? (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
- |SFNCT '(' str_exp ',' str_exp ')' {$$ = $1->fnctptr ? (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
- |SFNCT '(' exp ',' str_exp ')' {$$ = $1->fnctptr ? (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
- |SFNCT '(' str_exp ',' exp ')' {$$ = $1->fnctptr ? (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
- |SFNCT '(' exp ',' exp ')' {$$ = $1->fnctptr ? (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
+ |SFNCT '(' anyarg anysep anyarg ')' {$$ = $1->fnctptr ? (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
|FUNC4 '(' exp PSEP exp PSEP arr PSEP range ')' {proc_clause(&yyvsp[-3]); $$=$1->fnctptr ? (*$1->fnctptr)($3, $5, &yyvsp[-3], &yyvsp[-1]) : 0.0; yyval.type = NUM;}
|FUNC1 '(' arr PSEP range ')' {$$ = $1->fnctptr ? ((*$1->fnctptr)(proc_clause(&yyvsp[-3]), yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
|FUNC1 '(' arr PSEP RANGEARR ')' {$$ = $1->fnctptr ? ((*$1->fnctptr)(proc_clause(&yyvsp[-3]), yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
@@ -262,7 +254,7 @@ exp: NUM {$$ = $1; yyval.type = NUM;}
|DIM VAR %prec PDIM '[' exp ']' {yyval.a_data = PushArray((double*)calloc((int)$4, sizeof(double))); yyval.a_count=(int)($4);
yyval.type = ARR; $2->SetValue(&yyval,&yyval);}
|exp '[' exp ']' {if(yyvsp[-3].a_data && yyvsp[-1].val >= 0.0 && yyvsp[-1].val < yyvsp[-3].a_count) $$ = yyvsp[-3].a_data[(int)yyvsp[-1].val];
- else {$$ = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;}
+ else {$$ = 0.0; last_err_desc = "#INDEX";} yyval.a_data = 0L; yyval.a_count = 0; yyval.type = NUM;}
|exp '[' exp ']' '=' exp {if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count)
{$$ = yyvsp[-5].a_data[(int)yyvsp[-3].val] = $6;
if(yyvsp[-5].tptr && yyvsp[-5].tptr->type == VAR)yyvsp[-5].tptr->SetValue(0L, &yyvsp[-5]);}
@@ -583,7 +575,7 @@ symrec::GetValue()
{
anyResult ares;
- if(isSSval) {
+ if(isSSval && !bNoSS) {
if(row < 0 && col < 0) InitSS();
//GetResult( , , ,true) inhibits reentrance into parser !
if(curr_data->GetResult(&ares, row, col, parse_level > MAX_PARSE)){
@@ -601,9 +593,10 @@ symrec::GetValue(void *re)
{
anyResult ares;
YYSTYPE *res = (YYSTYPE*)re;
+ int i;
if(!res) return;
- if(isSSval) {
+ if(isSSval && !bNoSS) {
if(row < 0 && col < 0) InitSS();
res->a_data = 0L; res->a_count = 0;
//GetResult( , , ,true) inhibits reentrance into parser !
@@ -627,9 +620,21 @@ symrec::GetValue(void *re)
res->type = DATETIME1; res->val = ares.value;
res->text = 0L; break;
case ET_TEXT:
- res->type = STR; res->val = 0.0;
- if(ares.text) res->text = PushString(text = (char*)memdup(ares.text, (int)strlen(ares.text)+1, 0));
- else res->text = 0L; break;
+ i = 0; res->val = 0.0;
+ if(ares.text) for( ; ares.text && ares.text[i] != ':'; i++);
+ if(i > 1 && ares.text[i]
+ && (isalpha(ares.text[0]) || ares.text[0] =='$')
+ && (isalpha(ares.text[i+1]) || ares.text[i+1] =='$')
+ && isdigit(ares.text[i-1])) {
+ RangeData.GetData(ares.text, &res->a_data, &res->a_count, &res->text);
+ res->type = RANGEARR;
+ }
+ else {
+ res->type = STR;
+ if(ares.text) res->text = PushString(text = (char*)memdup(ares.text, (int)strlen(ares.text)+1, 0));
+ else res->text = 0L;
+ }
+ break;
default:
res->type = NUM; res->val = var;
res->text = 0L; break;
@@ -749,6 +754,7 @@ void LockData(bool lockExec, bool lockWrite)
RangeData.Clear();
bNoWrite = lockWrite;
bNoExec = lockExec;
+ bNoSS = false;
}
static void yyerror(char *s)
@@ -826,6 +832,69 @@ char *yywarn(char *txt, bool bNew)
else return 0L;
}
+static void yyCompare(YYSTYPE *res, YYSTYPE *arg1, YYSTYPE *arg2, int op)
+{
+ int cmp;
+
+ if(!res || !arg1 || !arg2) return;
+ if(arg1->type == STR && arg2->type == STR) {
+ if (arg1->text && arg1->text[0] && arg2->text
+ && arg2->text[0]) cmp = strcmp(arg1->text, arg2->text);
+ else if(arg1->text && arg1->text[0]) cmp = 1;
+ else if(arg2->text && arg2->text[0]) cmp = -1;
+ else cmp = 0;
+ switch(op) {
+ case AND:
+ res->val = (arg1->text && arg1->text[0] && arg2->text
+ && arg2->text[0]) ? 1.0 : 0.0; break;
+ case OR:
+ res->val = ((arg1->text && arg1->text[0]) || (arg2->text
+ && arg2->text[0])) ? 1.0 : 0.0; break;
+ case EQ:
+ res->val = cmp ? 0.0 : 1.0; break;
+ case NE:
+ res->val = cmp ? 1.0 : 0.0; break;
+ case GT:
+ res->val = cmp > 0 ? 1.0 : 0.0; break;
+ case GE:
+ res->val = cmp >= 0 ? 1.0 : 0.0; break;
+ case LT:
+ res->val = cmp < 0 ? 1.0 : 0.0; break;
+ case LE:
+ res->val = cmp <= 0 ? 1.0 : 0.0; break;
+ }
+ }
+ else {
+ switch(op) {
+ case AND:
+ res->val = (arg1->val != 0.0 && arg2->val != 0.0)
+ ? 1.0 : 0.0; break;
+ case OR:
+ res->val = (arg1->val != 0.0 || arg2->val != 0.0)
+ ? 1.0 : 0.0; break;
+ case EQ:
+ res->val = (arg1->val == arg2->val) ? 1.0 : 0.0;
+ break;
+ case NE:
+ res->val = (arg1->val != arg2->val) ? 1.0 : 0.0;
+ break;
+ case GT:
+ res->val = (arg1->val > arg2->val) ? 1.0 : 0.0;
+ break;
+ case GE:
+ res->val = (arg1->val >= arg2->val) ? 1.0 : 0.0;
+ break;
+ case LT:
+ res->val = (arg1->val < arg2->val) ? 1.0 : 0.0;
+ break;
+ case LE:
+ res->val = (arg1->val <= arg2->val) ? 1.0 : 0.0;
+ break;
+ }
+ }
+ res->type = BOOLVAL;
+}
+
static void store_res(YYSTYPE *res)
{
if(last_err_desc) {
@@ -871,7 +940,8 @@ static void store_res(YYSTYPE *res)
line_res.value = 0.0;
line_res.a_data = res->a_data;
line_res.a_count = res->a_count;
- rlp_strcpy(res_txt, 1000, "#ARRAY");
+ if(res->text) rlp_strcpy(res_txt, 1000, res->text);
+ else rlp_strcpy(res_txt, 1000, "#ARRAY");
}
else if(res->tptr && res->tptr->type == TXT) {
line_res.type = ET_TEXT;
@@ -1021,6 +1091,14 @@ static double srand(double v)
return v;
}
+static double maxiter(YYSTYPE *dst, YYSTYPE *src)
+{
+ if(!dst) return 0.0;
+ if(src) yy_maxiter = (int)src->val;
+ dst->type = NUM;
+ return(dst->val = (double)yy_maxiter);
+}
+
static double factorial(double v)
{
return factrl((int)v);
@@ -1564,6 +1642,50 @@ static double weibinv(YYSTYPE *sr)
return sr->val;
}
+static double geomfreq(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ sr->val = 0.0;
+ if(sr->a_data && sr->a_count == 2){
+ sr->val = geom_freq(sr->a_data[0], sr->a_data[1]);
+ }
+ else yyargcnterr("geomfreq(x, p)");
+ return sr->val;
+}
+
+static double geomdist(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ sr->val = 0.0;
+ if(sr->a_data && sr->a_count == 2){
+ sr->val = geom_dist(sr->a_data[0], sr->a_data[1]);
+ }
+ else yyargcnterr("geomdist(x, p)");
+ return sr->val;
+}
+
+static double hyperfreq(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ sr->val = 0.0;
+ if(sr->a_data && sr->a_count == 4){
+ sr->val = hyper_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2], sr->a_data[3]);
+ }
+ else yyargcnterr("hyperfreq(k, N, m, n)");
+ return sr->val;
+}
+
+static double hyperdist(YYSTYPE *sr)
+{
+ if(!sr) return 0.0;
+ sr->val = 0.0;
+ if(sr->a_data && sr->a_count == 4){
+ sr->val = hyper_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2], sr->a_data[3]);
+ }
+ else yyargcnterr("hyperdist(k, N, m, n)");
+ return sr->val;
+}
+
static double cauchydist(YYSTYPE *sr)
{
if(!sr) return 0.0;
@@ -2408,7 +2530,9 @@ void InitArithFuncs(DataObj *d)
double (*fnct)(double);
};
fdef fncts[] = {
- INIT_SYM(YYFNC3, "mkarr", mkarr),
+ INIT_SYM(AFNCT, "geomfreq", geomfreq), INIT_SYM(AFNCT, "geomdist", geomdist),
+ INIT_SYM(AFNCT, "hyperfreq", hyperfreq), INIT_SYM(AFNCT, "hyperdist", hyperdist),
+ INIT_SYM(YYFNC3, "mkarr", mkarr), INIT_SYM(YYFNC, "maxiter", maxiter),
INIT_SYM(YYFNC, "randarr", _randarr), INIT_SYM(YYFNC, "resample", _resample),
INIT_SYM(AFNCT, "weibdist", weibdist), INIT_SYM(AFNCT, "weibfreq", weibfreq),
INIT_SYM(AFNCT, "weibinv", weibinv), INIT_SYM(AFNCT, "cauchydist", cauchydist),
@@ -2852,17 +2976,17 @@ static char *copy_block()
}
static symrec *curr_sym;
-static double for_loop(char *block1, char *block2)
+static int for_loop(char *block1, char *block2)
{
char *last_buffer, *bb1, *bb2, *bb3;
- int i, a_count, last_buff_pos, cb1;
+ int i, a_count, last_buff_pos, cb1, bres;
double *a_data;
YYSTYPE yyres, yysrc;
symrec *var;
- if(!block1 || !block1[0] || bNoExec) return 0.0;
+ if(!block1 || !block1[0] || bNoExec) return 0;
bb1 = bb2 = bb3 = 0L; parse_level++;
- cb1 = (int)strlen(block1);
+ cb1 = (int)strlen(block1); bres = 0;
last_buffer = buffer; last_buff_pos = buff_pos;
buffer = block1; buff_pos = 0;
//test for syntax 1
@@ -2870,21 +2994,21 @@ static double for_loop(char *block1, char *block2)
if(buff_pos < cb1) bb2 = copy_block();
if(buff_pos < cb1) bb3 = copy_block();
if(bb1 && bb2 && bb3) { //syntax 1 found !
- yysrc.text = bb1; if(bb1[0]) eval(&yyres, &yysrc);
- for(i = 0; i < yy_maxiter; i++) {
+ yysrc.text = bb1; if(bb1[0]) bres = eval(&yyres, &yysrc);
+ for(i = 0; !bres && i < yy_maxiter; i++) {
yysrc.text = bb2;
if(bb2[0]) {
- eval(&yyres, &yysrc);
+ bres = eval(&yyres, &yysrc);
if(yyres.type != NUM && yyres.type != BOOLVAL) yyres.val = 0.0;
}
else yyres.val = 1.0;
if(yyres.val != 0.0) {
if(block2 && block2[0]) {
yysrc.text = block2;
- eval(&yyres, &yysrc);
+ bres = eval(&yyres, &yysrc);
}
yysrc.text = bb3;
- eval(&yyres, &yysrc);
+ bres = eval(&yyres, &yysrc);
}
else break;
}
@@ -2895,14 +3019,14 @@ static double for_loop(char *block1, char *block2)
buff_pos = 0;
if (VAR == yylex() && (var = curr_sym) && INARR == yylex() && buffer[buff_pos]){
yysrc.text = buffer + buff_pos;
- eval(&yyres, &yysrc);
+ bres = eval(&yyres, &yysrc);
a_count = yyres.a_count;
a_data = yyres.a_data;
- for(i = 0; i < a_count && i < yy_maxiter; i++) {
+ for(i = 0; !bres && i < a_count && i < yy_maxiter; i++) {
var->SetValue(a_data[i]);
if(block2 && block2[0]) {
yysrc.text = block2;
- eval(&yyres, &yysrc);
+ bres = eval(&yyres, &yysrc);
}
}
last_error = 0;
@@ -2913,7 +3037,7 @@ static double for_loop(char *block1, char *block2)
if(bb1) free(bb1); if(bb2) free(bb2); if(bb3) free(bb3);
buffer = last_buffer; buff_pos = last_buff_pos;
parse_level--;
- return 0.0;
+ return bres;
}
static int yylex()
@@ -2986,7 +3110,7 @@ static int yylex()
tmp_txt[i] = 0;
RangeData.GetData(tmp_txt, &yylval.a_data, &yylval.a_count, &yylval.text);
yylval.val = 0.0;
- return yylval.type = RANGEARR;
+ return yylval.type = (yylval.a_data && yylval.a_count) ? RANGEARR : STR;
}
tmp_txt[i] = 0;
h_nam = HashValue((unsigned char*)tmp_txt);
@@ -3261,7 +3385,7 @@ bool MoveFormula(DataObj *d, char *of, char *nf, int nfsize, int dx, int dy, int
char *res, desc1[2], desc2[2];
if(d) curr_data = d;
- if(!curr_data || !of || !nf) return false;
+ if(!curr_data || !of || !of[0] || !nf) return false;
push_parser(); //make code reentrant
init_table(); length = (int)strlen(of);
if(!(buffer = (char*)malloc(length+2))){
@@ -3412,10 +3536,12 @@ bool MoveFormula(DataObj *d, char *of, char *nf, int nfsize, int dx, int dy, int
pos += rlp_strcpy(res+pos, length2-pos, " break");
break;
case RANGEARR:
- for(i = 0; yylval.text[i]; i++) if(yylval.text[i] == ':') {
- yylval.text[i] = ';'; break;
+ if(yylval.text && yylval.text[0]) {
+ for(i = 0; yylval.text[i]; i++) if(yylval.text[i] == ':') {
+ yylval.text[i] = ';'; break;
+ }
+ MoveFormula(d, yylval.text, res+pos, nfsize-pos-2, dx, dy, r0, c0);
}
- MoveFormula(d, yylval.text, res+pos, nfsize-pos-2, dx, dy, r0, c0);
while(res[pos]) {
pos++; if(res[pos] == ';') res[pos] = ':';
}
@@ -3464,7 +3590,7 @@ static void fcurve(double x, double z, double **a, double *y, double dyda[], int
}
//calc result
symx->SetValue(x); symz->SetValue(z);
- buffer = txt_formula;
+ buffer = txt_formula; bNoSS = true;
buff_pos = 0; length = (int)strlen(txt_formula);
while(!(parse_res = yyparse()) && buff_pos < length);
if(sy = getsym(hn_y, h2_y)) *y = sy->GetValue();
@@ -3494,6 +3620,7 @@ static void fcurve(double x, double z, double **a, double *y, double dyda[], int
if(a != parval) for(i = 0; i < ma; i++) {
tmp = *parval[i]; *parval[i] = *a[i]; *a[i] = tmp;
}
+ bNoSS = false;
}
int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr, double conv, int maxiter, double *chi_2)
@@ -3588,6 +3715,7 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
mrqmin(x, y, z, ndata, parval, nparam, lista, nparam, covar, alpha, &chisq, fcurve, &alamda);
Check_MRQerror();
}
+ bNoSS = true;
for(i = nparam-1, j = k = l = 0; i >= 0; l = 0, i--) {
if(k > 20) {
if(tmp_txt[j-1] == ' ') j--;
@@ -3624,10 +3752,7 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
d->Command(CMD_CLEAR_ERROR, 0L, 0L);
d->Command(CMD_REDRAW, 0L, 0L);
}
+ bNoSS = false;
return itst < maxiter ? itst+1 : maxiter;
}
-
-
-
-
diff --git a/no_gui.cpp b/no_gui.cpp
index 2195534..c03da54 100755
--- a/no_gui.cpp
+++ b/no_gui.cpp
@@ -1,585 +1,590 @@
-//no_gui.cpp, Copyright 2000-2007 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 builds with no graphical user interface.
-// Builds using the GUI are compiled with use_gui.cpp instead.
-//
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//
-#include "rlplot.h"
-
-extern char *name1, *name2; //the filenames
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// STUBS: we do not need this objects or functions without GUI
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-dragHandle::dragHandle(GraphObj *par, int which):GraphObj(par, 0L)
-{
-}
-
-dragHandle::~dragHandle()
-{
-}
-
-void
-dragHandle::DoPlot(anyOutput *o)
-{
-}
-
-bool
-dragHandle::Command(int cmd, void *tmpl, anyOutput *o)
-{
- return false;
-}
-
-void *
-dragHandle::ObjThere(int x, int y)
-{
- return 0L;
-}
-
-void
-dragHandle::Track(POINT *p, anyOutput *o)
-{
-}
-
-dragRect::dragRect(GraphObj *par, int which):GraphObj(par, 0L)
-{
-}
-
-dragRect::~dragRect()
-{
-}
-
-void
-dragRect::DoPlot(anyOutput *o)
-{
-}
-
-void *
-dragRect::ObjThere(int x, int y)
-{
- return 0L;
-}
-
-bool
-dragRect::Command(int cmd, void *tmpl, anyOutput *o)
-{
- return false;
-}
-
-Drag3D::Drag3D(GraphObj *par):GraphObj(par, 0L)
-{
-}
-
-Drag3D::~Drag3D()
-{
-}
-
-void *
-Drag3D::ObjThere(int x, int y)
-{
- return 0L;
-}
-
-void
-Drag3D::DoPlot(anyOutput *o)
-{
-}
-
-FrmRect::FrmRect(GraphObj *par, fRECT *lim, fRECT *c, fRECT *chld):GraphObj(par, 0L)
-{
- Id = Id;
-}
-
-FrmRect::~FrmRect()
-{
-}
-
-double
-FrmRect::GetSize(int select)
-{
- return 0.0;
-}
-
-bool
-FrmRect::SetSize(int select, double value)
-{
- return false;
-}
-
-bool
-FrmRect::SetColor(int select, DWORD col)
-{
- return false;
-}
-
-void
-FrmRect::DoMark(anyOutput *o, bool mark)
-{
-}
-
-void
-FrmRect::DoPlot(anyOutput *o)
-{
-}
-
-bool
-FrmRect::Command(int cmd, void *tmpl, anyOutput *o)
-{
- return false;
-}
-
-void *
-FrmRect::ObjThere(int x, int y)
-{
- return 0L;
-}
-
-void
-FrmRect::Track(POINT *p, anyOutput *o)
-{
-}
-
-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;
-}
-
-void *
-Arrow::ObjThere(int x, int y)
-{
- return 0L;
-}
-
-void
-Arrow::Track(POINT *p, anyOutput *o)
-{
-}
-
-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;
-}
-
-void Label::ShowCursor(anyOutput *o)
-{
-}
-
-bool Label::AddChar(int ci, anyOutput *o)
-{
- return true;
-}
-
-void Label::CalcCursorPos(int x, int y, anyOutput *o)
-{
-}
-
-bool TextFrame::PropertyDlg()
-{
- return false;
-}
-
-void TextFrame::ShowCursor(anyOutput *o)
-{
-}
-
-void TextFrame::CalcCursorPos(int x, int y, anyOutput *o)
-{
-}
-
-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 xyStat::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 Grid3D::PropertyDlg()
-{
- return false;
-}
-
-bool Grid3D::Configure()
-{
- return false;
-}
-
-bool Scatt3D::PropertyDlg()
-{
- return false;
-}
-
-bool FitFunc::PropertyDlg()
-{
- return false;
-}
-
-bool NormQuant::PropertyDlg()
-{
- return false;
-}
-
-bool Plot3D::AddAxis()
-{
- return false;
-}
-
-bool Plot3D::PropertyDlg()
-{
- return false;
-}
-
-bool Plot3D::AddPlot(int)
-{
- return false;
-}
-
-bool Chart25D::PropertyDlg()
-{
- return false;
-}
-
-bool Ribbon25D::PropertyDlg()
-{
- return false;
-}
-
-bool Func3D::PropertyDlg()
-{
- return false;
-}
-
-bool FitFunc3D::PropertyDlg()
-{
- return false;
-}
-
-bool BubblePlot3D::PropertyDlg()
-{
- return false;
-}
-
-bool GridLine::PropertyDlg()
-{
- return false;
-}
-
-bool Tick::PropertyDlg()
-{
- return false;
-}
-
-void
-Axis::DoMark(anyOutput *o, bool mark)
-{
-}
-
-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 Graph::ExecTool(MouseEvent *mev)
-{
- return false;
-}
-
-bool Graph::MoveObj(int cmd, GraphObj *g)
-{
- return false;
-}
-
-bool Graph::DoZoom(char *z)
-{
- return false;
-}
-
-bool Page::Configure()
-{
- return false;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// some more STUBS .....
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-char *SaveGraphAsName(char *oldname)
-{
- return name2;
-}
-
-char *OpenGraphName(char *oldname)
-{
- return 0L;
-}
-
-void HideTextCursor()
-{
- return;
-}
-
-void HideTextCursorObj(anyOutput *out)
-{
- return;
-}
-
-void ShowTextCursor(anyOutput *out, RECT *disp, DWORD color)
-{
- return;
-}
-
-void InvalidateOutput(anyOutput *o)
-{
- return;
-}
-
-void SuspendAnimation(anyOutput *o, bool bSusp)
-{
- 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;
-}
-
+//no_gui.cpp, Copyright 2000-2007 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 builds with no graphical user interface.
+// Builds using the GUI are compiled with use_gui.cpp instead.
+//
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+#include "rlplot.h"
+
+extern char *name1, *name2; //the filenames
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// STUBS: we do not need this objects or functions without GUI
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+dragHandle::dragHandle(GraphObj *par, int which):GraphObj(par, 0L)
+{
+}
+
+dragHandle::~dragHandle()
+{
+}
+
+void
+dragHandle::DoPlot(anyOutput *o)
+{
+}
+
+bool
+dragHandle::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ return false;
+}
+
+void *
+dragHandle::ObjThere(int x, int y)
+{
+ return 0L;
+}
+
+void
+dragHandle::Track(POINT *p, anyOutput *o)
+{
+}
+
+dragRect::dragRect(GraphObj *par, int which):GraphObj(par, 0L)
+{
+}
+
+dragRect::~dragRect()
+{
+}
+
+void
+dragRect::DoPlot(anyOutput *o)
+{
+}
+
+void *
+dragRect::ObjThere(int x, int y)
+{
+ return 0L;
+}
+
+bool
+dragRect::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ return false;
+}
+
+Drag3D::Drag3D(GraphObj *par):GraphObj(par, 0L)
+{
+}
+
+Drag3D::~Drag3D()
+{
+}
+
+void *
+Drag3D::ObjThere(int x, int y)
+{
+ return 0L;
+}
+
+void
+Drag3D::DoPlot(anyOutput *o)
+{
+}
+
+FrmRect::FrmRect(GraphObj *par, fRECT *lim, fRECT *c, fRECT *chld):GraphObj(par, 0L)
+{
+ Id = Id;
+}
+
+FrmRect::~FrmRect()
+{
+}
+
+double
+FrmRect::GetSize(int select)
+{
+ return 0.0;
+}
+
+bool
+FrmRect::SetSize(int select, double value)
+{
+ return false;
+}
+
+bool
+FrmRect::SetColor(int select, DWORD col)
+{
+ return false;
+}
+
+void
+FrmRect::DoMark(anyOutput *o, bool mark)
+{
+}
+
+void
+FrmRect::DoPlot(anyOutput *o)
+{
+}
+
+bool
+FrmRect::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ return false;
+}
+
+void *
+FrmRect::ObjThere(int x, int y)
+{
+ return 0L;
+}
+
+void
+FrmRect::Track(POINT *p, anyOutput *o)
+{
+}
+
+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;
+}
+
+void *
+Arrow::ObjThere(int x, int y)
+{
+ return 0L;
+}
+
+void
+Arrow::Track(POINT *p, anyOutput *o)
+{
+}
+
+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;
+}
+
+void Label::ShowCursor(anyOutput *o)
+{
+}
+
+bool Label::AddChar(int ci, anyOutput *o)
+{
+ return true;
+}
+
+void Label::CalcCursorPos(int x, int y, anyOutput *o)
+{
+}
+
+bool TextFrame::PropertyDlg()
+{
+ return false;
+}
+
+void TextFrame::ShowCursor(anyOutput *o)
+{
+}
+
+void TextFrame::CalcCursorPos(int x, int y, anyOutput *o)
+{
+}
+
+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 xyStat::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 Grid3D::PropertyDlg()
+{
+ return false;
+}
+
+bool Grid3D::Configure()
+{
+ return false;
+}
+
+bool Scatt3D::PropertyDlg()
+{
+ return false;
+}
+
+bool FitFunc::PropertyDlg()
+{
+ return false;
+}
+
+bool NormQuant::PropertyDlg()
+{
+ return false;
+}
+
+bool ContourPlot::PropertyDlg()
+{
+ return false;
+}
+
+bool Plot3D::AddAxis()
+{
+ return false;
+}
+
+bool Plot3D::PropertyDlg()
+{
+ return false;
+}
+
+bool Plot3D::AddPlot(int)
+{
+ return false;
+}
+
+bool Chart25D::PropertyDlg()
+{
+ return false;
+}
+
+bool Ribbon25D::PropertyDlg()
+{
+ return false;
+}
+
+bool Func3D::PropertyDlg()
+{
+ return false;
+}
+
+bool FitFunc3D::PropertyDlg()
+{
+ return false;
+}
+
+bool BubblePlot3D::PropertyDlg()
+{
+ return false;
+}
+
+bool GridLine::PropertyDlg()
+{
+ return false;
+}
+
+bool Tick::PropertyDlg()
+{
+ return false;
+}
+
+void
+Axis::DoMark(anyOutput *o, bool mark)
+{
+}
+
+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 Graph::ExecTool(MouseEvent *mev)
+{
+ return false;
+}
+
+bool Graph::MoveObj(int cmd, GraphObj *g)
+{
+ return false;
+}
+
+bool Graph::DoZoom(char *z)
+{
+ return false;
+}
+
+bool Page::Configure()
+{
+ return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// some more STUBS .....
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+char *SaveGraphAsName(char *oldname)
+{
+ return name2;
+}
+
+char *OpenGraphName(char *oldname)
+{
+ return 0L;
+}
+
+void HideTextCursor()
+{
+ return;
+}
+
+void HideTextCursorObj(anyOutput *out)
+{
+ return;
+}
+
+void ShowTextCursor(anyOutput *out, RECT *disp, DWORD color)
+{
+ return;
+}
+
+void InvalidateOutput(anyOutput *o)
+{
+ return;
+}
+
+void SuspendAnimation(anyOutput *o, bool bSusp)
+{
+ 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;
+}
+
diff --git a/reports.cpp b/reports.cpp
index dcb9388..c522ea6 100755
--- a/reports.cpp
+++ b/reports.cpp
@@ -1,3078 +1,3245 @@
-//reports.cpp, Copyright (c) 2006, 2007 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
-//
-// Create statistical reports
-//
-
-#include "rlplot.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <math.h>
-#include <ctype.h>
-#include "TheDialog.h"
-
-extern char TmpTxt[];
-extern Default defs;
-extern GraphObj *LastOpenGO;
-
-#define _PREC 1.0e-12
-
-//prototypes: WinSpec.cpp
-void *CreateDlgWnd(char *title, int x, int y, int width, int height, tag_DlgObj *d, DWORD flags);
-
-static int curr_id, cbSymLineStr;
-static fRECT dBounds;
-static TextDEF txtdef1, txtdef2;
-static double linsp1, linsp2;
-static char SymLineStr[40];
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// init report variables
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static void rep_init()
-{
- curr_id = 1; defs.cUnits = defs.dUnits;
- txtdef1.ColTxt = txtdef2.ColTxt = 0x0L;
- txtdef1.ColBg = txtdef2.ColBg = 0x00ffffffL;
- txtdef1.fSize = defs.GetSize(SIZE_TEXT);
- txtdef2.fSize = txtdef1.fSize *1.2;
- txtdef1.RotBL = txtdef2.RotBL = 0.0;
- txtdef1.RotCHAR = txtdef2.RotCHAR = 0.0;
- txtdef1.iSize = txtdef2.iSize = 0;
- txtdef1.Align = txtdef2.Align = TXA_HLEFT | TXA_VTOP;
- txtdef1.Mode = txtdef2.Mode = TXM_TRANSPARENT;
- txtdef1.Style = txtdef2.Style = TXS_NORMAL;
- txtdef1.Font = txtdef2.Font = FONT_HELVETICA;
- txtdef1.text = txtdef2.text = 0L;
-#ifdef _WINDOWS
- linsp1 = txtdef1.fSize*1.2; linsp2 = txtdef1.fSize*1.5;
-#else
- linsp1 = txtdef1.fSize*1.7; linsp2 = txtdef1.fSize*2.5;
-#endif
-#ifdef USE_WIN_SECURE
- cbSymLineStr = sprintf_s(SymLineStr, 40, "Line= %g 1 0x0 0x0\n", defs.GetSize(SIZE_SYM_LINE));
-#else
- cbSymLineStr = sprintf(SymLineStr, "Line= %g 1 0x0 0x0\n", defs.GetSize(SIZE_SYM_LINE));
-#endif
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// create a text label for a report
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char* mk_label(double x, double y, bool moveable, int align, TextDEF *td, char*text)
-{
- int csize, pos = 0;
- char *res;
-
- if(!(res = (char*)malloc(csize = 1000)))return 0L;
- res[pos++] = '\n'; res[pos++] = '[';
- add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
- add_to_buff(&res, &pos, &csize, "=Label]\nPos=", 12);
- add_dbl_to_buff(&res, &pos, &csize, x, true);
- add_dbl_to_buff(&res, &pos, &csize, y, true);
- res[pos++] = '\n';
- if(moveable) add_to_buff(&res, &pos, &csize, "moveable= 1\n", 12);
- add_to_buff(&res, &pos, &csize, "TxtDef= 0x0 0x00ffffff", 22);
- add_dbl_to_buff(&res, &pos, &csize, td->fSize, true);
- add_dbl_to_buff(&res, &pos, &csize, td->RotBL, true);
- add_dbl_to_buff(&res, &pos, &csize, td->RotCHAR, true);
- add_int_to_buff(&res, &pos, &csize, align, true, 0);
- add_to_buff(&res, &pos, &csize, " 1 0 0 \"", 8);
- add_to_buff(&res, &pos, &csize, text, 0);
- add_to_buff(&res, &pos, &csize, "\"\n", 2);
- return res;
-}
-static void rep_DrawText(GraphObj *parent, double x, double y, bool moveable, int align, TextDEF *td, char*text)
-{
- char *txt_obj;
-
- if(txt_obj = mk_label(x, y, moveable, align, td, text)) {
- OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
- free(txt_obj);
- }
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// draw a rectangle
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char* mk_rect(double x1, double y1, double x2, double y2, DWORD lcol, DWORD fcol)
-{
- int csize, pos = 0;
- char *res;
-
- if(!(res = (char*)malloc(csize = 1000)))return 0L;
- res[pos++] = '\n'; res[pos++] = '[';
- add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
- add_to_buff(&res, &pos, &csize, "=rectangle]\np1=", 0);
- add_dbl_to_buff(&res, &pos, &csize, x1, true);
- add_dbl_to_buff(&res, &pos, &csize, y1, true);
- add_to_buff(&res, &pos, &csize, "\np2=", 0);
- add_dbl_to_buff(&res, &pos, &csize, x2, true);
- add_dbl_to_buff(&res, &pos, &csize, y2, true);
- add_to_buff(&res, &pos, &csize, "\nLine= 0 1", 0);
- add_hex_to_buff(&res, &pos, &csize, lcol, true);
- add_to_buff(&res, &pos, &csize, " 0x0\nFillLine= 0 1 0x0 0x0\nFill= 0", 0);
- add_hex_to_buff(&res, &pos, &csize, fcol, true);
- add_to_buff(&res, &pos, &csize, " 1 0x0 0x00ffffff\n", 0);
- return res;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// print values to string
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static int dbl_to_str1(char *dest, int size, char* fmt, double val)
-{
-#ifdef USE_WIN_SECURE
- return sprintf_s(dest, size, fmt, val);
-#else
- return sprintf(dest, fmt, val);
-#endif
-}
-
-static int dbl_to_str2(char *dest, int size, char* fmt, double val1, double val2)
-{
-#ifdef USE_WIN_SECURE
- return sprintf_s(dest, size, fmt, val1, val2);
-#else
- return sprintf(dest, fmt, val1, val2);
-#endif
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// create general information on report page
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static void mk_header(Page *page, char* desc, DataObj *data)
-{
- time_t ti = time(0L);
- char label[80];
- double rpos;
- int cb;
-
- if(!page) return;
- rpos = page->GetSize(SIZE_GRECT_RIGHT) - txtdef1.fSize*5.0;
- rep_DrawText(page, txtdef1.fSize*5.0, page->GetSize(SIZE_GRECT_TOP)+txtdef2.fSize*6.0,
- false, TXA_HLEFT, &txtdef2, desc);
-#ifdef USE_WIN_SECURE
- ctime_s(label, 32, &ti);
-#else
- rlp_strcpy(label, 25, ctime(&ti));
-#endif
- label[24] = 0;
- rep_DrawText(page, rpos, page->GetSize(SIZE_GRECT_TOP)+txtdef1.fSize*5.0,
- false, TXA_HRIGHT, &txtdef1, label);
- cb = rlp_strcpy(label, 80, "RLPlot "); cb += rlp_strcpy(label+cb, 80-cb, SZ_VERSION);
- rep_DrawText(page, rpos, page->GetSize(SIZE_GRECT_BOTTOM)-txtdef1.fSize*6.0,
- false, TXA_HRIGHT, &txtdef1, label);
- if(data && data->Command(CMD_GETFILENAME, TmpTxt, 0L)) {
- rpos = page->GetSize(SIZE_GRECT_LEFT) + txtdef1.fSize*5.0;
- rep_DrawText(page, rpos, page->GetSize(SIZE_GRECT_BOTTOM)-txtdef1.fSize*6.0,
- false, TXA_HLEFT, &txtdef1, TmpTxt);
- }
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// create horizontal ruler
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static void mk_hr(GraphObj *parent, double x1, double x2, double y)
-{
- int csize, pos = 0;
- char *res;
-
- if(!(res = (char*)malloc(csize = 100)))return;
- res[pos++] = '\n'; res[pos++] = '[';
- add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
- add_to_buff(&res, &pos, &csize, "=polyline]\nData= (2){", 21);
- add_dbl_to_buff(&res, &pos, &csize, x1, false);
- add_dbl_to_buff(&res, &pos, &csize, y, true);
- add_dbl_to_buff(&res, &pos, &csize, x2, true);
- add_dbl_to_buff(&res, &pos, &csize, y, true);
- add_to_buff(&res, &pos, &csize, "}\nLine=", 7);
- add_dbl_to_buff(&res, &pos, &csize, txtdef1.fSize/20.0, true);
- add_dbl_to_buff(&res, &pos, &csize, txtdef1.fSize, true);
- add_to_buff(&res, &pos, &csize, " 0x0 0x0\n", 9);
- OpenGraph(parent, 0L, (unsigned char*)res, false);
- free(res);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// create a means report
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static double mk_mean_report(GraphObj *parent, double x, double y, double *da, int n, double ci, char *name)
-{
- static char *mean_fmts[] = {"Mean = %g", "Std.Dev. = %g", "N = %g", "Std.Err. = %g", 0L,
- "Kurtosis = %g", "Skewness = %g"};
- char desc[80];
- int i, cb;
- double v, t, res[10];
-
- if(name && name[0]) {
- cb = rlp_strcpy(desc, 40, "<b>"); cb += rlp_strcpy(desc+cb, 40-cb, name);
- cb += rlp_strcpy(desc+cb, 40-cb, ":</b>");
- rep_DrawText(parent, x, y, false, TXA_HLEFT, &txtdef1, desc);
- y += linsp1; x += (txtdef1.fSize*3.0);
- }
- cb = dbl_to_str1(desc, 80, "%g%%%% C.I. = %%g", ci*100.0);
- mean_fmts[4] = (char*)malloc(cb+2);
- rlp_strcpy(mean_fmts[4], cb+1, desc); t = distinv(t_dist, n-1, 1, 1.0-ci, 2.0);
- v = d_variance(n, da, &res[0], 0L); res[2] = (double)n;
- res[1] = sqrt(v); res[3] = res[1] / sqrt(res[2]);
- res[4] = res[3] *t; res[5] = d_kurt(n, da);
- res[6] = d_skew(n, da);
- for(i = 0; i < 7; i++) {
- dbl_to_str1(desc, 80, mean_fmts[i], res[i]);
- rep_DrawText(parent, x, y, false, TXA_HLEFT, &txtdef1, desc);
- y += (i==2 ? linsp1/0.9 : linsp1/1.2);
- }
- free(mean_fmts[4]); mean_fmts[4] = 0L;
- return y;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// create a median report
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static double mk_median_report(GraphObj *parent, double x, double y, double *da, int n, double ci, char *name)
-{
- static char *mean_fmts[] = {"Median = %g", "25%% = %g", "75%% = %g", "N = %g", "Min. = %g", "Max. = %g" };
- char desc[80];
- int i, cb;
- double res[6];
-
- if(!da || !parent || !n) return y;
- if(name && name[0]) {
- cb = rlp_strcpy(desc, 40, "<b>"); cb += rlp_strcpy(desc+cb, 40-cb, name);
- cb += rlp_strcpy(desc+cb, 40-cb, ":</b>");
- rep_DrawText(parent, x, y, false, TXA_HLEFT, &txtdef1, desc);
- y += linsp1; x += (txtdef1.fSize*3.0);
- }
- d_quartile(n, da, &res[1], &res[0], &res[2]);
- res[4] = res[5] = *da;
- for(i = 1; i < n; i++) {
- if(da[i] > res[5]) res[5] = da[i]; if(da[i] < res[4]) res[4] = da[i];
- }
- res[3] = (double)n;
- for(i = 0; i < 6; i++) {
- dbl_to_str1(desc, 80, mean_fmts[i], res[i]);
- rep_DrawText(parent, x, y, false, TXA_HLEFT, &txtdef1, desc);
- y += linsp1/1.2;
- }
- return y;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// create report table for anova ...
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static double mk_table(GraphObj *parent, double x, double y, int type, double **dda)
-{
- char *cheaders[] = {"<i>df</i>", "<i>SS</i>", "<i>MS</i>", "<i>F</i>", "<i>P</i>"};
- char *rheaders1[] = {"Source of variation", type == 2 ? (char*)"Explained by regression":
- (char*)"Among groups", type == 2 ? (char*)"Unexplained":(char*)"Within groups", "Total"};
- char *rheaders2[] = {"Source of variation", "Between rows", "Between columns", "Interaction",
- "Within subgroups (error)", "Total"};
- char *rheaders3[] = {"Source of variation", "Between columns", "Between rows", "Error", "Total"};
- char *cfmt[8], **rheaders;
- int i, j, nl, nc[8];
- double posc[8], cinc;
-
-#ifdef _WINDOWS
- cinc = txtdef1.fSize;
-#else
- cinc = txtdef1.fSize *1.3;
-#endif
- cfmt[0] = "%.0lf"; cfmt[3] = "%0.3lf"; cfmt[4] = "%0.4lf";
- switch(type) {
- case 1: case 2:
- rheaders = rheaders1;
- nl = 3; nc[0] = 5; nc[1] = 3; nc[2] = 2;
- posc[0] = x + cinc*14.0; posc[1] = posc[0] + cinc*5.0;
- posc[2] = posc[1] + cinc*6.0; posc[3] = posc[2] + cinc*6.0;
- posc[4] = posc[3] + cinc*6.0;
- cfmt[1] = GetNumFormat(floor(log10(dda[2][1])-3.0));
- cfmt[2] = GetNumFormat(floor(log10(dda[0][2]+dda[1][2])-3.0));
- break;
- case 3:
- rheaders = rheaders2;
- nl = 5; nc[0] = nc[1] = nc[2] = 5; nc[3] = 3; nc[4] = 2;
- posc[0] = x + cinc*14.0; posc[1] = posc[0] + cinc*5.0;
- posc[2] = posc[1] + cinc*6.0; posc[3] = posc[2] + cinc*6.0;
- posc[4] = posc[3] + cinc*6.0;
- cfmt[1] = GetNumFormat(floor(log10(dda[2][1])-3.0));
- cfmt[2] = GetNumFormat(floor(log10(dda[0][2]+dda[0][1])-3.0));
- break;
- case 4:
- rheaders = rheaders3;
- nl = 4; nc[0] = nc[1] = 5; nc[2] = 3; nc[3] = 2;
- posc[0] = x + cinc*14.0; posc[1] = posc[0] + cinc*5.0;
- posc[2] = posc[1] + cinc*6.0; posc[3] = posc[2] + cinc*6.0;
- posc[4] = posc[3] + cinc*6.0;
- cfmt[1] = GetNumFormat(floor(log10(dda[3][1])-4.0));
- cfmt[2] = GetNumFormat(floor(log10(dda[0][2]+dda[1][2]+dda[2][2])-4.0));
- break;
- default: return y;
- }
- if(type == 1 || type == 2 || type == 3 || type == 4) {
- rep_DrawText(parent, x, y, false, TXA_HLEFT, &txtdef1, rheaders[0]);
- for(i = 0; i < 5; i++) {
- rep_DrawText(parent, posc[i], y, false, TXA_HRIGHT, &txtdef1, cheaders[i]);
- if(i) posc[i] += linsp1;
- }
- mk_hr(parent, x, posc[4], y + linsp1); y += linsp2;
- }
- for(i = 0; i < nl; i++) {
- rep_DrawText(parent, x, y, false, TXA_HLEFT, &txtdef1, rheaders[i+1]);
- for(j = 0; j < nc[i]; j++) {
- if(j == 4 && dda[i][j] > 0.0 && dda[i][j] < 0.0001) rlp_strcpy(TmpTxt, 10, "< 0.0001");
-#ifdef USE_WIN_SECURE
- else sprintf_s(TmpTxt, 20, cfmt[j], dda[i][j]);
-#else
- else sprintf(TmpTxt, cfmt[j], dda[i][j]);
-#endif
- rep_DrawText(parent, posc[j], y, false, TXA_HRIGHT, &txtdef1, TmpTxt);
- }
- if(i < (nl-2)) y += linsp1;
- else {
- mk_hr(parent, x, posc[4], y + linsp1); y += linsp2;
- }
- }
- return y;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// create a boxplot for a report
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char* mk_boxplot(int style, double *x, double *y, double *by1, double *by2, double *wy1, double *wy2, int *ny, int n,
- char *s_nam, char *b_nam, char *w_nam)
-{
- int i, csize, pos, first_s, first_b, first_w, first_l;
- char *res;
- double size;
-
- if(!(res = (char*)malloc(csize = 2000)))return 0L;
- if(n < 20) size = defs.GetSize(SIZE_SYMBOL);
- else size = defs.GetSize(SIZE_SYMBOL)/2.0 + 20.0 * defs.GetSize(SIZE_SYMBOL)/(2.0 * n);
- first_b = curr_id;
- for(i = pos = 0; i < n && res; i++) {
- add_to_buff(&res, &pos, &csize, "\n[", 2); add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
- add_to_buff(&res, &pos, &csize, "=Box]\nType= 256\nHigh=", 21);
- if(style == 1) {
- add_dbl_to_buff(&res, &pos, &csize, by2[i], true);
- add_dbl_to_buff(&res, &pos, &csize, y[i], true);
- add_to_buff(&res, &pos, &csize,"\nLow=", 5);
- add_dbl_to_buff(&res, &pos, &csize, by1[i], true);
- add_dbl_to_buff(&res, &pos, &csize,y[i], true);
- }
- else {
- add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
- add_dbl_to_buff(&res, &pos, &csize, by2[i], true);
- add_to_buff(&res, &pos, &csize,"\nLow=", 5);
- add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
- add_dbl_to_buff(&res, &pos, &csize, by1[i], true);
- }
- add_to_buff(&res, &pos, &csize,"\nSize= 60\nName= \"", 17);
- add_to_buff(&res, &pos, &csize, b_nam, 0);
- add_to_buff(&res, &pos, &csize, "\"\n", 2);
- }
- first_w = curr_id;
- for(i = 0; i < n && res; i++) {
- add_to_buff(&res, &pos, &csize, "\n[", 2); add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
- add_to_buff(&res, &pos, &csize, "=Whisker]\nHigh=", 15);
- if(style == 1) {
- add_dbl_to_buff(&res, &pos, &csize, wy2[i], true);
- add_dbl_to_buff(&res, &pos, &csize, y[i], true);
- add_to_buff(&res, &pos, &csize,"\nLow=", 5);
- add_dbl_to_buff(&res, &pos, &csize, wy1[i], true);
- add_dbl_to_buff(&res, &pos, &csize,y[i], true);
- }
- else {
- add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
- add_dbl_to_buff(&res, &pos, &csize, wy2[i], true);
- add_to_buff(&res, &pos, &csize,"\nLow=", 5);
- add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
- add_dbl_to_buff(&res, &pos, &csize, wy1[i], true);
- }
- add_to_buff(&res, &pos, &csize, "\nDesc= \"", 8);
- add_to_buff(&res, &pos, &csize, w_nam, 0);
- add_to_buff(&res, &pos, &csize, "\"\n", 2);
- }
- first_s = curr_id;
- for(i = 0; i < n && res; i++) {
- add_to_buff(&res, &pos, &csize, "\n[", 2); add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
- add_to_buff(&res, &pos, &csize, "=Symbol]\nType= 10\nPos=", 22);
- add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
- add_dbl_to_buff(&res, &pos, &csize, y[i], true);
- add_to_buff(&res, &pos, &csize, "\nSize=", 6); add_dbl_to_buff(&res, &pos, &csize, size, true);
- add_to_buff(&res, &pos, &csize, "\n", 1);
- add_to_buff(&res, &pos, &csize, SymLineStr, cbSymLineStr);
- add_to_buff(&res, &pos, &csize, "FillCol= 0x00ffffff\n", 20);
- if(s_nam) {
- add_to_buff(&res, &pos, &csize, "Name=\"", 6);
- add_to_buff(&res, &pos, &csize, s_nam, 0); add_to_buff(&res, &pos, &csize, "\"\n", 2);
- }
- }
- first_l = curr_id;
- for(i = 0; i < n && res; i++) {
- add_to_buff(&res, &pos, &csize, "\n[", 2);
- add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
- add_to_buff(&res, &pos, &csize, "=Label]\nPos=", 12);
- if(style == 1) {
- add_dbl_to_buff(&res, &pos, &csize, wy2[i], true);
- add_dbl_to_buff(&res, &pos, &csize, y[i], true);
- add_to_buff(&res, &pos, &csize, "\nDist=", 6);
- add_dbl_to_buff(&res, &pos, &csize, txtdef1.fSize/2.0, true);
- add_to_buff(&res, &pos, &csize, " 0", 2);
- }
- else {
- add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
- add_dbl_to_buff(&res, &pos, &csize, wy2[i], true);
- add_to_buff(&res, &pos, &csize, "\nDist= 0", 8);
- add_dbl_to_buff(&res, &pos, &csize, -txtdef1.fSize/4.0, true);
- }
- add_to_buff(&res, &pos, &csize, "\nFlags= 0x00000011\nTxtDef= 0x00000000 0x00ffffff", 48);
- add_dbl_to_buff(&res, &pos, &csize, txtdef1.fSize, true);
- add_dbl_to_buff(&res, &pos, &csize, txtdef1.RotBL, true);
- add_dbl_to_buff(&res, &pos, &csize, txtdef1.RotCHAR, true);
- add_int_to_buff(&res, &pos, &csize, style == 1 ? (TXA_HLEFT | TXA_VCENTER):(TXA_HCENTER | TXA_VBOTTOM), true, 0);
- add_to_buff(&res, &pos, &csize, " 1 0 0 \"", 8);
- if(n < 7) add_to_buff(&res, &pos, &csize, "n = ", 4);
- add_int_to_buff(&res, &pos, &csize, ny[i], false, 0);
- add_to_buff(&res, &pos, &csize, "\"\n", 2);
- }
- add_to_buff(&res,&pos,&csize, "\n[", 2); add_int_to_buff(&res,&pos,&csize, curr_id++, false, 0);
- add_to_buff(&res, &pos, &csize, "=BoxPlot]\nBounds=", 17);
- add_dbl_to_buff(&res,&pos,&csize, dBounds.Xmin, true); add_dbl_to_buff(&res,&pos,&csize, dBounds.Ymax, true);
- add_dbl_to_buff(&res,&pos,&csize, dBounds.Xmax, true); add_dbl_to_buff(&res,&pos,&csize, dBounds.Ymin, true);
-
- add_to_buff(&res,&pos,&csize, "\nBoxes=(", 0); add_int_to_buff(&res,&pos,&csize, n, false, 0);
- add_to_buff(&res,&pos,&csize, "){", 2);
- for(i = 0; i < n; i++, first_b++) {
- add_int_to_buff(&res,&pos,&csize, first_b, false, 0); add_to_buff(&res,&pos,&csize, ",", 1);
- if(i && (i%16)== 0 && first_b < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n ", 4);
- }
- while(res[pos-1] == ',' || res[pos-1] < 33) pos --; add_to_buff(&res, &pos, &csize, "}", 2);
- add_to_buff(&res,&pos,&csize, "\nWhiskers=(", 0); add_int_to_buff(&res,&pos,&csize, n, false, 0);
- add_to_buff(&res,&pos,&csize, "){", 2);
- for(i = 0; i < n; i++, first_w++) {
- add_int_to_buff(&res,&pos,&csize, first_w, false, 0); add_to_buff(&res,&pos,&csize, ",", 1);
- if(i && (i%16)== 0 && first_b < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n ", 4);
- }
- while(res[pos-1] == ',' || res[pos-1] < 33) pos --; add_to_buff(&res, &pos, &csize, "}", 2);
- add_to_buff(&res,&pos,&csize, "\nSymbols=(", 10); add_int_to_buff(&res,&pos,&csize, n, false, 0);
- add_to_buff(&res,&pos,&csize, "){", 2);
- for(i = 0; i < n; i++, first_s++) {
- add_int_to_buff(&res,&pos,&csize, first_s, false, 0); add_to_buff(&res,&pos,&csize, ",", 1);
- if(i && (i%16)== 0 && first_s < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n ", 4);
- }
- while(res[pos-1] == ',' || res[pos-1] < 33) pos --; add_to_buff(&res, &pos, &csize, "}", 2);
- add_to_buff(&res,&pos,&csize, "\nLabels=(", 9); add_int_to_buff(&res,&pos,&csize, n, false, 0);
- add_to_buff(&res,&pos,&csize, "){", 2);
- for(i = 0; i < n; i++, first_l++) {
- add_int_to_buff(&res,&pos,&csize, first_l, false, 0); add_to_buff(&res,&pos,&csize, ",", 1);
- if(i && (i%16)== 0 && first_s < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n ", 4);
- }
- while(res[pos-1] == ',' || res[pos-1] < 33) pos --; add_to_buff(&res, &pos, &csize, "}\n", 2);
- return res;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// create a scatterplot for a report
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char* mk_scatt(int style, double *x, double *y, double *ss, int *ny, int n, char *s_nam, char *x_desc, char *y_desc)
-{
- int i, csize, pos, first;
- char *res;
- double size, linew, tmp, val;
-
- if(!(res = (char*)malloc(csize = 2000)))return 0L;
- if(n < 20) size = defs.GetSize(SIZE_SYMBOL);
- else size = defs.GetSize(SIZE_SYMBOL)/2.0 + 20.0 * defs.GetSize(SIZE_SYMBOL)/(2.0 * n);
- linew = defs.GetSize(SIZE_SYM_LINE);
- first = curr_id;
- for(i = pos = 0; i < n && res; i++) {
- add_to_buff(&res, &pos, &csize, "\n[", 2); add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
- add_to_buff(&res, &pos, &csize, "=Symbol]\nPos=", 13);
- add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
- add_dbl_to_buff(&res, &pos, &csize, y[i], true);
- add_to_buff(&res, &pos, &csize, "\nSize=", 6); add_dbl_to_buff(&res, &pos, &csize, size, true);
- add_to_buff(&res, &pos, &csize, "\n", 1);
- add_to_buff(&res, &pos, &csize, SymLineStr, cbSymLineStr);
- add_to_buff(&res, &pos, &csize, "FillCol= 0x00ffffff\n", 20);
- }
- if(ss && ny) {
- for(i = 0; i < n && res; i++) {
- if(ny[i] > 1) tmp = sqrt(ss[i]/(ny[i]-1));
- else tmp = 0.0;
- add_to_buff(&res, &pos, &csize, "\n[", 2);
- add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
- add_to_buff(&res, &pos, &csize, "=ErrorBar]\nType=", 16);
- add_int_to_buff(&res, &pos, &csize, style & 0x10 ? 3 : 0, true, 0);
- add_to_buff(&res, &pos, &csize, "\nPos=", 5);
- add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
- add_dbl_to_buff(&res, &pos, &csize, y[i], true);
- add_to_buff(&res, &pos, &csize, "\nErr=", 5);
- add_dbl_to_buff(&res, &pos, &csize, tmp, true);
- add_to_buff(&res, &pos, &csize, "\nDesc= \"Std. Dev.\"\n", 19);
- }
- for(i = 0; i < n && res; i++) {
- if(ny[i] > 1) tmp = sqrt(ss[i]/(ny[i]-1));
- else tmp = 0.0;
- add_to_buff(&res, &pos, &csize, "\n[", 2);
- add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
- add_to_buff(&res, &pos, &csize, "=Label]\nPos=", 12);
- if(style & 0x10) {
- val = x ? x[i] : (double)(i+1);
- if(dBounds.Xmin > (val-tmp)) dBounds.Xmin = val-tmp;
- if(dBounds.Xmax < (val+tmp)) dBounds.Xmax = val+tmp;
- add_dbl_to_buff(&res, &pos, &csize, val+tmp, true);
- add_dbl_to_buff(&res, &pos, &csize, y[i], true);
- add_to_buff(&res, &pos, &csize, "\nDist=", 6);
- add_dbl_to_buff(&res, &pos, &csize, txtdef1.fSize/2.0, true);
- add_to_buff(&res, &pos, &csize, " 0", 2);
- }
- else {
- if(dBounds.Ymin > (y[i]-tmp)) dBounds.Ymin = y[i]-tmp;
- if(dBounds.Ymax < (y[i]+tmp)) dBounds.Ymax = y[i]+tmp;
- add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : ((double)(i+1)), true);
- add_dbl_to_buff(&res, &pos, &csize, y[i] +tmp, true);
- add_to_buff(&res, &pos, &csize, "\nDist= 0", 8);
- add_dbl_to_buff(&res, &pos, &csize, -txtdef1.fSize/4.0, true);
- }
- add_to_buff(&res, &pos, &csize, "\nFlags= 0x00000011\nTxtDef= 0x00000000 0x00ffffff", 48);
- add_dbl_to_buff(&res, &pos, &csize, txtdef1.fSize, true);
- add_dbl_to_buff(&res, &pos, &csize, txtdef1.RotBL, true);
- add_dbl_to_buff(&res, &pos, &csize, txtdef1.RotCHAR, true);
- add_int_to_buff(&res, &pos, &csize, (style & 0x10)?(TXA_HLEFT | TXA_VCENTER) : (TXA_HCENTER | TXA_VBOTTOM), true, 0);
- add_to_buff(&res, &pos, &csize, " 1 0 0 \"", 8);
- if(n < 7) add_to_buff(&res, &pos, &csize, "n = ", 4);
- add_int_to_buff(&res, &pos, &csize, ny[i], false, 0);
- add_to_buff(&res, &pos, &csize, "\"\n", 2);
- }
- }
- add_to_buff(&res,&pos,&csize, "\n[", 2); add_int_to_buff(&res,&pos,&csize, curr_id++, false, 0);
- add_to_buff(&res, &pos, &csize, "=PlotScatt]\nBounds=", 19);
- add_dbl_to_buff(&res,&pos,&csize, dBounds.Xmin, true); add_dbl_to_buff(&res,&pos,&csize, dBounds.Ymax, true);
- add_dbl_to_buff(&res,&pos,&csize, dBounds.Xmax, true); add_dbl_to_buff(&res,&pos,&csize, dBounds.Ymin, true);
- add_to_buff(&res,&pos,&csize, "\nSymbols=(", 10); add_int_to_buff(&res,&pos,&csize, n, false, 0);
- add_to_buff(&res,&pos,&csize, "){", 2);
- for(i = 0; i < n; i++, first++) {
- add_int_to_buff(&res,&pos,&csize, first, false,0); add_to_buff(&res,&pos,&csize, ",", 1);
- if(i && (i%16)== 0 && first < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n ", 4);
- }
- while(res[pos-1] == ',' || res[pos-1] < 33) pos --; add_to_buff(&res, &pos, &csize, "}\n", 2);
- if(ss && ny) {
- add_to_buff(&res,&pos,&csize, "ErrBars=(", 9); add_int_to_buff(&res,&pos,&csize, n, false, 0);
- add_to_buff(&res,&pos,&csize, "){", 2);
- for(i = 0; i < n; i++, first++) {
- add_int_to_buff(&res,&pos,&csize, first,false,0); add_to_buff(&res,&pos,&csize, ",", 1);
- if(i && (i%16)== 0 && first < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n ", 4);
- }
- while(res[pos-1] == ',' || res[pos-1] < 33) pos --; add_to_buff(&res, &pos, &csize, "}\n", 2);
- add_to_buff(&res,&pos,&csize, "Labels=(", 8); add_int_to_buff(&res,&pos,&csize, n, false, 0);
- add_to_buff(&res,&pos,&csize, "){", 2);
- for(i = 0; i < n; i++, first++) {
- add_int_to_buff(&res,&pos,&csize, first,false,0); add_to_buff(&res,&pos,&csize, ",", 1);
- if(i && (i%16)== 0 && first < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n ", 4);
- }
- while(res[pos-1] == ',' || res[pos-1] < 33) pos --; add_to_buff(&res, &pos, &csize, "}\n", 2);
- }
- if(x_desc && x_desc[0]){
- add_to_buff(&res,&pos,&csize, "x_info= \"", 9); add_to_buff(&res,&pos,&csize, x_desc, 0);
- add_to_buff(&res,&pos,&csize, "\"\n", 2);
- }
- if(y_desc && y_desc[0]){
- add_to_buff(&res,&pos,&csize, "y_info= \"", 9); add_to_buff(&res,&pos,&csize, y_desc, 0);
- add_to_buff(&res,&pos,&csize, "\"\n", 2);
- }
- if(s_nam && s_nam[0]) {
- add_to_buff(&res, &pos, &csize, "DataDesc=\"", 10);
- add_to_buff(&res, &pos, &csize, s_nam, 0); add_to_buff(&res, &pos, &csize, "\"\n", 2);
- }
- return res;
-}
-
-static double contrasts_level = 95.0;
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// create a contrasts report for one way anova
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static void mk_contrasts(GraphObj* par, int type, double dx, double dy, double *y, double *ss, int *ny, int n,
- char **names, double ci, double msw, double msdf)
-{
- double tmp, tkd, pcorr, cx[10], *raw;
- int i, j, k, l, c, df, *co, nco, cb;
- char ctext[5], **contrasts;
- char *headings[] = {"<i>Groups</i>", "<i>Mean</i>", "<i>Std. Dev.</i>", "<i>N</i>",
- "<i>Contrasts</i><sup>1)</sup>"};
-
- if(!par || !y || !ss || !ny || n < 2) return;
- cx[0] = txtdef1.fSize*5.0; cx[1] = cx[0] + linsp1*5.0;
- cx[2] = cx[1] + linsp1*5.0; cx[3] = cx[2] + linsp1*5.0;
- cx[4] = cx[3] + linsp1*4.0; cx[5] = cx[4] + linsp1*3.0;
- cx[6] = cx[5] + linsp1*4.0;
-
- rep_DrawText(par, dx, dy, false, TXA_HLEFT, &txtdef1, "<b>Summary:</b>");
- for(i = 0, dy += linsp2; i < 5; i++) { //column headers
- c = (i == 4) ? TXA_HLEFT : TXA_HRIGHT;
- rep_DrawText(par, cx[i+1], dy, false, c, &txtdef1, headings[i]);
- }
- mk_hr(par, cx[0], cx[6]+txtdef1.fSize*2.0, dy +linsp1);
- if(type == 1 || type == 2) {
- if(!(co = (int*)malloc(n*sizeof(int)))) return;
- if(!(contrasts = (char**)malloc(n*sizeof(char*)))) return;
- rlp_strcpy(ctext, 5, ", a");
- for(i = df = 0, nco = n; i < n; i++) {
- if(ny[i] > 0) df += (ny[i]-1);
- co[i] = i;
- contrasts[i] = (char*)calloc(50, sizeof(char));
- }
- tkd = qtukey(1.0-ci, 1.0, (double) n, (double)df, 1, 0);
- for(i = 0; nco; ) {
- for(j = 0; j < n; j++) {
- switch(type) {
- case 1: //Tukey-Kramer
- tmp = tkd * sqrt((msw*(1.0/((double)ny[j]) + 1.0/((double)ny[co[i]])))/2.0);
- break;
- case 2: //Tukey's HSD
- tmp = tkd * sqrt(msw/(ny[j] <= ny[co[i]] ? ny[j] : ny[co[i]]));
- break;
- }
- if(fabs(y[j]-y[co[i]]) < tmp) {
- cb = (int)strlen(contrasts[j]);
- rlp_strcpy((contrasts[j])+cb, 50-cb, ctext);
- }
- }
- for(j = nco = 0; j < n; j++) {
- if(!(contrasts[j][0])) co[nco++] = j;
- }
- ctext[2]++;
- }
- }
- else if(type == 10) {
- if(!(co = (int*)malloc(n*sizeof(int)))) return;
- if(!(contrasts = (char**)malloc(n*sizeof(char*)))) return;
- if(!(raw = (double*)malloc((n*n-1)*sizeof(double))))return;
- rlp_strcpy(ctext, 5, ", a");
- for(i = df = 0, nco = n; i < n; i++) {
- if(ny[i] > 0) df += (ny[i]-1);
- co[i] = i;
- contrasts[i] = (char*)calloc(50, sizeof(char));
- }
- for(i = k = 0; i < (n-1); i++) for(j = i+1; j < n; j++) {
- raw[k++] = t_dist(fabs(0.5*(y[i]-y[j])/sqrt(msw/(ny[i]+ny[j]))), msdf, 0.0);
- }
- SortArray(k, raw);
- for(i = 0; nco; ) {
- for(j = 0; j < n; j++) {
- tmp = t_dist(fabs(0.5*(y[j]-y[co[i]])/sqrt(msw/(ny[j]+ny[co[i]]))), msdf, 0.0);
- for(l = 0; l < k && tmp > raw[l]; l++);
- switch(type) {
- case 10: //Dunn Sidak
- pcorr = 1.0 - pow((1.0 - ci), 1.0 /(double(k-l)));
- break;
- }
- if(tmp > pcorr || j == co[i]) {
- cb = (int)strlen(contrasts[j]);
- rlp_strcpy((contrasts[j])+cb, 50-cb, ctext);
- }
- }
- for(j = nco = 0; j < n; j++) {
- if(!(contrasts[j][0])) co[nco++] = j;
- }
- ctext[2]++;
- }
- free(raw);
- }
- else return;
-
- for(i = 0, dy += linsp2; i < n; i++, dy +=linsp1) {
- if(ny[i] > 1) tmp = sqrt(ss[i]/(ny[i]-1));
- else tmp = 0.0;
- rep_DrawText(par, cx[1], dy, false, TXA_HRIGHT, &txtdef1, names[i]);
- dbl_to_str1(TmpTxt, 20, "%g", y[i]);
- rep_DrawText(par, cx[2], dy, false, TXA_HRIGHT, &txtdef1, TmpTxt);
- if(tmp > 0.0) {
- dbl_to_str1(TmpTxt, 20, "%g", tmp);
- rep_DrawText(par, cx[3], dy, false, TXA_HRIGHT, &txtdef1, TmpTxt);
- }
- if(ny[i] >1) {
- dbl_to_str1(TmpTxt, 20, "%.0lf", (double)ny[i]);
- rep_DrawText(par, cx[4], dy, false, TXA_HRIGHT, &txtdef1, TmpTxt);
- }
- rep_DrawText(par, cx[5], dy, false, TXA_HLEFT, &txtdef1, contrasts[i]+2);
- }
- mk_hr(par, cx[0], cx[6]+txtdef1.fSize*2.0, dy+txtdef1.fSize*0.2);
- cb = dbl_to_str1(TmpTxt, 200, "<sup>1)</sup> Groups not sharing the same letter are different "
- "on the %g%% level ", (1.0-ci)*100.0);
- switch (type) {
- case 1: //Tukey-Kramer
- rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE - cb, "(Tukey-Kramer method)");
- break;
- case 2: //Tukey's HSD
- rep_DrawText(par, cx[0]+ txtdef1.fSize*2.0, dy + txtdef2.fSize + linsp1, false,
- TXA_HLEFT, &txtdef1, "(Tukey's honest significant difference)");
- break;
- case 10: //Dunn-Sidak
- rep_DrawText(par, cx[0]+ txtdef1.fSize*2.0, dy + txtdef2.fSize + linsp1, false,
- TXA_HLEFT, &txtdef1, "(sequential Dunn-Sidak method)");
- break;
- }
- rep_DrawText(par, cx[0], dy += txtdef2.fSize , false, TXA_HLEFT, &txtdef1, TmpTxt);
- for(i = 0; i < n; i++) free(contrasts[i]);
- free(co); free(contrasts);
- return;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// create a homogeneity of variances report for one way anova
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static void mk_v_homogeneity(GraphObj* par, DataObj *data, double *dx, double *dy, double *y, double *ss,
- int *ny, int n, double **vals)
-{
- int i;
- double tmp, *sd, f1, f2, p1, p2;
- char *txt_obj;
- scaleINFO scale = {{0.0, 0.8}, {0.0, 0.8}, {0.0, 0.8}};
- Graph *graph;
-
- if(!par || !y || !ss || !ny || n < 2) return;
- if(!(sd = (double*)malloc(n*sizeof(double)))) return;
- rep_DrawText(par, *dx, *dy, false, TXA_HLEFT, &txtdef1, "<b>Homogeneity of Variances:</b>");
- for(i = 0; i < n; i++) {
- if(ny[i] > 1) sd[i] = sqrt(ss[i]/(ny[i]-1));
- else sd[i] = 0.0;
- if(i) {
- if(dBounds.Xmax < y[i]) dBounds.Xmax = y[i];
- if(dBounds.Xmin > y[i]) dBounds.Xmin = y[i];
- if(dBounds.Ymax < sd[i]) dBounds.Ymax = sd[i];
- if(dBounds.Ymin > sd[i]) dBounds.Ymin = sd[i];
- }
- else {
- dBounds.Xmax = dBounds.Xmin = y[0];
- dBounds.Ymax = dBounds.Ymin = sd[0];
- }
- }
- if((graph = new Graph(par, data, 0L, 0)) && (txt_obj = mk_scatt(0, y, sd, 0L, ny, n,
- "Variables", "Means", "Std.Dev."))){
- graph->GRect.Xmax = defs.GetSize(SIZE_GRECT_BOTTOM)*0.8;
- graph->GRect.Ymax *= 0.8;
- graph->DRect.Xmin *= 0.8; graph->DRect.Ymax *= 0.8;
- graph->DRect.Xmax = graph->GRect.Xmax - (txtdef1.fSize*2.0);
- scale.sx.fx = par->GetSize(SIZE_GRECT_RIGHT) - txtdef1.fSize*5.0 - graph->GRect.Xmax*0.8 + graph->GRect.Xmin*0.8;
- scale.sy.fx = *dy;
- OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
- free(txt_obj);
- graph->Command(CMD_SCALE, &scale, 0L);
- if(!(par->Command(CMD_DROP_GRAPH, graph, 0L))) delete graph;
- else graph->moveable = 0;
- }
- if(bartlett(n, ny, ss, &tmp)) {
- rep_DrawText(par, *dx + txtdef1.fSize*2.0, *dy += (linsp2*1.5), false, TXA_HLEFT, &txtdef1, "Bartlett's test:");
- i = dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "Chi<sup>2</sup> = %.2lf, ", tmp);
- tmp = chi_dist(tmp, n-1, 0);
- dbl_to_str1(TmpTxt+i, TMP_TXT_SIZE-i, tmp < 0.0001 ? (char*)"P < 0.0001" : (char*)"P = %.4lf", tmp);
- rep_DrawText(par, *dx + txtdef1.fSize*3.0, *dy += linsp1, false, TXA_HLEFT, &txtdef1, TmpTxt);
- }
- if(levene(1, n, ny, y, vals, &f1, &p1) && levene(2, n, ny, y, vals, &f2, &p2) ) {
- rep_DrawText(par, *dx + txtdef1.fSize*2.0, *dy += (linsp2*1.5), false, TXA_HLEFT, &txtdef1, "Levene's test:");
- i = dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "using means: F = %.2lf, ", f1);
- dbl_to_str1(TmpTxt+i, TMP_TXT_SIZE-i, tmp < 0.0001 ? (char*)"P < 0.0001" : (char*)"P = %.4lf", p1);
- rep_DrawText(par, *dx + txtdef1.fSize*3.0, *dy += linsp1, false, TXA_HLEFT, &txtdef1, TmpTxt);
- i = dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "using medians: F = %.2lf, ", f2);
- dbl_to_str1(TmpTxt+i, TMP_TXT_SIZE-i, tmp < 0.0001 ? (char*)"P < 0.0001" : (char*)"P = %.4lf", p2);
- rep_DrawText(par, *dx + txtdef1.fSize*3.0, *dy += linsp1, false, TXA_HLEFT, &txtdef1, TmpTxt);
- }
- free(sd);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// one way anova
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *AnovaDlg_Tmpl =
- "1,+,,DEFAULT,PUSHBUTTON,-1,158,10,45,12\n"
- ".,.,,,PUSHBUTTON,-2,158,25,45,12\n"
- ".,,10,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "10,+,152,ISPARENT | CHECKED,SHEET,1,5,10,140,90\n"
- ".,20,100,ISPARENT,SHEET,2,5,10,140,90\n"
- "20,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
- "100,104,,ISRADIO,CHECKBOX,8,20,25,100,9\n"
- "104,+,,,LTEXT,4,15,37,100,9\n"
- ".,.,,ISRADIO,CHECKBOX,5,20,47,100,9\n"
- ".,.,,ISRADIO,CHECKBOX,9,20,57,100,9\n"
- ".,110,,ISRADIO,CHECKBOX,10,20,67,100,9\n"
- "110,+,,,LTEXT,7,20,85,55,9\n"
- ".,.,,,EDVAL1,6,80,85,25,10\n"
- ".,,,,LTEXT,-10,107,85,10,9\n"
- "152,+,,ISPARENT | CHECKED,GROUPBOX,3,12,30,128,65\n"
- ".,.,,,LTEXT,0,25,45,60,8\n"
- ".,.,,,RANGEINPUT,0,25,55,100,10\n"
- ".,.,0,,PUSHBUTTON,-8,95,70,30,12\n"
- ".,,,LASTOBJ,PUSHBUTTON,-9,60,70,35,12";
-
-void rep_anova(GraphObj *parent, DataObj *data)
-{
- TabSHEET tab1 = {0, 45, 10, "Anova Input"};
- TabSHEET tab2 = {45, 75, 10, "Tests"};
- DlgInfo *AnovaDlg;
- void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)" select one range for every variable ",
- (void*)"Contrasts:", (void*)" Tukey-Kramer method", (void*)&contrasts_level, (void*)"significance level:",
- (void*)" Homogeneity of Variances", (void*)" Tukey's honest sig. difference", (void*)" Dunn-Sidak"};
- DlgRoot *Dlg;
- void *hDlg;
- double **cols = 0L, *csums=0L, mtot, *css=0L, cx, cy;
- double **res_tab = 0L, ci;
- int i, j, n, c, r, res, nc, ntot, currYR = 0, maxYR=0, ny, *ncols = 0L;;
- bool bContinue = false, updateYR = true;
- anyResult ares;
- AccRange *rD =0L;
- char **rd = 0L, **names, *txt_obj;
- Graph *graph;
- Page *page;
-
- if(!parent || !data) return;
- if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
- TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return;
- if(!(AnovaDlg = CompileDialog(AnovaDlg_Tmpl, dyndata))) return;
- if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
- for(i=j=0; i <= 1000; i +=100) if(TmpTxt[i])
- rd[j++] = (char*)memdup(TmpTxt+i, ((int)strlen(TmpTxt+i))+2, 0); maxYR = j-1;
- }
- if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return;
- if(!(Dlg = new DlgRoot(AnovaDlg, data)))return;
- if(rd && rd[currYR] && *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
- hDlg = CreateDlgWnd("Single-Classification Anova", 50, 50, 420, 240, Dlg, 0x0L);
- do {
- if(updateYR) {
- if(currYR >0) Dlg->ShowItem(156, true);
- else Dlg->ShowItem(156, false);
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "variable # %d/%d", currYR+1, maxYR+1);
-#else
- sprintf(TmpTxt,"variable # %d/%d", currYR+1, maxYR+1);
-#endif
- Dlg->SetText(153, TmpTxt);
- updateYR = false;
- }
- 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 155: case 156:
- res = com_StackDlg(res, Dlg, 0L, 0L, &rd, &currYR,
- &rD, &bContinue, &ny, &maxYR, &updateYR);
- break;
- }
- }while (res < 0);
- if(res == 1 && (res_tab = (double**)calloc(3, sizeof(double*)))
- && (res_tab[0] = (double*) malloc(5*sizeof(double)))
- && (res_tab[1] = (double*) malloc(5*sizeof(double)))
- && (res_tab[2] = (double*) malloc(5*sizeof(double)))
- && (cols = (double**)calloc(maxYR+1, sizeof(double*)))
- && (names = (char**)calloc(maxYR+1, sizeof(char*)))
- && (ncols = (int*)calloc(maxYR+1, sizeof(int)))) {
- rep_init(); if(rD) delete rD; rD = 0L;
- if(Dlg->GetValue(111, &ci)) {
- contrasts_level = ci; ci = 1.0-(ci/100.0);
- }
- dBounds.Ymin = HUGE_VAL; dBounds.Ymax = -HUGE_VAL;
- // get data into two dimensional array
- for(nc = maxYR+1, i = ntot = 0, mtot = 0.0; i < nc; i++) {
- if((rD = new AccRange(rd[i])) && (n = rD->CountItems()) && (cols[i] = (double*)malloc(n*sizeof(double)))) {
- names[i] = rD->RangeDesc(data, 1);
- for(n = 0, rD->GetFirst(&c, &r); rD->GetNext(&c, &r); ) {
- if(data->GetResult(&ares, r, c, false) && ares.type == ET_VALUE) {
- if(ares.value < dBounds.Ymin) dBounds.Ymin = ares.value;
- if(ares.value > dBounds.Ymax) dBounds.Ymax = ares.value;
- cols[i][n++] = ares.value;
- }
- }
- ncols[i] = n; ntot += n; //mtot += csums[i];
- delete(rD); rD = 0L;
- }
- if(!names[i] && (names[i] = (char*)malloc(20*sizeof(char)))){
-#ifdef USE_WIN_SECURE
- sprintf_s(names[i], 20, "Group %d", i+1);
-#else
- sprintf(names[i], "Group %d", i+1);
-#endif
- }
- }
- // check for unique names
- for(i = 0; i < (nc-1); i++) for(j = i+1; j < nc; j++) {
- if(!strcmp(names[i], names[j])) {
- names[i] = (char*) realloc(names[i], 20 *sizeof(char));
- names[j] = (char*) realloc(names[j], 20 *sizeof(char));
-#ifdef USE_WIN_SECURE
- sprintf_s(names[i], 20, "Group %d", i+1); sprintf_s(names[j], 20, "Group %d", j+1);
-#else
- sprintf(names[i], "Group %d", i+1); sprintf(names[j], "Group %d", j+1);
-#endif
- }
- }
-
- if(do_anova1(nc, ncols, cols, res_tab, &mtot, &csums, &css)){
- dBounds.Xmin = 0.5; dBounds.Xmax = ((double)nc)+0.5;
- page = new Page(parent, data);
- mk_header(page, "<b>Single-Classification ANOVA</b>", data);
- if((graph = new Graph(parent, data, 0L, 0)) && (txt_obj = mk_scatt(0, 0L, csums, css, ncols, nc, "Mean", "Groups", "Means <u>+</u> S.D."))){
- OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
- if(LastOpenGO && LastOpenGO->Id == GO_PLOTSCATT) {
- if(((PlotScatt*)LastOpenGO)->x_tv = new TextValue()){
- for(i = 0; i < nc; i++) ((PlotScatt*)LastOpenGO)->x_tv->GetValue(names[i]);
- }
- }
- free(txt_obj); graph->moveable = 0;
- graph->GRect.Xmin += (txtdef1.fSize*5.0); graph->GRect.Xmax += (txtdef1.fSize*5.0);
- graph->GRect.Ymin += (txtdef1.fSize*10.0); graph->GRect.Ymax += (txtdef1.fSize*10.0);
- page->Command(CMD_DROP_GRAPH, graph, 0L);
- }
- cx = graph->GRect.Xmin; cy = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*2.0;
- rep_DrawText(page, cx, cy, false, TXA_HLEFT, &txtdef1, "<b>Anova:</b>");
- cy = mk_table(page, cx, cy+txtdef2.fSize, 1, res_tab)+txtdef2.fSize;
- if(Dlg->GetCheck(100)) mk_v_homogeneity(page, data, &cx, &cy, csums, css, ncols, nc, cols);
- else if(Dlg->GetCheck(105)) mk_contrasts(page, 1, cx, cy, csums, css, ncols, nc, names, ci, res_tab[1][2], res_tab[1][0]);
- else if(Dlg->GetCheck(106)) mk_contrasts(page, 2, cx, cy, csums, css, ncols, nc, names, ci, res_tab[1][2], res_tab[1][0]);
- else if(Dlg->GetCheck(107)) mk_contrasts(page, 10, cx, cy, csums, css, ncols, nc, names, ci, res_tab[1][2], res_tab[1][0]);
- if(ntot > (nc<<1) && nc >1 && parent->Command(CMD_DROP_GRAPH, page, 0L));
- else {
- delete page;
- InfoBox("No or insufficient\ndata for ANOVA\n");
- }
- }
- for(i = 0; i < nc; i++){
- if(cols[i]) free(cols[i]); if(names[i]) free(names[i]);
- }
- for(i = 0; i < 3; i++) if(res_tab[i]) free(res_tab[i]);
- free(cols); free(ncols); free(names);
- free(res_tab); if(css)free(css); if(csums)free(csums);
- }
- if(rD) delete rD; CloseDlgWnd(hDlg);
- delete Dlg; free(AnovaDlg);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Parametric two way anova
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *TwAnov_DlgTmpl =
- "1,2,,DEFAULT,PUSHBUTTON,-1,148,10,45,12\n"
- "2,3,,,PUSHBUTTON,-2,148,25,45,12\n"
- "3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "4,10,100,ISPARENT | CHECKED,SHEET,1,5,10,130,80\n"
- "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
- "100,+,,,LTEXT,2,10,30,60,8\n"
- ".,.,,,RANGEINPUT,-15,20,40,100,10\n"
- ".,,,LASTOBJ,CHECKBOX,3,20,60,100,9";
-
-void rep_twanova(GraphObj *parent, DataObj *data)
-{
- TabSHEET tab1 = {0, 40, 10, "Input Data"};
- DlgInfo *TwAnovDlg;
- void *dyndata[] = {(void*)&tab1, (void*)"rectangular range for variables",
- (void*)" column/row headers present"};
- DlgRoot *Dlg;
- void *hDlg;
- int i, hc, hr, mr, mc, nr, nc, c, r, res, *nvr=0L, *nvc=0L;
- bool bContinue = false;
- char *mrk, *txt_obj, **cnames = 0L, **rnames = 0L;
- double gm, ssc, ssr, sse, tmp, cx, cy, dmin, dmax;
- double **vals = 0L, *cs = 0L, *rs = 0L, **res_tab = 0L, *c_ss, *r_ss, *c_m, *r_m, *abc;
- RECT rec;
- scaleINFO scale = {{0.0, 0.7}, {0.0, 0.7}, {0.0, 0.7}};
- AccRange *rD =0L, *rDesc;
- anyResult ares;
- Graph *graph;
- Page *page;
-
- if(!parent || !data) return;
- if(!(TwAnovDlg = CompileDialog(TwAnov_DlgTmpl, dyndata))) return;
- if(data->Command(CMD_GETMARK, &mrk, 0L))rlp_strcpy(TmpTxt, TMP_TXT_SIZE, mrk);
- else {
- data->ValueRec(&rec);
- rlp_strcpy(TmpTxt, 100, mkRangeRef(rec.top, rec.left, rec.bottom, rec.right));
- }
- if(!(Dlg = new DlgRoot(TwAnovDlg, data)))return;
- hDlg = CreateDlgWnd("Two-Way Anova", 50, 50, 420, 220, 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 1:
- if(Dlg->GetText(101, TmpTxt+200, TMP_TXT_SIZE-200) &&(rD = new AccRange(TmpTxt+200))&& rD->BoundRec(&rec)
- && (vals = (double**)calloc(rec.bottom - rec.top +1, sizeof(double*)))) {
- nc = rec.right-rec.left+1; nr = rec.bottom-rec.top+1;
- nvc = (int*)calloc(nc, sizeof(int)); nvr = (int*)calloc(nr, sizeof(int));
- dmin = HUGE_VAL; dmax = -HUGE_VAL;
- if(Dlg->GetCheck(102)) hr = hc = 1;
- else hr = hc = 0;
- for(i = rec.top+hr; i <= rec.bottom; i++) vals[i-rec.top] = (double*)calloc(nc, sizeof(double));
- for(c = rec.left+hc; c <= rec.right; c++) for(r = rec.top; r <= rec.bottom; r++) {
- if(data->GetResult(&ares, r, c,false) && ares.type == ET_VALUE){
- nvc[c-rec.left]++; nvr[r-rec.top]++;
- if(vals[r-rec.top]) vals[r-rec.top][c-rec.left] = ares.value;
- if(ares.value > dmax) dmax = ares.value;
- if(ares.value < dmin) dmin = ares.value;
- }
- }
- while(!nvc[nc-1] && nc > 1) nc--;
- while(!nvr[nr-1] && nr > 1) nr--;
- for(i = 1, mr = nvr[0]; i < nr; i++)if(nvr[i] > mr) mr = nvr[i];
- for(i = 1, mc = nvc[0]; i < nc; i++)if(nvc[i] > mc) mc = nvc[i];
- for( ; nvr[hr] < mr && hr < nr; hr++);
- for( ; nvc[hc] < mc && hc < nc; hc++);
- for(i = hr; i < nr; i++) if(nvr[i] < mr) res = -1;
- for(i = hc; i < nc; i++) if(nvc[i] < mc) res = -1;
- for(i = 0, mr = nc-hc; i < nr; i++) nvr[i] = mr;
- for(i = 0, mc = nr-hr; i < nc; i++) nvc[i] = mc;
- if(res < 0 || mr < 2 || mc < 2) {
- InfoBox("There are missing data!");
- for(i = 0; i < nc; i++) if(vals[i]) free(vals[i]);
- free(vals); free(nvr); free(nvc);
- nvr = nvc = 0L; vals = 0L;
- bContinue = true;
- }
- delete rD;
- }
- break;
- default:
- nr = nc = 0; break;
- }
- }while (res < 0);
- if(res == 1 && (vals) && (cs = (double*)calloc(nc, sizeof(double)))
- && (rs = (double*)calloc(nr, sizeof(double)))
- && (c_ss = (double*)calloc(nc, sizeof(double)))
- && (r_ss = (double*)calloc(nr, sizeof(double)))
- && (c_m = (double*)calloc(nc, sizeof(double)))
- && (r_m = (double*)calloc(nr, sizeof(double)))
- && (abc = (double*)calloc(nr > nc ? nr : nc, sizeof(double)))
- && (cnames = (char**)calloc(rec.right-rec.left+1, sizeof(char*)))
- && (rnames = (char**)calloc(rec.bottom-rec.top+1, sizeof(char*)))
- && (res_tab = (double**)calloc(4, sizeof(double*)))
- && (res_tab[0] = (double*)calloc(5, sizeof(double)))
- && (res_tab[1] = (double*)calloc(5, sizeof(double)))
- && (res_tab[2] = (double*)calloc(5, sizeof(double)))
- && (res_tab[3] = (double*)calloc(5, sizeof(double)))){
- //get column and row descriptors
- for(c = hc; c < nc; c++) {
- if(rDesc = new AccRange(mkRangeRef(rec.top, rec.left+c, rec.bottom, rec.left+c))) {
- cnames[c-hc] = rDesc->RangeDesc(data, hr ? 4 : 1);
- delete rDesc;
- }
- }
- for(r = hr; r < nr; r++) {
- if(rDesc = new AccRange(mkRangeRef(rec.top+r, rec.left, rec.top+r, rec.right))) {
- rnames[r-hr] = rDesc->RangeDesc(data, hc ? 4 : 1);
- delete rDesc;
- }
- }
- //grand mean
- for(c = hc, gm = 0.0; c < nc; c++) for(r = hr; r < nr; r++) {
- gm += vals[r][c]; cs[c] += vals[r][c]; rs[r] += vals[r][c];
- }
- gm /= ((double)((nc-hc)*(nr-hr)));
- //anova stats
- for(c = hc; c < nc; c++) cs[c] /= ((double)nvc[c]);
- for(c = hc, ssc = 0.0; c < nc; c++) ssc += ((tmp = cs[c]-gm)*tmp);
- for(r = hr; r < nr; r++) rs[r] /= ((double)nvr[r]);
- for(r = hr, ssr = 0.0; r < nr; r++) ssr += ((tmp = rs[r]-gm)*tmp);
- ssc *= ((double)(nr-hr)); ssr *= ((double)(nc-hc));
- for(c = hc, sse = 0.0; c < nc; c++) for(r = hr; r < nr; r++) {
- sse += ((tmp = vals[r][c]-cs[c]-rs[r]+gm)*tmp);
- }
- for(c = hc; c < nc; c++) for(r = hr; r < nr; r++) {
- c_m[c-hc] += vals[r][c]; r_m[r-hr] += vals[r][c];
- }
- for(c = hc; c < nc; c++) c_m[c-hc] /= ((double)(nvc[c]));
- for(r = hr; r < nr; r++) r_m[r-hr] /= ((double)(nvr[r]));
- for(c = hc; c < nc; c++) for(r = hr; r < nr; r++) {
- c_ss[c-hc] += ((tmp = vals[r][c]-c_m[c-hc])*tmp);
- r_ss[r-hr] += ((tmp = vals[r][c]-r_m[r-hr])*tmp);
- }
- //prepare table for report
- res_tab[0][0] = (double)(nc-hc-1); res_tab[1][0] = (double)(nr-hr-1);
- res_tab[2][0] = res_tab[0][0] * res_tab[1][0];
- res_tab[3][0] = res_tab[0][0] + res_tab[1][0] + res_tab[2][0];
- res_tab[0][1] = ssc; res_tab[0][2] = ssc/res_tab[0][0];
- res_tab[1][1] = ssr; res_tab[1][2] = ssr/res_tab[1][0];
- res_tab[2][1] = sse; res_tab[2][2] = sse/res_tab[2][0];
- res_tab[3][1] = ssc + ssr + sse;
- res_tab[0][3] = res_tab[0][2] / res_tab[2][2];
- res_tab[1][3] = res_tab[1][2] / res_tab[2][2];
- res_tab[0][4] = f_dist(res_tab[0][3], res_tab[0][0], res_tab[2][0]);
- res_tab[1][4] = f_dist(res_tab[1][3], res_tab[1][0], res_tab[2][0]);
- rep_init();
- page = new Page(parent, data);
- mk_header(page, "<b>Two-Way ANOVA</b>", data);
- cx = txtdef1.fSize*5.0; cy = txtdef1.fSize*10.0;
- dBounds.Xmin = 0.5; dBounds.Xmax = ((double)(nc-hc))+0.5;
- dBounds.Ymin = dmin; dBounds.Ymax = dmax;
- //plot column results
- if((graph = new Graph(parent, data, 0L, 0)) && (txt_obj = mk_scatt(0, 0L, c_m, c_ss, nvc+hc, nc-hc, "Mean", "Columns", "Means <u>+</u> S.D."))){
- OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
- if(LastOpenGO && LastOpenGO->Id == GO_PLOTSCATT) {
- if(((PlotScatt*)LastOpenGO)->x_tv = new TextValue()){
- for(i = 0; i < (nc-hc); i++) ((PlotScatt*)LastOpenGO)->x_tv->GetValue(cnames[i]);
- }
- }
- free(txt_obj); graph->moveable = 0;
- graph->DRect.Xmax = graph->DRect.Xmin + graph->DRect.Ymax - graph->DRect.Ymin;
- graph->GRect.Xmax = graph->GRect.Xmin + graph->GRect.Ymax - graph->GRect.Ymin;
- scale.sx.fx = txtdef1.fSize*5.0; scale.sy.fx = txtdef1.fSize*10.0;
- graph->Command(CMD_SCALE, &scale, 0L);
- page->Command(CMD_DROP_GRAPH, graph, 0L);
- cx = graph->GetSize(SIZE_GRECT_RIGHT)+txtdef1.fSize;
- cy = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*2.0;
- }
- dBounds.Ymin = 0.5; dBounds.Ymax = ((double)(nr-hr))+0.5;
- dBounds.Xmin = dmin; dBounds.Xmax = dmax;
- for(r = 0, tmp = 1.0; r < (nr-hr); r++, tmp += 1.0) abc[r] = tmp;
- //plot row results
- if((graph = new Graph(parent, data, 0L, 0x10)) && (txt_obj = mk_scatt(0x10, r_m, abc, r_ss, nvr+hr, nr-hr, "Mean", "Means <u>+</u> S.D.", "Rows"))){
- OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
- if(LastOpenGO && LastOpenGO->Id == GO_PLOTSCATT) {
- if(((PlotScatt*)LastOpenGO)->y_tv = new TextValue()){
- for(i = 0; i < nr; i++) ((PlotScatt*)LastOpenGO)->y_tv->GetValue(rnames[i]);
- }
- }
- free(txt_obj); graph->moveable = 0;
- graph->DRect.Xmax = graph->DRect.Xmin + graph->DRect.Ymax - graph->DRect.Ymin;
- graph->GRect.Xmax = graph->GRect.Xmin + graph->GRect.Ymax - graph->GRect.Ymin;
- scale.sx.fx = cx; scale.sy.fx = txtdef1.fSize*10.0;
- graph->Command(CMD_SCALE, &scale, 0L);
- page->Command(CMD_DROP_GRAPH, graph, 0L);
- }
- cx = txtdef1.fSize*5.0;
- //draw anova table and clean up
- rep_DrawText(page, cx, cy, false, TXA_HLEFT, &txtdef1, "<b>Anova:</b>");
- cy = mk_table(page, cx, cy+txtdef2.fSize, 4, res_tab)+txtdef2.fSize;
- if(!(parent->Command(CMD_DROP_GRAPH, page, 0L))) delete page;
- free(c_ss); free(r_ss);
- free(c_m); free(r_m);
- }
- if(vals) {
- for(i = 0; i < nc; i++) if(vals[i]) free(vals[i]);
- free(vals);
- }
- if(res_tab) {
- for(i = 0; i < 4; i++) if(res_tab[i]) free(res_tab[i]);
- free(res_tab);
- }
- if (cnames) {
- for(c = 0; c < (rec.right-rec.left+1); c++) if(cnames[c]) free(cnames[c]);
- free(cnames);
- }
- if (rnames) {
- for(r = 0; r < (rec.bottom-rec.top+1); r++) if(rnames[r]) free(rnames[r]);
- free(rnames);
- }
- if(nvr) free(nvr); if(nvc) free(nvc);
- CloseDlgWnd(hDlg); delete Dlg; free(TwAnovDlg);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Friedman's non-parametric two way anova
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-void rep_fmanova(GraphObj *parent, DataObj *data)
-{
- TabSHEET tab1 = {0, 40, 10, "Input Data"};
- DlgInfo *FmAnovDlg;
- void *dyndata[] = {(void*)&tab1, (void*)"rectangular range for variables",
- (void*)" column/row headers present"};
- DlgRoot *Dlg;
- void *hDlg;
- int i, hc, hr, mr, mc, nr, nc, c, r, res, *nvr=0L, *nvc=0L;
- bool bContinue = false;
- char *mrk, *txt_obj, **cnames = 0L, **rnames = 0L;
- double tmp, cx, cy, dmin, dmax, cchi2, rchi2, prob;
- double **vals = 0L, **rows = 0L, **cols = 0L, *idx, *cs = 0L, *rs = 0L;
- double *m, *b1, *b2, *w1, *w2, *trc;
- RECT rec;
- scaleINFO scale = {{0.0, 0.7}, {0.0, 0.7}, {0.0, 0.7}};
- AccRange *rD =0L, *rDesc;
- anyResult ares;
- Graph *graph;
- Page *page;
-
- if(!parent || !data) return;
- if(!(FmAnovDlg = CompileDialog(TwAnov_DlgTmpl, dyndata))) return;
- if(data->Command(CMD_GETMARK, &mrk, 0L))rlp_strcpy(TmpTxt, TMP_TXT_SIZE, mrk);
- else {
- data->ValueRec(&rec);
- rlp_strcpy(TmpTxt, 100, mkRangeRef(rec.top, rec.left, rec.bottom, rec.right));
- }
- if(!(Dlg = new DlgRoot(FmAnovDlg, data)))return;
- hDlg = CreateDlgWnd("Friedman's Non-Parametric Two-Way Anova", 50, 50, 420, 220, 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 1:
- if(Dlg->GetText(101, TmpTxt+200, TMP_TXT_SIZE-200) &&(rD = new AccRange(TmpTxt+200))&& rD->BoundRec(&rec)
- && (vals = (double**)calloc(rec.bottom - rec.top +1, sizeof(double*)))) {
- nc = rec.right-rec.left+1; nr = rec.bottom-rec.top+1;
- nvc = (int*)calloc(nc, sizeof(int)); nvr = (int*)calloc(nr, sizeof(int));
- dmin = HUGE_VAL; dmax = -HUGE_VAL;
- if(Dlg->GetCheck(102)) hr = hc = 1;
- else hr = hc = 0;
- for(i = rec.top+hr; i <= rec.bottom; i++) vals[i-rec.top] = (double*)calloc(nc, sizeof(double));
- for(c = rec.left+hc; c <= rec.right; c++) for(r = rec.top; r <= rec.bottom; r++) {
- if(data->GetResult(&ares, r, c,false) && ares.type == ET_VALUE){
- nvc[c-rec.left]++; nvr[r-rec.top]++;
- if(vals[r-rec.top]) vals[r-rec.top][c-rec.left] = ares.value;
- if(ares.value > dmax) dmax = ares.value;
- if(ares.value < dmin) dmin = ares.value;
- }
- }
- while(!nvc[nc-1] && nc > 1) nc--;
- while(!nvr[nr-1] && nr > 1) nr--;
- for(i = 1, mr = nvr[0]; i < nr; i++)if(nvr[i] > mr) mr = nvr[i];
- for(i = 1, mc = nvc[0]; i < nc; i++)if(nvc[i] > mc) mc = nvc[i];
- for( ; nvr[hr] < mr && hr < nr; hr++);
- for( ; nvc[hc] < mc && hc < nc; hc++);
- for(i = hr; i < nr; i++) if(nvr[i] < mr) res = -1;
- for(i = hc; i < nc; i++) if(nvc[i] < mc) res = -1;
- for(i = 0, mr = nc-hc; i < nr; i++) nvr[i] = mr;
- for(i = 0, mc = nr-hr; i < nc; i++) nvc[i] = mc;
- if(res < 0 || mr < 2 || mc < 2) {
- InfoBox("There are missing data!");
- for(i = 0; i < nc; i++) if(vals[i]) free(vals[i]);
- free(vals); free(nvr); free(nvc);
- nvr = nvc = 0L; vals = 0L;
- bContinue = true;
- }
- delete rD;
- }
- break;
- default:
- nr = nc = 0; break;
- }
- }while (res < 0);
- if(res == 1&& (vals) && (cs = (double*)calloc(nr, sizeof(double)))
- && (rs = (double*)calloc(nc, sizeof(double)))
- && (cols = (double**)calloc(nc, sizeof(double*)))
- && (rows = (double**)calloc(nr, sizeof(double*)))
- && (cnames = (char**)calloc(rec.right-rec.left+1, sizeof(char*)))
- && (rnames = (char**)calloc(rec.bottom-rec.top+1, sizeof(char*)))
- && (idx = (double*)malloc((nr > nc ? nr:nc)*sizeof(double)))
- && (m = (double*)malloc((nr > nc ? nr:nc)*sizeof(double)))
- && (b1 = (double*)malloc((nr > nc ? nr:nc)*sizeof(double)))
- && (b2 = (double*)malloc((nr > nc ? nr:nc)*sizeof(double)))
- && (w1 = (double*)malloc((nr > nc ? nr:nc)*sizeof(double)))
- && (w2 = (double*)malloc((nr > nc ? nr:nc)*sizeof(double)))
- && (trc = (double*)malloc((nr > nc ? nr:nc)*sizeof(double)))) {
- //get column and row descriptors
- for(c = hc; c < nc; c++) {
- if(rDesc = new AccRange(mkRangeRef(rec.top, rec.left+c, rec.bottom, rec.left+c))) {
- cnames[c-hc] = rDesc->RangeDesc(data, hr ? 4 : 1);
- delete rDesc;
- }
- }
- for(r = hr; r < nr; r++) {
- if(rDesc = new AccRange(mkRangeRef(rec.top+r, rec.left, rec.top+r, rec.right))) {
- rnames[r-hr] = rDesc->RangeDesc(data, hc ? 4 : 1);
- delete rDesc;
- }
- }
- //create ranks
- for(c = hc; c < nc; c++) if(cols[c-hc] = (double*)calloc(nr, sizeof(double))) {
- for(r = hr; r < nr; r++) {
- cols[c-hc][r-hr] = vals[r][c]; idx[r-hr] = (double)(r-hr);
- }
- SortArray2(nr-hr, cols[c-hc], idx); crank(nr-hr, cols[c-hc], &tmp);
- SortArray2(nr-hr, idx, cols[c-hc]);
- }
- for(r = hr; r < nr; r++) if(rows[r-hr] = (double*)calloc(nc, sizeof(double))) {
- for(c = hc; c < nc; c++) {
- rows[r-hr][c-hc] = vals[r][c]; idx[c-hc] = (double)(c-hc);
- }
- SortArray2(nc-hc, rows[r-hr], idx); crank(nc-hc, rows[r-hr], &tmp);
- SortArray2(nc-hc, idx, rows[r-hr]);
- }
- for(r = 0; r < (nr-hr); r++) for(c = 0; c < (nc-hc); c++){
- cs[r] += cols[c][r]; rs[c] += rows[r][c];
- }
- //rank sums and statistics
- for(r = 0, cchi2 = 0.0; r < (nr-hr); r++) cchi2 += (cs[r]*cs[r]);
- cchi2 = cchi2 * 12.0 / ((double)((nr-hr)*(nc-hc)*(nr-hr+1))) - 3.0*(nc-hc)*(nr-hr+1);
- for(c = 0, rchi2 = 0.0; c < (nc-hc); c++) rchi2 += (rs[c]*rs[c]);
- rchi2 = rchi2 * 12.0 / ((double)((nc-hc)*(nr-hr)*(nc-hc+1))) - 3.0*(nr-hr)*(nc-hc+1);
- //create report page
- rep_init();
- page = new Page(parent, data);
- mk_header(page, "<b>Friedman's non-parametric two-way ANOVA</b>", data);
- cx = txtdef1.fSize*5.0; cy = txtdef1.fSize*10.0;
- //plot column results
- for(c = hc; c < nc; c++) {
- w1[c-hc] = HUGE_VAL; w2[c-hc] = -HUGE_VAL;
- for(r = hr; r < nr; r++) {
- trc[r-hr] = vals[r][c];
- if(vals[r][c] < w1[c-hc]) w1[c-hc] = vals[r][c];
- if(vals[r][c] > w2[c-hc]) w2[c-hc] = vals[r][c];
- }
- d_quartile(r-hr, trc, b1+c-hc, m+c-hc, b2+c-hc);
- }
- dBounds.Xmin = 0.5; dBounds.Xmax = ((double)(nc-hc))+0.5;
- dBounds.Ymin = dmin; dBounds.Ymax = dmax;
- if((graph = new Graph(parent, data, 0L, 0)) &&
- (txt_obj = mk_boxplot(0, 0L, m, b1, b2, w1, w2, nvc, nc-hc, "medians", "25-75%", "min/max"))){
- OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
- if(LastOpenGO && LastOpenGO->Id == GO_BOXPLOT) {
- if(((BoxPlot*)LastOpenGO)->x_tv = new TextValue()){
- for(i = 0; i < (nc-hc); i++) ((PlotScatt*)LastOpenGO)->x_tv->GetValue(cnames[i]);
- }
- if(((BoxPlot*)LastOpenGO)->x_info=(char*)malloc(20*sizeof(char)))
- rlp_strcpy(((BoxPlot*)LastOpenGO)->x_info, 20, "Columns");
- if(((BoxPlot*)LastOpenGO)->y_info=(char*)malloc(20*sizeof(char)))
- rlp_strcpy(((BoxPlot*)LastOpenGO)->y_info, 20, "Location");
- }
- free(txt_obj); graph->moveable = 0;
- graph->DRect.Xmax = graph->DRect.Xmin + graph->DRect.Ymax - graph->DRect.Ymin;
- graph->GRect.Xmax = graph->GRect.Xmin + graph->GRect.Ymax - graph->GRect.Ymin;
- scale.sx.fx = txtdef1.fSize*5.0; scale.sy.fx = txtdef1.fSize*10.0;
- graph->Command(CMD_SCALE, &scale, 0L);
- page->Command(CMD_DROP_GRAPH, graph, 0L);
- cx = graph->GetSize(SIZE_GRECT_RIGHT)+txtdef1.fSize;
- }
- //plot row results
- for(r = hr; r < nr; r++) {
- w1[r-hr] = HUGE_VAL; w2[r-hr] = -HUGE_VAL;
- for(c = hc; c < nc; c++) {
- trc[c-hc] = vals[r][c];
- if(vals[r][c] < w1[r-hr]) w1[r-hr] = vals[r][c];
- if(vals[r][c] > w2[r-hr]) w2[r-hr] = vals[r][c];
- if(vals[r][c] < dBounds.Xmin) dBounds.Xmin = vals[r][c];
- if(vals[r][c] > dBounds.Xmax) dBounds.Xmax = vals[r][c];
- }
- d_quartile(c-hc, trc, b1+r-hr, m+r-hr, b2+r-hr);
- }
- for(r = hr; r < nr; r++) trc[r-hr] = ((double)(r-hr+1));
- dBounds.Ymin = 0.5; dBounds.Ymax = ((double)(nr-hr))+0.5;
- dBounds.Xmin = dmin; dBounds.Xmax = dmax;
- if((graph = new Graph(parent, data, 0L, 0x10)) &&
- (txt_obj = mk_boxplot(1, m, trc, b1, b2, w1, w2, nvr, nr-hr, "medians", "25-75%", "min/max"))){
- OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
- if(LastOpenGO && LastOpenGO->Id == GO_BOXPLOT) {
- if(((BoxPlot*)LastOpenGO)->y_tv = new TextValue()){
- for(i = 0; i < (nr-hr); i++)((PlotScatt*)LastOpenGO)->y_tv->GetValue(rnames[i]);
- }
- if(((BoxPlot*)LastOpenGO)->y_info=(char*)malloc(20*sizeof(char)))
- rlp_strcpy(((BoxPlot*)LastOpenGO)->y_info, 20, "Rows");
- if(((BoxPlot*)LastOpenGO)->x_info=(char*)malloc(20*sizeof(char)))
- rlp_strcpy(((BoxPlot*)LastOpenGO)->x_info, 20, "Location");
- }
- free(txt_obj); graph->moveable = 0;
- graph->DRect.Xmax = graph->DRect.Xmin + graph->DRect.Ymax - graph->DRect.Ymin;
- graph->GRect.Xmax = graph->GRect.Xmin + graph->GRect.Ymax - graph->GRect.Ymin;
- scale.sx.fx = cx; scale.sy.fx = txtdef1.fSize*10.0;
- graph->Command(CMD_SCALE, &scale, 0L);
- page->Command(CMD_DROP_GRAPH, graph, 0L);
- }
- cx = txtdef1.fSize*5.0; cy = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*2.0;
- free(m); free(b1); free(b2); free(w1); free(w2); free(trc);
- rep_DrawText(page, cx, cy, false, TXA_HLEFT, &txtdef1, "<b>Between columns:</b>");
- cy += txtdef1.fSize *1.5;
- prob = chi_dist(fabs(rchi2), nc-hc-1, 0.0);
-#ifdef USE_WIN_SECURE
- i = sprintf_s(TmpTxt, 60, "N = %d, Chi<sup>2</sup> = %.2lf, P ", nc-hc, rchi2);
- if(prob > 0.001) sprintf_s(TmpTxt+i, 20, "= %.3lf", prob);
-#else
- i = sprintf(TmpTxt, "N = %d, Chi<sup>2</sup> = %.2lf, P ", nc-hc, rchi2);
- if(prob > 0.001) sprintf(TmpTxt+i, "= %.3lf", prob);
-#endif
- else rlp_strcpy(TmpTxt+i, 40, "< 0.001");
- rep_DrawText(page, cx+txtdef1.fSize*3.0, cy, false, TXA_HLEFT, &txtdef1, TmpTxt);
- cy += txtdef1.fSize*2.0;
- rep_DrawText(page, cx, cy, false, TXA_HLEFT, &txtdef1, "<b>Between rows:</b>");
- cy += txtdef1.fSize *1.5;
- prob = chi_dist(fabs(cchi2), nr-hr-1, 0.0);
-#ifdef USE_WIN_SECURE
- i = sprintf_s(TmpTxt, 60, "N = %d, Chi<sup>2</sup> = %.2lf, P ", nr-hr, cchi2);
- if(prob > 0.001) sprintf_s(TmpTxt+i, 20, "= %.3lf", prob);
-#else
- i = sprintf(TmpTxt, "N = %d, Chi<sup>2</sup> = %.2lf, P ", nr-hr, cchi2);
- if(prob > 0.001) sprintf(TmpTxt+i, "= %.3lf", prob);
-#endif
- else rlp_strcpy(TmpTxt+i, 40, "< 0.001");
- rep_DrawText(page, cx+txtdef1.fSize*3.0, cy, false, TXA_HLEFT, &txtdef1, TmpTxt);
- if(!(parent->Command(CMD_DROP_GRAPH, page, 0L))) delete page;
- free(rs); free(cs); free(idx);
- }
- if(cols) {
- for(i = 0; i < nc; i++) if(cols[i]) free(cols[i]);
- free(cols);
- }
- if(rows) {
- for(i = 0; i < nr; i++) if(rows[i]) free(rows[i]);
- free(rows);
- }
- if(vals) {
- for(i = 0; i < nc; i++) if(vals[i]) free(vals[i]);
- free(vals);
- }
- if (cnames) {
- for(c = 0; c < (rec.right-rec.left+1); c++) if(cnames[c]) free(cnames[c]);
- free(cnames);
- }
- if (rnames) {
- for(r = 0; r < (rec.bottom-rec.top+1); r++) if(rnames[r]) free(rnames[r]);
- free(rnames);
- }
- if(nvr) free(nvr); if(nvc) free(nvc);
- CloseDlgWnd(hDlg); delete Dlg; free(FmAnovDlg);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Two way anova with replica
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *TwAnovDlg_Tmpl =
- "1,2,,DEFAULT,PUSHBUTTON,-1,148,10,45,12\n"
- "2,3,,,PUSHBUTTON,-2,148,25,45,12\n"
- "3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "4,10,100,ISPARENT | CHECKED,SHEET,1,5,10,130,80\n"
- "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
- "100,101,,,LTEXT,2,10,30,60,8\n"
- "101,102,,,RANGEINPUT,-15,20,40,100,10\n"
- "102,103,,,LTEXT,3,20,55,53,8\n"
- "103,,,LASTOBJ,EDVAL1,4,75,55,30,10";
-
-typedef struct _anov_group_info {
- double *rmeans, *cmeans;
- int *vpr, *vpc, nvals;
- double mean;
- }anov_group_info;
-
-void rep_twoway_anova(GraphObj *parent, DataObj *data)
-{
- TabSHEET tab1 = {0, 40, 10, "Input Data"};
- DlgInfo *TwAnovDlg;
- double dlpr = 3.0, *cmeans;
- void *dyndata[] = {(void*)&tab1, (void*)"rectangular range for variables", (void*)"lines per replica:",
- (void*)&dlpr};
- DlgRoot *Dlg;
- void *hDlg;
- int i, j, k, res, ntot, lpr, ngr, r1, r2, c1, c2, iErr;
- int *vpc, *vpr;
- double tmp, dn, gMean, SSwithin, SSsubgr, SStotal, SSrows, SScols, SSinteract;
- double **res_tab = 0L, cx, cy;
- bool bContinue = false;
- AccRange *rD =0L;
- char *mrk;
- RECT rec;
- anyResult ares;
- anov_group_info *agr;
- Page *page;
-
- if(!parent || !data) return;
- if(!(TwAnovDlg = CompileDialog(TwAnovDlg_Tmpl, dyndata))) return;
- if(data->Command(CMD_GETMARK, &mrk, 0L))rlp_strcpy(TmpTxt, TMP_TXT_SIZE, mrk);
- else {
- data->ValueRec(&rec);
- rlp_strcpy(TmpTxt, 100, mkRangeRef(rec.top, rec.left, rec.bottom, rec.right));
- }
- if(!(Dlg = new DlgRoot(TwAnovDlg, data)))return;
- hDlg = CreateDlgWnd("Two-Way Anova with Replica", 50, 50, 420, 220, Dlg, 0x0L);
-loop1:
- 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 1:
- Dlg->GetValue(103, &dlpr); lpr = (int)dlpr;
- break;
- }
- }while (res < 0);
- if(res == 1 && Dlg->GetText(101, TmpTxt+200, TMP_TXT_SIZE-200) &&(rD = new AccRange(TmpTxt+200))
- && rD->BoundRec(&rec) && (ntot = rD->CountItems())){
- r1 = rec.top; r2 = rec.bottom+1; c1= rec.left; c2 = rec.right+1;
- vpc = (int*)calloc(c2-c1+1, sizeof(int)); vpr = (int*)calloc(r2-r1+1, sizeof(int));
- for(k = iErr = 0; k < 2; k++) {
- for(i = c1; i < c2; i++) for(j = r1; j < r2; j++) {
- data->GetResult(&ares, j, i, false);
- if(ares.type == ET_VALUE) {
- vpc[i-c1]++; vpr[j-r1]++;
- }
- }
- if(!k) {
- for(i = 0; !vpc[i]; i++); for(j = 0; !vpr[j]; j++);
- memset(vpc,0,sizeof(int)*(c2-c1)); memset(vpr,0,sizeof(int)*(r2-r1));
- c1 += i; r1 += j;
- }
- }
- while(c2 > c1 && !vpc[c2-c1-1]) c2--; while(r2 > r1 && !vpr[r2-r1-1]) r2--;
- ngr = (int)(((double)(r2-r1))/dlpr);
- if(ngr * lpr < r2 -r1) iErr = 2;
- agr = (anov_group_info *)calloc(ngr+1, sizeof(anov_group_info));
- cmeans = (double *)calloc(c2-c1+1, sizeof(double));
- for(i = 0; i <= ngr; i++) {
- agr[i].cmeans = (double*)calloc(c2-c1+2, sizeof(double));
- agr[i].vpc = (int*)calloc(c2-c1+2, sizeof(int));
- agr[i].rmeans = (double*)calloc(lpr+2, sizeof(double));
- agr[i].vpr = (int*)calloc(lpr+2, sizeof(int));
- }
- for(i = c1; i < c2; i++) for(j = r1; j < r2; j++) {
- k = (j-r1)/lpr; data->GetResult(&ares, j, i, false);
- if(ares.type == ET_VALUE) {
- agr[k].cmeans[i-c1] += ares.value; agr[k].vpc[i-c1]++;
- agr[k].rmeans[j-k*lpr] += ares.value; agr[k].vpr[j-k*lpr]++;
- agr[k].mean += ares.value; agr[k].nvals++;
- cmeans[i-c1] += ares.value;
- }
- else iErr = 1;
- }
- for(k = 0; k < ngr; k++) {
- agr[k].mean /= ((double)(agr[k].nvals));
- for(i = 0; i < (c2-c1); i++) {
- agr[k].cmeans[i] /= ((double)(agr[k].vpc[i]));
- }
- }
- for(i = c1, SSwithin = gMean = 0.0, dn = 1.0; i < c2; i++) for(j = r1; j < r2; j++) {
- k = (j-r1)/lpr; data->GetResult(&ares, j, i, false);
- if(ares.type == ET_VALUE) {
- SSwithin += ((tmp = ares.value-agr[k].cmeans[i-c1])*tmp);
- gMean += ((ares.value - gMean)/dn); dn += 1.0;
- }
- }
- for(k = 0, SSsubgr = SSrows = 0.0; k < ngr; k++) {
- for(i = 0; i < (c2-c1); i++) {
- SSsubgr += (dlpr*((tmp = agr[k].cmeans[i] - gMean) * tmp));
- }
- SSrows += ((tmp = (agr[k].mean - gMean)) * tmp);
- }
- for(i = c1, SScols = 0.0; i < c2; i++) {
- cmeans[i-c1] /= ((double)(r2-r1));
- SScols += ((tmp = cmeans[i-c1]-gMean) * tmp);
- }
- SStotal = SSsubgr + SSwithin; SSrows *= (dlpr *((double)(c2-c1)));
- SScols *= (dlpr * ((double)ngr)); SSinteract = fabs(SSsubgr - SSrows - SScols);
- if(!iErr&& (res_tab = (double**)calloc(5, sizeof(double*)))
- && (res_tab[0] = (double*)calloc(5, sizeof(double)))
- && (res_tab[1] = (double*)calloc(5, sizeof(double)))
- && (res_tab[2] = (double*)calloc(5, sizeof(double)))
- && (res_tab[3] = (double*)calloc(5, sizeof(double)))
- && (res_tab[4] = (double*)calloc(5, sizeof(double)))) {
- res_tab[0][0] = (double)(ngr-1); res_tab[1][0] = (double)(c2-c1-1);
- res_tab[2][0] = res_tab[0][0]* res_tab[1][0]; res_tab[3][0] = (double)(ngr*(c2-c1)*(lpr-1));
- res_tab[4][0] = res_tab[0][0] + res_tab[1][0] + res_tab[2][0] + res_tab[3][0];
- res_tab[0][1] = SSrows; res_tab[0][2] = res_tab[0][1] / res_tab[0][0];
- res_tab[1][1] = SScols; res_tab[1][2] = res_tab[1][1] / res_tab[1][0];
- res_tab[2][1] = SSinteract; res_tab[2][2] = res_tab[2][1] / res_tab[2][0];
- res_tab[3][1] = SSwithin; res_tab[3][2] = res_tab[3][1] / res_tab[3][0];
- res_tab[4][1] = SStotal; res_tab[0][3] = res_tab[0][2] / res_tab[3][2];
- res_tab[1][3] = res_tab[1][2] / res_tab[3][2];
- res_tab[2][3] = res_tab[2][2] / res_tab[3][2];
- res_tab[0][4] = f_dist(res_tab[0][3], res_tab[0][0], res_tab[3][0]);
- res_tab[1][4] = f_dist(res_tab[1][3], res_tab[1][0], res_tab[3][0]);
- res_tab[2][4] = f_dist(res_tab[2][3], res_tab[2][0], res_tab[3][0]);
-
-
- rep_init();
-// dBounds.Xmin = 0.5; dBounds.Xmax = ((double)nc)+0.5;
- page = new Page(parent, data);
- mk_header(page, "<b>Two-Way ANOVA with Replication</b>", data);
-
- cx = txtdef1.fSize*5.0; cy = txtdef1.fSize*10.0;
-
- rep_DrawText(page, cx, cy, false, TXA_HLEFT, &txtdef1, "<b>Anova:</b>");
- cy = mk_table(page, cx, cy+txtdef2.fSize, 3, res_tab)+txtdef2.fSize;
- if(!(parent->Command(CMD_DROP_GRAPH, page, 0L))) delete page;
- free(res_tab[0]); free(res_tab[1]); free(res_tab[2]);
- free(res_tab[3]); free(res_tab[4]); free(res_tab);
- }
- for(i = 0; i <= ngr; i++) {
- free(agr[i].cmeans); free(agr[i].vpc);
- free(agr[i].rmeans); free(agr[i].vpr);
- }
- free(vpc); free(vpr); free(cmeans);
- delete rD;
- switch(iErr) {
- case 1:
- ErrorBox("There are missing Data!");
- goto loop1;
- case 2:
- ErrorBox("The total number of lines\nmust be a multiple of\nlines per replica.");
- goto loop1;
- }
- }
- CloseDlgWnd(hDlg); delete Dlg; free(TwAnovDlg);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Kruskal-Wallis Test for Differences of Location
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *RepKruskal_DlgTmpl =
- "1,2,,DEFAULT,PUSHBUTTON,-1,158,10,45,12\n"
- "2,3,,,PUSHBUTTON,-2,158,25,45,12\n"
- "3,,10,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "10,20,152,ISPARENT | CHECKED, SHEET,1,5,10,140,70\n"
- "20,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
- "152,153,,ISPARENT | CHECKED,GROUPBOX,2,12,30,128,45\n"
- "153,154,,,LTEXT,0,25,35,60,8\n"
- "154,155,,,RANGEINPUT,0,25,45,100,10\n"
- "155,156,0,,PUSHBUTTON,-8,95,57,30,12\n"
- "156,,,LASTOBJ,PUSHBUTTON,-9,60,57,35,12";
-
-void rep_kruskal(GraphObj *parent, DataObj *data)
-{
- TabSHEET tab1 = {0, 25, 10, "Data"};
-
- void *dyndata[] = {(void*)&tab1, (void*)" select one range for every variable "};
- DlgInfo *KruskalDlg;
- DlgRoot *Dlg;
- void *hDlg;
- int i, j, n, c, r, nt, res, currYR = 0, maxYR = 0, ny, nr, *nvals;
- bool updateYR = true, bContinue = false;
- double h, h1, p, **vals, *x, *y, *by1, *by2, *wy1, *wy2, *ranks, *ridx, *rsums, th, cy, cx[10];
- char **rd = 0L, **names, *txt_obj;
- char *headings[] = {"<i>Groups</i>", "<i>N</i>", "<i>Median</i>", "<i>25% - 75%</i>",
- "<i>Range</i>","<i>Rank Sums</i>"};
- scaleINFO scale = {{0.0, 1.0}, {0.0, 1.0}, {0.0, 1.0}};
- AccRange *rV1 = 0L;
- anyResult ares;
- Page *page;
- Graph *graph;
-
- if(!parent || !data) return;
- if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
- TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return;
- if(!(KruskalDlg = CompileDialog(RepKruskal_DlgTmpl, dyndata))) return;
- if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
- for(i=j=0; i <= 1000; i +=100) if(TmpTxt[i])
- rd[j++] = (char*)memdup(TmpTxt+i, ((int)strlen(TmpTxt+i))+2, 0); maxYR = j-1;
- }
- if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return;
- if(!(Dlg = new DlgRoot(KruskalDlg, data))) return;
- if(rd && rd[currYR] && *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
- hDlg = CreateDlgWnd("Kruskal-Wallis Nonparametric Anova", 50, 50, 420, 200, Dlg, 0x0L);
- do {
- if(updateYR) {
- if(currYR >0) Dlg->ShowItem(156, true);
- else Dlg->ShowItem(156, false);
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "variable # %d/%d", currYR+1, maxYR+1);
-#else
- sprintf(TmpTxt,"variable # %d/%d", currYR+1, maxYR+1);
-#endif
- Dlg->SetText(153, 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 155: case 156:
- res = com_StackDlg(res, Dlg, 0L, 0L, &rd, &currYR,
- &rV1, &bContinue, &ny, &maxYR, &updateYR);
- break;
- }
- }while (res < 0);
- if(res == 1 && (vals = (double**)calloc(sizeof(double*), maxYR+1)) && (nvals = (int*)calloc(sizeof(int), maxYR+1))
- && (names = (char**)calloc(maxYR+1, sizeof(char*))) && (x = (double*)calloc(maxYR+1, sizeof(double)))
- && (y = (double*)calloc(maxYR+1, sizeof(double))) && (by1 = (double*)calloc(maxYR+1, sizeof(double)))
- && (by2 = (double*)calloc(maxYR+1, sizeof(double))) && (wy1 = (double*)calloc(maxYR+1, sizeof(double)))
- && (wy2 = (double*)calloc(maxYR+1, sizeof(double)))
- && (rsums = (double*)calloc(maxYR+1, sizeof(double)))) {
- maxYR++; rep_init(); page = new Page(parent, data);
- dBounds.Xmin = 0.5; dBounds.Xmax = (double)maxYR+0.3;
- if(rV1) delete rV1; rV1 = 0L; ranks = ridx = 0L;
- cy = txtdef1.fSize*10.0;
- mk_header(page, "<b>Kruskal-Wallis Test for Differences of Location</b>", data);
- dBounds.Ymin = HUGE_VAL; dBounds.Ymax = -HUGE_VAL;
- // get data into two dimensional array
- for(nr = maxYR, i = nt = 0; i < nr; i++) {
- x [i] = y[i] = by1[i] = by2[i] = wy1[i] = wy2[i] = 0.0; nvals[i] = 0;
- if((rV1 = new AccRange(rd[i])) && (n = rV1->CountItems()) && (vals[i] = (double*)malloc(n*sizeof(double)))) {
- names[i] = rV1->RangeDesc(data, 1);
- for(n = 0, rV1->GetFirst(&c, &r); rV1->GetNext(&c, &r); ) {
- if(data->GetResult(&ares, r, c, false) && ares.type == ET_VALUE) {
- if(!n) wy1[i] = wy2[i] = ares.value;
- else {
- if(ares.value < wy1[i]) wy1[i] = ares.value;
- if(ares.value > wy2[i]) wy2[i] = ares.value;
- }
- if(ares.value < dBounds.Ymin) dBounds.Ymin = ares.value;
- if(ares.value > dBounds.Ymax) dBounds.Ymax = ares.value;
- vals[i][n] = ares.value; n++;
- }
- }
- nvals[i] = n; nt += n; delete rV1; rV1 = 0;
- }
- if(!names[i] && (names[i] = (char*)malloc(20*sizeof(char)))){
-#ifdef USE_WIN_SECURE
- sprintf_s(names[i], 20, "Group %d", i+1);
-#else
- sprintf(names[i], "Group %d", i+1);
-#endif
- }
- }
- // rank sums
- if(nt && (ranks=(double*)malloc(nt*sizeof(double))) && (ridx=(double*)malloc(nt*sizeof(double)))) {
- for(i = n = 0; i < nr; i++) {
- for(j = 0; j < nvals[i]; j++) {
- ridx[n] = (double)(i); ranks[n] = vals[i][j]; n++;
- }
- }
- SortArray2(n, ranks, ridx); crank(n, ranks, &th);
- for(i = 0; i < n; i++) rsums[(int)ridx[i]] += ranks[i];
- //statistics on range sums
- for(i = 0, h = 0.0; i < nr; i++) h += rsums[i]*rsums[i]/((double)nvals[i]);
- h = h * 12.0/(((double)n)*((double)(n+1))) - 3.0*((double)n+1);
- h1 = h / (1.0 - th/(((double)(n-1)) * ((double)n)* ((double)(n+1))));
- }
- else h = h1 = -1.0;
- // check for unique names
- for(i = 0; i < (nr-1); i++) for(j = i+1; j < nr; j++) {
- if(!strcmp(names[i], names[j])) {
- names[i] = (char*) realloc(names[i], 20 *sizeof(char));
- names[j] = (char*) realloc(names[j], 20 *sizeof(char));
-#ifdef USE_WIN_SECURE
- sprintf_s(names[i], 20, "Group %d", i+1); sprintf_s(names[j], 20, "Group %d", j+1);
-#else
- sprintf(names[i], "Group %d", i+1); sprintf(names[j], "Group %d", j+1);
-#endif
- }
- }
- // simple group statistics
- for(i = 0; i < nr; i++) {
- x[i] = (double)(i+1); d_quartile(nvals[i], vals[i], by1+i, y+i, by2+i);
- }
- // create boxplot
- if((graph = new Graph(parent, data, 0L, 0)) && (txt_obj = mk_boxplot(0, x, y, by1, by2, wy1, wy2,
- nvals, nr,"Median","25-75%","Min./Max."))){
- scale.sx.fx = (txtdef1.fSize*5.0); scale.sy.fx = (txtdef1.fSize*10.0);
- OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
- if(LastOpenGO && LastOpenGO->Id == GO_BOXPLOT) {
- if(((BoxPlot*)LastOpenGO)->x_tv = new TextValue()){
- for(i = 0; i < nr; i++) ((BoxPlot*)LastOpenGO)->x_tv->GetValue(names[i]);
- }
- if(((BoxPlot*)LastOpenGO)->x_info = (char*)malloc(20*sizeof(char)))
- rlp_strcpy(((BoxPlot*)LastOpenGO)->x_info, 20, "Groups");
- if(((BoxPlot*)LastOpenGO)->y_info = (char*)malloc(20*sizeof(char)))
- rlp_strcpy(((BoxPlot*)LastOpenGO)->y_info, 20, "Location");
- }
- free(txt_obj); graph->Command(CMD_SCALE, &scale, 0L);
- cy = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef1.fSize*2.0;
- page->Command(CMD_DROP_GRAPH, graph, 0L);
- }
- parent->Command(CMD_DROP_GRAPH, page, 0L);
- //report statistics
- cx[0] = txtdef1.fSize*5.0; cx[1] = cx[0] + linsp1*5.0;
- cx[2] = cx[1] + linsp1*2.5; cx[3] = cx[2] + linsp1*4.0;
- cx[4] = cx[3] + linsp1*5.0; cx[5] = cx[4] + linsp1*7.0;
- cx[6] = cx[5] + linsp1*8.0;
- rep_DrawText(page, cx[0], cy, false, TXA_HLEFT, &txtdef1, "<b>Test Statistics:</b>");
- cy += linsp2; p = chi_dist(h,(double)(nr-1), 0.0);
- dbl_to_str2(TmpTxt, 100, p < 0.0001 ?(char*)"H = %.2lf, P < 0.0001" : (char*)"H = %.2lf, P = %.4lf", h, p);
- rep_DrawText(page, cx[1], cy, false, TXA_HLEFT, &txtdef1, TmpTxt);
- cy += linsp1; p = chi_dist(h1,(double)(nr-1), 0.0);
- dbl_to_str2(TmpTxt, 100, p < 0.0001 ?(char*)"H(corr.) = %.2lf, P < 0.0001" : (char*)"H(corr.) = %.2lf, P = %.4lf", h1, p);
- if(th >= 1.0) {
- rep_DrawText(page, cx[1], cy, false, TXA_HLEFT, &txtdef1, TmpTxt);
- cy += linsp1;
- }
- cy += linsp2;
- // create summary table
- rep_DrawText(page, cx[0], cy, false, TXA_HLEFT, &txtdef1, "<b>Summary:</b>");
- for(i = 0, cy += linsp2; i < 6; i++) { //column headers
- c = (i == 3 || i == 4) ? TXA_HCENTER : TXA_HRIGHT;
- rep_DrawText(page, cx[i+1], cy, false, c, &txtdef1, headings[i]);
- }
- mk_hr(page, cx[0], cx[6]+txtdef1.fSize*2.0, cy +linsp1);
- for(i = 0, cy += linsp2; i < nr; i++, cy += linsp1) {
- for(j = 0; j < 6; j++) {
- switch(j) {
- default: rlp_strcpy(TmpTxt, 20, names[i]); break;
- case 1: dbl_to_str1(TmpTxt, 20, "%.0lf", (double)nvals[i]); break;
- case 2: dbl_to_str1(TmpTxt, 20, "%g", y[i]); break;
- case 3: dbl_to_str2(TmpTxt, 20, "%g - %g", by1[i], by2[i]); break;
- case 4: dbl_to_str2(TmpTxt, 20, "%g - %g", wy1[i], wy2[i]); break;
- case 5: dbl_to_str1(TmpTxt, 20, "%g", rsums[i]); break;
- }
- c = (j == 3 || j == 4) ? TXA_HCENTER : TXA_HRIGHT;
- rep_DrawText(page, cx[j+1], cy, false, c, &txtdef1,TmpTxt);
- }
- }
- mk_hr(page, cx[0], cx[6]+txtdef1.fSize*2.0, cy+txtdef1.fSize*0.2);
- for(i= 0; i< nr; i++) {
- if(vals[i]) free(vals[i]); if(names[i]) free(names[i]);
- }
- free(vals); free(nvals); free(names);
- free(x); free(y); free(by1);
- free(by2); free(wy1); free(wy2);
- free(rsums);
- }
- CloseDlgWnd(hDlg);
- delete Dlg;
- if(rd) {
- for (i = 0; i < maxYR; i++) if(rd[i]) free(rd[i]);
- free(rd);
- }
- if(ranks)free(ranks); if(ridx)free(ridx);
- if(rV1) delete rV1; free(KruskalDlg);
- return;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// simple sample statistics
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *SmplStatDlg_Tmpl =
- "1,2,,DEFAULT,PUSHBUTTON,-1,148,10,45,12\n"
- "2,3,,,PUSHBUTTON,-2,148,25,45,12\n"
- "3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "4,10,100,ISPARENT | CHECKED,SHEET,1,5,10,130,80\n"
- "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
- "100,101,,,LTEXT,2,10,30,60,8\n"
- "101,,,LASTOBJ,RANGEINPUT,-15,20,40,100,10";
-void rep_samplestats(GraphObj *parent, DataObj *data)
-{
- TabSHEET tab1 = {0, 40, 10, "Input Data"};
- DlgInfo *SmplStatDlg;
- void *dyndata[] = {(void*)&tab1, (void*)"rectangular range for variables"};
- DlgRoot *Dlg;
- void *hDlg;
- int res, nr, nc, ntot, cb;
- double val, *src_data, cx, cy, ksprob, ksd, sww, swp, mean, sd;
- bool bContinue = false;
- AccRange *rD =0L;
- char *mrk, *x_info, *y_info;
- RECT rec;
- Plot *plot;
- Graph *graph;
- Page *page;
-
- if(!parent || !data) return;
- if(!(SmplStatDlg = CompileDialog(SmplStatDlg_Tmpl, dyndata))) return;
- if(data->Command(CMD_GETMARK, &mrk, 0L))rlp_strcpy(TmpTxt, TMP_TXT_SIZE, mrk);
- else {
- data->ValueRec(&rec);
- rlp_strcpy(TmpTxt, 100, mkRangeRef(rec.top, rec.left, rec.bottom, rec.right));
- }
- if(!(Dlg = new DlgRoot(SmplStatDlg, data)))return;
- hDlg = CreateDlgWnd("Sample Statistics", 50, 50, 420, 220, 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;
- }
- }while (res < 0);
- if(res == 1 && Dlg->GetText(101, TmpTxt+200, TMP_TXT_SIZE) &&(rD = new AccRange(TmpTxt+200))
- && rD->BoundRec(&rec) && (ntot = rD->CountItems()) && (src_data = (double*)malloc(ntot*sizeof(double)))){
- rep_init();
- x_info = rD->RangeDesc(data, 2);
- if(y_info = (char*)malloc(20)) rlp_strcpy(y_info, 20, "Normal quantiles");
- page = new Page(parent, data);
- cb = rlp_strcpy(TmpTxt, 100, "<b>Sample Statistics for \"");
- if(x_info && x_info[0]) cb += rlp_strcpy(TmpTxt+cb, 100-cb, x_info);
- else cb += rlp_strcpy(TmpTxt+cb, 100-cb, TmpTxt+200);
- rlp_strcpy(TmpTxt+cb,100-cb, "\"</b>"); mk_header(page, TmpTxt, data);
- for(ntot = 0, rD->GetFirst(&nc, &nr); rD->GetNext(&nc, &nr); ) {
- if(data->GetValue(nr, nc, &val)) src_data[ntot++] = val;
- }
- if(ntot > 5 && (graph = new Graph(page, data, 0L, 0))) {
- if(plot = new NormQuant(page, data, src_data, ntot)) {
- plot->x_info = x_info; plot->y_info = y_info;
- }
- if(!(graph->Command(CMD_DROP_PLOT, (void *)plot, 0L))) {
- delete plot; plot =0L;
- }
- graph->moveable = 0; graph->GRect.Xmin += (txtdef1.fSize*5.0);
- graph->GRect.Xmax += (txtdef1.fSize*5.0); graph->GRect.Ymin += (txtdef1.fSize*10.0);
- graph->GRect.Ymax += (txtdef1.fSize*10.0); page->Command(CMD_DROP_GRAPH, graph, 0L);
- }
- cy = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef1.fSize*3;
- rep_DrawText(page, graph->GRect.Xmin, cy, false, TXA_HLEFT, &txtdef1, "<b>Descriptive Statistics:</b>");
- cy += txtdef1.fSize*1.5; cx = graph->GetSize(SIZE_GRECT_LEFT)+txtdef1.fSize*25.0;
- mk_median_report(page, cx, cy, src_data, ntot, .95, 0L);
- cx = graph->GetSize(SIZE_GRECT_LEFT)+txtdef1.fSize*2.0;
- cy = mk_mean_report(page, cx, cy, src_data, ntot, .95, 0L);
- //data are sorted by the mk_median_report();
- d_variance(ntot, src_data, &mean, &sd);
- sd = sqrt(sd/((double)(ntot-1)));
- KolSmir(ntot, src_data, norm_dist, mean, sd, true, &ksd, &ksprob);
- cy += txtdef1.fSize*1.5; cx = graph->GRect.Xmin;
- rep_DrawText(page, cx , cy, false, TXA_HLEFT, &txtdef1, "<b>Test for Normal Distribution:</b>");
- cy += linsp1; cx += (txtdef1.fSize*2.0);
- cb = dbl_to_str1(TmpTxt, 100, "Kolmogorov-Smirnov D = %.4lf, P ", ksd);
- dbl_to_str1(TmpTxt+cb, 100-cb, ksprob >= 0.0001 ? (char*)"= %.4lf" : (char*)"< 0.0001", ksprob);
- rep_DrawText(page, cx , cy, false, TXA_HLEFT, &txtdef1,TmpTxt); cy += linsp1/1.2;
- swilk1(ntot, src_data, norm_dist, 0.0, 1.0, true, &sww, &swp);
- if(sww >= 0.0 && swp >= 0.0 && (cb = dbl_to_str1(TmpTxt, 100, "Shapiro-Wilk W = %.4lf, P ", sww))
- && (dbl_to_str1(TmpTxt+cb, 100-cb, swp >= 0.0001 ? (char*)"= %.4lf" : (char*)"< 0.0001", swp))){
- rep_DrawText(page, cx , cy, false, TXA_HLEFT, &txtdef1,TmpTxt); cy += linsp1/1.2;
- }
- parent->Command(CMD_DROP_GRAPH, page, 0L);
- delete rD; free(src_data);
- }
- CloseDlgWnd(hDlg); delete Dlg; free(SmplStatDlg);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// linear regression analysis
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static double mk_regr_summary(GraphObj *parent, double x, double y, double *dres, double ci, int n)
-{
- char *fmts[] = {"slope = %g", "intercept = %g", "observations = %g", "r<sup> 2</sup> = %g", "r = %g"};
- char *ci_fmt = "%g - %g";
- char lbl[80];
- double z, s;
- double x1 = x + txtdef1.fSize*3.0;
- double x2 = x + txtdef1.fSize*25.0;
-#ifdef _WINDOWS
- double hrw = txtdef1.fSize*38.0;
-#else
- double hrw = txtdef1.fSize*1.3*38.0;
-#endif
-
- rep_DrawText(parent, x, y, false, TXA_HLEFT, &txtdef1, "<b>Regression:</b>");
- dbl_to_str1(lbl, 80, "%g%% C.I.", ci);
- rep_DrawText(parent, x2, y, false, TXA_HCENTER, &txtdef1, lbl);
- mk_hr(parent, x, x+hrw, y+txtdef1.fSize*1.2);
- y += linsp1*1.5; dbl_to_str1(lbl, 80, fmts[0], dres[0]);
- rep_DrawText(parent, x1, y, false, TXA_HLEFT, &txtdef1, lbl);
- dbl_to_str2(lbl, 80, ci_fmt, dres[0]-dres[10], dres[0]+dres[10]);
- rep_DrawText(parent, x2, y, false, TXA_HCENTER, &txtdef1, lbl);
- y += linsp1; dbl_to_str1(lbl, 80, fmts[1], dres[1]);
- rep_DrawText(parent, x1, y, false, TXA_HLEFT, &txtdef1, lbl);
- dbl_to_str2(lbl, 80, ci_fmt, dres[1]-dres[11], dres[1]+dres[11]);
- rep_DrawText(parent, x2, y, false, TXA_HCENTER, &txtdef1, lbl);
- y += linsp1; dbl_to_str1(lbl, 80, fmts[2], (double)n);
- rep_DrawText(parent, x1, y, false, TXA_HLEFT, &txtdef1, lbl);
- y += linsp1; dbl_to_str1(lbl, 80, fmts[3], dres[12]);
- rep_DrawText(parent, x1, y, false, TXA_HLEFT, &txtdef1, lbl);
- y += linsp1; dbl_to_str1(lbl, 80, fmts[4], sqrt(dres[12]));
- rep_DrawText(parent, x1, y, false, TXA_HLEFT, &txtdef1, lbl);
- z = 0.5 * log((1.0+sqrt(dres[12])+_PREC)/(1.0-sqrt(dres[12])+_PREC)); //Fishers z-transform
- s = distinv(t_dist, 1.0E+10, 1.0, (100-ci)/100.0, 2.0)/sqrt((double)(n-3));
- dbl_to_str2(lbl, 80, ci_fmt, tanh(z-s), tanh(z+s));
- rep_DrawText(parent, x2, y, false, TXA_HCENTER, &txtdef1, lbl);
- mk_hr(parent, x, x+hrw, y+txtdef1.fSize*1.2);
- return y + linsp1*3.0;
-}
-
-static char *RegrDlg_Tmpl =
- "1,+,,DEFAULT,PUSHBUTTON,-1,148,10,45,12\n"
- ".,.,,,PUSHBUTTON,-2,148,25,45,12\n"
- ".,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "4,10,100,ISPARENT | CHECKED,SHEET,1,5,10,130,100\n"
- "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
- "100,+,,,LTEXT,2,10,30,60,8\n"
- ".,.,,,RANGEINPUT,-15,20,40,100,10\n"
- ".,.,,,LTEXT,3,10,55,60,8\n"
- ".,.,,,RANGEINPUT,-16,20,65,100,10\n"
- ".,.,,,LTEXT,4,10,80,60,8\n"
- ".,.,,,EDVAL1,5,74,80,25,10\n"
- ".,.,,,LTEXT,-10,101,80,60,8\n"
- ".,,,LASTOBJ,CHECKBOX,6,10,95,100,8";
-
-void
-rep_regression(GraphObj *parent, DataObj *data)
-{
- TabSHEET tab1 = {0, 60, 10, "Regression Input"};
- double ci = 95.0;
- DlgInfo *RegrDlg;
- void *dyndata[] = {(void*)&tab1, (void*)"range for independent variable (x)",
- (void*)"range for dependent variable (y)", (void*)"confidence interval:",
- (void*)&ci, (void*)" include origin"};
- DlgRoot *Dlg;
- void *hDlg;
- int i, n, n1, rx, cx, ry, cy, res, align = 0;
- int x_dtype, y_dtype, nVals, nTxt, nTime;
- bool bContinue = false, bValid, bParZ;
- AccRange *rX = 0L, *rY = 0L;
- double *x = 0L, *y = 0L, **res_tab = 0L, c_x, c_y;
- double sx, sy, dx, dy, sxy, sxx, syy, sdy, df, t, ts, ty;
- double dres[14], ly[4];
- char *txt_obj, *x_desc=0L, *y_desc=0L;
- anyResult xRes, yRes;
- TextValue *x_tv, *y_tv;
- Graph *graph;
- Page *page;
-
- if(!parent || !data) return;
- if(!(RegrDlg = CompileDialog(RegrDlg_Tmpl, dyndata))) return;
- UseRangeMark(data, 1, TmpTxt, TmpTxt+100);
- if(!(Dlg = new DlgRoot(RegrDlg, data)))return;
- hDlg = CreateDlgWnd("Linear Regression", 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 1:
- Dlg->GetValue(105, &ci); bParZ = Dlg->GetCheck(107);
- if(rX) delete rX; if(rY) delete rY;
- rX = rY = 0L;
- if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) rX = new AccRange(TmpTxt);
- n = rX ? rX->CountItems() : 0;
- if(!n) {
- ErrorBox("Range not specified\nor not valid.");
- bContinue = true;
- res = -1;
- }
- if(n && Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE) && (rY = new AccRange(TmpTxt))){
- if(n != rY->CountItems()) {
- ErrorBox("Both ranges must be given\nand must have the same size");
- bContinue = true;
- res = -1;
- }
- }
- }
- }while (res < 0);
- n1 = n;
- if(res == 1 && n >1 && rX && rY && (x = (double*)malloc(n*sizeof(double)))
- && (y = (double*)malloc(n*sizeof(double)))
- && (res_tab = (double**)calloc(3, sizeof(double*)))
- && (res_tab[0] = (double*) malloc(5*sizeof(double)))
- && (res_tab[1] = (double*) malloc(5*sizeof(double)))
- && (res_tab[2] = (double*) malloc(5*sizeof(double)))) {
- x_desc = rX->RangeDesc(data, 0); y_desc = rY->RangeDesc(data, 0);
- //analyse data types
- x_dtype = y_dtype = 0; x_tv = y_tv = 0L;
- if(rX->DataTypes(data, &nVals, &nTxt, &nTime)){
- if(!nVals && nTxt > 1 && nTxt > nTime) x_tv = new TextValue();
- else if(!nVals && nTime > 1 && nTime > nTxt) x_dtype = ET_DATETIME;
- }
- if(rY->DataTypes(data, &nVals, &nTxt, &nTime)){
- if(!nVals && nTxt > 1 && nTxt > nTime) y_tv = new TextValue();
- else if(!nVals && nTime > 1 && nTime > nTxt) y_dtype = ET_DATETIME;
- }
- rX->GetFirst(&cx, &rx); rY->GetFirst(&cy, &ry);
- rep_init();
- dBounds.Xmin = dBounds.Ymin = HUGE_VAL; dBounds.Xmax = dBounds.Ymax = -HUGE_VAL;
- //read data into x[] and y[]
- for(i = n = 0; i < n1 && rX->GetNext(&cx, &rx) && rY->GetNext(&cy, &ry); i++) {
- bValid = false;
- if(data->GetResult(&xRes, rx, cx, false) && data->GetResult(&yRes, ry, cy, false)) {
- bValid = true;
- if(x_tv) {
- if(xRes.type == ET_TEXT) dx = x_tv->GetValue(xRes.text);
- else bValid = false;
- }
- else if(x_dtype == ET_DATETIME) {
- if(xRes.type == ET_DATE || xRes.type == ET_TIME || xRes.type == ET_DATETIME) dx = xRes.value;
- else bValid = false;
- }
- else {
- if(xRes.type == ET_VALUE) dx = xRes.value;
- else bValid = false;
- }
- if(y_tv) {
- if(yRes.type == ET_TEXT) dy = y_tv->GetValue(yRes.text);
- else bValid = false;
- }
- else if(y_dtype == ET_DATETIME) {
- if(yRes.type == ET_DATE || yRes.type == ET_TIME || yRes.type == ET_DATETIME) dy = yRes.value;
- else bValid = false;
- }
- else {
- if(yRes.type == ET_VALUE) dy = yRes.value;
- else bValid = false;
- }
- }
- if(bValid){
- x[n] = dx; y[n] = dy;
- if(dBounds.Xmin > x[n]) dBounds.Xmin = x[n];
- if(dBounds.Xmax < x[n]) dBounds.Xmax = x[n];
- if(dBounds.Ymin > y[n]) dBounds.Ymin = y[n];
- if(dBounds.Ymax < y[n]) dBounds.Ymax = y[n];
- n++;
- }
- }
- if(!bParZ) {
- for(i = 0, sx = sy = 0.0; i < n; i++) {
- sx += x[i]; sy += y[i];
- }
- dres[2] = sx /n; dres[3] = sy/n;
- }
- else {
- dres[2] = sx = dres[3] = sy = 0.0;
- }
- sxy = sxx = syy = 0.0;
- for(i = 0; i < n; i++) {
- dx = x[i]-dres[2]; dy = y[i]-dres[3];
- sxx += (dx*dx); syy += (dy*dy); sxy += (dx*dy);
- }
- dres[0] = sxy / sxx; dres[1] = dres[3] - dres[0] * dres[2];
- for(i = 0, sdy = 0.0; i < n; i++) {
- dy = y[i] - (dres[1] + x[i] *dres[0]);
- sdy += (dy * dy);
- }
- df = bParZ ? (n-1) : (n-2); sdy = sdy/df; dres[4] = sqrt(sdy/sxx);
- dres[5] = sxx/(n-1); dres[6] = syy/(n-1); dres[7] = sdy;
- dres[8] = sxy/sdy*sxy/sxx; dres[9] = f_dist(dres[8], 1.0, df);
- t = distinv(t_dist, df, 1.0, (100.0-ci)/100.0, 2.0);
- dres[10] = t * sqrt(dres[7]/sxx);
- dres[11] = t * sqrt(dres[7]*(dres[2]*dres[2]/sxx +1.0/(double)n));
- if (n && (graph = new Graph(parent, data, 0L, 0))) {
- if(txt_obj = mk_scatt(0, x, y, 0L, 0L, n, "Data", x_desc, y_desc)){
- OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
- free(txt_obj);
- if(LastOpenGO && LastOpenGO->Id >= GO_PLOT && LastOpenGO ->Id < GO_GRAPH) {
- ((Plot*)LastOpenGO)->x_dtype = x_dtype; ((Plot*)LastOpenGO)->y_dtype = y_dtype;
- ((Plot*)LastOpenGO)->x_tv = x_tv; ((Plot*)LastOpenGO)->y_tv = y_tv;
- }
- }
-#ifdef USE_WIN_SECURE
- i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "[1=Function]\nx1= %g\nx2= %g\nxstep= %g\nLine= %g 1 0x000000ff 0x0\n",
- dBounds.Xmin, dBounds.Xmax, (dBounds.Xmax -dBounds.Xmin)/100.0, defs.GetSize(SIZE_DATA_LINE));
- i += sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, "f_xy=\"%g+x*%g\\n\"\n", dres[1], dres[0]);
- i += sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, "Desc=\"Regression\"\n");
- OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
- i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "[1=Function]\nx1= %g\nx2= %g\nxstep= %g\nLine= %g 1 0x000000ff 0x0\n",
- dBounds.Xmin, dBounds.Xmax, (dBounds.Xmax -dBounds.Xmin)/100.0, defs.GetSize(SIZE_DATA_LINE)*0.5);
- i += sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, "f_xy=\"y=%g+x*%g;\\nts=sqrt((((x-(%g))^2)/%g+%g)*%g);\\ny=y+ts*%g\\n\"\n",
- dres[1], dres[0], dres[2], sxx, (1.0/(double)n), dres[7], t);
- i += sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, "Desc=\"%g%% C.I.\"\n", ci);
- OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
- i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "[1=Function]\nx1= %g\nx2= %g\nxstep= %g\nLine= %g 1 0x000000ff 0x0\n",
- dBounds.Xmin, dBounds.Xmax, (dBounds.Xmax -dBounds.Xmin)/100.0, defs.GetSize(SIZE_DATA_LINE)*0.5);
- i += sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, "f_xy=\"y=%g+x*%g;\\nts=sqrt((((x-(%g))^2)/%g+%g)*%g);\\ny=y-ts*%g\\n\"\n",
- dres[1], dres[0], dres[2], sxx, (1.0/(double)n), dres[7], t);
- i += sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, "Desc=\"%g%% C.I.\"\n", ci);
- OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
-#else
- i = sprintf(TmpTxt, "[1=Function]\nx1= %g\nx2= %g\nxstep= %g\nLine= %g 1 0x000000ff 0x0\n",
- dBounds.Xmin, dBounds.Xmax, (dBounds.Xmax -dBounds.Xmin)/100.0, defs.GetSize(SIZE_DATA_LINE));
- i += sprintf(TmpTxt+i, "f_xy=\"%g+x*%g\\n\"\n", dres[1], dres[0]);
- i += sprintf(TmpTxt+i, "Desc=\"Regression\"\n");
- OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
- i = sprintf(TmpTxt, "[1=Function]\nx1= %g\nx2= %g\nxstep= %g\nLine= %g 1 0x000000ff 0x0\n",
- dBounds.Xmin, dBounds.Xmax, (dBounds.Xmax -dBounds.Xmin)/100.0, defs.GetSize(SIZE_DATA_LINE)*0.5);
- i += sprintf(TmpTxt+i, "f_xy=\"y=%g+x*%g;\\nts=sqrt((((x-(%g))^2)/%g+%g)*%g);\\ny=y+ts*%g\\n\"\n",
- dres[1], dres[0], dres[2], sxx, (1.0/(double)n), dres[7], t);
- i += sprintf(TmpTxt+i, "Desc=\"%g%% C.I.\"\n", ci);
- OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
- i = sprintf(TmpTxt, "[1=Function]\nx1= %g\nx2= %g\nxstep= %g\nLine= %g 1 0x000000ff 0x0\n",
- dBounds.Xmin, dBounds.Xmax, (dBounds.Xmax -dBounds.Xmin)/100.0, defs.GetSize(SIZE_DATA_LINE)*0.5);
- i += sprintf(TmpTxt+i, "f_xy=\"y=%g+x*%g;\\nts=sqrt((((x-(%g))^2)/%g+%g)*%g);\\ny=y-ts*%g\\n\"\n",
- dres[1], dres[0], dres[2], sxx, (1.0/(double)n), dres[7], t);
- i += sprintf(TmpTxt+i, "Desc=\"%g%% C.I.\"\n", ci);
- OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
-#endif
- ts = t * sqrt(dres[7]*((dBounds.Xmax-dres[2])*(dBounds.Xmax-dres[2])/sxx +1.0/(double)n));
- ty = dBounds.Xmax * dres[0] +dres[1];
- ly[0] = ty +ts; ly[1] = ty -ts;
- ts = t * sqrt(dres[7]*((dBounds.Xmin-dres[2])*(dBounds.Xmin-dres[2])/sxx +1.0/(double)n));
- ty = dBounds.Xmin * dres[0] +dres[1];
- ly[2] = ty +ts; ly[3] = ty -ts;
- for(i = 0; i < 4; i++) if(ly[i] > -HUGE_VAL && ly[i] < HUGE_VAL) {
- if(ly[i] < dBounds.Ymin) dBounds.Ymin = ly[i];
- if(ly[i] > dBounds.Ymax) dBounds.Ymax = ly[i];
- }
-#ifdef USE_WIN_SECURE
- if(!bParZ) sprintf_s(TmpTxt, TMP_TXT_SIZE, "y = %g %c %g * x",dres[1],(dres[0] < 0.0 ? '-' : '+'), fabs(dres[0]));
- else sprintf_s(TmpTxt, TMP_TXT_SIZE, "y = %g * x", fabs(dres[0]));
-#else
- if(!bParZ) sprintf(TmpTxt, "y = %g %c %g * x",dres[1],(dres[0] < 0.0 ? '-' : '+'), fabs(dres[0]));
- else sprintf(TmpTxt, "y = %g * x", fabs(dres[0]));
-#endif
- rep_DrawText(graph, (graph->GetSize(SIZE_DRECT_LEFT) + graph->GetSize(SIZE_DRECT_RIGHT))/2.0,
- graph->GetSize(SIZE_DRECT_TOP)+txtdef1.fSize/2.0, true, TXA_HCENTER, &txtdef1, TmpTxt);
- page = new Page(parent, data); page->Command(CMD_DROP_GRAPH, graph, 0L);
- graph->moveable = 0;
- graph->GRect.Xmin += (txtdef1.fSize*5.0); graph->GRect.Xmax += (txtdef1.fSize*5.0);
- graph->GRect.Ymin += (txtdef1.fSize*10.0); graph->GRect.Ymax += (txtdef1.fSize*10.0);
- mk_header(page, "<b>Linear Regression Analysis</b>", data);
- res_tab[0][0] = 1; res_tab[1][0] = df;
- res_tab[2][0] = df+1.0; res_tab[0][1] = sxy*sxy/sxx;
- res_tab[1][1] = syy-res_tab[0][1]; res_tab[2][1] = syy;
- res_tab[0][2] = res_tab[0][1]; res_tab[1][2] = res_tab[1][1]/df;
- res_tab[0][3] = dres[8]; res_tab[0][4] = dres[9];
- dres[12] = res_tab[0][1]/res_tab[2][1];
- c_y = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*3.0;
- c_x = graph->GRect.Xmin;
- c_y = mk_regr_summary(page, c_x, c_y, dres, ci, n);
- rep_DrawText(page, c_x, c_y, false, TXA_HLEFT, &txtdef1, "<b>Anova:</b>");
- c_y += txtdef1.fSize*1.5; mk_table(page, c_x, c_y, 2, res_tab);
- parent->Command(CMD_DROP_GRAPH, page, 0L);
- }
- }
- CloseDlgWnd(hDlg);
- delete Dlg; if(res_tab) {
- for(i = 0; i < 3; i++) if(res_tab[i]) free(res_tab[i]);
- free(res_tab);
- }
- if(x_desc) free(x_desc); if(y_desc)free(y_desc);
- if(x) free(x); if(y) free(y);
- if(rX) delete rX; if(rY) delete rY; free(RegrDlg);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Kendall's robust line-fit
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *RobLineDlg_Tmpl =
- "1,+,,DEFAULT,PUSHBUTTON,-1,148,10,45,12\n"
- ".,.,,,PUSHBUTTON,-2,148,25,45,12\n"
- ".,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "4,10,100,ISPARENT | CHECKED,SHEET,1,5,10,130,78\n"
- "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
- "100,+,,,LTEXT,2,10,30,60,8\n"
- ".,.,,,RANGEINPUT,-15,20,40,100,10\n"
- ".,.,,,LTEXT,3,10,55,60,8\n"
- ".,,,LASTOBJ,RANGEINPUT,-16,20,65,100,10";
-
-void
-rep_robustline(GraphObj *parent, DataObj *data)
-{
- TabSHEET tab1 = {0, 90, 10, "Nonparametric Regression"};
- DlgInfo *RegrDlg;
- void *dyndata[] = {(void*)&tab1, (void*)"range for x-data", (void*)"range for y-data"};
- DlgRoot *Dlg;
- void *hDlg;
- int i, j, k, n, n1, rx, cx, ry, cy, res, align = 0;
- int x_dtype, y_dtype, nVals, nTxt, nTime;
- bool bContinue = false, bValid;
- AccRange *rX = 0L, *rY = 0L;
- double *x = 0L, *y = 0L, *a = 0L, *b = 0L, c_x, c_y;
- double dx, dy, slope, intercept;
- char *txt_obj, *x_desc=0L, *y_desc=0L;
- scaleINFO scale = {{0.0, 0.45}, {0.0, 0.45}, {0.0, 0.45}};
- anyResult xRes, yRes;
- TextValue *x_tv, *y_tv;
- Plot *plot;
- Graph *graph;
- Page *page;
-
- if(!parent || !data) return;
- if(!(RegrDlg = CompileDialog(RobLineDlg_Tmpl, dyndata))) return;
- UseRangeMark(data, 1, TmpTxt, TmpTxt+100);
- if(!(Dlg = new DlgRoot(RegrDlg, data)))return;
- hDlg = CreateDlgWnd("Kendall's robust line-fit", 50, 50, 420, 220, 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 1:
- if(rX) delete rX; if(rY) delete rY;
- rX = rY = 0L;
- if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) rX = new AccRange(TmpTxt);
- n = rX ? rX->CountItems() : 0;
- if(!n) {
- ErrorBox("Range not specified\nor not valid.");
- bContinue = true;
- res = -1;
- }
- if(n && Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE) && (rY = new AccRange(TmpTxt))){
- if(n != rY->CountItems()) {
- ErrorBox("Both ranges must be given\nand must have the same size");
- bContinue = true;
- res = -1;
- }
- }
- }
- }while (res < 0);
- for(n1 = n, i = k = 1; i < n; i++) k += i;
- if(res == 1 && n >1 && rX && rY && (x = (double*)malloc(n*sizeof(double)))
- && (y = (double*)malloc(n*sizeof(double)))
- && (a = (double*)malloc(k*sizeof(double)))
- && (b = (double*)malloc(k*sizeof(double)))){
- x_desc = rX->RangeDesc(data, 0); y_desc = rY->RangeDesc(data, 0);
- //analyse data types
- x_dtype = y_dtype = 0; x_tv = y_tv = 0L;
- if(rX->DataTypes(data, &nVals, &nTxt, &nTime)){
- if(!nVals && nTxt > 1 && nTxt > nTime) x_tv = new TextValue();
- else if(!nVals && nTime > 1 && nTime > nTxt) x_dtype = ET_DATETIME;
- }
- if(rY->DataTypes(data, &nVals, &nTxt, &nTime)){
- if(!nVals && nTxt > 1 && nTxt > nTime) y_tv = new TextValue();
- else if(!nVals && nTime > 1 && nTime > nTxt) y_dtype = ET_DATETIME;
- }
- rX->GetFirst(&cx, &rx); rY->GetFirst(&cy, &ry);
- rep_init();
- dBounds.Xmin = dBounds.Ymin = HUGE_VAL; dBounds.Xmax = dBounds.Ymax = -HUGE_VAL;
- //read data into x[] and y[]
- for(i = n = 0; i < n1 && rX->GetNext(&cx, &rx) && rY->GetNext(&cy, &ry); i++) {
- bValid = false;
- if(data->GetResult(&xRes, rx, cx, false) && data->GetResult(&yRes, ry, cy, false)) {
- bValid = true;
- if(x_tv) {
- if(xRes.type == ET_TEXT) dx = x_tv->GetValue(xRes.text);
- else bValid = false;
- }
- else if(x_dtype == ET_DATETIME) {
- if(xRes.type == ET_DATE || xRes.type == ET_TIME || xRes.type == ET_DATETIME) dx = xRes.value;
- else bValid = false;
- }
- else {
- if(xRes.type == ET_VALUE) dx = xRes.value;
- else bValid = false;
- }
- if(y_tv) {
- if(yRes.type == ET_TEXT) dy = y_tv->GetValue(yRes.text);
- else bValid = false;
- }
- else if(y_dtype == ET_DATETIME) {
- if(yRes.type == ET_DATE || yRes.type == ET_TIME || yRes.type == ET_DATETIME) dy = yRes.value;
- else bValid = false;
- }
- else {
- if(yRes.type == ET_VALUE) dy = yRes.value;
- else bValid = false;
- }
- }
- if(bValid){
- x[n] = dx; y[n] = dy;
- if(dBounds.Xmin > x[n]) dBounds.Xmin = x[n];
- if(dBounds.Xmax < x[n]) dBounds.Xmax = x[n];
- if(dBounds.Ymin > y[n]) dBounds.Ymin = y[n];
- if(dBounds.Ymax < y[n]) dBounds.Ymax = y[n];
- n++;
- }
- }
- SortArray2(n, x, y);
- for(i = k = 0; i < (n-1); i++) for(j = i+1; j < n; j++) {
- if(x[i] != x[j]) {
- b[k] = (y[j] - y[i])/(x[j] - x[i]);
- a[k] = y[i] - b[k]*x[i]; k++;
- }
- }
- d_quartile(k, b, 0L, &slope, 0L); d_quartile(k, a, 0L, &intercept, 0L);
- slope = slope; intercept = intercept;
- if (n && (graph = new Graph(parent, data, 0L, 0))) {
- if(txt_obj = mk_scatt(0, x, y, 0L, 0L, n, "Data", x_desc, y_desc)){
- OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
- free(txt_obj);
- if(LastOpenGO && LastOpenGO->Id >= GO_PLOT && LastOpenGO ->Id < GO_GRAPH) {
- ((Plot*)LastOpenGO)->x_dtype = x_dtype; ((Plot*)LastOpenGO)->y_dtype = y_dtype;
- ((Plot*)LastOpenGO)->x_tv = x_tv; ((Plot*)LastOpenGO)->y_tv = y_tv;
- }
- }
-#ifdef USE_WIN_SECURE
- i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "[1=Function]\nx1= %g\nx2= %g\nxstep= %g\nLine= %g 1 0x000000ff 0x0\n",
- dBounds.Xmin, dBounds.Xmax, (dBounds.Xmax -dBounds.Xmin)/100.0, defs.GetSize(SIZE_DATA_LINE));
- i += sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, "f_xy=\"%g+x*%g\\n\"\n", intercept, slope);
- i += sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, "Desc=\"Fitted Line\"\n");
- OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "y = %g %c %g * x",intercept,(slope < 0.0 ? '-' : '+'), fabs(slope));
-#else
- i = sprintf(TmpTxt, "[1=Function]\nx1= %g\nx2= %g\nxstep= %g\nLine= %g 1 0x000000ff 0x0\n",
- dBounds.Xmin, dBounds.Xmax, (dBounds.Xmax -dBounds.Xmin)/100.0, defs.GetSize(SIZE_DATA_LINE));
- i += sprintf(TmpTxt+i, "f_xy=\"%g+x*%g\\n\"\n", intercept, slope);
- i += sprintf(TmpTxt+i, "Desc=\"Fitted Line\"\n");
- OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
- sprintf(TmpTxt, "y = %g %c %g * x", intercept, (slope < 0.0 ? '-' : '+'), fabs(slope));
-#endif
- rep_DrawText(graph, (graph->GetSize(SIZE_DRECT_LEFT) + graph->GetSize(SIZE_DRECT_RIGHT))/2.0,
- graph->GetSize(SIZE_DRECT_TOP)+txtdef1.fSize/2.0, true, TXA_HCENTER, &txtdef1, TmpTxt);
- page = new Page(parent, data); page->Command(CMD_DROP_GRAPH, graph, 0L);
- graph->moveable = 0;
- graph->GRect.Xmin += (txtdef1.fSize*5.0); graph->GRect.Xmax += (txtdef1.fSize*5.0);
- graph->GRect.Ymin += (txtdef1.fSize*9.0); graph->GRect.Ymax += (txtdef1.fSize*9.0);
- mk_header(page, "<b>Kendall's Robust Line-Fit</b>", data);
- c_y = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*2.0;
- c_x = graph->GRect.Xmin;
- j = (int)isqr(k); i = (int)((double)k/10.0);
- if(j < 8) j = 8;
- else if (j >40) j = 40;
- scale.sx.fx = (graph->GRect.Xmin + graph->GRect.Xmax)/2.0;
- scale.sy.fx = c_y;
- graph = new Graph(parent, data, 0L, 0);
- if(plot = new FreqDist(graph, data, b+(i>>1), k-i, j)){
- if(plot->x_info = (char*)malloc(30)) rlp_strcpy(plot->x_info, 30, "90% of all slopes");
- if(plot->y_info = (char*)malloc(30)) rlp_strcpy(plot->y_info, 30, "No. of observations");
- if(!(graph->Command(CMD_DROP_PLOT, plot, 0L))) delete(plot);
- }
- graph->Command(CMD_SCALE, &scale, 0L);
- page->Command(CMD_DROP_GRAPH, graph, 0L);
- mk_median_report(page, c_x, c_y, b, k, .95, "Slope");
- scale.sy.fx = c_y = graph->GRect.Ymax + txtdef1.fSize;
- graph = new Graph(parent, data, 0L, 0);
- if(plot = new FreqDist(graph, data, a+(i>>1), k-i, j)){
- if(plot->x_info = (char*)malloc(30)) rlp_strcpy(plot->x_info, 30, "90% of all intercepts");
- if(plot->y_info = (char*)malloc(30)) rlp_strcpy(plot->y_info, 30, "No. of observations");
- if(!(graph->Command(CMD_DROP_PLOT, plot, 0L))) delete(plot);
- }
- graph->Command(CMD_SCALE, &scale, 0L);
- page->Command(CMD_DROP_GRAPH, graph, 0L);
- c_y = mk_median_report(page, c_x, c_y, a, k, .95, "Intercept");
- parent->Command(CMD_DROP_GRAPH, page, 0L);
- }
- }
- CloseDlgWnd(hDlg);
- delete Dlg;
- if(x_desc) free(x_desc); if(y_desc)free(y_desc);
- if(x) free(x); if(y) free(y);
- if(a) free(a); if(b) free(b);
- if(rX) delete rX; if(rY) delete rY; free(RegrDlg);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Correlation reports
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *RepCorrel_DlgTmpl =
- "1,2,,DEFAULT,PUSHBUTTON,-1,158,10,45,12\n"
- "2,3,,,PUSHBUTTON,-2,158,25,45,12\n"
- "3,,10,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "10,11,152,ISPARENT | CHECKED, SHEET,1,5,10,140,70\n"
- "11,20,200,ISPARENT | TOUCHEXIT,SHEET,2,5,10,140,70\n"
- "20,21,,CHECKED,CHECKPIN,0,5,0,12,8\n"
- "21,22,,CHECKED,CHECKBOX,7,25,85,130,9\n"
- "22,23,,,LTEXT,8,35,95,50,9\n"
- "23,24,,,EDVAL1,9,87,95,30,10\n"
- "24,,,,LTEXT,-10,120,95,10,9\n"
- "152,153,,ISPARENT | CHECKED,GROUPBOX,3,12,30,128,45\n"
- "153,154,,,LTEXT,0,25,35,60,8\n"
- "154,155,,,RANGEINPUT,0,25,45,100,10\n"
- "155,156,0,,PUSHBUTTON,-8,95,57,30,12\n"
- "156,,,,PUSHBUTTON,-9,60,57,35,12\n"
- "200,201,,TOUCHEXIT,RADIO1,4,25,30,60,8\n"
- "201,202,,TOUCHEXIT,RADIO1,5,25,45,60,8\n"
- "202,,,TOUCHEXIT,RADIO1,6,25,60,60,8\n"
- "300,,,LASTOBJ,NONE,0,0,0,0,0";
-static int use_corr = 2;
-static double use_ci = 95.0;
-
-void rep_correl(GraphObj *parent, DataObj *data, int style)
-{
- TabSHEET tab1 = {0, 25, 10, "Data"};
- TabSHEET tab2 = {25, 57, 10, "Method"};
-
- void *dyndata[] = {(void*)&tab1, (void*)&tab2,
- (void*)" select one range for every variable ", (void*)" Pearsons product moment",
- (void*)" Spearmans rank correlation", (void*)" Kendalls Tau", (void*)" highlight significant correlations,",
- (void*)"sigificance level", (void*)&use_ci};
- DlgInfo *CorrelDlg;
- DlgRoot *Dlg;
- void *hDlg;
- int i, j, res, nr, currYR = 0, maxYR = 0, ny, corr;
- int r1, c1, r2, c2, n, cb;
- bool updateYR = true, bContinue = false, bMtab = false, bHiLite;
- double lmarg, line_inc, *v1, *v2, val1, val2, cx, cy, r,dn, p, sf, ra[20], cl;
- char **rd = 0L, *txt_obj, *info1, *info2;
- scaleINFO scale = {{0.0, 0.14}, {0.0, 0.14}, {0.0, 0.14}};
- AccRange *rV1 = 0L, *rV2 = 0L;
- TextDEF mtext;
- Plot *plot;
- Graph *graph;
- Page *page;
-
- if(!parent || !data) return;
- info1 = info2 = 0L;
- if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
- TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return;
- if(!(CorrelDlg = CompileDialog(RepCorrel_DlgTmpl, dyndata))) return;
- if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
- for(i=j=0; i <= 1000; i +=100) if(TmpTxt[i])
- rd[j++] = (char*)memdup(TmpTxt+i, ((int)strlen(TmpTxt+i))+2, 0); maxYR = j-1;
- }
- if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return;
- if(!(Dlg = new DlgRoot(CorrelDlg, data))) return;
- if(rd && rd[currYR] && *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
- switch(use_corr) {
- case 1: Dlg->SetCheck(200, 0L, true); corr = 1; break;
- default: Dlg->SetCheck(201, 0L, true); corr = 2; break;
- case 3: Dlg->SetCheck(202, 0L, true); corr = 3; break;
- }
- hDlg = CreateDlgWnd(style? (char*)"Create Tiled Correlation Plots" :
- (char*)"Create a Correlation Matrix", 50, 50, 420, 252, Dlg, 0x0L);
- do {
- if(updateYR) {
- if(currYR >0) Dlg->ShowItem(156, true);
- else Dlg->ShowItem(156, false);
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "variable # %d/%d", currYR+1, maxYR+1);
-#else
- sprintf(TmpTxt,"variable # %d/%d", currYR+1, maxYR+1);
-#endif
- Dlg->SetText(153, 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 11: //select correlation method
- bMtab = true; res =-1; break;
- case 200: //select pearson
- case 201: //select spearman
- case 202: //select kendall
- corr = res-199; res =-1; break;
- case 1:
- if(!bMtab) {
- Dlg->SetCheck(11, 0L, true);
- bMtab = true; res = -1;
- break;
- }
- case 155: case 156:
- res = com_StackDlg(res, Dlg, 0L, 0L, &rd, &currYR,
- &rV1, &bContinue, &ny, &maxYR, &updateYR);
- break;
- }
- }while (res < 0);
-
- if(res ==1) {
- if(bHiLite = Dlg->GetCheck(21)) {
- Dlg->GetValue(23, &use_ci); cl = 1.0 - use_ci/100.0;
- }
- maxYR++; rep_init(); page = new Page(parent, data);
- if(rV1) delete rV1; rV1 = 0L; use_corr = corr;
- switch(corr) {
- case 1:
- mk_header(page, "<b>Pearsons product moment correlations</b>", data);
- break;
- case 2:
- mk_header(page, "<b>Spearmans rank correlations</b>", data);
- break;
- case 3:
- mk_header(page, "<b>Kendalls non parametric correlations</b>", data);
- break;
- default:
- mk_header(page, "<b>### Correlation Error ###</b>", data);
- break;
- }
- memcpy(&mtext, &txtdef1, sizeof(TextDEF));
- if(style == 0) {
- lmarg = txtdef1.fSize*12.0;
- cy = txtdef1.fSize*13.0; cx = txtdef1.fSize*6.0;
- line_inc = linsp1;
- sf = (page->GetSize(SIZE_GRECT_RIGHT)-lmarg-linsp1)/(cx *(double)maxYR);
- if(sf< 1.0) {
- cx *= sf; line_inc *= sf; lmarg *= sf;
- mtext.fSize *= sf; mtext.iSize = 0;
- }
- }
- else {
- lmarg = txtdef1.fSize*8.0;
- cy = txtdef1.fSize*13.0;
- cx = (page->GetSize(SIZE_GRECT_RIGHT)-txtdef1.fSize*3.0-lmarg)/maxYR;
- switch(defs.cUnits) {
- default:
- scale.sx.fy = scale.sy.fy = scale.sz.fy = cx/165.0; break;
- case 1:
- scale.sx.fy = scale.sy.fy = scale.sz.fy = cx/16.50; break;
- case 2:
- scale.sx.fy = scale.sy.fy = scale.sz.fy = cx/6.49606; break;
- }
- line_inc = cx/1.44;
- }
- for(nr = maxYR, i = 0; i < nr; i++) for(j = 0; j < nr; j++) {
- if(i == 0 &&(rV1 = new AccRange(rd[j]))) { //first row
- if(info1 = rV1->RangeDesc(data, style == 0 || nr > 5 ? 1 : 2)) {
- if(style == 0)
- rep_DrawText(page, lmarg+cx*j, cy-txtdef1.fSize*2.0, false, TXA_HCENTER, &mtext, info1);
- else if(style == 1)
- rep_DrawText(page, lmarg+cx*j+cx/2.0, cy-txtdef1.fSize*2.0, false, TXA_HCENTER, &mtext, info1);
- free(info1); info1 = 0L;
- }
- delete rV1; rV1 = 0L;
- }
- if(j == 0 &&(rV1 = new AccRange(rd[i]))) { //first column
- if(info1 = rV1->RangeDesc(data, 1)) {
- if(style == 0)
- rep_DrawText(page, lmarg-cx/2.0-txtdef1.fSize, cy+line_inc, false, TXA_HRIGHT, &mtext, info1);
- else if(style == 1)
- rep_DrawText(page, lmarg-txtdef1.fSize, cy+line_inc/2.0-mtext.fSize/2.0, false, TXA_HRIGHT, &mtext, info1);
- free(info1); info1 = 0L;
- }
- delete rV1; rV1 = 0L;
- }
- if(i == j) { //self correlation: do something else ...
- if(style == 0) { //correlation matrix
- rep_DrawText(page, lmarg+cx*j, cy+line_inc, false, TXA_HCENTER, &mtext, "---");
- }
- else if(style = 1) { //tiled plots
- graph = new Graph(parent, data, 0L, 0);
- scale.sx.fx = lmarg+cx*j; scale.sy.fx = cy;
- if(plot = new FreqDist(graph, data, rd[i], true)){
- if(rV1 = new AccRange(rd[i])){
- plot->x_info = rV1->RangeDesc(data, 2);
- delete rV1; rV1 = 0L;
- }
- if(!(graph->Command(CMD_DROP_PLOT, plot, 0L))) delete(plot);
- }
- graph->Command(CMD_SCALE, &scale, 0L);
- page->Command(CMD_DROP_GRAPH, graph, 0L);
- }
- }
- else {
- rV1 = new AccRange(rd[i]); rV2 = new AccRange(rd[j]);
- v1 = (double*)malloc((rV1->CountItems()+1) * sizeof(double));
- v2 = (double*)malloc((rV2->CountItems()+1) * sizeof(double));
- dBounds.Xmin = dBounds.Ymin = HUGE_VAL; dBounds.Xmax = dBounds.Ymax = -HUGE_VAL;
- rV1->GetFirst(&c1, &r1); rV2->GetFirst(&c2, &r2);
- //copy values into arrays
- for(n = 0; rV1->GetNext(&c1, &r1) && rV2->GetNext(&c2, &r2); ) {
- if(data->GetValue(r1, c1, &val1) && data->GetValue(r2, c2, &val2)) {
- if(dBounds.Xmin > val1) dBounds.Xmin = val1;
- if(dBounds.Xmax < val1) dBounds.Xmax = val1;
- if(dBounds.Ymin > val2) dBounds.Ymin = val2;
- if(dBounds.Ymax < val2) dBounds.Ymax = val2;
- v1[n] = val1; v2[n] = val2; n++;
- }
- }
- //do correlation
- dn = n; r = 0.0;
- if(n) switch(corr) {
- case 1:
- d_pearson(v1, v2, n, 0L, 0L, ra);
- r = ra[0]; p = ra[2]; dn = ra[3];
- break;
- case 2:
- d_spearman(v1, v2, n, 0L, 0L, ra);
- r = ra[3]; p = ra[4]; dn = ra[5];
- break;
- case 3:
- d_kendall(v1, v2, n, 0L, 0L, ra);
- r = ra[0]; p = ra[2]; dn = ra[3];
- break;
- default:
- r = 0.0; dn = 0.0; p = 1.0; break;
- }
- //process result
- if(dn > 1.0 && style == 0) { //correlation matrix
- if(bHiLite && p < cl && (txt_obj = mk_rect(lmarg+cx*j-cx/2.1, cy-line_inc/4.0, lmarg+cx*j+cx/2.1,
- cy+line_inc*3.25, 0x0000ffffL, 0x0080ffffL))) {
- OpenGraph(page, 0L, (unsigned char*)txt_obj, false);
- free(txt_obj);
- }
- dbl_to_str1(TmpTxt, 80, "%g", r);
- rep_DrawText(page, lmarg+cx*j, cy, false, TXA_HCENTER, &mtext, TmpTxt);
- dbl_to_str1(TmpTxt, 80, "n = %g", dn);
- rep_DrawText(page, lmarg+cx*j, cy+line_inc, false, TXA_HCENTER, &mtext, TmpTxt);
- dbl_to_str1(TmpTxt, 80, p < 0.001 ? (char*)"P < 0.0001" : (char*)"P = %.4lf", p);
- rep_DrawText(page, lmarg+cx*j, cy+line_inc*2.0, false, TXA_HCENTER, &mtext, TmpTxt);
- if(j == (nr-1)) cy += (line_inc*4.0);
- }
- else if(style == 0) { //corr. matrix but no data
- if(j == (nr-1)) cy += (line_inc*4.0);
- }
- else if(style == 1) { //tiled plots
- graph = new Graph(parent, data, 0L, 0);
- scale.sx.fx = lmarg+cx*j; scale.sy.fx = cy;
- info1 = rV1->RangeDesc(data, 2); info2 = rV2->RangeDesc(data, 2);
- if(txt_obj = mk_scatt(0, v1, v2, 0L, 0L, n, "Data", info1, info2)){
- OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
- free(txt_obj);
- }
- if(info1) free(info1); if(info2) free(info2);
- info1 = info2 = 0L;
- if(bHiLite && p < cl) {
- graph->SetColor(COL_GRECT, 0x0000ffffL); graph->SetColor(COL_DRECT, 0x00c0ffffL);
- }
- switch(corr) {
- case 1:
- cb = dbl_to_str2(TmpTxt, 80, "r = %.4lf, n = %g, ", r, dn); break;
- case 2:
- cb = dbl_to_str2(TmpTxt, 80, "r<sub>S</sub> = %.4lf, n = %g, ", r, dn); break;
- case 3:
- cb = dbl_to_str2(TmpTxt, 80, "r<sub>K</sub> = %.4lf, n = %g, ", r, dn); break;
- default:
- TmpTxt[0] = 0; cb = 0; break;
- }
- dbl_to_str1(TmpTxt+cb, 80, p < 0.001 ? (char*)"P < 0.0001" : (char*)"P = %.4lf", p);
- rep_DrawText(graph, graph->GetSize(SIZE_DRECT_LEFT)+txtdef1.fSize,
- graph->GetSize(SIZE_DRECT_TOP)+txtdef1.fSize, false, TXA_HLEFT, &txtdef1, TmpTxt);
- if(LastOpenGO)LastOpenGO->SetColor(COL_TEXT, 0x00cb0000L);
- graph->Command(CMD_SCALE, &scale, 0L);
- if(dn > 1.0) page->Command(CMD_DROP_GRAPH, graph, 0L);
- if(j == (nr-1)) cy += line_inc;
- }
- free(v1); free(v2);
- if(rV1)delete rV1; if(rV2)delete rV2; rV1 = rV2 = 0L;
- }
- }
- parent->Command(CMD_DROP_GRAPH, page, 0L);
- }
- CloseDlgWnd(hDlg);
- delete Dlg;
- if(rd) {
- for (i = 0; i < maxYR; i++) if(rd[i]) free(rd[i]);
- free(rd);
- }
- if(rV2) delete rV2; if(rV1) delete rV1; free(CorrelDlg);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 2x2 table
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *twDlg_Tmpl =
- "1,2,100,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "2,3,400,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "3,4,600,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
- "4,5,,DEFAULT,PUSHBUTTON,-1,168,10,45,12\n"
- "5,,,,PUSHBUTTON,2,168,25,45,12\n"
- "100,101,,,CTEXT,1,35,10,40,8\n"
- "101,102,,,EDTEXT,0,35,20,40,10\n"
- "102,103,,,EDTEXT,0,77,20,40,10\n"
- "103,104,,,EDTEXT,0,35,32,40,10\n"
- "104,105,,,EDTEXT,0,77,32,40,10\n"
- "105,106,,,LTEXT,3,10,20,40,8\n"
- "106,107,,,LTEXT,4,10,32,40,8\n"
- "107,,,,CTEXT,5,77,10,40,8\n"
- "400,401,,,EDTEXT,0,119,20,40,10\n"
- "401,402,,,EDTEXT,0,119,32,40,10\n"
- "402,403,,,EDTEXT,0,35,44,40,10\n"
- "403,404,,,EDTEXT,0,77,44,40,10\n"
- "404,405,,,EDTEXT,0,119,44,40,10\n"
- "405,406,,,CTEXT,6,119,10,40,8\n"
- "406,407,,,LTEXT,7,10,44,40,8\n"
- "407,408,,,LTEXT,2,35,59,40,8\n"
- "408,409,,,LTEXT,2,35,69,40,8\n"
- "409,410,,,LTEXT,8,119,59,60,8\n"
- "410,,,,LTEXT,0,119,69,60,8\n"
- "600,601,,DEFAULT,PUSHBUTTON,-1,128,10,45,12\n"
- "601,,,LASTOBJ,PUSHBUTTON,-2,128,25,45,12";
-
-void rep_twowaytable(GraphObj *parent, DataObj *data)
-{
- DlgInfo *twDlg;
- void *dyndata[] = {(void*)"Group A", (void*)"Close", (void*)"Case 1", (void*)"Case 2",
- (void*)"Group B", (void*)"A + B", (void*)"C1+C2", (void*)"Fisher's exact:"};
- DlgRoot *Dlg;
- void *hDlg;
- int i, r, c, level, res, wcc;
- int v_idx[] = {101,102,400,103,104,401,402,403,404};
- double tmp, v[9], chi2, p, dn, pf, pfa[128];
- char *rng;
- AccRange *ar;
-
- if(!parent || !data) return;
- if(!(twDlg = CompileDialog(twDlg_Tmpl, dyndata))) return;
- if(!(Dlg = new DlgRoot(twDlg, data)))return;
- for(i = 400; i < 405; i++) Dlg->Activate(i, false);
- if(data->Command(CMD_GETMARK, &rng, 0L) && rng && rng[0] && (ar = new AccRange(rng)) && ar->GetFirst(&c, &r)) {
- for(i = 0; i < 4 && ar->GetNext(&c, &r); ) {
- if(data->GetValue(r, c, &tmp)) {
- Dlg->SetValue(101+i, tmp); i++;
- }
- }
- delete ar;
- if(i == 4) Dlg->ItemCmd(600, CMD_ENDDIALOG, 0L);
- }
- level = wcc = 0;
- Dlg->ShowItem(2, false); Dlg->ShowItem(4, false);
- Dlg->ShowItem(5, false);
- hDlg = CreateDlgWnd("2x2 Table", 50, 50, 450, 200, Dlg, 0);
- ResizeDlgWnd(hDlg, 370, 150);
- do {
- LoopDlgWnd();
- res = Dlg->GetResult();
- switch(res) {
- case 0:
- res = -1;
- break;
- case 600: //level 0 OK
- Dlg->ShowItem(2, true); Dlg->ShowItem(4, true);
- Dlg->ShowItem(5, true); Dlg->ShowItem(3, false);
- ResizeDlgWnd(hDlg, 450, 200); Dlg->Command(CMD_REDRAW, 0L, 0L);
- level = 1;
- case 4: //level 1 OK
- for(i = 0; i < 9; i++) {
- v[i] = 0.0; Dlg->GetValue(v_idx[i], &v[i]);
- v[i] = fabs(floor(v[i]));
- }
- v[2] = v[0] + v[1]; v[5] = v[3] + v[4];
- v[6] = v[0] + v[3]; v[7] = v[1] + v[4];
- v[8] = v[6] + v[7]; chi2 = v[0]*v[4]-v[1]*v[3];
- for(i = wcc = 0; i < 9; i++) {
- dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "%g", v[i]);
- Dlg->SetText(v_idx[i], TmpTxt);
- }
- if(v[8] < 128.0) do {
- pf = factrl((int)v[2])/factrl((int)v[0])*factrl((int)v[5])/factrl((int)v[1])
- *factrl((int)v[6])/factrl((int)v[3])*factrl((int)v[7])/factrl((int)v[4]);
- pf /= factrl((int)v[8]);
- pfa[wcc++] = pf;
- //worse case correction
- //RR Sokal & FJ Rohlf: Biometry, 3rd ed., pp. 734 ff.
- if((v[0]*v[4]- v[1]*v[3]) < 0.0) {
- v[0]-=1.0; v[4]-=1.0; v[1]+=1.0; v[3]+=1.0;
- }
- else if((v[0]*v[4]- v[1]*v[3]) > 0.0) {
- v[0]+=1.0; v[4]+=1.0; v[1]-=1.0; v[3]-=1.0;
- }
- else break;
- }while(v[0]>=0.0 && v[1]>=0.0 && v[3]>=0.0 && v[4]>=0.0 && wcc < 128);
- if(wcc){
- for(i = 1, pf = pfa[0]; i < wcc; i++){
- pf += pfa[i];
- }
- if(pf > 1.0) pf = 1.0;
- dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "P(one sided) = %.4lf", pf);
- Dlg->SetText(410, pf >= 0.001 ? TmpTxt : (char*)"P < 0.001");
- }
- else Dlg->SetText(410, "- - -");
- dn = (v[2]*v[5]*v[6]*v[7]);
- chi2 = dn > 0.0 ? (chi2*chi2*v[8])/dn : 0.0;
- p = chi_dist(chi2, 1.0, 1.0);
- dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "Chi2 = %g", chi2);
- Dlg->SetText(407, TmpTxt);
- if(p >= 0.001) {
- dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "P = %g", p);
- Dlg->SetText(408, TmpTxt);
- }
- else Dlg->SetText(408, "P < 0.001");
- Dlg->Command(CMD_REDRAW, 0L, 0L);
- res= -1;
- break;
- }
- }while (res < 0);
- CloseDlgWnd(hDlg);
- delete Dlg; free(twDlg);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// compare means / medians of two groups
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-void rep_compmeans(GraphObj *parent, DataObj *data)
-{
- TabSHEET tab1 = {0, 42, 10, "Data Input"};
- double ci = 95.0;
- DlgInfo *MeanDlg;
- void *dyndata[] = {(void*)&tab1, (void*)"range for first variable",
- (void*)"range for second variable", (void*)"confidence interval:",
- (void*)&ci, (void*)" "};
- char *ttest[] = {"Student's t = %g", "P = %g", "P(corr.) = %g"};
- char *utest[] = {"Mann-Whitney U = %g", "z = %g", "P = %g", "z(corr.) = %g", "P(corr.) = %g"};
- char g1_nam[30], g2_nam[30], *c_name;
- DlgRoot *Dlg;
- void *hDlg;
- int i, j, res, n1, n2, r, c, *ny;
- bool bContinue = false;
- double *d1, *d2, dtmp, *rs, cx, cy, min1,max1, min2, max2;
- scaleINFO scale = {{0.0, 0.9}, {0.0, 0.9}, {0.0, 0.9}};
- char *txt_obj;
- anyResult ares;
- AccRange *rD;
- Graph *graph;
- Page *page;
-
- if(!parent || !data) return;
- if(!(MeanDlg = CompileDialog(RegrDlg_Tmpl, dyndata))) return;
- UseRangeMark(data, 1, TmpTxt, TmpTxt+100);
- if(!(Dlg = new DlgRoot(MeanDlg, data)))return;
- Dlg->ShowItem(107, false);
- d1 = d2 = 0L;
- hDlg = CreateDlgWnd("Compare Means", 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 1:
- if(d1) free(d1); if(d2) free(d2); d1 = d2 = 0L;
- min1 = min2 = dBounds.Ymin = HUGE_VAL; max1 = max2 = dBounds.Ymax = -HUGE_VAL;
- if(Dlg->GetText(101,TmpTxt,TMP_TXT_SIZE)&&(rD=new AccRange(TmpTxt))&&(n1=rD->CountItems())&&(d1=(double*)malloc(n1*sizeof(double)))){
- if(c_name = rD->RangeDesc(data, 2)) {
- rlp_strcpy(g1_nam, 30, c_name); g1_nam[0] = toupper(g1_nam[0]);
- free(c_name);
- }
- else rlp_strcpy(g1_nam, 30, "Group 1");
- for(n1 = 0, rD->GetFirst(&c, &r); rD->GetNext(&c, &r); ) {
- if(data->GetResult(&ares, r, c, false) && ares.type == ET_VALUE){
- if(dBounds.Ymin > ares.value) dBounds.Ymin = ares.value;
- if(dBounds.Ymax < ares.value) dBounds.Ymax = ares.value;
- if(min1 > ares.value) min1 = ares.value; if(max1 < ares.value) max1 = ares.value;
- d1[n1++] = ares.value;
- }
- }
- delete rD;
- }
- if(Dlg->GetText(103,TmpTxt,TMP_TXT_SIZE)&&(rD=new AccRange(TmpTxt))&&(n2=rD->CountItems())&&(d2=(double*)malloc(n2*sizeof(double)))){
- if(c_name = rD->RangeDesc(data, 2)) {
- rlp_strcpy(g2_nam, 30, c_name); g2_nam[0] = toupper(g2_nam[0]);
- free(c_name);
- }
- else rlp_strcpy(g2_nam, 30, "Group 2");
- for(n2 = 0, rD->GetFirst(&c, &r); rD->GetNext(&c, &r); ) {
- if(data->GetResult(&ares, r, c, false) && ares.type == ET_VALUE){
- if(dBounds.Ymin > ares.value) dBounds.Ymin = ares.value;
- if(dBounds.Ymax < ares.value) dBounds.Ymax = ares.value;
- if(min2 > ares.value) min2 = ares.value; if(max2 < ares.value) max2 = ares.value;
- d2[n2++] = ares.value;
- }
- }
- delete rD;
- }
- if(g1_nam[0] && g2_nam[0] && 0==strcmp(g1_nam, g2_nam)) {
- rlp_strcpy(g1_nam, 30, "Group 1"); rlp_strcpy(g2_nam, 30, "Group 2");
- }
- if(!d1 || !d2 || n1 < 2 || n2 < 2) {
- InfoBox("Insufficient data to calculate means!");
- bContinue = true;
- res = -1;
- }
- Dlg->GetValue(105, &ci);
- break;
- }
- }while (res < 0);
- if(res == 1 && d1 && d2 && n1>1 && n2>1 && (rs = (double*)malloc(40*sizeof(double))) && (ny = (int*)malloc(2*sizeof(int)))) {
- dBounds.Xmin = 0.5; rs[0] = 1.0; dBounds.Xmax = 2.3; rs[1] = 2.0;
- dtmp = d_variance(n1, d1, &rs[2], 0L); rs[10] = sqrt(dtmp);
- dtmp = d_variance(n2, d2, &rs[3], 0L); rs[11] = sqrt(dtmp);
- rs[12] = (double)n1; rs[13] = (double)n2;
- rs[6] = rs[10]/sqrt(rs[12]); rs[7] = rs[11]/sqrt(rs[13]);
- rs[4] = rs[2] - rs[6]; rs[5] = rs[3] - rs[7];
- rs[6] += rs[2]; rs[7] += rs[3];
- rs[8] = rs[2] - rs[10]; rs[9] = rs[3] - rs[11];
- rs[10] += rs[2]; rs[11] += rs[3];
- ny[0] = n1; ny[1] = n2;
- rep_init(); page = new Page(parent, data);
- ci /= 100.0;
- mk_header(page, "<b>Compare Means of Two Groups</b>", data);
- if((graph = new Graph(parent, data, 0L, 0)) && (txt_obj = mk_boxplot(0, rs, rs+2, rs+4, rs+6, rs+8, rs+10,
- ny, 2,"Mean","Std. Err.","Std. Dev."))){
- scale.sx.fx = (txtdef1.fSize*5.0); scale.sy.fx = (txtdef1.fSize*10.0);
- graph->GRect.Xmax = defs.GetSize(SIZE_GRECT_BOTTOM);
- graph->DRect.Xmin *= 0.8; graph->moveable = 0;
- graph->DRect.Xmax = graph->GRect.Xmax - (txtdef1.fSize*2.0);
- OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
- if(LastOpenGO && LastOpenGO->Id == GO_BOXPLOT) {
- if(((BoxPlot*)LastOpenGO)->x_tv = new TextValue()){
- ((BoxPlot*)LastOpenGO)->x_tv->GetValue(g1_nam);
- ((BoxPlot*)LastOpenGO)->x_tv->GetValue(g2_nam);
- }
- }
- free(txt_obj); graph->Command(CMD_SCALE, &scale, 0L);
- cx = graph->GetSize(SIZE_GRECT_RIGHT)+txtdef1.fSize*3.0;
- cy = mk_mean_report(page, cx, graph->GetSize(SIZE_GRECT_TOP), d1, n1, ci, g1_nam);
- cy = mk_mean_report(page, cx, cy + txtdef1.fSize, d2, n2, ci, g2_nam);
- cy += linsp1;
- rep_DrawText(page, graph->GetSize(SIZE_GRECT_RIGHT)+txtdef1.fSize*3.0, cy, false, TXA_HLEFT, &txtdef1, "<b>t-Test:</b>");
- cy += linsp1; d_ttest(d1, d2, n1, n2, 0L, 0L, rs+15);
- for(i = 0; i < 3; i++) {
- switch(i) {
- case 0: dtmp = rs[24]; break;
- case 1: dtmp = rs[21]; break;
- case 2: dtmp = rs[23]; break;
- }
-#ifdef USE_WIN_SECURE
- j = sprintf_s(TmpTxt, 80, ttest[i], dtmp);
-#else
- j = sprintf(TmpTxt, ttest[i], dtmp);
-#endif
- if(i && dtmp < 0.0001) {
- while(TmpTxt[j] != '=' && j) j--;
- rlp_strcpy(TmpTxt+j, 10, "< 0.0001");
- }
- rep_DrawText(page, cx+(txtdef1.fSize*3.0), cy, false, TXA_HLEFT, &txtdef1, TmpTxt);
- cy += linsp1/1.2;
- }
- page->Command(CMD_DROP_GRAPH, graph, 0L);
- }
- d_quartile(n1, d1, &rs[6], &rs[2], &rs[4]);
- d_quartile(n2, d2, &rs[7], &rs[3], &rs[5]);
- rs[8] = min1; rs[9] = min2; rs[10] = max1; rs[11] = max2;
- cy = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*3.0;
- if((graph = new Graph(parent, data, 0L, 0)) && (txt_obj = mk_boxplot(0, rs, rs+2, rs+4, rs+6, rs+8, rs+10,
- ny, 2,"Median","25-75%","Min./Max."))){
- scale.sy.fx = cy;
- graph->GRect.Xmax = defs.GetSize(SIZE_GRECT_BOTTOM);
- graph->DRect.Xmin *= 0.8; graph->moveable = 0;
- graph->DRect.Xmax = graph->GRect.Xmax - (txtdef1.fSize*2.0);
- OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
- if(LastOpenGO && LastOpenGO->Id == GO_BOXPLOT) {
- if(((BoxPlot*)LastOpenGO)->x_tv = new TextValue()){
- ((BoxPlot*)LastOpenGO)->x_tv->GetValue(g1_nam);
- ((BoxPlot*)LastOpenGO)->x_tv->GetValue(g2_nam);
- }
- }
- free(txt_obj); graph->Command(CMD_SCALE, &scale, 0L);
- cy = mk_median_report(page, cx, graph->GetSize(SIZE_GRECT_TOP), d1, n1, .95, g1_nam);
- cy = mk_median_report(page, cx, cy + txtdef1.fSize, d2, n2, .95, g2_nam);
- cy += linsp1;
- rep_DrawText(page, graph->GetSize(SIZE_GRECT_RIGHT)+txtdef1.fSize*3.0, cy, false, TXA_HLEFT, &txtdef1, "<b>u-Test:</b>");
- cy += linsp1; d_utest(d1, d2, n1, n2, 0L, 0L, rs+15);
- for(i = 0; i < 5; i++) {
- switch(i) {
- case 0: dtmp = rs[17]; break;
- case 1: dtmp = rs[18]; break;
- case 2: dtmp = rs[21]; break;
- case 3: dtmp = rs[22]; break;
- case 4: dtmp = rs[23]; break;
- }
-#ifdef USE_WIN_SECURE
- j = sprintf_s(TmpTxt, 80, utest[i], dtmp);
-#else
- j = sprintf(TmpTxt, utest[i], dtmp);
-#endif
- if(i && dtmp < 0.0001) {
- while(TmpTxt[j] != '=' && j) j--;
- rlp_strcpy(TmpTxt+j, 10, "< 0.0001");
- }
- rep_DrawText(page, cx+(txtdef1.fSize*3.0), cy, false, TXA_HLEFT, &txtdef1, TmpTxt);
- cy += linsp1/1.2;
- }
- page->Command(CMD_DROP_GRAPH, graph, 0L);
- }
- parent->Command(CMD_DROP_GRAPH, page, 0L);
- free(rs); free(ny);
- }
- CloseDlgWnd(hDlg); delete Dlg; free(MeanDlg);
- if(d1) free(d1); if(d2) free(d2);
-}
+//reports.cpp, Copyright (c) 2006-2008 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
+//
+// Create statistical reports
+//
+
+#include "rlplot.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <math.h>
+#include <ctype.h>
+#include "TheDialog.h"
+
+extern char TmpTxt[];
+extern Default defs;
+extern GraphObj *LastOpenGO;
+
+#define _PREC 1.0e-12
+
+//prototypes: WinSpec.cpp
+void *CreateDlgWnd(char *title, int x, int y, int width, int height, tag_DlgObj *d, DWORD flags);
+
+static int curr_id, cbSymLineStr;
+static fRECT dBounds;
+static TextDEF txtdef1, txtdef2;
+static double linsp1, linsp2;
+static char SymLineStr[40];
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// init report variables
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static void rep_init()
+{
+ curr_id = 1; defs.cUnits = defs.dUnits;
+ txtdef1.ColTxt = txtdef2.ColTxt = 0x0L;
+ txtdef1.ColBg = txtdef2.ColBg = 0x00ffffffL;
+ txtdef1.fSize = defs.GetSize(SIZE_TEXT);
+ txtdef2.fSize = txtdef1.fSize *1.2;
+ txtdef1.RotBL = txtdef2.RotBL = 0.0;
+ txtdef1.RotCHAR = txtdef2.RotCHAR = 0.0;
+ txtdef1.iSize = txtdef2.iSize = 0;
+ txtdef1.Align = txtdef2.Align = TXA_HLEFT | TXA_VTOP;
+ txtdef1.Mode = txtdef2.Mode = TXM_TRANSPARENT;
+ txtdef1.Style = txtdef2.Style = TXS_NORMAL;
+ txtdef1.Font = txtdef2.Font = FONT_HELVETICA;
+ txtdef1.text = txtdef2.text = 0L;
+#ifdef _WINDOWS
+ linsp1 = txtdef1.fSize*1.2; linsp2 = txtdef1.fSize*1.5;
+#else
+ linsp1 = txtdef1.fSize*1.7; linsp2 = txtdef1.fSize*2.5;
+#endif
+#ifdef USE_WIN_SECURE
+ cbSymLineStr = sprintf_s(SymLineStr, 40, "Line= %g 1 0x0 0x0\n", defs.GetSize(SIZE_SYM_LINE));
+#else
+ cbSymLineStr = sprintf(SymLineStr, "Line= %g 1 0x0 0x0\n", defs.GetSize(SIZE_SYM_LINE));
+#endif
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create a text label for a report
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char* mk_label(double x, double y, bool moveable, int align, TextDEF *td, char*text)
+{
+ int csize, pos = 0;
+ char *res;
+
+ if(!(res = (char*)malloc(csize = 1000)))return 0L;
+ res[pos++] = '\n'; res[pos++] = '[';
+ add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
+ add_to_buff(&res, &pos, &csize, "=Label]\nPos=", 12);
+ add_dbl_to_buff(&res, &pos, &csize, x, true);
+ add_dbl_to_buff(&res, &pos, &csize, y, true);
+ res[pos++] = '\n';
+ if(moveable) add_to_buff(&res, &pos, &csize, "moveable= 1\n", 12);
+ add_to_buff(&res, &pos, &csize, "TxtDef= 0x0 0x00ffffff", 22);
+ add_dbl_to_buff(&res, &pos, &csize, td->fSize, true);
+ add_dbl_to_buff(&res, &pos, &csize, td->RotBL, true);
+ add_dbl_to_buff(&res, &pos, &csize, td->RotCHAR, true);
+ add_int_to_buff(&res, &pos, &csize, align, true, 0);
+ add_to_buff(&res, &pos, &csize, " 1 0 0 \"", 8);
+ add_to_buff(&res, &pos, &csize, text, 0);
+ add_to_buff(&res, &pos, &csize, "\"\n", 2);
+ return res;
+}
+static void rep_DrawText(GraphObj *parent, double x, double y, bool moveable, int align, TextDEF *td, char*text)
+{
+ char *txt_obj;
+
+ if(txt_obj = mk_label(x, y, moveable, align, td, text)) {
+ OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
+ free(txt_obj);
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// draw a rectangle
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char* mk_rect(double x1, double y1, double x2, double y2, DWORD lcol, DWORD fcol)
+{
+ int csize, pos = 0;
+ char *res;
+
+ if(!(res = (char*)malloc(csize = 1000)))return 0L;
+ res[pos++] = '\n'; res[pos++] = '[';
+ add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
+ add_to_buff(&res, &pos, &csize, "=rectangle]\np1=", 0);
+ add_dbl_to_buff(&res, &pos, &csize, x1, true);
+ add_dbl_to_buff(&res, &pos, &csize, y1, true);
+ add_to_buff(&res, &pos, &csize, "\np2=", 0);
+ add_dbl_to_buff(&res, &pos, &csize, x2, true);
+ add_dbl_to_buff(&res, &pos, &csize, y2, true);
+ add_to_buff(&res, &pos, &csize, "\nLine= 0 1", 0);
+ add_hex_to_buff(&res, &pos, &csize, lcol, true);
+ add_to_buff(&res, &pos, &csize, " 0x0\nFillLine= 0 1 0x0 0x0\nFill= 0", 0);
+ add_hex_to_buff(&res, &pos, &csize, fcol, true);
+ add_to_buff(&res, &pos, &csize, " 1 0x0 0x00ffffff\n", 0);
+ return res;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// print values to string
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static int dbl_to_str1(char *dest, int size, char* fmt, double val)
+{
+#ifdef USE_WIN_SECURE
+ return sprintf_s(dest, size, fmt, val);
+#else
+ return sprintf(dest, fmt, val);
+#endif
+}
+
+static int dbl_to_str2(char *dest, int size, char* fmt, double val1, double val2)
+{
+#ifdef USE_WIN_SECURE
+ return sprintf_s(dest, size, fmt, val1, val2);
+#else
+ return sprintf(dest, fmt, val1, val2);
+#endif
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create general information on report page
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static void mk_header(Page *page, char* desc, DataObj *data)
+{
+ time_t ti = time(0L);
+ char label[80];
+ double rpos;
+ int cb;
+
+ if(!page) return;
+ rpos = page->GetSize(SIZE_GRECT_RIGHT) - txtdef1.fSize*5.0;
+ rep_DrawText(page, txtdef1.fSize*5.0, page->GetSize(SIZE_GRECT_TOP)+txtdef2.fSize*6.0,
+ false, TXA_HLEFT, &txtdef2, desc);
+#ifdef USE_WIN_SECURE
+ ctime_s(label, 32, &ti);
+#else
+ rlp_strcpy(label, 25, ctime(&ti));
+#endif
+ label[24] = 0;
+ rep_DrawText(page, rpos, page->GetSize(SIZE_GRECT_TOP)+txtdef1.fSize*5.0,
+ false, TXA_HRIGHT, &txtdef1, label);
+ cb = rlp_strcpy(label, 80, "RLPlot "); cb += rlp_strcpy(label+cb, 80-cb, SZ_VERSION);
+ rep_DrawText(page, rpos, page->GetSize(SIZE_GRECT_BOTTOM)-txtdef1.fSize*6.0,
+ false, TXA_HRIGHT, &txtdef1, label);
+ if(data && data->Command(CMD_GETFILENAME, TmpTxt, 0L)) {
+ rpos = page->GetSize(SIZE_GRECT_LEFT) + txtdef1.fSize*5.0;
+ rep_DrawText(page, rpos, page->GetSize(SIZE_GRECT_BOTTOM)-txtdef1.fSize*6.0,
+ false, TXA_HLEFT, &txtdef1, TmpTxt);
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create horizontal ruler
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static void mk_hr(GraphObj *parent, double x1, double x2, double y)
+{
+ int csize, pos = 0;
+ char *res;
+
+ if(!(res = (char*)malloc(csize = 100)))return;
+ res[pos++] = '\n'; res[pos++] = '[';
+ add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
+ add_to_buff(&res, &pos, &csize, "=polyline]\nData= (2){", 21);
+ add_dbl_to_buff(&res, &pos, &csize, x1, false);
+ add_dbl_to_buff(&res, &pos, &csize, y, true);
+ add_dbl_to_buff(&res, &pos, &csize, x2, true);
+ add_dbl_to_buff(&res, &pos, &csize, y, true);
+ add_to_buff(&res, &pos, &csize, "}\nLine=", 7);
+ add_dbl_to_buff(&res, &pos, &csize, txtdef1.fSize/20.0, true);
+ add_dbl_to_buff(&res, &pos, &csize, txtdef1.fSize, true);
+ add_to_buff(&res, &pos, &csize, " 0x0 0x0\n", 9);
+ OpenGraph(parent, 0L, (unsigned char*)res, false);
+ free(res);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create a means report
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static double mk_mean_report(GraphObj *parent, double x, double y, double *da, int n, double ci, char *name)
+{
+ static char *mean_fmts[] = {"Mean = %g", "Std.Dev. = %g", "N = %g", "Std.Err. = %g", 0L,
+ "Kurtosis = %g", "Skewness = %g"};
+ char desc[80];
+ int i, cb;
+ double v, t, res[10];
+
+ if(name && name[0]) {
+ cb = rlp_strcpy(desc, 40, "<b>"); cb += rlp_strcpy(desc+cb, 40-cb, name);
+ cb += rlp_strcpy(desc+cb, 40-cb, ":</b>");
+ rep_DrawText(parent, x, y, false, TXA_HLEFT, &txtdef1, desc);
+ y += linsp1; x += (txtdef1.fSize*3.0);
+ }
+ cb = dbl_to_str1(desc, 80, "%g%%%% C.I. = %%g", ci*100.0);
+ mean_fmts[4] = (char*)malloc(cb+2);
+ rlp_strcpy(mean_fmts[4], cb+1, desc); t = distinv(t_dist, n-1, 1, 1.0-ci, 2.0);
+ v = d_variance(n, da, &res[0], 0L); res[2] = (double)n;
+ res[1] = sqrt(v); res[3] = res[1] / sqrt(res[2]);
+ res[4] = res[3] *t; res[5] = d_kurt(n, da);
+ res[6] = d_skew(n, da);
+ for(i = 0; i < 7; i++) {
+ dbl_to_str1(desc, 80, mean_fmts[i], res[i]);
+ rep_DrawText(parent, x, y, false, TXA_HLEFT, &txtdef1, desc);
+ y += (i==2 ? linsp1/0.9 : linsp1/1.2);
+ }
+ free(mean_fmts[4]); mean_fmts[4] = 0L;
+ return y;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create a median report
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static double mk_median_report(GraphObj *parent, double x, double y, double *da, int n, double ci, char *name)
+{
+ static char *mean_fmts[] = {"Median = %g", "25%% = %g", "75%% = %g", "N = %g", "Min. = %g", "Max. = %g" };
+ char desc[80];
+ int i, cb;
+ double res[6];
+
+ if(!da || !parent || !n) return y;
+ if(name && name[0]) {
+ cb = rlp_strcpy(desc, 40, "<b>"); cb += rlp_strcpy(desc+cb, 40-cb, name);
+ cb += rlp_strcpy(desc+cb, 40-cb, ":</b>");
+ rep_DrawText(parent, x, y, false, TXA_HLEFT, &txtdef1, desc);
+ y += linsp1; x += (txtdef1.fSize*3.0);
+ }
+ d_quartile(n, da, &res[1], &res[0], &res[2]);
+ res[4] = res[5] = *da;
+ for(i = 1; i < n; i++) {
+ if(da[i] > res[5]) res[5] = da[i]; if(da[i] < res[4]) res[4] = da[i];
+ }
+ res[3] = (double)n;
+ for(i = 0; i < 6; i++) {
+ dbl_to_str1(desc, 80, mean_fmts[i], res[i]);
+ rep_DrawText(parent, x, y, false, TXA_HLEFT, &txtdef1, desc);
+ y += linsp1/1.2;
+ }
+ return y;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create report table for anova ...
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static double mk_table(GraphObj *parent, double x, double y, int type, double **dda)
+{
+ char *cheaders[] = {"<i>df</i>", "<i>SS</i>", "<i>MS</i>", "<i>F</i>", "<i>P</i>"};
+ char *rheaders1[] = {"Source of variation", type == 2 ? (char*)"Explained by regression":
+ (char*)"Among groups", type == 2 ? (char*)"Unexplained":(char*)"Within groups", "Total"};
+ char *rheaders2[] = {"Source of variation", "Between rows", "Between columns", "Interaction",
+ "Within subgroups (error)", "Total"};
+ char *rheaders3[] = {"Source of variation", "Between columns", "Between rows", "Error", "Total"};
+ char *cfmt[8], **rheaders;
+ int i, j, nl, nc[8];
+ double posc[8], cinc;
+
+#ifdef _WINDOWS
+ cinc = txtdef1.fSize;
+#else
+ cinc = txtdef1.fSize *1.3;
+#endif
+ cfmt[0] = "%.0lf"; cfmt[3] = "%0.3lf"; cfmt[4] = "%0.4lf";
+ switch(type) {
+ case 1: case 2:
+ rheaders = rheaders1;
+ nl = 3; nc[0] = 5; nc[1] = 3; nc[2] = 2;
+ posc[0] = x + cinc*14.0; posc[1] = posc[0] + cinc*5.0;
+ posc[2] = posc[1] + cinc*6.0; posc[3] = posc[2] + cinc*6.0;
+ posc[4] = posc[3] + cinc*6.0;
+ cfmt[1] = GetNumFormat(floor(log10(dda[2][1])-3.0));
+ cfmt[2] = GetNumFormat(floor(log10(dda[0][2]+dda[1][2])-3.0));
+ break;
+ case 3:
+ rheaders = rheaders2;
+ nl = 5; nc[0] = nc[1] = nc[2] = 5; nc[3] = 3; nc[4] = 2;
+ posc[0] = x + cinc*14.0; posc[1] = posc[0] + cinc*5.0;
+ posc[2] = posc[1] + cinc*6.0; posc[3] = posc[2] + cinc*6.0;
+ posc[4] = posc[3] + cinc*6.0;
+ cfmt[1] = GetNumFormat(floor(log10(dda[2][1])-3.0));
+ cfmt[2] = GetNumFormat(floor(log10(dda[0][2]+dda[0][1])-3.0));
+ break;
+ case 4:
+ rheaders = rheaders3;
+ nl = 4; nc[0] = nc[1] = 5; nc[2] = 3; nc[3] = 2;
+ posc[0] = x + cinc*14.0; posc[1] = posc[0] + cinc*5.0;
+ posc[2] = posc[1] + cinc*6.0; posc[3] = posc[2] + cinc*6.0;
+ posc[4] = posc[3] + cinc*6.0;
+ cfmt[1] = GetNumFormat(floor(log10(dda[3][1])-4.0));
+ cfmt[2] = GetNumFormat(floor(log10(dda[0][2]+dda[1][2]+dda[2][2])-4.0));
+ break;
+ default: return y;
+ }
+ if(type == 1 || type == 2 || type == 3 || type == 4) {
+ rep_DrawText(parent, x, y, false, TXA_HLEFT, &txtdef1, rheaders[0]);
+ for(i = 0; i < 5; i++) {
+ rep_DrawText(parent, posc[i], y, false, TXA_HRIGHT, &txtdef1, cheaders[i]);
+ if(i) posc[i] += linsp1;
+ }
+ mk_hr(parent, x, posc[4], y + linsp1); y += linsp2;
+ }
+ for(i = 0; i < nl; i++) {
+ rep_DrawText(parent, x, y, false, TXA_HLEFT, &txtdef1, rheaders[i+1]);
+ for(j = 0; j < nc[i]; j++) {
+ if(j == 4 && dda[i][j] > 0.0 && dda[i][j] < 0.0001) rlp_strcpy(TmpTxt, 10, "< 0.0001");
+#ifdef USE_WIN_SECURE
+ else sprintf_s(TmpTxt, 20, cfmt[j], dda[i][j]);
+#else
+ else sprintf(TmpTxt, cfmt[j], dda[i][j]);
+#endif
+ rep_DrawText(parent, posc[j], y, false, TXA_HRIGHT, &txtdef1, TmpTxt);
+ }
+ if(i < (nl-2)) y += linsp1;
+ else {
+ mk_hr(parent, x, posc[4], y + linsp1); y += linsp2;
+ }
+ }
+ return y;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create a boxplot for a report
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char* mk_boxplot(int style, double *x, double *y, double *by1, double *by2, double *wy1, double *wy2, int *ny, int n,
+ char *s_nam, char *b_nam, char *w_nam)
+{
+ int i, csize, pos, first_s, first_b, first_w, first_l;
+ char *res;
+ double size;
+
+ if(!(res = (char*)malloc(csize = 2000)))return 0L;
+ if(n < 20) size = defs.GetSize(SIZE_SYMBOL);
+ else size = defs.GetSize(SIZE_SYMBOL)/2.0 + 20.0 * defs.GetSize(SIZE_SYMBOL)/(2.0 * n);
+ first_b = curr_id;
+ for(i = pos = 0; i < n && res; i++) {
+ add_to_buff(&res, &pos, &csize, "\n[", 2); add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
+ add_to_buff(&res, &pos, &csize, "=Box]\nType= 256\nHigh=", 21);
+ if(style == 1) {
+ add_dbl_to_buff(&res, &pos, &csize, by2[i], true);
+ add_dbl_to_buff(&res, &pos, &csize, y[i], true);
+ add_to_buff(&res, &pos, &csize,"\nLow=", 5);
+ add_dbl_to_buff(&res, &pos, &csize, by1[i], true);
+ add_dbl_to_buff(&res, &pos, &csize,y[i], true);
+ }
+ else {
+ add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
+ add_dbl_to_buff(&res, &pos, &csize, by2[i], true);
+ add_to_buff(&res, &pos, &csize,"\nLow=", 5);
+ add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
+ add_dbl_to_buff(&res, &pos, &csize, by1[i], true);
+ }
+ add_to_buff(&res, &pos, &csize,"\nSize= 60\nName= \"", 17);
+ add_to_buff(&res, &pos, &csize, b_nam, 0);
+ add_to_buff(&res, &pos, &csize, "\"\n", 2);
+ }
+ first_w = curr_id;
+ for(i = 0; i < n && res; i++) {
+ add_to_buff(&res, &pos, &csize, "\n[", 2); add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
+ add_to_buff(&res, &pos, &csize, "=Whisker]\nHigh=", 15);
+ if(style == 1) {
+ add_dbl_to_buff(&res, &pos, &csize, wy2[i], true);
+ add_dbl_to_buff(&res, &pos, &csize, y[i], true);
+ add_to_buff(&res, &pos, &csize,"\nLow=", 5);
+ add_dbl_to_buff(&res, &pos, &csize, wy1[i], true);
+ add_dbl_to_buff(&res, &pos, &csize,y[i], true);
+ }
+ else {
+ add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
+ add_dbl_to_buff(&res, &pos, &csize, wy2[i], true);
+ add_to_buff(&res, &pos, &csize,"\nLow=", 5);
+ add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
+ add_dbl_to_buff(&res, &pos, &csize, wy1[i], true);
+ }
+ add_to_buff(&res, &pos, &csize, "\nDesc= \"", 8);
+ add_to_buff(&res, &pos, &csize, w_nam, 0);
+ add_to_buff(&res, &pos, &csize, "\"\n", 2);
+ }
+ first_s = curr_id;
+ for(i = 0; i < n && res; i++) {
+ add_to_buff(&res, &pos, &csize, "\n[", 2); add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
+ add_to_buff(&res, &pos, &csize, "=Symbol]\nType= 10\nPos=", 22);
+ add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
+ add_dbl_to_buff(&res, &pos, &csize, y[i], true);
+ add_to_buff(&res, &pos, &csize, "\nSize=", 6); add_dbl_to_buff(&res, &pos, &csize, size, true);
+ add_to_buff(&res, &pos, &csize, "\n", 1);
+ add_to_buff(&res, &pos, &csize, SymLineStr, cbSymLineStr);
+ add_to_buff(&res, &pos, &csize, "FillCol= 0x00ffffff\n", 20);
+ if(s_nam) {
+ add_to_buff(&res, &pos, &csize, "Name=\"", 6);
+ add_to_buff(&res, &pos, &csize, s_nam, 0); add_to_buff(&res, &pos, &csize, "\"\n", 2);
+ }
+ }
+ first_l = curr_id;
+ for(i = 0; i < n && res; i++) {
+ add_to_buff(&res, &pos, &csize, "\n[", 2);
+ add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
+ add_to_buff(&res, &pos, &csize, "=Label]\nPos=", 12);
+ if(style == 1) {
+ add_dbl_to_buff(&res, &pos, &csize, wy2[i], true);
+ add_dbl_to_buff(&res, &pos, &csize, y[i], true);
+ add_to_buff(&res, &pos, &csize, "\nDist=", 6);
+ add_dbl_to_buff(&res, &pos, &csize, txtdef1.fSize/2.0, true);
+ add_to_buff(&res, &pos, &csize, " 0", 2);
+ }
+ else {
+ add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
+ add_dbl_to_buff(&res, &pos, &csize, wy2[i], true);
+ add_to_buff(&res, &pos, &csize, "\nDist= 0", 8);
+ add_dbl_to_buff(&res, &pos, &csize, -txtdef1.fSize/4.0, true);
+ }
+ add_to_buff(&res, &pos, &csize, "\nFlags= 0x00000011\nTxtDef= 0x00000000 0x00ffffff", 48);
+ add_dbl_to_buff(&res, &pos, &csize, txtdef1.fSize, true);
+ add_dbl_to_buff(&res, &pos, &csize, txtdef1.RotBL, true);
+ add_dbl_to_buff(&res, &pos, &csize, txtdef1.RotCHAR, true);
+ add_int_to_buff(&res, &pos, &csize, style == 1 ? (TXA_HLEFT | TXA_VCENTER):(TXA_HCENTER | TXA_VBOTTOM), true, 0);
+ add_to_buff(&res, &pos, &csize, " 1 0 0 \"", 8);
+ if(n < 7) add_to_buff(&res, &pos, &csize, "n = ", 4);
+ add_int_to_buff(&res, &pos, &csize, ny[i], false, 0);
+ add_to_buff(&res, &pos, &csize, "\"\n", 2);
+ }
+ add_to_buff(&res,&pos,&csize, "\n[", 2); add_int_to_buff(&res,&pos,&csize, curr_id++, false, 0);
+ add_to_buff(&res, &pos, &csize, "=BoxPlot]\nBounds=", 17);
+ add_dbl_to_buff(&res,&pos,&csize, dBounds.Xmin, true); add_dbl_to_buff(&res,&pos,&csize, dBounds.Ymax, true);
+ add_dbl_to_buff(&res,&pos,&csize, dBounds.Xmax, true); add_dbl_to_buff(&res,&pos,&csize, dBounds.Ymin, true);
+
+ add_to_buff(&res,&pos,&csize, "\nBoxes=(", 0); add_int_to_buff(&res,&pos,&csize, n, false, 0);
+ add_to_buff(&res,&pos,&csize, "){", 2);
+ for(i = 0; i < n; i++, first_b++) {
+ add_int_to_buff(&res,&pos,&csize, first_b, false, 0); add_to_buff(&res,&pos,&csize, ",", 1);
+ if(i && (i%16)== 0 && first_b < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n ", 4);
+ }
+ while(res[pos-1] == ',' || res[pos-1] < 33) pos --; add_to_buff(&res, &pos, &csize, "}", 2);
+ add_to_buff(&res,&pos,&csize, "\nWhiskers=(", 0); add_int_to_buff(&res,&pos,&csize, n, false, 0);
+ add_to_buff(&res,&pos,&csize, "){", 2);
+ for(i = 0; i < n; i++, first_w++) {
+ add_int_to_buff(&res,&pos,&csize, first_w, false, 0); add_to_buff(&res,&pos,&csize, ",", 1);
+ if(i && (i%16)== 0 && first_b < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n ", 4);
+ }
+ while(res[pos-1] == ',' || res[pos-1] < 33) pos --; add_to_buff(&res, &pos, &csize, "}", 2);
+ add_to_buff(&res,&pos,&csize, "\nSymbols=(", 10); add_int_to_buff(&res,&pos,&csize, n, false, 0);
+ add_to_buff(&res,&pos,&csize, "){", 2);
+ for(i = 0; i < n; i++, first_s++) {
+ add_int_to_buff(&res,&pos,&csize, first_s, false, 0); add_to_buff(&res,&pos,&csize, ",", 1);
+ if(i && (i%16)== 0 && first_s < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n ", 4);
+ }
+ while(res[pos-1] == ',' || res[pos-1] < 33) pos --; add_to_buff(&res, &pos, &csize, "}", 2);
+ add_to_buff(&res,&pos,&csize, "\nLabels=(", 9); add_int_to_buff(&res,&pos,&csize, n, false, 0);
+ add_to_buff(&res,&pos,&csize, "){", 2);
+ for(i = 0; i < n; i++, first_l++) {
+ add_int_to_buff(&res,&pos,&csize, first_l, false, 0); add_to_buff(&res,&pos,&csize, ",", 1);
+ if(i && (i%16)== 0 && first_s < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n ", 4);
+ }
+ while(res[pos-1] == ',' || res[pos-1] < 33) pos --; add_to_buff(&res, &pos, &csize, "}\n", 2);
+ return res;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create a scatterplot for a report
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char* mk_scatt(int style, double *x, double *y, double *ss, int *ny, int n, char *s_nam, char *x_desc, char *y_desc)
+{
+ int i, csize, pos, first;
+ char *res;
+ double size, linew, tmp, val;
+
+ if(!(res = (char*)malloc(csize = 2000)))return 0L;
+ if(n < 20) size = defs.GetSize(SIZE_SYMBOL);
+ else size = defs.GetSize(SIZE_SYMBOL)/2.0 + 20.0 * defs.GetSize(SIZE_SYMBOL)/(2.0 * n);
+ linew = defs.GetSize(SIZE_SYM_LINE);
+ first = curr_id;
+ for(i = pos = 0; i < n && res; i++) {
+ add_to_buff(&res, &pos, &csize, "\n[", 2); add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
+ add_to_buff(&res, &pos, &csize, "=Symbol]\nPos=", 13);
+ add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
+ add_dbl_to_buff(&res, &pos, &csize, y[i], true);
+ add_to_buff(&res, &pos, &csize, "\nSize=", 6); add_dbl_to_buff(&res, &pos, &csize, size, true);
+ add_to_buff(&res, &pos, &csize, "\n", 1);
+ add_to_buff(&res, &pos, &csize, SymLineStr, cbSymLineStr);
+ add_to_buff(&res, &pos, &csize, "FillCol= 0x00ffffff\n", 20);
+ }
+ if(ss && ny) {
+ for(i = 0; i < n && res; i++) {
+ if(ny[i] > 1) tmp = sqrt(ss[i]/(ny[i]-1));
+ else tmp = 0.0;
+ add_to_buff(&res, &pos, &csize, "\n[", 2);
+ add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
+ add_to_buff(&res, &pos, &csize, "=ErrorBar]\nType=", 16);
+ add_int_to_buff(&res, &pos, &csize, style & 0x10 ? 3 : 0, true, 0);
+ add_to_buff(&res, &pos, &csize, "\nPos=", 5);
+ add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
+ add_dbl_to_buff(&res, &pos, &csize, y[i], true);
+ add_to_buff(&res, &pos, &csize, "\nErr=", 5);
+ add_dbl_to_buff(&res, &pos, &csize, tmp, true);
+ add_to_buff(&res, &pos, &csize, "\nDesc= \"Std. Dev.\"\n", 19);
+ }
+ for(i = 0; i < n && res; i++) {
+ if(ny[i] > 1) tmp = sqrt(ss[i]/(ny[i]-1));
+ else tmp = 0.0;
+ add_to_buff(&res, &pos, &csize, "\n[", 2);
+ add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
+ add_to_buff(&res, &pos, &csize, "=Label]\nPos=", 12);
+ if(style & 0x10) {
+ val = x ? x[i] : (double)(i+1);
+ if(dBounds.Xmin > (val-tmp)) dBounds.Xmin = val-tmp;
+ if(dBounds.Xmax < (val+tmp)) dBounds.Xmax = val+tmp;
+ add_dbl_to_buff(&res, &pos, &csize, val+tmp, true);
+ add_dbl_to_buff(&res, &pos, &csize, y[i], true);
+ add_to_buff(&res, &pos, &csize, "\nDist=", 6);
+ add_dbl_to_buff(&res, &pos, &csize, txtdef1.fSize/2.0, true);
+ add_to_buff(&res, &pos, &csize, " 0", 2);
+ }
+ else {
+ if(dBounds.Ymin > (y[i]-tmp)) dBounds.Ymin = y[i]-tmp;
+ if(dBounds.Ymax < (y[i]+tmp)) dBounds.Ymax = y[i]+tmp;
+ add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : ((double)(i+1)), true);
+ add_dbl_to_buff(&res, &pos, &csize, y[i] +tmp, true);
+ add_to_buff(&res, &pos, &csize, "\nDist= 0", 8);
+ add_dbl_to_buff(&res, &pos, &csize, -txtdef1.fSize/4.0, true);
+ }
+ add_to_buff(&res, &pos, &csize, "\nFlags= 0x00000011\nTxtDef= 0x00000000 0x00ffffff", 48);
+ add_dbl_to_buff(&res, &pos, &csize, txtdef1.fSize, true);
+ add_dbl_to_buff(&res, &pos, &csize, txtdef1.RotBL, true);
+ add_dbl_to_buff(&res, &pos, &csize, txtdef1.RotCHAR, true);
+ add_int_to_buff(&res, &pos, &csize, (style & 0x10)?(TXA_HLEFT | TXA_VCENTER) : (TXA_HCENTER | TXA_VBOTTOM), true, 0);
+ add_to_buff(&res, &pos, &csize, " 1 0 0 \"", 8);
+ if(n < 7) add_to_buff(&res, &pos, &csize, "n = ", 4);
+ add_int_to_buff(&res, &pos, &csize, ny[i], false, 0);
+ add_to_buff(&res, &pos, &csize, "\"\n", 2);
+ }
+ }
+ add_to_buff(&res,&pos,&csize, "\n[", 2); add_int_to_buff(&res,&pos,&csize, curr_id++, false, 0);
+ add_to_buff(&res, &pos, &csize, "=PlotScatt]\nBounds=", 19);
+ add_dbl_to_buff(&res,&pos,&csize, dBounds.Xmin, true); add_dbl_to_buff(&res,&pos,&csize, dBounds.Ymax, true);
+ add_dbl_to_buff(&res,&pos,&csize, dBounds.Xmax, true); add_dbl_to_buff(&res,&pos,&csize, dBounds.Ymin, true);
+ add_to_buff(&res,&pos,&csize, "\nSymbols=(", 10); add_int_to_buff(&res,&pos,&csize, n, false, 0);
+ add_to_buff(&res,&pos,&csize, "){", 2);
+ for(i = 0; i < n; i++, first++) {
+ add_int_to_buff(&res,&pos,&csize, first, false,0); add_to_buff(&res,&pos,&csize, ",", 1);
+ if(i && (i%16)== 0 && first < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n ", 4);
+ }
+ while(res[pos-1] == ',' || res[pos-1] < 33) pos --; add_to_buff(&res, &pos, &csize, "}\n", 2);
+ if(ss && ny) {
+ add_to_buff(&res,&pos,&csize, "ErrBars=(", 9); add_int_to_buff(&res,&pos,&csize, n, false, 0);
+ add_to_buff(&res,&pos,&csize, "){", 2);
+ for(i = 0; i < n; i++, first++) {
+ add_int_to_buff(&res,&pos,&csize, first,false,0); add_to_buff(&res,&pos,&csize, ",", 1);
+ if(i && (i%16)== 0 && first < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n ", 4);
+ }
+ while(res[pos-1] == ',' || res[pos-1] < 33) pos --; add_to_buff(&res, &pos, &csize, "}\n", 2);
+ add_to_buff(&res,&pos,&csize, "Labels=(", 8); add_int_to_buff(&res,&pos,&csize, n, false, 0);
+ add_to_buff(&res,&pos,&csize, "){", 2);
+ for(i = 0; i < n; i++, first++) {
+ add_int_to_buff(&res,&pos,&csize, first,false,0); add_to_buff(&res,&pos,&csize, ",", 1);
+ if(i && (i%16)== 0 && first < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n ", 4);
+ }
+ while(res[pos-1] == ',' || res[pos-1] < 33) pos --; add_to_buff(&res, &pos, &csize, "}\n", 2);
+ }
+ if(x_desc && x_desc[0]){
+ add_to_buff(&res,&pos,&csize, "x_info= \"", 9); add_to_buff(&res,&pos,&csize, x_desc, 0);
+ add_to_buff(&res,&pos,&csize, "\"\n", 2);
+ }
+ if(y_desc && y_desc[0]){
+ add_to_buff(&res,&pos,&csize, "y_info= \"", 9); add_to_buff(&res,&pos,&csize, y_desc, 0);
+ add_to_buff(&res,&pos,&csize, "\"\n", 2);
+ }
+ if(s_nam && s_nam[0]) {
+ add_to_buff(&res, &pos, &csize, "DataDesc=\"", 10);
+ add_to_buff(&res, &pos, &csize, s_nam, 0); add_to_buff(&res, &pos, &csize, "\"\n", 2);
+ }
+ return res;
+}
+
+static double contrasts_level = 95.0;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create a contrasts report for one way anova
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static void mk_contrasts(GraphObj* par, int type, double dx, double dy, double *y, double *ss, int *ny, int n,
+ char **names, double ci, double msw, double msdf)
+{
+ double tmp, tkd, pcorr, cx[10], *raw;
+ int i, j, k, l, c, df, *co, nco, cb;
+ char ctext[5], **contrasts;
+ char *headings[] = {"<i>Groups</i>", "<i>Mean</i>", "<i>Std. Dev.</i>", "<i>N</i>",
+ "<i>Contrasts</i><sup>1)</sup>"};
+
+ if(!par || !y || !ss || !ny || n < 2) return;
+ cx[0] = txtdef1.fSize*5.0; cx[1] = cx[0] + linsp1*5.0;
+ cx[2] = cx[1] + linsp1*5.0; cx[3] = cx[2] + linsp1*5.0;
+ cx[4] = cx[3] + linsp1*4.0; cx[5] = cx[4] + linsp1*3.0;
+ cx[6] = cx[5] + linsp1*4.0;
+
+ rep_DrawText(par, dx, dy, false, TXA_HLEFT, &txtdef1, "<b>Summary:</b>");
+ for(i = 0, dy += linsp2; i < 5; i++) { //column headers
+ c = (i == 4) ? TXA_HLEFT : TXA_HRIGHT;
+ rep_DrawText(par, cx[i+1], dy, false, c, &txtdef1, headings[i]);
+ }
+ mk_hr(par, cx[0], cx[6]+txtdef1.fSize*2.0, dy +linsp1);
+ if(type == 1 || type == 2) {
+ if(!(co = (int*)malloc(n*sizeof(int)))) return;
+ if(!(contrasts = (char**)malloc(n*sizeof(char*)))) return;
+ rlp_strcpy(ctext, 5, ", a");
+ for(i = df = 0, nco = n; i < n; i++) {
+ if(ny[i] > 0) df += (ny[i]-1);
+ co[i] = i;
+ contrasts[i] = (char*)calloc(50, sizeof(char));
+ }
+ tkd = qtukey(1.0-ci, 1.0, (double) n, (double)df, 1, 0);
+ for(i = 0; nco; ) {
+ for(j = 0; j < n; j++) {
+ switch(type) {
+ case 1: //Tukey-Kramer
+ tmp = tkd * sqrt((msw*(1.0/((double)ny[j]) + 1.0/((double)ny[co[i]])))/2.0);
+ break;
+ case 2: //Tukey's HSD
+ tmp = tkd * sqrt(msw/(ny[j] <= ny[co[i]] ? ny[j] : ny[co[i]]));
+ break;
+ }
+ if(fabs(y[j]-y[co[i]]) < tmp) {
+ cb = (int)strlen(contrasts[j]);
+ rlp_strcpy((contrasts[j])+cb, 50-cb, ctext);
+ }
+ }
+ for(j = nco = 0; j < n; j++) {
+ if(!(contrasts[j][0])) co[nco++] = j;
+ }
+ ctext[2]++;
+ }
+ }
+ else if(type == 10) {
+ if(!(co = (int*)malloc(n*sizeof(int)))) return;
+ if(!(contrasts = (char**)malloc(n*sizeof(char*)))) return;
+ if(!(raw = (double*)malloc((n*n-1)*sizeof(double))))return;
+ rlp_strcpy(ctext, 5, ", a");
+ for(i = df = 0, nco = n; i < n; i++) {
+ if(ny[i] > 0) df += (ny[i]-1);
+ co[i] = i;
+ contrasts[i] = (char*)calloc(50, sizeof(char));
+ }
+ for(i = k = 0; i < (n-1); i++) for(j = i+1; j < n; j++) {
+ raw[k++] = t_dist(fabs(0.5*(y[i]-y[j])/sqrt(msw/(ny[i]+ny[j]))), msdf, 0.0);
+ }
+ SortArray(k, raw);
+ for(i = 0; nco; ) {
+ for(j = 0; j < n; j++) {
+ tmp = t_dist(fabs(0.5*(y[j]-y[co[i]])/sqrt(msw/(ny[j]+ny[co[i]]))), msdf, 0.0);
+ for(l = 0; l < k && tmp > raw[l]; l++);
+ switch(type) {
+ case 10: //Dunn Sidak
+ pcorr = 1.0 - pow((1.0 - ci), 1.0 /(double(k-l)));
+ break;
+ }
+ if(tmp > pcorr || j == co[i]) {
+ cb = (int)strlen(contrasts[j]);
+ rlp_strcpy((contrasts[j])+cb, 50-cb, ctext);
+ }
+ }
+ for(j = nco = 0; j < n; j++) {
+ if(!(contrasts[j][0])) co[nco++] = j;
+ }
+ ctext[2]++;
+ }
+ free(raw);
+ }
+ else return;
+
+ for(i = 0, dy += linsp2; i < n; i++, dy +=linsp1) {
+ if(ny[i] > 1) tmp = sqrt(ss[i]/(ny[i]-1));
+ else tmp = 0.0;
+ rep_DrawText(par, cx[1], dy, false, TXA_HRIGHT, &txtdef1, names[i]);
+ dbl_to_str1(TmpTxt, 20, "%g", y[i]);
+ rep_DrawText(par, cx[2], dy, false, TXA_HRIGHT, &txtdef1, TmpTxt);
+ if(tmp > 0.0) {
+ dbl_to_str1(TmpTxt, 20, "%g", tmp);
+ rep_DrawText(par, cx[3], dy, false, TXA_HRIGHT, &txtdef1, TmpTxt);
+ }
+ if(ny[i] >1) {
+ dbl_to_str1(TmpTxt, 20, "%.0lf", (double)ny[i]);
+ rep_DrawText(par, cx[4], dy, false, TXA_HRIGHT, &txtdef1, TmpTxt);
+ }
+ rep_DrawText(par, cx[5], dy, false, TXA_HLEFT, &txtdef1, contrasts[i]+2);
+ }
+ mk_hr(par, cx[0], cx[6]+txtdef1.fSize*2.0, dy+txtdef1.fSize*0.2);
+ cb = dbl_to_str1(TmpTxt, 200, "<sup>1)</sup> Groups not sharing the same letter are different "
+ "on the %g%% level ", (1.0-ci)*100.0);
+ switch (type) {
+ case 1: //Tukey-Kramer
+ rlp_strcpy(TmpTxt+cb, TMP_TXT_SIZE - cb, "(Tukey-Kramer method)");
+ break;
+ case 2: //Tukey's HSD
+ rep_DrawText(par, cx[0]+ txtdef1.fSize*2.0, dy + txtdef2.fSize + linsp1, false,
+ TXA_HLEFT, &txtdef1, "(Tukey's honest significant difference)");
+ break;
+ case 10: //Dunn-Sidak
+ rep_DrawText(par, cx[0]+ txtdef1.fSize*2.0, dy + txtdef2.fSize + linsp1, false,
+ TXA_HLEFT, &txtdef1, "(sequential Dunn-Sidak method)");
+ break;
+ }
+ rep_DrawText(par, cx[0], dy += txtdef2.fSize , false, TXA_HLEFT, &txtdef1, TmpTxt);
+ for(i = 0; i < n; i++) free(contrasts[i]);
+ free(co); free(contrasts);
+ return;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// create a homogeneity of variances report for one way anova
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static void mk_v_homogeneity(GraphObj* par, DataObj *data, double *dx, double *dy, double *y, double *ss,
+ int *ny, int n, double **vals)
+{
+ int i;
+ double tmp, *sd, f1, f2, p1, p2;
+ char *txt_obj;
+ scaleINFO scale = {{0.0, 0.8}, {0.0, 0.8}, {0.0, 0.8}};
+ Graph *graph;
+
+ if(!par || !y || !ss || !ny || n < 2) return;
+ if(!(sd = (double*)malloc(n*sizeof(double)))) return;
+ rep_DrawText(par, *dx, *dy, false, TXA_HLEFT, &txtdef1, "<b>Homogeneity of Variances:</b>");
+ for(i = 0; i < n; i++) {
+ if(ny[i] > 1) sd[i] = sqrt(ss[i]/(ny[i]-1));
+ else sd[i] = 0.0;
+ if(i) {
+ if(dBounds.Xmax < y[i]) dBounds.Xmax = y[i];
+ if(dBounds.Xmin > y[i]) dBounds.Xmin = y[i];
+ if(dBounds.Ymax < sd[i]) dBounds.Ymax = sd[i];
+ if(dBounds.Ymin > sd[i]) dBounds.Ymin = sd[i];
+ }
+ else {
+ dBounds.Xmax = dBounds.Xmin = y[0];
+ dBounds.Ymax = dBounds.Ymin = sd[0];
+ }
+ }
+ if((graph = new Graph(par, data, 0L, 0)) && (txt_obj = mk_scatt(0, y, sd, 0L, ny, n,
+ "Variables", "Means", "Std.Dev."))){
+ graph->GRect.Xmax = defs.GetSize(SIZE_GRECT_BOTTOM)*0.8;
+ graph->GRect.Ymax *= 0.8;
+ graph->DRect.Xmin *= 0.8; graph->DRect.Ymax *= 0.8;
+ graph->DRect.Xmax = graph->GRect.Xmax - (txtdef1.fSize*2.0);
+ scale.sx.fx = par->GetSize(SIZE_GRECT_RIGHT) - txtdef1.fSize*5.0 - graph->GRect.Xmax*0.8 + graph->GRect.Xmin*0.8;
+ scale.sy.fx = *dy;
+ OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+ free(txt_obj);
+ graph->Command(CMD_SCALE, &scale, 0L);
+ if(!(par->Command(CMD_DROP_GRAPH, graph, 0L))) delete graph;
+ else graph->moveable = 0;
+ }
+ if(bartlett(n, ny, ss, &tmp)) {
+ rep_DrawText(par, *dx + txtdef1.fSize*2.0, *dy += (linsp2*1.5), false, TXA_HLEFT, &txtdef1, "Bartlett's test:");
+ i = dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "Chi<sup>2</sup> = %.2lf, ", tmp);
+ tmp = chi_dist(tmp, n-1, 0);
+ dbl_to_str1(TmpTxt+i, TMP_TXT_SIZE-i, tmp < 0.0001 ? (char*)"P < 0.0001" : (char*)"P = %.4lf", tmp);
+ rep_DrawText(par, *dx + txtdef1.fSize*3.0, *dy += linsp1, false, TXA_HLEFT, &txtdef1, TmpTxt);
+ }
+ if(levene(1, n, ny, y, vals, &f1, &p1) && levene(2, n, ny, y, vals, &f2, &p2) ) {
+ rep_DrawText(par, *dx + txtdef1.fSize*2.0, *dy += (linsp2*1.5), false, TXA_HLEFT, &txtdef1, "Levene's test:");
+ i = dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "using means: F = %.2lf, ", f1);
+ dbl_to_str1(TmpTxt+i, TMP_TXT_SIZE-i, tmp < 0.0001 ? (char*)"P < 0.0001" : (char*)"P = %.4lf", p1);
+ rep_DrawText(par, *dx + txtdef1.fSize*3.0, *dy += linsp1, false, TXA_HLEFT, &txtdef1, TmpTxt);
+ i = dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "using medians: F = %.2lf, ", f2);
+ dbl_to_str1(TmpTxt+i, TMP_TXT_SIZE-i, tmp < 0.0001 ? (char*)"P < 0.0001" : (char*)"P = %.4lf", p2);
+ rep_DrawText(par, *dx + txtdef1.fSize*3.0, *dy += linsp1, false, TXA_HLEFT, &txtdef1, TmpTxt);
+ }
+ free(sd);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// one way anova
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *AnovaDlg_Tmpl =
+ "1,+,,DEFAULT,PUSHBUTTON,-1,158,10,45,12\n"
+ ".,.,,,PUSHBUTTON,-2,158,25,45,12\n"
+ ".,,10,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "10,+,152,ISPARENT | CHECKED,SHEET,1,5,10,140,90\n"
+ ".,20,100,ISPARENT,SHEET,2,5,10,140,90\n"
+ "20,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+ "100,104,,ISRADIO,CHECKBOX,8,20,25,100,9\n"
+ "104,+,,,LTEXT,4,15,37,100,9\n"
+ ".,.,,ISRADIO,CHECKBOX,5,20,47,100,9\n"
+ ".,.,,ISRADIO,CHECKBOX,9,20,57,100,9\n"
+ ".,110,,ISRADIO,CHECKBOX,10,20,67,100,9\n"
+ "110,+,,,LTEXT,7,20,85,55,9\n"
+ ".,.,,,EDVAL1,6,80,85,25,10\n"
+ ".,,,,LTEXT,-10,107,85,10,9\n"
+ "152,+,,ISPARENT | CHECKED,GROUPBOX,3,12,30,128,65\n"
+ ".,.,,,LTEXT,0,25,45,60,8\n"
+ ".,.,,,RANGEINPUT,0,25,55,100,10\n"
+ ".,.,0,,PUSHBUTTON,-8,95,70,30,12\n"
+ ".,,,LASTOBJ,PUSHBUTTON,-9,60,70,35,12";
+
+void rep_anova(GraphObj *parent, DataObj *data)
+{
+ TabSHEET tab1 = {0, 45, 10, "Anova Input"};
+ TabSHEET tab2 = {45, 75, 10, "Tests"};
+ DlgInfo *AnovaDlg;
+ void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)" select one range for every variable ",
+ (void*)"Contrasts:", (void*)" Tukey-Kramer method", (void*)&contrasts_level, (void*)"significance level:",
+ (void*)" Homogeneity of Variances", (void*)" Tukey's honest sig. difference", (void*)" Dunn-Sidak"};
+ DlgRoot *Dlg;
+ void *hDlg;
+ double **cols = 0L, *csums=0L, mtot, *css=0L, cx, cy;
+ double **res_tab = 0L, ci;
+ int i, j, n, c, r, res, nc, ntot, currYR = 0, maxYR=0, ny, *ncols = 0L;;
+ bool bContinue = false, updateYR = true;
+ anyResult ares;
+ AccRange *rD =0L;
+ char **rd = 0L, **names, *txt_obj;
+ Graph *graph;
+ Page *page;
+
+ if(!parent || !data) return;
+ if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
+ TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return;
+ if(!(AnovaDlg = CompileDialog(AnovaDlg_Tmpl, dyndata))) return;
+ if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
+ for(i=j=0; i <= 1000; i +=100) if(TmpTxt[i])
+ rd[j++] = (char*)memdup(TmpTxt+i, ((int)strlen(TmpTxt+i))+2, 0); maxYR = j-1;
+ }
+ if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return;
+ if(!(Dlg = new DlgRoot(AnovaDlg, data)))return;
+ if(rd && rd[currYR] && *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
+ hDlg = CreateDlgWnd("Single-Classification Anova", 50, 50, 420, 240, Dlg, 0x4L);
+ do {
+ if(updateYR) {
+ if(currYR >0) Dlg->ShowItem(156, true);
+ else Dlg->ShowItem(156, false);
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "variable # %d/%d", currYR+1, maxYR+1);
+#else
+ sprintf(TmpTxt,"variable # %d/%d", currYR+1, maxYR+1);
+#endif
+ Dlg->SetText(153, TmpTxt);
+ updateYR = false;
+ }
+ 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 155: case 156:
+ res = com_StackDlg(res, Dlg, 0L, 0L, &rd, &currYR,
+ &rD, &bContinue, &ny, &maxYR, &updateYR);
+ break;
+ }
+ }while (res < 0);
+ if(res == 1 && (res_tab = (double**)calloc(3, sizeof(double*)))
+ && (res_tab[0] = (double*) malloc(5*sizeof(double)))
+ && (res_tab[1] = (double*) malloc(5*sizeof(double)))
+ && (res_tab[2] = (double*) malloc(5*sizeof(double)))
+ && (cols = (double**)calloc(maxYR+1, sizeof(double*)))
+ && (names = (char**)calloc(maxYR+1, sizeof(char*)))
+ && (ncols = (int*)calloc(maxYR+1, sizeof(int)))) {
+ rep_init(); if(rD) delete rD; rD = 0L;
+ if(Dlg->GetValue(111, &ci)) {
+ contrasts_level = ci; ci = 1.0-(ci/100.0);
+ }
+ dBounds.Ymin = HUGE_VAL; dBounds.Ymax = -HUGE_VAL;
+ // get data into two dimensional array
+ for(nc = maxYR+1, i = ntot = 0, mtot = 0.0; i < nc; i++) {
+ if((rD = new AccRange(rd[i])) && (n = rD->CountItems()) && (cols[i] = (double*)malloc(n*sizeof(double)))) {
+ names[i] = rD->RangeDesc(data, 1);
+ for(n = 0, rD->GetFirst(&c, &r); rD->GetNext(&c, &r); ) {
+ if(data->GetResult(&ares, r, c, false) && ares.type == ET_VALUE) {
+ if(ares.value < dBounds.Ymin) dBounds.Ymin = ares.value;
+ if(ares.value > dBounds.Ymax) dBounds.Ymax = ares.value;
+ cols[i][n++] = ares.value;
+ }
+ }
+ ncols[i] = n; ntot += n;
+ delete(rD); rD = 0L;
+ }
+ if(!names[i] && (names[i] = (char*)malloc(20*sizeof(char)))){
+#ifdef USE_WIN_SECURE
+ sprintf_s(names[i], 20, "Group %d", i+1);
+#else
+ sprintf(names[i], "Group %d", i+1);
+#endif
+ }
+ }
+ // check for unique names
+ for(i = 0; i < (nc-1); i++) for(j = i+1; j < nc; j++) {
+ if(!strcmp(names[i], names[j])) {
+ names[i] = (char*) realloc(names[i], 20 *sizeof(char));
+ names[j] = (char*) realloc(names[j], 20 *sizeof(char));
+#ifdef USE_WIN_SECURE
+ sprintf_s(names[i], 20, "Group %d", i+1); sprintf_s(names[j], 20, "Group %d", j+1);
+#else
+ sprintf(names[i], "Group %d", i+1); sprintf(names[j], "Group %d", j+1);
+#endif
+ }
+ }
+
+ if(do_anova1(nc, ncols, cols, res_tab, &mtot, &csums, &css)){
+ dBounds.Xmin = 0.5; dBounds.Xmax = ((double)nc)+0.5;
+ page = new Page(parent, data);
+ mk_header(page, "<b>Single-Classification ANOVA</b>", data);
+ if((graph = new Graph(parent, data, 0L, 0)) && (txt_obj = mk_scatt(0, 0L, csums, css, ncols, nc, "Mean", "Groups", "Means <u>+</u> S.D."))){
+ OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+ if(LastOpenGO && LastOpenGO->Id == GO_PLOTSCATT) {
+ if(((PlotScatt*)LastOpenGO)->x_tv = new TextValue()){
+ for(i = 0; i < nc; i++) ((PlotScatt*)LastOpenGO)->x_tv->GetValue(names[i]);
+ }
+ }
+ free(txt_obj); graph->moveable = 0;
+ graph->GRect.Xmin += (txtdef1.fSize*5.0); graph->GRect.Xmax += (txtdef1.fSize*5.0);
+ graph->GRect.Ymin += (txtdef1.fSize*10.0); graph->GRect.Ymax += (txtdef1.fSize*10.0);
+ page->Command(CMD_DROP_GRAPH, graph, 0L);
+ }
+ cx = graph->GRect.Xmin; cy = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*2.0;
+ rep_DrawText(page, cx, cy, false, TXA_HLEFT, &txtdef1, "<b>Anova:</b>");
+ cy = mk_table(page, cx, cy+txtdef2.fSize, 1, res_tab)+txtdef2.fSize;
+ if(Dlg->GetCheck(100)) mk_v_homogeneity(page, data, &cx, &cy, csums, css, ncols, nc, cols);
+ else if(Dlg->GetCheck(105)) mk_contrasts(page, 1, cx, cy, csums, css, ncols, nc, names, ci, res_tab[1][2], res_tab[1][0]);
+ else if(Dlg->GetCheck(106)) mk_contrasts(page, 2, cx, cy, csums, css, ncols, nc, names, ci, res_tab[1][2], res_tab[1][0]);
+ else if(Dlg->GetCheck(107)) mk_contrasts(page, 10, cx, cy, csums, css, ncols, nc, names, ci, res_tab[1][2], res_tab[1][0]);
+ if(ntot > (nc<<1) && nc >1 && parent->Command(CMD_DROP_GRAPH, page, 0L));
+ else {
+ delete page;
+ InfoBox("No or insufficient\ndata for ANOVA\n");
+ }
+ }
+ for(i = 0; i < nc; i++){
+ if(cols[i]) free(cols[i]); if(names[i]) free(names[i]);
+ }
+ for(i = 0; i < 3; i++) if(res_tab[i]) free(res_tab[i]);
+ free(cols); free(ncols); free(names);
+ free(res_tab); if(css)free(css); if(csums)free(csums);
+ }
+ if(rD) delete rD; CloseDlgWnd(hDlg);
+ delete Dlg; free(AnovaDlg);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Breakdown One Way Anova
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *BdAnovDlg_Tmpl =
+ "1,+,,DEFAULT,PUSHBUTTON,-1,158,10,45,12\n"
+ ".,.,,,PUSHBUTTON,-2,158,25,45,12\n"
+ ".,,10,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "10,+,150,ISPARENT | CHECKED,SHEET,1,5,10,140,90\n"
+ ".,20,100,ISPARENT,SHEET,2,5,10,140,90\n"
+ "20,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+ "100,104,,ISRADIO,CHECKBOX,8,20,25,100,9\n"
+ "104,+,,,LTEXT,4,15,37,100,9\n"
+ ".,.,,ISRADIO,CHECKBOX,5,20,47,100,9\n"
+ ".,.,,ISRADIO,CHECKBOX,9,20,57,100,9\n"
+ ".,110,,ISRADIO,CHECKBOX,10,20,67,100,9\n"
+ "110,+,,,LTEXT,7,20,85,55,9\n"
+ ".,.,,,EDVAL1,6,80,85,25,10\n"
+ ".,,,,LTEXT,-10,107,85,10,9\n"
+ "150,+,,,LTEXT,3,20,32,100,9\n"
+ ".,.,,,RANGEINPUT,-16,20,44,110,10\n"
+ ".,.,,,LTEXT,11,20,60,100,9\n"
+ ".,,,LASTOBJ,RANGEINPUT,-17,20,72,110,10";
+
+void rep_bdanova(GraphObj *parent, DataObj *data)
+{
+ TabSHEET tab1 = {0, 45, 10, "Anova Input"};
+ TabSHEET tab2 = {45, 75, 10, "Tests"};
+ DlgInfo *AnovaDlg;
+ void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)"range for grouping variable",
+ (void*)"Contrasts:", (void*)" Tukey-Kramer method", (void*)&contrasts_level, (void*)"significance level:",
+ (void*)" Homogeneity of Variances", (void*)" Tukey's honest sig. difference", (void*)" Dunn-Sidak",
+ (void*)"range for values"};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, l, nc, nv, res, gr, gc, dr, dc;
+ int *ncols = 0L;
+ double cv, mv, ci, **cols = 0L, *csums=0L, mtot, *css=0L;
+ double **res_tab = 0L, cx, cy;
+ anyResult gres, dres;
+ AccRange *rG = 0L, *rD = 0L;
+ TextValue *tv = 0L;
+ char *txt_obj, **names;
+ bool bContinue = false;
+ Graph *graph;
+ Page *page;
+
+ if(!UseRangeMark(data, 2, TmpTxt+100, TmpTxt+200, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L)) return;
+ if(!(AnovaDlg = CompileDialog(BdAnovDlg_Tmpl, dyndata))) return;
+ if(!(Dlg = new DlgRoot(AnovaDlg, data)))return;
+ hDlg = CreateDlgWnd("Breakdown One Way Anova", 50, 50, 420, 250, Dlg, 0x4L);
+ 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 1:
+ if(!Dlg->GetText(151, TmpTxt+100, 100) || !Dlg->GetText(153, TmpTxt+200, 100)) {
+ ErrorBox("Invalid Ranges!\nBoth ranges must be defined\nand must be of equal size.\n");
+ res = -1; bContinue = true;
+ }
+ else if(!(rG = new AccRange(TmpTxt+100)) || !(rD = new AccRange(TmpTxt+200))
+ || (l = rG->CountItems()) < 3 || (l = rD->CountItems()) < 3) {
+ ErrorBox("Insufficient Data!\nCheck data ranges.\n");
+ res = -1; bContinue = true;
+ }
+ else for(l = nv = 0, mv = 0.0; l < 2 && rG->GetFirst(&gc, &gr) && rD->GetFirst(&dc, &dr); l++) {
+ if(l) {
+ dBounds.Ymin = HUGE_VAL; dBounds.Ymax = -HUGE_VAL;
+ nc = (int)(mv);
+ cols = (double**)calloc(nc, sizeof(double*));
+ ncols = (int*)calloc(nc, sizeof(int));
+ if(cols && ncols) for(i = 0; i < nc; i++) cols[i] = (double*) malloc(nv * sizeof(double));
+ while(rG->GetNext(&gc, &gr) && rD->GetNext(&dc, &dr)) {
+ if(data->GetResult(&gres, gr, gc, false) && data->GetResult(&dres, dr, dc, false)
+ && dres.type == ET_VALUE) {
+ switch (gres.type) {
+ case ET_TEXT:
+ cv = tv->GetValue(gres.text); break;
+ default:
+ TranslateResult(&gres);
+ cv = tv->GetValue(gres.text); break;
+ }
+ i = (int)(cv);
+ if(dres.value < dBounds.Ymin) dBounds.Ymin = dres.value;
+ if(dres.value > dBounds.Ymax) dBounds.Ymax = dres.value;
+ if(cols && ncols && cols[i-1]) cols[i-1][ncols[i-1]++] = dres.value;
+ }
+ }
+ }
+ else if(tv = new TextValue()) {
+ while(rG->GetNext(&gc, &gr) && rD->GetNext(&dc, &dr)) {
+ if(data->GetResult(&gres, gr, gc, false) && data->GetResult(&dres, dr, dc, false)
+ && dres.type == ET_VALUE) {
+ switch (gres.type) {
+ case ET_TEXT:
+ cv = tv->GetValue(gres.text); break;
+ default:
+ TranslateResult(&gres);
+ cv = tv->GetValue(gres.text); break;
+ }
+ if(mv < cv) mv = cv; nv++;
+ }
+ }
+ }
+ }
+ }
+ }while (res < 0);
+ if(res == 1 && tv && cols && ncols && (res_tab = (double**)calloc(3, sizeof(double*)))
+ && (res_tab[0] = (double*) malloc(5*sizeof(double)))
+ && (res_tab[1] = (double*) malloc(5*sizeof(double)))
+ && (res_tab[2] = (double*) malloc(5*sizeof(double)))
+ && (names = (char**)malloc(nc*sizeof(char*)))) {
+ if(Dlg->GetValue(111, &ci)) {
+ contrasts_level = ci; ci = 1.0-(ci/100.0);
+ }
+ else ci = 0.05; rep_init();
+ for(i = 0; i < nc; i++) tv->GetItem(i, &names[i], &cv);
+ if(rD) delete rD; rD = 0L;
+ if(do_anova1(nc, ncols, cols, res_tab, &mtot, &csums, &css)){
+ dBounds.Xmin = 0.5; dBounds.Xmax = ((double)nc)+0.5;
+ page = new Page(parent, data);
+ mk_header(page, "<b>Breakdown and Single-Classification ANOVA</b>", data);
+ if((graph = new Graph(parent, data, 0L, 0)) && (txt_obj = mk_scatt(0, 0L, csums, css, ncols, nc, "Mean", "Groups", "Means <u>+</u> S.D."))){
+ OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+ if(LastOpenGO && LastOpenGO->Id == GO_PLOTSCATT) {
+ ((PlotScatt*)LastOpenGO)->x_tv = tv;
+ }
+ else delete tv;
+ free(txt_obj); graph->moveable = 0;
+ graph->GRect.Xmin += (txtdef1.fSize*5.0); graph->GRect.Xmax += (txtdef1.fSize*5.0);
+ graph->GRect.Ymin += (txtdef1.fSize*10.0); graph->GRect.Ymax += (txtdef1.fSize*10.0);
+ page->Command(CMD_DROP_GRAPH, graph, 0L);
+ }
+ cx = graph->GRect.Xmin; cy = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*2.0;
+ rep_DrawText(page, cx, cy, false, TXA_HLEFT, &txtdef1, "<b>Anova:</b>");
+ cy = mk_table(page, cx, cy+txtdef2.fSize, 1, res_tab)+txtdef2.fSize;
+ if(Dlg->GetCheck(100)) mk_v_homogeneity(page, data, &cx, &cy, csums, css, ncols, nc, cols);
+ else if(Dlg->GetCheck(105)) mk_contrasts(page, 1, cx, cy, csums, css, ncols, nc, names, ci, res_tab[1][2], res_tab[1][0]);
+ else if(Dlg->GetCheck(106)) mk_contrasts(page, 2, cx, cy, csums, css, ncols, nc, names, ci, res_tab[1][2], res_tab[1][0]);
+ else if(Dlg->GetCheck(107)) mk_contrasts(page, 10, cx, cy, csums, css, ncols, nc, names, ci, res_tab[1][2], res_tab[1][0]);
+ if(nv > (nc<<1) && nc >1 && parent->Command(CMD_DROP_GRAPH, page, 0L));
+ else {
+ delete page;
+ InfoBox("No or insufficient\ndata for ANOVA\n");
+ }
+ }
+ for(i = 0; i < nc; i++) if(cols[i]) free(cols[i]);
+ for(i = 0; i < 3; i++) if(res_tab[i]) free(res_tab[i]);
+ free(cols); free(ncols); free(names);
+ free(res_tab); if(css)free(css); if(csums)free(csums);
+ }
+
+ if(rD) delete rD; if(rG) delete rG;
+ CloseDlgWnd(hDlg);
+ delete Dlg; free(AnovaDlg);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Parametric two way anova
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *TwAnov_DlgTmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,-1,148,10,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,148,25,45,12\n"
+ "3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "4,10,100,ISPARENT | CHECKED,SHEET,1,5,10,130,80\n"
+ "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+ "100,+,,,LTEXT,2,10,30,60,8\n"
+ ".,.,,,RANGEINPUT,-15,20,40,100,10\n"
+ ".,,,LASTOBJ,CHECKBOX,3,20,60,100,9";
+
+void rep_twanova(GraphObj *parent, DataObj *data)
+{
+ TabSHEET tab1 = {0, 40, 10, "Input Data"};
+ DlgInfo *TwAnovDlg;
+ void *dyndata[] = {(void*)&tab1, (void*)"rectangular range for variables",
+ (void*)" column/row headers present"};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, hc, hr, mr, mc, nr, nc, c, r, res, *nvr=0L, *nvc=0L;
+ bool bContinue = false;
+ char *mrk, *txt_obj, **cnames = 0L, **rnames = 0L;
+ double gm, ssc, ssr, sse, tmp, cx, cy, dmin, dmax;
+ double **vals = 0L, *cs = 0L, *rs = 0L, **res_tab = 0L, *c_ss, *r_ss, *c_m, *r_m, *abc;
+ RECT rec;
+ scaleINFO scale = {{0.0, 0.7}, {0.0, 0.7}, {0.0, 0.7}};
+ AccRange *rD =0L, *rDesc;
+ anyResult ares;
+ Graph *graph;
+ Page *page;
+
+ if(!parent || !data) return;
+ if(!(TwAnovDlg = CompileDialog(TwAnov_DlgTmpl, dyndata))) return;
+ if(data->Command(CMD_GETMARK, &mrk, 0L))rlp_strcpy(TmpTxt, TMP_TXT_SIZE, mrk);
+ else {
+ data->ValueRec(&rec);
+ rlp_strcpy(TmpTxt, 100, mkRangeRef(rec.top, rec.left, rec.bottom, rec.right));
+ }
+ if(!(Dlg = new DlgRoot(TwAnovDlg, data)))return;
+ hDlg = CreateDlgWnd("Two-Way Anova", 50, 50, 420, 220, Dlg, 0x4L);
+ 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 1:
+ if(Dlg->GetText(101, TmpTxt+200, TMP_TXT_SIZE-200) &&(rD = new AccRange(TmpTxt+200))&& rD->BoundRec(&rec)
+ && (vals = (double**)calloc(rec.bottom - rec.top +1, sizeof(double*)))) {
+ nc = rec.right-rec.left+1; nr = rec.bottom-rec.top+1;
+ nvc = (int*)calloc(nc, sizeof(int)); nvr = (int*)calloc(nr, sizeof(int));
+ dmin = HUGE_VAL; dmax = -HUGE_VAL;
+ if(Dlg->GetCheck(102)) hr = hc = 1;
+ else hr = hc = 0;
+ for(i = rec.top+hr; i <= rec.bottom; i++) vals[i-rec.top] = (double*)calloc(nc, sizeof(double));
+ for(c = rec.left+hc; c <= rec.right; c++) for(r = rec.top; r <= rec.bottom; r++) {
+ if(data->GetResult(&ares, r, c,false) && ares.type == ET_VALUE){
+ nvc[c-rec.left]++; nvr[r-rec.top]++;
+ if(vals[r-rec.top]) vals[r-rec.top][c-rec.left] = ares.value;
+ if(ares.value > dmax) dmax = ares.value;
+ if(ares.value < dmin) dmin = ares.value;
+ }
+ }
+ while(!nvc[nc-1] && nc > 1) nc--;
+ while(!nvr[nr-1] && nr > 1) nr--;
+ for(i = 1, mr = nvr[0]; i < nr; i++)if(nvr[i] > mr) mr = nvr[i];
+ for(i = 1, mc = nvc[0]; i < nc; i++)if(nvc[i] > mc) mc = nvc[i];
+ for( ; nvr[hr] < mr && hr < nr; hr++);
+ for( ; nvc[hc] < mc && hc < nc; hc++);
+ for(i = hr; i < nr; i++) if(nvr[i] < mr) res = -1;
+ for(i = hc; i < nc; i++) if(nvc[i] < mc) res = -1;
+ for(i = 0, mr = nc-hc; i < nr; i++) nvr[i] = mr;
+ for(i = 0, mc = nr-hr; i < nc; i++) nvc[i] = mc;
+ if(res < 0 || mr < 2 || mc < 2) {
+ InfoBox("There are missing data!");
+ for(i = 0; i < nc; i++) if(vals[i]) free(vals[i]);
+ free(vals); free(nvr); free(nvc);
+ nvr = nvc = 0L; vals = 0L;
+ bContinue = true;
+ }
+ delete rD;
+ }
+ break;
+ default:
+ nr = nc = 0; break;
+ }
+ }while (res < 0);
+ if(res == 1 && (vals) && (cs = (double*)calloc(nc, sizeof(double)))
+ && (rs = (double*)calloc(nr, sizeof(double)))
+ && (c_ss = (double*)calloc(nc, sizeof(double)))
+ && (r_ss = (double*)calloc(nr, sizeof(double)))
+ && (c_m = (double*)calloc(nc, sizeof(double)))
+ && (r_m = (double*)calloc(nr, sizeof(double)))
+ && (abc = (double*)calloc(nr > nc ? nr : nc, sizeof(double)))
+ && (cnames = (char**)calloc(rec.right-rec.left+1, sizeof(char*)))
+ && (rnames = (char**)calloc(rec.bottom-rec.top+1, sizeof(char*)))
+ && (res_tab = (double**)calloc(4, sizeof(double*)))
+ && (res_tab[0] = (double*)calloc(5, sizeof(double)))
+ && (res_tab[1] = (double*)calloc(5, sizeof(double)))
+ && (res_tab[2] = (double*)calloc(5, sizeof(double)))
+ && (res_tab[3] = (double*)calloc(5, sizeof(double)))){
+ //get column and row descriptors
+ for(c = hc; c < nc; c++) {
+ if(rDesc = new AccRange(mkRangeRef(rec.top, rec.left+c, rec.bottom, rec.left+c))) {
+ cnames[c-hc] = rDesc->RangeDesc(data, hr ? 4 : 1);
+ delete rDesc;
+ }
+ }
+ for(r = hr; r < nr; r++) {
+ if(rDesc = new AccRange(mkRangeRef(rec.top+r, rec.left, rec.top+r, rec.right))) {
+ rnames[r-hr] = rDesc->RangeDesc(data, hc ? 4 : 1);
+ delete rDesc;
+ }
+ }
+ //grand mean
+ for(c = hc, gm = 0.0; c < nc; c++) for(r = hr; r < nr; r++) {
+ gm += vals[r][c]; cs[c] += vals[r][c]; rs[r] += vals[r][c];
+ }
+ gm /= ((double)((nc-hc)*(nr-hr)));
+ //anova stats
+ for(c = hc; c < nc; c++) cs[c] /= ((double)nvc[c]);
+ for(c = hc, ssc = 0.0; c < nc; c++) ssc += ((tmp = cs[c]-gm)*tmp);
+ for(r = hr; r < nr; r++) rs[r] /= ((double)nvr[r]);
+ for(r = hr, ssr = 0.0; r < nr; r++) ssr += ((tmp = rs[r]-gm)*tmp);
+ ssc *= ((double)(nr-hr)); ssr *= ((double)(nc-hc));
+ for(c = hc, sse = 0.0; c < nc; c++) for(r = hr; r < nr; r++) {
+ sse += ((tmp = vals[r][c]-cs[c]-rs[r]+gm)*tmp);
+ }
+ for(c = hc; c < nc; c++) for(r = hr; r < nr; r++) {
+ c_m[c-hc] += vals[r][c]; r_m[r-hr] += vals[r][c];
+ }
+ for(c = hc; c < nc; c++) c_m[c-hc] /= ((double)(nvc[c]));
+ for(r = hr; r < nr; r++) r_m[r-hr] /= ((double)(nvr[r]));
+ for(c = hc; c < nc; c++) for(r = hr; r < nr; r++) {
+ c_ss[c-hc] += ((tmp = vals[r][c]-c_m[c-hc])*tmp);
+ r_ss[r-hr] += ((tmp = vals[r][c]-r_m[r-hr])*tmp);
+ }
+ //prepare table for report
+ res_tab[0][0] = (double)(nc-hc-1); res_tab[1][0] = (double)(nr-hr-1);
+ res_tab[2][0] = res_tab[0][0] * res_tab[1][0];
+ res_tab[3][0] = res_tab[0][0] + res_tab[1][0] + res_tab[2][0];
+ res_tab[0][1] = ssc; res_tab[0][2] = ssc/res_tab[0][0];
+ res_tab[1][1] = ssr; res_tab[1][2] = ssr/res_tab[1][0];
+ res_tab[2][1] = sse; res_tab[2][2] = sse/res_tab[2][0];
+ res_tab[3][1] = ssc + ssr + sse;
+ res_tab[0][3] = res_tab[0][2] / res_tab[2][2];
+ res_tab[1][3] = res_tab[1][2] / res_tab[2][2];
+ res_tab[0][4] = f_dist(res_tab[0][3], res_tab[0][0], res_tab[2][0]);
+ res_tab[1][4] = f_dist(res_tab[1][3], res_tab[1][0], res_tab[2][0]);
+ rep_init();
+ page = new Page(parent, data);
+ mk_header(page, "<b>Two-Way ANOVA</b>", data);
+ cx = txtdef1.fSize*5.0; cy = txtdef1.fSize*10.0;
+ dBounds.Xmin = 0.5; dBounds.Xmax = ((double)(nc-hc))+0.5;
+ dBounds.Ymin = dmin; dBounds.Ymax = dmax;
+ //plot column results
+ if((graph = new Graph(parent, data, 0L, 0)) && (txt_obj = mk_scatt(0, 0L, c_m, c_ss, nvc+hc, nc-hc, "Mean", "Columns", "Means <u>+</u> S.D."))){
+ OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+ if(LastOpenGO && LastOpenGO->Id == GO_PLOTSCATT) {
+ if(((PlotScatt*)LastOpenGO)->x_tv = new TextValue()){
+ for(i = 0; i < (nc-hc); i++) ((PlotScatt*)LastOpenGO)->x_tv->GetValue(cnames[i]);
+ }
+ }
+ free(txt_obj); graph->moveable = 0;
+ graph->DRect.Xmax = graph->DRect.Xmin + graph->DRect.Ymax - graph->DRect.Ymin;
+ graph->GRect.Xmax = graph->GRect.Xmin + graph->GRect.Ymax - graph->GRect.Ymin;
+ scale.sx.fx = txtdef1.fSize*5.0; scale.sy.fx = txtdef1.fSize*10.0;
+ graph->Command(CMD_SCALE, &scale, 0L);
+ page->Command(CMD_DROP_GRAPH, graph, 0L);
+ cx = graph->GetSize(SIZE_GRECT_RIGHT)+txtdef1.fSize;
+ cy = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*2.0;
+ }
+ dBounds.Ymin = 0.5; dBounds.Ymax = ((double)(nr-hr))+0.5;
+ dBounds.Xmin = dmin; dBounds.Xmax = dmax;
+ for(r = 0, tmp = 1.0; r < (nr-hr); r++, tmp += 1.0) abc[r] = tmp;
+ //plot row results
+ if((graph = new Graph(parent, data, 0L, 0x10)) && (txt_obj = mk_scatt(0x10, r_m, abc, r_ss, nvr+hr, nr-hr, "Mean", "Means <u>+</u> S.D.", "Rows"))){
+ OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+ if(LastOpenGO && LastOpenGO->Id == GO_PLOTSCATT) {
+ if(((PlotScatt*)LastOpenGO)->y_tv = new TextValue()){
+ for(i = 0; i < nr; i++) ((PlotScatt*)LastOpenGO)->y_tv->GetValue(rnames[i]);
+ }
+ }
+ free(txt_obj); graph->moveable = 0;
+ graph->DRect.Xmax = graph->DRect.Xmin + graph->DRect.Ymax - graph->DRect.Ymin;
+ graph->GRect.Xmax = graph->GRect.Xmin + graph->GRect.Ymax - graph->GRect.Ymin;
+ scale.sx.fx = cx; scale.sy.fx = txtdef1.fSize*10.0;
+ graph->Command(CMD_SCALE, &scale, 0L);
+ page->Command(CMD_DROP_GRAPH, graph, 0L);
+ }
+ cx = txtdef1.fSize*5.0;
+ //draw anova table and clean up
+ rep_DrawText(page, cx, cy, false, TXA_HLEFT, &txtdef1, "<b>Anova:</b>");
+ cy = mk_table(page, cx, cy+txtdef2.fSize, 4, res_tab)+txtdef2.fSize;
+ if(!(parent->Command(CMD_DROP_GRAPH, page, 0L))) delete page;
+ free(c_ss); free(r_ss);
+ free(c_m); free(r_m);
+ }
+ if(vals) {
+ for(i = 0; i < nc; i++) if(vals[i]) free(vals[i]);
+ free(vals);
+ }
+ if(res_tab) {
+ for(i = 0; i < 4; i++) if(res_tab[i]) free(res_tab[i]);
+ free(res_tab);
+ }
+ if (cnames) {
+ for(c = 0; c < (rec.right-rec.left+1); c++) if(cnames[c]) free(cnames[c]);
+ free(cnames);
+ }
+ if (rnames) {
+ for(r = 0; r < (rec.bottom-rec.top+1); r++) if(rnames[r]) free(rnames[r]);
+ free(rnames);
+ }
+ if(nvr) free(nvr); if(nvc) free(nvc);
+ CloseDlgWnd(hDlg); delete Dlg; free(TwAnovDlg);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Friedman's non-parametric two way anova
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void rep_fmanova(GraphObj *parent, DataObj *data)
+{
+ TabSHEET tab1 = {0, 40, 10, "Input Data"};
+ DlgInfo *FmAnovDlg;
+ void *dyndata[] = {(void*)&tab1, (void*)"rectangular range for variables",
+ (void*)" column/row headers present"};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, hc, hr, mr, mc, nr, nc, c, r, res, *nvr=0L, *nvc=0L;
+ bool bContinue = false;
+ char *mrk, *txt_obj, **cnames = 0L, **rnames = 0L;
+ double tmp, cx, cy, dmin, dmax, cchi2, rchi2, prob;
+ double **vals = 0L, **rows = 0L, **cols = 0L, *idx, *cs = 0L, *rs = 0L;
+ double *m, *b1, *b2, *w1, *w2, *trc;
+ RECT rec;
+ scaleINFO scale = {{0.0, 0.7}, {0.0, 0.7}, {0.0, 0.7}};
+ AccRange *rD =0L, *rDesc;
+ anyResult ares;
+ Graph *graph;
+ Page *page;
+
+ if(!parent || !data) return;
+ if(!(FmAnovDlg = CompileDialog(TwAnov_DlgTmpl, dyndata))) return;
+ if(data->Command(CMD_GETMARK, &mrk, 0L))rlp_strcpy(TmpTxt, TMP_TXT_SIZE, mrk);
+ else {
+ data->ValueRec(&rec);
+ rlp_strcpy(TmpTxt, 100, mkRangeRef(rec.top, rec.left, rec.bottom, rec.right));
+ }
+ if(!(Dlg = new DlgRoot(FmAnovDlg, data)))return;
+ hDlg = CreateDlgWnd("Friedman's Non-Parametric Two-Way Anova", 50, 50, 420, 220, Dlg, 0x4L);
+ 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 1:
+ if(Dlg->GetText(101, TmpTxt+200, TMP_TXT_SIZE-200) &&(rD = new AccRange(TmpTxt+200))&& rD->BoundRec(&rec)
+ && (vals = (double**)calloc(rec.bottom - rec.top +1, sizeof(double*)))) {
+ nc = rec.right-rec.left+1; nr = rec.bottom-rec.top+1;
+ nvc = (int*)calloc(nc, sizeof(int)); nvr = (int*)calloc(nr, sizeof(int));
+ dmin = HUGE_VAL; dmax = -HUGE_VAL;
+ if(Dlg->GetCheck(102)) hr = hc = 1;
+ else hr = hc = 0;
+ for(i = rec.top+hr; i <= rec.bottom; i++) vals[i-rec.top] = (double*)calloc(nc, sizeof(double));
+ for(c = rec.left+hc; c <= rec.right; c++) for(r = rec.top; r <= rec.bottom; r++) {
+ if(data->GetResult(&ares, r, c,false) && ares.type == ET_VALUE){
+ nvc[c-rec.left]++; nvr[r-rec.top]++;
+ if(vals[r-rec.top]) vals[r-rec.top][c-rec.left] = ares.value;
+ if(ares.value > dmax) dmax = ares.value;
+ if(ares.value < dmin) dmin = ares.value;
+ }
+ }
+ while(!nvc[nc-1] && nc > 1) nc--;
+ while(!nvr[nr-1] && nr > 1) nr--;
+ for(i = 1, mr = nvr[0]; i < nr; i++)if(nvr[i] > mr) mr = nvr[i];
+ for(i = 1, mc = nvc[0]; i < nc; i++)if(nvc[i] > mc) mc = nvc[i];
+ for( ; nvr[hr] < mr && hr < nr; hr++);
+ for( ; nvc[hc] < mc && hc < nc; hc++);
+ for(i = hr; i < nr; i++) if(nvr[i] < mr) res = -1;
+ for(i = hc; i < nc; i++) if(nvc[i] < mc) res = -1;
+ for(i = 0, mr = nc-hc; i < nr; i++) nvr[i] = mr;
+ for(i = 0, mc = nr-hr; i < nc; i++) nvc[i] = mc;
+ if(res < 0 || mr < 2 || mc < 2) {
+ InfoBox("There are missing data!");
+ for(i = 0; i < nc; i++) if(vals[i]) free(vals[i]);
+ free(vals); free(nvr); free(nvc);
+ nvr = nvc = 0L; vals = 0L;
+ bContinue = true;
+ }
+ delete rD;
+ }
+ break;
+ default:
+ nr = nc = 0; break;
+ }
+ }while (res < 0);
+ if(res == 1&& (vals) && (cs = (double*)calloc(nr, sizeof(double)))
+ && (rs = (double*)calloc(nc, sizeof(double)))
+ && (cols = (double**)calloc(nc, sizeof(double*)))
+ && (rows = (double**)calloc(nr, sizeof(double*)))
+ && (cnames = (char**)calloc(rec.right-rec.left+1, sizeof(char*)))
+ && (rnames = (char**)calloc(rec.bottom-rec.top+1, sizeof(char*)))
+ && (idx = (double*)malloc((nr > nc ? nr:nc)*sizeof(double)))
+ && (m = (double*)malloc((nr > nc ? nr:nc)*sizeof(double)))
+ && (b1 = (double*)malloc((nr > nc ? nr:nc)*sizeof(double)))
+ && (b2 = (double*)malloc((nr > nc ? nr:nc)*sizeof(double)))
+ && (w1 = (double*)malloc((nr > nc ? nr:nc)*sizeof(double)))
+ && (w2 = (double*)malloc((nr > nc ? nr:nc)*sizeof(double)))
+ && (trc = (double*)malloc((nr > nc ? nr:nc)*sizeof(double)))) {
+ //get column and row descriptors
+ for(c = hc; c < nc; c++) {
+ if(rDesc = new AccRange(mkRangeRef(rec.top, rec.left+c, rec.bottom, rec.left+c))) {
+ cnames[c-hc] = rDesc->RangeDesc(data, hr ? 4 : 1);
+ delete rDesc;
+ }
+ }
+ for(r = hr; r < nr; r++) {
+ if(rDesc = new AccRange(mkRangeRef(rec.top+r, rec.left, rec.top+r, rec.right))) {
+ rnames[r-hr] = rDesc->RangeDesc(data, hc ? 4 : 1);
+ delete rDesc;
+ }
+ }
+ //create ranks
+ for(c = hc; c < nc; c++) if(cols[c-hc] = (double*)calloc(nr, sizeof(double))) {
+ for(r = hr; r < nr; r++) {
+ cols[c-hc][r-hr] = vals[r][c]; idx[r-hr] = (double)(r-hr);
+ }
+ SortArray2(nr-hr, cols[c-hc], idx); crank(nr-hr, cols[c-hc], &tmp);
+ SortArray2(nr-hr, idx, cols[c-hc]);
+ }
+ for(r = hr; r < nr; r++) if(rows[r-hr] = (double*)calloc(nc, sizeof(double))) {
+ for(c = hc; c < nc; c++) {
+ rows[r-hr][c-hc] = vals[r][c]; idx[c-hc] = (double)(c-hc);
+ }
+ SortArray2(nc-hc, rows[r-hr], idx); crank(nc-hc, rows[r-hr], &tmp);
+ SortArray2(nc-hc, idx, rows[r-hr]);
+ }
+ for(r = 0; r < (nr-hr); r++) for(c = 0; c < (nc-hc); c++){
+ cs[r] += cols[c][r]; rs[c] += rows[r][c];
+ }
+ //rank sums and statistics
+ for(r = 0, cchi2 = 0.0; r < (nr-hr); r++) cchi2 += (cs[r]*cs[r]);
+ cchi2 = cchi2 * 12.0 / ((double)((nr-hr)*(nc-hc)*(nr-hr+1))) - 3.0*(nc-hc)*(nr-hr+1);
+ for(c = 0, rchi2 = 0.0; c < (nc-hc); c++) rchi2 += (rs[c]*rs[c]);
+ rchi2 = rchi2 * 12.0 / ((double)((nc-hc)*(nr-hr)*(nc-hc+1))) - 3.0*(nr-hr)*(nc-hc+1);
+ //create report page
+ rep_init();
+ page = new Page(parent, data);
+ mk_header(page, "<b>Friedman's non-parametric two-way ANOVA</b>", data);
+ cx = txtdef1.fSize*5.0; cy = txtdef1.fSize*10.0;
+ //plot column results
+ for(c = hc; c < nc; c++) {
+ w1[c-hc] = HUGE_VAL; w2[c-hc] = -HUGE_VAL;
+ for(r = hr; r < nr; r++) {
+ trc[r-hr] = vals[r][c];
+ if(vals[r][c] < w1[c-hc]) w1[c-hc] = vals[r][c];
+ if(vals[r][c] > w2[c-hc]) w2[c-hc] = vals[r][c];
+ }
+ d_quartile(r-hr, trc, b1+c-hc, m+c-hc, b2+c-hc);
+ }
+ dBounds.Xmin = 0.5; dBounds.Xmax = ((double)(nc-hc))+0.5;
+ dBounds.Ymin = dmin; dBounds.Ymax = dmax;
+ if((graph = new Graph(parent, data, 0L, 0)) &&
+ (txt_obj = mk_boxplot(0, 0L, m, b1, b2, w1, w2, nvc, nc-hc, "medians", "25-75%", "min/max"))){
+ OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+ if(LastOpenGO && LastOpenGO->Id == GO_BOXPLOT) {
+ if(((BoxPlot*)LastOpenGO)->x_tv = new TextValue()){
+ for(i = 0; i < (nc-hc); i++) ((PlotScatt*)LastOpenGO)->x_tv->GetValue(cnames[i]);
+ }
+ if(((BoxPlot*)LastOpenGO)->x_info=(char*)malloc(20*sizeof(char)))
+ rlp_strcpy(((BoxPlot*)LastOpenGO)->x_info, 20, "Columns");
+ if(((BoxPlot*)LastOpenGO)->y_info=(char*)malloc(20*sizeof(char)))
+ rlp_strcpy(((BoxPlot*)LastOpenGO)->y_info, 20, "Location");
+ }
+ free(txt_obj); graph->moveable = 0;
+ graph->DRect.Xmax = graph->DRect.Xmin + graph->DRect.Ymax - graph->DRect.Ymin;
+ graph->GRect.Xmax = graph->GRect.Xmin + graph->GRect.Ymax - graph->GRect.Ymin;
+ scale.sx.fx = txtdef1.fSize*5.0; scale.sy.fx = txtdef1.fSize*10.0;
+ graph->Command(CMD_SCALE, &scale, 0L);
+ page->Command(CMD_DROP_GRAPH, graph, 0L);
+ cx = graph->GetSize(SIZE_GRECT_RIGHT)+txtdef1.fSize;
+ }
+ //plot row results
+ for(r = hr; r < nr; r++) {
+ w1[r-hr] = HUGE_VAL; w2[r-hr] = -HUGE_VAL;
+ for(c = hc; c < nc; c++) {
+ trc[c-hc] = vals[r][c];
+ if(vals[r][c] < w1[r-hr]) w1[r-hr] = vals[r][c];
+ if(vals[r][c] > w2[r-hr]) w2[r-hr] = vals[r][c];
+ if(vals[r][c] < dBounds.Xmin) dBounds.Xmin = vals[r][c];
+ if(vals[r][c] > dBounds.Xmax) dBounds.Xmax = vals[r][c];
+ }
+ d_quartile(c-hc, trc, b1+r-hr, m+r-hr, b2+r-hr);
+ }
+ for(r = hr; r < nr; r++) trc[r-hr] = ((double)(r-hr+1));
+ dBounds.Ymin = 0.5; dBounds.Ymax = ((double)(nr-hr))+0.5;
+ dBounds.Xmin = dmin; dBounds.Xmax = dmax;
+ if((graph = new Graph(parent, data, 0L, 0x10)) &&
+ (txt_obj = mk_boxplot(1, m, trc, b1, b2, w1, w2, nvr, nr-hr, "medians", "25-75%", "min/max"))){
+ OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+ if(LastOpenGO && LastOpenGO->Id == GO_BOXPLOT) {
+ if(((BoxPlot*)LastOpenGO)->y_tv = new TextValue()){
+ for(i = 0; i < (nr-hr); i++)((PlotScatt*)LastOpenGO)->y_tv->GetValue(rnames[i]);
+ }
+ if(((BoxPlot*)LastOpenGO)->y_info=(char*)malloc(20*sizeof(char)))
+ rlp_strcpy(((BoxPlot*)LastOpenGO)->y_info, 20, "Rows");
+ if(((BoxPlot*)LastOpenGO)->x_info=(char*)malloc(20*sizeof(char)))
+ rlp_strcpy(((BoxPlot*)LastOpenGO)->x_info, 20, "Location");
+ }
+ free(txt_obj); graph->moveable = 0;
+ graph->DRect.Xmax = graph->DRect.Xmin + graph->DRect.Ymax - graph->DRect.Ymin;
+ graph->GRect.Xmax = graph->GRect.Xmin + graph->GRect.Ymax - graph->GRect.Ymin;
+ scale.sx.fx = cx; scale.sy.fx = txtdef1.fSize*10.0;
+ graph->Command(CMD_SCALE, &scale, 0L);
+ page->Command(CMD_DROP_GRAPH, graph, 0L);
+ }
+ cx = txtdef1.fSize*5.0; cy = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*2.0;
+ free(m); free(b1); free(b2); free(w1); free(w2); free(trc);
+ rep_DrawText(page, cx, cy, false, TXA_HLEFT, &txtdef1, "<b>Between columns:</b>");
+ cy += txtdef1.fSize *1.5;
+ prob = chi_dist(fabs(rchi2), nc-hc-1, 0.0);
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, 60, "N = %d, Chi<sup>2</sup> = %.2lf, P ", nc-hc, rchi2);
+ if(prob > 0.001) sprintf_s(TmpTxt+i, 20, "= %.3lf", prob);
+#else
+ i = sprintf(TmpTxt, "N = %d, Chi<sup>2</sup> = %.2lf, P ", nc-hc, rchi2);
+ if(prob > 0.001) sprintf(TmpTxt+i, "= %.3lf", prob);
+#endif
+ else rlp_strcpy(TmpTxt+i, 40, "< 0.001");
+ rep_DrawText(page, cx+txtdef1.fSize*3.0, cy, false, TXA_HLEFT, &txtdef1, TmpTxt);
+ cy += txtdef1.fSize*2.0;
+ rep_DrawText(page, cx, cy, false, TXA_HLEFT, &txtdef1, "<b>Between rows:</b>");
+ cy += txtdef1.fSize *1.5;
+ prob = chi_dist(fabs(cchi2), nr-hr-1, 0.0);
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, 60, "N = %d, Chi<sup>2</sup> = %.2lf, P ", nr-hr, cchi2);
+ if(prob > 0.001) sprintf_s(TmpTxt+i, 20, "= %.3lf", prob);
+#else
+ i = sprintf(TmpTxt, "N = %d, Chi<sup>2</sup> = %.2lf, P ", nr-hr, cchi2);
+ if(prob > 0.001) sprintf(TmpTxt+i, "= %.3lf", prob);
+#endif
+ else rlp_strcpy(TmpTxt+i, 40, "< 0.001");
+ rep_DrawText(page, cx+txtdef1.fSize*3.0, cy, false, TXA_HLEFT, &txtdef1, TmpTxt);
+ if(!(parent->Command(CMD_DROP_GRAPH, page, 0L))) delete page;
+ free(rs); free(cs); free(idx);
+ }
+ if(cols) {
+ for(i = 0; i < nc; i++) if(cols[i]) free(cols[i]);
+ free(cols);
+ }
+ if(rows) {
+ for(i = 0; i < nr; i++) if(rows[i]) free(rows[i]);
+ free(rows);
+ }
+ if(vals) {
+ for(i = 0; i < nc; i++) if(vals[i]) free(vals[i]);
+ free(vals);
+ }
+ if (cnames) {
+ for(c = 0; c < (rec.right-rec.left+1); c++) if(cnames[c]) free(cnames[c]);
+ free(cnames);
+ }
+ if (rnames) {
+ for(r = 0; r < (rec.bottom-rec.top+1); r++) if(rnames[r]) free(rnames[r]);
+ free(rnames);
+ }
+ if(nvr) free(nvr); if(nvc) free(nvc);
+ CloseDlgWnd(hDlg); delete Dlg; free(FmAnovDlg);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Two way anova with replica
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *TwAnovDlg_Tmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,-1,148,10,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,148,25,45,12\n"
+ "3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "4,10,100,ISPARENT | CHECKED,SHEET,1,5,10,130,80\n"
+ "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+ "100,101,,,LTEXT,2,10,30,60,8\n"
+ "101,102,,,RANGEINPUT,-15,20,40,100,10\n"
+ "102,103,,,LTEXT,3,20,55,53,8\n"
+ "103,,,LASTOBJ,EDVAL1,4,75,55,30,10";
+
+typedef struct _anov_group_info {
+ double *rmeans, *cmeans;
+ int *vpr, *vpc, nvals;
+ double mean;
+ }anov_group_info;
+
+void rep_twoway_anova(GraphObj *parent, DataObj *data)
+{
+ TabSHEET tab1 = {0, 40, 10, "Input Data"};
+ DlgInfo *TwAnovDlg;
+ double dlpr = 3.0, *cmeans;
+ void *dyndata[] = {(void*)&tab1, (void*)"rectangular range for variables", (void*)"lines per replica:",
+ (void*)&dlpr};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, j, k, res, ntot, lpr, ngr, r1, r2, c1, c2, iErr;
+ int *vpc, *vpr;
+ double tmp, dn, gMean, SSwithin, SSsubgr, SStotal, SSrows, SScols, SSinteract;
+ double **res_tab = 0L, cx, cy;
+ bool bContinue = false;
+ AccRange *rD =0L;
+ char *mrk;
+ RECT rec;
+ anyResult ares;
+ anov_group_info *agr;
+ Page *page;
+
+ if(!parent || !data) return;
+ if(!(TwAnovDlg = CompileDialog(TwAnovDlg_Tmpl, dyndata))) return;
+ if(data->Command(CMD_GETMARK, &mrk, 0L))rlp_strcpy(TmpTxt, TMP_TXT_SIZE, mrk);
+ else {
+ data->ValueRec(&rec);
+ rlp_strcpy(TmpTxt, 100, mkRangeRef(rec.top, rec.left, rec.bottom, rec.right));
+ }
+ if(!(Dlg = new DlgRoot(TwAnovDlg, data)))return;
+ hDlg = CreateDlgWnd("Two-Way Anova with Replica", 50, 50, 420, 220, Dlg, 0x4L);
+loop1:
+ 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 1:
+ Dlg->GetValue(103, &dlpr); lpr = (int)dlpr;
+ break;
+ }
+ }while (res < 0);
+ if(res == 1 && Dlg->GetText(101, TmpTxt+200, TMP_TXT_SIZE-200) &&(rD = new AccRange(TmpTxt+200))
+ && rD->BoundRec(&rec) && (ntot = rD->CountItems())){
+ r1 = rec.top; r2 = rec.bottom+1; c1= rec.left; c2 = rec.right+1;
+ vpc = (int*)calloc(c2-c1+1, sizeof(int)); vpr = (int*)calloc(r2-r1+1, sizeof(int));
+ for(k = iErr = 0; k < 2; k++) {
+ for(i = c1; i < c2; i++) for(j = r1; j < r2; j++) {
+ data->GetResult(&ares, j, i, false);
+ if(ares.type == ET_VALUE) {
+ vpc[i-c1]++; vpr[j-r1]++;
+ }
+ }
+ if(!k) {
+ for(i = 0; !vpc[i]; i++); for(j = 0; !vpr[j]; j++);
+ memset(vpc,0,sizeof(int)*(c2-c1)); memset(vpr,0,sizeof(int)*(r2-r1));
+ c1 += i; r1 += j;
+ }
+ }
+ while(c2 > c1 && !vpc[c2-c1-1]) c2--; while(r2 > r1 && !vpr[r2-r1-1]) r2--;
+ ngr = (int)(((double)(r2-r1))/dlpr);
+ if(ngr * lpr < r2 -r1) iErr = 2;
+ agr = (anov_group_info *)calloc(ngr+1, sizeof(anov_group_info));
+ cmeans = (double *)calloc(c2-c1+1, sizeof(double));
+ for(i = 0; i <= ngr; i++) {
+ agr[i].cmeans = (double*)calloc(c2-c1+2, sizeof(double));
+ agr[i].vpc = (int*)calloc(c2-c1+2, sizeof(int));
+ agr[i].rmeans = (double*)calloc(lpr+2, sizeof(double));
+ agr[i].vpr = (int*)calloc(lpr+2, sizeof(int));
+ }
+ for(i = c1; i < c2; i++) for(j = r1; j < r2; j++) {
+ k = (j-r1)/lpr; data->GetResult(&ares, j, i, false);
+ if(ares.type == ET_VALUE) {
+ agr[k].cmeans[i-c1] += ares.value; agr[k].vpc[i-c1]++;
+ agr[k].rmeans[j-k*lpr] += ares.value; agr[k].vpr[j-k*lpr]++;
+ agr[k].mean += ares.value; agr[k].nvals++;
+ cmeans[i-c1] += ares.value;
+ }
+ else iErr = 1;
+ }
+ for(k = 0; k < ngr; k++) {
+ agr[k].mean /= ((double)(agr[k].nvals));
+ for(i = 0; i < (c2-c1); i++) {
+ agr[k].cmeans[i] /= ((double)(agr[k].vpc[i]));
+ }
+ }
+ for(i = c1, SSwithin = gMean = 0.0, dn = 1.0; i < c2; i++) for(j = r1; j < r2; j++) {
+ k = (j-r1)/lpr; data->GetResult(&ares, j, i, false);
+ if(ares.type == ET_VALUE) {
+ SSwithin += ((tmp = ares.value-agr[k].cmeans[i-c1])*tmp);
+ gMean += ((ares.value - gMean)/dn); dn += 1.0;
+ }
+ }
+ for(k = 0, SSsubgr = SSrows = 0.0; k < ngr; k++) {
+ for(i = 0; i < (c2-c1); i++) {
+ SSsubgr += (dlpr*((tmp = agr[k].cmeans[i] - gMean) * tmp));
+ }
+ SSrows += ((tmp = (agr[k].mean - gMean)) * tmp);
+ }
+ for(i = c1, SScols = 0.0; i < c2; i++) {
+ cmeans[i-c1] /= ((double)(r2-r1));
+ SScols += ((tmp = cmeans[i-c1]-gMean) * tmp);
+ }
+ SStotal = SSsubgr + SSwithin; SSrows *= (dlpr *((double)(c2-c1)));
+ SScols *= (dlpr * ((double)ngr)); SSinteract = fabs(SSsubgr - SSrows - SScols);
+ if(!iErr&& (res_tab = (double**)calloc(5, sizeof(double*)))
+ && (res_tab[0] = (double*)calloc(5, sizeof(double)))
+ && (res_tab[1] = (double*)calloc(5, sizeof(double)))
+ && (res_tab[2] = (double*)calloc(5, sizeof(double)))
+ && (res_tab[3] = (double*)calloc(5, sizeof(double)))
+ && (res_tab[4] = (double*)calloc(5, sizeof(double)))) {
+ res_tab[0][0] = (double)(ngr-1); res_tab[1][0] = (double)(c2-c1-1);
+ res_tab[2][0] = res_tab[0][0]* res_tab[1][0]; res_tab[3][0] = (double)(ngr*(c2-c1)*(lpr-1));
+ res_tab[4][0] = res_tab[0][0] + res_tab[1][0] + res_tab[2][0] + res_tab[3][0];
+ res_tab[0][1] = SSrows; res_tab[0][2] = res_tab[0][1] / res_tab[0][0];
+ res_tab[1][1] = SScols; res_tab[1][2] = res_tab[1][1] / res_tab[1][0];
+ res_tab[2][1] = SSinteract; res_tab[2][2] = res_tab[2][1] / res_tab[2][0];
+ res_tab[3][1] = SSwithin; res_tab[3][2] = res_tab[3][1] / res_tab[3][0];
+ res_tab[4][1] = SStotal; res_tab[0][3] = res_tab[0][2] / res_tab[3][2];
+ res_tab[1][3] = res_tab[1][2] / res_tab[3][2];
+ res_tab[2][3] = res_tab[2][2] / res_tab[3][2];
+ res_tab[0][4] = f_dist(res_tab[0][3], res_tab[0][0], res_tab[3][0]);
+ res_tab[1][4] = f_dist(res_tab[1][3], res_tab[1][0], res_tab[3][0]);
+ res_tab[2][4] = f_dist(res_tab[2][3], res_tab[2][0], res_tab[3][0]);
+
+
+ rep_init();
+// dBounds.Xmin = 0.5; dBounds.Xmax = ((double)nc)+0.5;
+ page = new Page(parent, data);
+ mk_header(page, "<b>Two-Way ANOVA with Replication</b>", data);
+
+ cx = txtdef1.fSize*5.0; cy = txtdef1.fSize*10.0;
+
+ rep_DrawText(page, cx, cy, false, TXA_HLEFT, &txtdef1, "<b>Anova:</b>");
+ cy = mk_table(page, cx, cy+txtdef2.fSize, 3, res_tab)+txtdef2.fSize;
+ if(!(parent->Command(CMD_DROP_GRAPH, page, 0L))) delete page;
+ free(res_tab[0]); free(res_tab[1]); free(res_tab[2]);
+ free(res_tab[3]); free(res_tab[4]); free(res_tab);
+ }
+ for(i = 0; i <= ngr; i++) {
+ free(agr[i].cmeans); free(agr[i].vpc);
+ free(agr[i].rmeans); free(agr[i].vpr);
+ }
+ free(vpc); free(vpr); free(cmeans);
+ delete rD;
+ switch(iErr) {
+ case 1:
+ ErrorBox("There are missing Data!");
+ goto loop1;
+ case 2:
+ ErrorBox("The total number of lines\nmust be a multiple of\nlines per replica.");
+ goto loop1;
+ }
+ }
+ CloseDlgWnd(hDlg); delete Dlg; free(TwAnovDlg);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Kruskal-Wallis Test for Differences of Location
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *RepKruskal_DlgTmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,-1,158,10,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,158,25,45,12\n"
+ "3,,10,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "10,20,152,ISPARENT | CHECKED, SHEET,1,5,10,140,70\n"
+ "20,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+ "152,153,,ISPARENT | CHECKED,GROUPBOX,2,12,30,128,45\n"
+ "153,154,,,LTEXT,0,25,35,60,8\n"
+ "154,155,,,RANGEINPUT,0,25,45,100,10\n"
+ "155,156,0,,PUSHBUTTON,-8,95,57,30,12\n"
+ "156,,,LASTOBJ,PUSHBUTTON,-9,60,57,35,12";
+
+void rep_kruskal(GraphObj *parent, DataObj *data)
+{
+ TabSHEET tab1 = {0, 25, 10, "Data"};
+
+ void *dyndata[] = {(void*)&tab1, (void*)" select one range for every variable "};
+ DlgInfo *KruskalDlg;
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, j, n, c, r, nt, res, currYR = 0, maxYR = 0, ny, nr, *nvals;
+ bool updateYR = true, bContinue = false;
+ double h, h1, p, **vals, *x, *y, *by1, *by2, *wy1, *wy2, *ranks, *ridx, *rsums, th, cy, cx[10];
+ char **rd = 0L, **names, *txt_obj;
+ char *headings[] = {"<i>Groups</i>", "<i>N</i>", "<i>Median</i>", "<i>25% - 75%</i>",
+ "<i>Range</i>","<i>Rank Sums</i>"};
+ scaleINFO scale = {{0.0, 1.0}, {0.0, 1.0}, {0.0, 1.0}};
+ AccRange *rV1 = 0L;
+ anyResult ares;
+ Page *page;
+ Graph *graph;
+
+ if(!parent || !data) return;
+ if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
+ TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return;
+ if(!(KruskalDlg = CompileDialog(RepKruskal_DlgTmpl, dyndata))) return;
+ if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
+ for(i=j=0; i <= 1000; i +=100) if(TmpTxt[i])
+ rd[j++] = (char*)memdup(TmpTxt+i, ((int)strlen(TmpTxt+i))+2, 0); maxYR = j-1;
+ }
+ if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return;
+ if(!(Dlg = new DlgRoot(KruskalDlg, data))) return;
+ if(rd && rd[currYR] && *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
+ hDlg = CreateDlgWnd("Kruskal-Wallis Nonparametric Anova", 50, 50, 420, 200, Dlg, 0x4L);
+ do {
+ if(updateYR) {
+ if(currYR >0) Dlg->ShowItem(156, true);
+ else Dlg->ShowItem(156, false);
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "variable # %d/%d", currYR+1, maxYR+1);
+#else
+ sprintf(TmpTxt,"variable # %d/%d", currYR+1, maxYR+1);
+#endif
+ Dlg->SetText(153, 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 155: case 156:
+ res = com_StackDlg(res, Dlg, 0L, 0L, &rd, &currYR,
+ &rV1, &bContinue, &ny, &maxYR, &updateYR);
+ break;
+ }
+ }while (res < 0);
+ if(res == 1 && (vals = (double**)calloc(sizeof(double*), maxYR+1)) && (nvals = (int*)calloc(sizeof(int), maxYR+1))
+ && (names = (char**)calloc(maxYR+1, sizeof(char*))) && (x = (double*)calloc(maxYR+1, sizeof(double)))
+ && (y = (double*)calloc(maxYR+1, sizeof(double))) && (by1 = (double*)calloc(maxYR+1, sizeof(double)))
+ && (by2 = (double*)calloc(maxYR+1, sizeof(double))) && (wy1 = (double*)calloc(maxYR+1, sizeof(double)))
+ && (wy2 = (double*)calloc(maxYR+1, sizeof(double)))
+ && (rsums = (double*)calloc(maxYR+1, sizeof(double)))) {
+ maxYR++; rep_init(); page = new Page(parent, data);
+ dBounds.Xmin = 0.5; dBounds.Xmax = (double)maxYR+0.3;
+ if(rV1) delete rV1; rV1 = 0L; ranks = ridx = 0L;
+ cy = txtdef1.fSize*10.0;
+ mk_header(page, "<b>Kruskal-Wallis Test for Differences of Location</b>", data);
+ dBounds.Ymin = HUGE_VAL; dBounds.Ymax = -HUGE_VAL;
+ // get data into two dimensional array
+ for(nr = maxYR, i = nt = 0; i < nr; i++) {
+ x [i] = y[i] = by1[i] = by2[i] = wy1[i] = wy2[i] = 0.0; nvals[i] = 0;
+ if((rV1 = new AccRange(rd[i])) && (n = rV1->CountItems()) && (vals[i] = (double*)malloc(n*sizeof(double)))) {
+ names[i] = rV1->RangeDesc(data, 1);
+ for(n = 0, rV1->GetFirst(&c, &r); rV1->GetNext(&c, &r); ) {
+ if(data->GetResult(&ares, r, c, false) && ares.type == ET_VALUE) {
+ if(!n) wy1[i] = wy2[i] = ares.value;
+ else {
+ if(ares.value < wy1[i]) wy1[i] = ares.value;
+ if(ares.value > wy2[i]) wy2[i] = ares.value;
+ }
+ if(ares.value < dBounds.Ymin) dBounds.Ymin = ares.value;
+ if(ares.value > dBounds.Ymax) dBounds.Ymax = ares.value;
+ vals[i][n] = ares.value; n++;
+ }
+ }
+ nvals[i] = n; nt += n; delete rV1; rV1 = 0;
+ }
+ if(!names[i] && (names[i] = (char*)malloc(20*sizeof(char)))){
+#ifdef USE_WIN_SECURE
+ sprintf_s(names[i], 20, "Group %d", i+1);
+#else
+ sprintf(names[i], "Group %d", i+1);
+#endif
+ }
+ }
+ // rank sums
+ if(nt && (ranks=(double*)malloc(nt*sizeof(double))) && (ridx=(double*)malloc(nt*sizeof(double)))) {
+ for(i = n = 0; i < nr; i++) {
+ for(j = 0; j < nvals[i]; j++) {
+ ridx[n] = (double)(i); ranks[n] = vals[i][j]; n++;
+ }
+ }
+ SortArray2(n, ranks, ridx); crank(n, ranks, &th);
+ for(i = 0; i < n; i++) rsums[(int)ridx[i]] += ranks[i];
+ //statistics on range sums
+ for(i = 0, h = 0.0; i < nr; i++) h += rsums[i]*rsums[i]/((double)nvals[i]);
+ h = h * 12.0/(((double)n)*((double)(n+1))) - 3.0*((double)n+1);
+ h1 = h / (1.0 - th/(((double)(n-1)) * ((double)n)* ((double)(n+1))));
+ }
+ else h = h1 = -1.0;
+ // check for unique names
+ for(i = 0; i < (nr-1); i++) for(j = i+1; j < nr; j++) {
+ if(!strcmp(names[i], names[j])) {
+ names[i] = (char*) realloc(names[i], 20 *sizeof(char));
+ names[j] = (char*) realloc(names[j], 20 *sizeof(char));
+#ifdef USE_WIN_SECURE
+ sprintf_s(names[i], 20, "Group %d", i+1); sprintf_s(names[j], 20, "Group %d", j+1);
+#else
+ sprintf(names[i], "Group %d", i+1); sprintf(names[j], "Group %d", j+1);
+#endif
+ }
+ }
+ // simple group statistics
+ for(i = 0; i < nr; i++) {
+ x[i] = (double)(i+1); d_quartile(nvals[i], vals[i], by1+i, y+i, by2+i);
+ }
+ // create boxplot
+ if((graph = new Graph(parent, data, 0L, 0)) && (txt_obj = mk_boxplot(0, x, y, by1, by2, wy1, wy2,
+ nvals, nr,"Median","25-75%","Min./Max."))){
+ scale.sx.fx = (txtdef1.fSize*5.0); scale.sy.fx = (txtdef1.fSize*10.0);
+ OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+ if(LastOpenGO && LastOpenGO->Id == GO_BOXPLOT) {
+ if(((BoxPlot*)LastOpenGO)->x_tv = new TextValue()){
+ for(i = 0; i < nr; i++) ((BoxPlot*)LastOpenGO)->x_tv->GetValue(names[i]);
+ }
+ if(((BoxPlot*)LastOpenGO)->x_info = (char*)malloc(20*sizeof(char)))
+ rlp_strcpy(((BoxPlot*)LastOpenGO)->x_info, 20, "Groups");
+ if(((BoxPlot*)LastOpenGO)->y_info = (char*)malloc(20*sizeof(char)))
+ rlp_strcpy(((BoxPlot*)LastOpenGO)->y_info, 20, "Location");
+ }
+ free(txt_obj); graph->Command(CMD_SCALE, &scale, 0L);
+ cy = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef1.fSize*2.0;
+ page->Command(CMD_DROP_GRAPH, graph, 0L);
+ }
+ parent->Command(CMD_DROP_GRAPH, page, 0L);
+ //report statistics
+ cx[0] = txtdef1.fSize*5.0; cx[1] = cx[0] + linsp1*5.0;
+ cx[2] = cx[1] + linsp1*2.5; cx[3] = cx[2] + linsp1*4.0;
+ cx[4] = cx[3] + linsp1*5.0; cx[5] = cx[4] + linsp1*7.0;
+ cx[6] = cx[5] + linsp1*8.0;
+ rep_DrawText(page, cx[0], cy, false, TXA_HLEFT, &txtdef1, "<b>Test Statistics:</b>");
+ cy += linsp2; p = chi_dist(h,(double)(nr-1), 0.0);
+ dbl_to_str2(TmpTxt, 100, p < 0.0001 ?(char*)"H = %.2lf, P < 0.0001" : (char*)"H = %.2lf, P = %.4lf", h, p);
+ rep_DrawText(page, cx[1], cy, false, TXA_HLEFT, &txtdef1, TmpTxt);
+ cy += linsp1; p = chi_dist(h1,(double)(nr-1), 0.0);
+ dbl_to_str2(TmpTxt, 100, p < 0.0001 ?(char*)"H(corr.) = %.2lf, P < 0.0001" : (char*)"H(corr.) = %.2lf, P = %.4lf", h1, p);
+ if(th >= 1.0) {
+ rep_DrawText(page, cx[1], cy, false, TXA_HLEFT, &txtdef1, TmpTxt);
+ cy += linsp1;
+ }
+ cy += linsp2;
+ // create summary table
+ rep_DrawText(page, cx[0], cy, false, TXA_HLEFT, &txtdef1, "<b>Summary:</b>");
+ for(i = 0, cy += linsp2; i < 6; i++) { //column headers
+ c = (i == 3 || i == 4) ? TXA_HCENTER : TXA_HRIGHT;
+ rep_DrawText(page, cx[i+1], cy, false, c, &txtdef1, headings[i]);
+ }
+ mk_hr(page, cx[0], cx[6]+txtdef1.fSize*2.0, cy +linsp1);
+ for(i = 0, cy += linsp2; i < nr; i++, cy += linsp1) {
+ for(j = 0; j < 6; j++) {
+ switch(j) {
+ default: rlp_strcpy(TmpTxt, 20, names[i]); break;
+ case 1: dbl_to_str1(TmpTxt, 20, "%.0lf", (double)nvals[i]); break;
+ case 2: dbl_to_str1(TmpTxt, 20, "%g", y[i]); break;
+ case 3: dbl_to_str2(TmpTxt, 20, "%g - %g", by1[i], by2[i]); break;
+ case 4: dbl_to_str2(TmpTxt, 20, "%g - %g", wy1[i], wy2[i]); break;
+ case 5: dbl_to_str1(TmpTxt, 20, "%g", rsums[i]); break;
+ }
+ c = (j == 3 || j == 4) ? TXA_HCENTER : TXA_HRIGHT;
+ rep_DrawText(page, cx[j+1], cy, false, c, &txtdef1,TmpTxt);
+ }
+ }
+ mk_hr(page, cx[0], cx[6]+txtdef1.fSize*2.0, cy+txtdef1.fSize*0.2);
+ for(i= 0; i< nr; i++) {
+ if(vals[i]) free(vals[i]); if(names[i]) free(names[i]);
+ }
+ free(vals); free(nvals); free(names);
+ free(x); free(y); free(by1);
+ free(by2); free(wy1); free(wy2);
+ free(rsums);
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(rd) {
+ for (i = 0; i < maxYR; i++) if(rd[i]) free(rd[i]);
+ free(rd);
+ }
+ if(ranks)free(ranks); if(ridx)free(ridx);
+ if(rV1) delete rV1; free(KruskalDlg);
+ return;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// simple sample statistics
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *SmplStatDlg_Tmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,-1,148,10,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,148,25,45,12\n"
+ "3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "4,10,100,ISPARENT | CHECKED,SHEET,1,5,10,130,80\n"
+ "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+ "100,101,,,LTEXT,2,10,30,60,8\n"
+ "101,,,LASTOBJ,RANGEINPUT,-15,20,40,100,10";
+void rep_samplestats(GraphObj *parent, DataObj *data)
+{
+ TabSHEET tab1 = {0, 40, 10, "Input Data"};
+ DlgInfo *SmplStatDlg;
+ void *dyndata[] = {(void*)&tab1, (void*)"rectangular range for variables"};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int res, nr, nc, ntot, cb;
+ double val, *src_data, cx, cy, ksprob, ksd, sww, swp, mean, sd;
+ bool bContinue = false;
+ AccRange *rD =0L;
+ char *mrk, *x_info, *y_info;
+ RECT rec;
+ Plot *plot;
+ Graph *graph;
+ Page *page;
+
+ if(!parent || !data) return;
+ if(!(SmplStatDlg = CompileDialog(SmplStatDlg_Tmpl, dyndata))) return;
+ if(data->Command(CMD_GETMARK, &mrk, 0L))rlp_strcpy(TmpTxt, TMP_TXT_SIZE, mrk);
+ else {
+ data->ValueRec(&rec);
+ rlp_strcpy(TmpTxt, 100, mkRangeRef(rec.top, rec.left, rec.bottom, rec.right));
+ }
+ if(!(Dlg = new DlgRoot(SmplStatDlg, data)))return;
+ hDlg = CreateDlgWnd("Sample Statistics", 50, 50, 420, 220, Dlg, 0x4L);
+ 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;
+ }
+ }while (res < 0);
+ if(res == 1 && Dlg->GetText(101, TmpTxt+200, TMP_TXT_SIZE) &&(rD = new AccRange(TmpTxt+200))
+ && rD->BoundRec(&rec) && (ntot = rD->CountItems()) && (src_data = (double*)malloc(ntot*sizeof(double)))){
+ rep_init();
+ x_info = rD->RangeDesc(data, 2);
+ if(y_info = (char*)malloc(20)) rlp_strcpy(y_info, 20, "Normal quantiles");
+ page = new Page(parent, data);
+ cb = rlp_strcpy(TmpTxt, 100, "<b>Sample Statistics for \"");
+ if(x_info && x_info[0]) cb += rlp_strcpy(TmpTxt+cb, 100-cb, x_info);
+ else cb += rlp_strcpy(TmpTxt+cb, 100-cb, TmpTxt+200);
+ rlp_strcpy(TmpTxt+cb,100-cb, "\"</b>"); mk_header(page, TmpTxt, data);
+ for(ntot = 0, rD->GetFirst(&nc, &nr); rD->GetNext(&nc, &nr); ) {
+ if(data->GetValue(nr, nc, &val)) src_data[ntot++] = val;
+ }
+ if(ntot > 2 && (graph = new Graph(page, data, 0L, 0))) {
+ if(plot = new NormQuant(page, data, src_data, ntot)) {
+ plot->x_info = x_info; plot->y_info = y_info;
+ }
+ if(!(graph->Command(CMD_DROP_PLOT, (void *)plot, 0L))) {
+ delete plot; plot =0L;
+ }
+ graph->moveable = 0; graph->GRect.Xmin += (txtdef1.fSize*5.0);
+ graph->GRect.Xmax += (txtdef1.fSize*5.0); graph->GRect.Ymin += (txtdef1.fSize*10.0);
+ graph->GRect.Ymax += (txtdef1.fSize*10.0); page->Command(CMD_DROP_GRAPH, graph, 0L);
+ cy = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef1.fSize*3;
+ rep_DrawText(page, graph->GRect.Xmin, cy, false, TXA_HLEFT, &txtdef1, "<b>Descriptive Statistics:</b>");
+ cy += txtdef1.fSize*1.5; cx = graph->GetSize(SIZE_GRECT_LEFT)+txtdef1.fSize*25.0;
+ mk_median_report(page, cx, cy, src_data, ntot, .95, 0L);
+ cx = graph->GetSize(SIZE_GRECT_LEFT)+txtdef1.fSize*2.0;
+ cy = mk_mean_report(page, cx, cy, src_data, ntot, .95, 0L);
+ //data are sorted by the mk_median_report();
+ d_variance(ntot, src_data, &mean, &sd);
+ sd = sqrt(sd/((double)(ntot-1)));
+ KolSmir(ntot, src_data, norm_dist, mean, sd, true, &ksd, &ksprob);
+ cy += txtdef1.fSize*1.5; cx = graph->GRect.Xmin;
+ rep_DrawText(page, cx , cy, false, TXA_HLEFT, &txtdef1, "<b>Test for Normal Distribution:</b>");
+ cy += linsp1; cx += (txtdef1.fSize*2.0);
+ cb = dbl_to_str1(TmpTxt, 100, "Kolmogorov-Smirnov D = %.4lf, P ", ksd);
+ dbl_to_str1(TmpTxt+cb, 100-cb, ksprob >= 0.0001 ? (char*)"= %.4lf" : (char*)"< 0.0001", ksprob);
+ rep_DrawText(page, cx , cy, false, TXA_HLEFT, &txtdef1,TmpTxt); cy += linsp1/1.2;
+ swilk1(ntot, src_data, norm_dist, 0.0, 1.0, true, &sww, &swp);
+ if(sww >= 0.0 && swp >= 0.0 && (cb = dbl_to_str1(TmpTxt, 100, "Shapiro-Wilk W = %.4lf, P ", sww))
+ && (dbl_to_str1(TmpTxt+cb, 100-cb, swp >= 0.0001 ? (char*)"= %.4lf" : (char*)"< 0.0001", swp))){
+ rep_DrawText(page, cx , cy, false, TXA_HLEFT, &txtdef1,TmpTxt); cy += linsp1/1.2;
+ }
+ parent->Command(CMD_DROP_GRAPH, page, 0L);
+ }
+ else {
+ ErrorBox("Insuficient data to do stats\n");
+ delete page;
+ }
+ delete rD; free(src_data);
+ }
+ CloseDlgWnd(hDlg); delete Dlg; free(SmplStatDlg);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// linear regression analysis
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static double mk_regr_summary(GraphObj *parent, double x, double y, double *dres, double ci, int n)
+{
+ char *fmts[] = {"slope = %g", "intercept = %g", "observations = %g", "r<sup> 2</sup> = %g", "r = %g"};
+ char *ci_fmt = "%g - %g";
+ char lbl[80];
+ double z, s;
+ double x1 = x + txtdef1.fSize*3.0;
+ double x2 = x + txtdef1.fSize*25.0;
+#ifdef _WINDOWS
+ double hrw = txtdef1.fSize*38.0;
+#else
+ double hrw = txtdef1.fSize*1.3*38.0;
+#endif
+
+ rep_DrawText(parent, x, y, false, TXA_HLEFT, &txtdef1, "<b>Regression:</b>");
+ dbl_to_str1(lbl, 80, "%g%% C.I.", ci);
+ rep_DrawText(parent, x2, y, false, TXA_HCENTER, &txtdef1, lbl);
+ mk_hr(parent, x, x+hrw, y+txtdef1.fSize*1.2);
+ y += linsp1*1.5; dbl_to_str1(lbl, 80, fmts[0], dres[0]);
+ rep_DrawText(parent, x1, y, false, TXA_HLEFT, &txtdef1, lbl);
+ dbl_to_str2(lbl, 80, ci_fmt, dres[0]-dres[10], dres[0]+dres[10]);
+ rep_DrawText(parent, x2, y, false, TXA_HCENTER, &txtdef1, lbl);
+ y += linsp1; dbl_to_str1(lbl, 80, fmts[1], dres[1]);
+ rep_DrawText(parent, x1, y, false, TXA_HLEFT, &txtdef1, lbl);
+ dbl_to_str2(lbl, 80, ci_fmt, dres[1]-dres[11], dres[1]+dres[11]);
+ rep_DrawText(parent, x2, y, false, TXA_HCENTER, &txtdef1, lbl);
+ y += linsp1; dbl_to_str1(lbl, 80, fmts[2], (double)n);
+ rep_DrawText(parent, x1, y, false, TXA_HLEFT, &txtdef1, lbl);
+ y += linsp1; dbl_to_str1(lbl, 80, fmts[3], dres[12]);
+ rep_DrawText(parent, x1, y, false, TXA_HLEFT, &txtdef1, lbl);
+ y += linsp1; dbl_to_str1(lbl, 80, fmts[4], sqrt(dres[12]));
+ rep_DrawText(parent, x1, y, false, TXA_HLEFT, &txtdef1, lbl);
+ z = 0.5 * log((1.0+sqrt(dres[12])+_PREC)/(1.0-sqrt(dres[12])+_PREC)); //Fishers z-transform
+ s = distinv(t_dist, 1.0E+10, 1.0, (100-ci)/100.0, 2.0)/sqrt((double)(n-3));
+ dbl_to_str2(lbl, 80, ci_fmt, tanh(z-s), tanh(z+s));
+ rep_DrawText(parent, x2, y, false, TXA_HCENTER, &txtdef1, lbl);
+ mk_hr(parent, x, x+hrw, y+txtdef1.fSize*1.2);
+ return y + linsp1*3.0;
+}
+
+static char *RegrDlg_Tmpl =
+ "1,+,,DEFAULT,PUSHBUTTON,-1,148,10,45,12\n"
+ ".,.,,,PUSHBUTTON,-2,148,25,45,12\n"
+ ".,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "4,10,100,ISPARENT | CHECKED,SHEET,1,5,10,130,100\n"
+ "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+ "100,+,,,LTEXT,2,10,30,60,8\n"
+ ".,.,,,RANGEINPUT,-15,20,40,100,10\n"
+ ".,.,,,LTEXT,3,10,55,60,8\n"
+ ".,.,,,RANGEINPUT,-16,20,65,100,10\n"
+ ".,.,,,LTEXT,4,10,80,60,8\n"
+ ".,.,,,EDVAL1,5,74,80,25,10\n"
+ ".,.,,,LTEXT,-10,101,80,60,8\n"
+ ".,,,LASTOBJ,CHECKBOX,6,10,95,100,8";
+
+void
+rep_regression(GraphObj *parent, DataObj *data)
+{
+ TabSHEET tab1 = {0, 60, 10, "Regression Input"};
+ double ci = 95.0;
+ DlgInfo *RegrDlg;
+ void *dyndata[] = {(void*)&tab1, (void*)"range for independent variable (x)",
+ (void*)"range for dependent variable (y)", (void*)"confidence interval:",
+ (void*)&ci, (void*)" include origin"};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, n, n1, rx, cx, ry, cy, res, align = 0;
+ int x_dtype, y_dtype, nVals, nTxt, nTime;
+ bool bContinue = false, bValid, bParZ;
+ AccRange *rX = 0L, *rY = 0L;
+ double *x = 0L, *y = 0L, **res_tab = 0L, c_x, c_y;
+ double sx, sy, dx, dy, sxy, sxx, syy, sdy, df, t, ts, ty;
+ double dres[14], ly[4];
+ char *txt_obj, *x_desc=0L, *y_desc=0L;
+ anyResult xRes, yRes;
+ TextValue *x_tv, *y_tv;
+ Graph *graph;
+ Page *page;
+
+ if(!parent || !data) return;
+ if(!(RegrDlg = CompileDialog(RegrDlg_Tmpl, dyndata))) return;
+ UseRangeMark(data, 1, TmpTxt, TmpTxt+100);
+ if(!(Dlg = new DlgRoot(RegrDlg, data)))return;
+ hDlg = CreateDlgWnd("Linear Regression", 50, 50, 420, 260, Dlg, 0x4L);
+ 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 1:
+ Dlg->GetValue(105, &ci); bParZ = Dlg->GetCheck(107);
+ if(rX) delete rX; if(rY) delete rY;
+ rX = rY = 0L;
+ if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) rX = new AccRange(TmpTxt);
+ n = rX ? rX->CountItems() : 0;
+ if(!n) {
+ ErrorBox("Range not specified\nor not valid.");
+ bContinue = true;
+ res = -1;
+ }
+ if(n && Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE) && (rY = new AccRange(TmpTxt))){
+ if(n != rY->CountItems()) {
+ ErrorBox("Both ranges must be given\nand must have the same size");
+ bContinue = true;
+ res = -1;
+ }
+ }
+ }
+ }while (res < 0);
+ n1 = n;
+ if(res == 1 && n >1 && rX && rY && (x = (double*)malloc(n*sizeof(double)))
+ && (y = (double*)malloc(n*sizeof(double)))
+ && (res_tab = (double**)calloc(3, sizeof(double*)))
+ && (res_tab[0] = (double*) malloc(5*sizeof(double)))
+ && (res_tab[1] = (double*) malloc(5*sizeof(double)))
+ && (res_tab[2] = (double*) malloc(5*sizeof(double)))) {
+ x_desc = rX->RangeDesc(data, 0); y_desc = rY->RangeDesc(data, 0);
+ //analyse data types
+ x_dtype = y_dtype = 0; x_tv = y_tv = 0L;
+ if(rX->DataTypes(data, &nVals, &nTxt, &nTime)){
+ if(!nVals && nTxt > 1 && nTxt > nTime) x_tv = new TextValue();
+ else if(!nVals && nTime > 1 && nTime > nTxt) x_dtype = ET_DATETIME;
+ }
+ if(rY->DataTypes(data, &nVals, &nTxt, &nTime)){
+ if(!nVals && nTxt > 1 && nTxt > nTime) y_tv = new TextValue();
+ else if(!nVals && nTime > 1 && nTime > nTxt) y_dtype = ET_DATETIME;
+ }
+ rX->GetFirst(&cx, &rx); rY->GetFirst(&cy, &ry);
+ rep_init();
+ dBounds.Xmin = dBounds.Ymin = HUGE_VAL; dBounds.Xmax = dBounds.Ymax = -HUGE_VAL;
+ //read data into x[] and y[]
+ for(i = n = 0; i < n1 && rX->GetNext(&cx, &rx) && rY->GetNext(&cy, &ry); i++) {
+ bValid = false;
+ if(data->GetResult(&xRes, rx, cx, false) && data->GetResult(&yRes, ry, cy, false)) {
+ bValid = true;
+ if(x_tv) {
+ if(xRes.type == ET_TEXT) dx = x_tv->GetValue(xRes.text);
+ else bValid = false;
+ }
+ else if(x_dtype == ET_DATETIME) {
+ if(xRes.type == ET_DATE || xRes.type == ET_TIME || xRes.type == ET_DATETIME) dx = xRes.value;
+ else bValid = false;
+ }
+ else {
+ if(xRes.type == ET_VALUE) dx = xRes.value;
+ else bValid = false;
+ }
+ if(y_tv) {
+ if(yRes.type == ET_TEXT) dy = y_tv->GetValue(yRes.text);
+ else bValid = false;
+ }
+ else if(y_dtype == ET_DATETIME) {
+ if(yRes.type == ET_DATE || yRes.type == ET_TIME || yRes.type == ET_DATETIME) dy = yRes.value;
+ else bValid = false;
+ }
+ else {
+ if(yRes.type == ET_VALUE) dy = yRes.value;
+ else bValid = false;
+ }
+ }
+ if(bValid){
+ x[n] = dx; y[n] = dy;
+ if(dBounds.Xmin > x[n]) dBounds.Xmin = x[n];
+ if(dBounds.Xmax < x[n]) dBounds.Xmax = x[n];
+ if(dBounds.Ymin > y[n]) dBounds.Ymin = y[n];
+ if(dBounds.Ymax < y[n]) dBounds.Ymax = y[n];
+ n++;
+ }
+ }
+ if(!bParZ) {
+ for(i = 0, sx = sy = 0.0; i < n; i++) {
+ sx += x[i]; sy += y[i];
+ }
+ dres[2] = sx /n; dres[3] = sy/n;
+ }
+ else {
+ dres[2] = sx = dres[3] = sy = 0.0;
+ }
+ sxy = sxx = syy = 0.0;
+ for(i = 0; i < n; i++) {
+ dx = x[i]-dres[2]; dy = y[i]-dres[3];
+ sxx += (dx*dx); syy += (dy*dy); sxy += (dx*dy);
+ }
+ dres[0] = sxy / sxx; dres[1] = dres[3] - dres[0] * dres[2];
+ for(i = 0, sdy = 0.0; i < n; i++) {
+ dy = y[i] - (dres[1] + x[i] *dres[0]);
+ sdy += (dy * dy);
+ }
+ df = bParZ ? (n-1) : (n-2); sdy = sdy/df; dres[4] = sqrt(sdy/sxx);
+ dres[5] = sxx/(n-1); dres[6] = syy/(n-1); dres[7] = sdy;
+ dres[8] = sxy/sdy*sxy/sxx; dres[9] = f_dist(dres[8], 1.0, df);
+ t = distinv(t_dist, df, 1.0, (100.0-ci)/100.0, 2.0);
+ dres[10] = t * sqrt(dres[7]/sxx);
+ dres[11] = t * sqrt(dres[7]*(dres[2]*dres[2]/sxx +1.0/(double)n));
+ if (n && (graph = new Graph(parent, data, 0L, 0))) {
+ if(txt_obj = mk_scatt(0, x, y, 0L, 0L, n, "Data", x_desc, y_desc)){
+ OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+ free(txt_obj);
+ if(LastOpenGO && LastOpenGO->Id >= GO_PLOT && LastOpenGO ->Id < GO_GRAPH) {
+ ((Plot*)LastOpenGO)->x_dtype = x_dtype; ((Plot*)LastOpenGO)->y_dtype = y_dtype;
+ ((Plot*)LastOpenGO)->x_tv = x_tv; ((Plot*)LastOpenGO)->y_tv = y_tv;
+ }
+ }
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "[1=Function]\nx1= %g\nx2= %g\nxstep= %g\nLine= %g 1 0x000000ff 0x0\n",
+ dBounds.Xmin, dBounds.Xmax, (dBounds.Xmax -dBounds.Xmin)/100.0, defs.GetSize(SIZE_DATA_LINE));
+ i += sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, "f_xy=\"%g+x*%g\\n\"\n", dres[1], dres[0]);
+ i += sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, "Desc=\"Regression\"\n");
+ OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "[1=Function]\nx1= %g\nx2= %g\nxstep= %g\nLine= %g 1 0x000000ff 0x0\n",
+ dBounds.Xmin, dBounds.Xmax, (dBounds.Xmax -dBounds.Xmin)/100.0, defs.GetSize(SIZE_DATA_LINE)*0.5);
+ i += sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, "f_xy=\"y=%g+x*%g;\\nts=sqrt((((x-(%g))^2)/%g+%g)*%g);\\ny=y+ts*%g\\n\"\n",
+ dres[1], dres[0], dres[2], sxx, (1.0/(double)n), dres[7], t);
+ i += sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, "Desc=\"%g%% C.I.\"\n", ci);
+ OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "[1=Function]\nx1= %g\nx2= %g\nxstep= %g\nLine= %g 1 0x000000ff 0x0\n",
+ dBounds.Xmin, dBounds.Xmax, (dBounds.Xmax -dBounds.Xmin)/100.0, defs.GetSize(SIZE_DATA_LINE)*0.5);
+ i += sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, "f_xy=\"y=%g+x*%g;\\nts=sqrt((((x-(%g))^2)/%g+%g)*%g);\\ny=y-ts*%g\\n\"\n",
+ dres[1], dres[0], dres[2], sxx, (1.0/(double)n), dres[7], t);
+ i += sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, "Desc=\"%g%% C.I.\"\n", ci);
+ OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
+#else
+ i = sprintf(TmpTxt, "[1=Function]\nx1= %g\nx2= %g\nxstep= %g\nLine= %g 1 0x000000ff 0x0\n",
+ dBounds.Xmin, dBounds.Xmax, (dBounds.Xmax -dBounds.Xmin)/100.0, defs.GetSize(SIZE_DATA_LINE));
+ i += sprintf(TmpTxt+i, "f_xy=\"%g+x*%g\\n\"\n", dres[1], dres[0]);
+ i += sprintf(TmpTxt+i, "Desc=\"Regression\"\n");
+ OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
+ i = sprintf(TmpTxt, "[1=Function]\nx1= %g\nx2= %g\nxstep= %g\nLine= %g 1 0x000000ff 0x0\n",
+ dBounds.Xmin, dBounds.Xmax, (dBounds.Xmax -dBounds.Xmin)/100.0, defs.GetSize(SIZE_DATA_LINE)*0.5);
+ i += sprintf(TmpTxt+i, "f_xy=\"y=%g+x*%g;\\nts=sqrt((((x-(%g))^2)/%g+%g)*%g);\\ny=y+ts*%g\\n\"\n",
+ dres[1], dres[0], dres[2], sxx, (1.0/(double)n), dres[7], t);
+ i += sprintf(TmpTxt+i, "Desc=\"%g%% C.I.\"\n", ci);
+ OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
+ i = sprintf(TmpTxt, "[1=Function]\nx1= %g\nx2= %g\nxstep= %g\nLine= %g 1 0x000000ff 0x0\n",
+ dBounds.Xmin, dBounds.Xmax, (dBounds.Xmax -dBounds.Xmin)/100.0, defs.GetSize(SIZE_DATA_LINE)*0.5);
+ i += sprintf(TmpTxt+i, "f_xy=\"y=%g+x*%g;\\nts=sqrt((((x-(%g))^2)/%g+%g)*%g);\\ny=y-ts*%g\\n\"\n",
+ dres[1], dres[0], dres[2], sxx, (1.0/(double)n), dres[7], t);
+ i += sprintf(TmpTxt+i, "Desc=\"%g%% C.I.\"\n", ci);
+ OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
+#endif
+ ts = t * sqrt(dres[7]*((dBounds.Xmax-dres[2])*(dBounds.Xmax-dres[2])/sxx +1.0/(double)n));
+ ty = dBounds.Xmax * dres[0] +dres[1];
+ ly[0] = ty +ts; ly[1] = ty -ts;
+ ts = t * sqrt(dres[7]*((dBounds.Xmin-dres[2])*(dBounds.Xmin-dres[2])/sxx +1.0/(double)n));
+ ty = dBounds.Xmin * dres[0] +dres[1];
+ ly[2] = ty +ts; ly[3] = ty -ts;
+ for(i = 0; i < 4; i++) if(ly[i] > -HUGE_VAL && ly[i] < HUGE_VAL) {
+ if(ly[i] < dBounds.Ymin) dBounds.Ymin = ly[i];
+ if(ly[i] > dBounds.Ymax) dBounds.Ymax = ly[i];
+ }
+#ifdef USE_WIN_SECURE
+ if(!bParZ) sprintf_s(TmpTxt, TMP_TXT_SIZE, "y = %g %c %g * x",dres[1],(dres[0] < 0.0 ? '-' : '+'), fabs(dres[0]));
+ else sprintf_s(TmpTxt, TMP_TXT_SIZE, "y = %g * x", fabs(dres[0]));
+#else
+ if(!bParZ) sprintf(TmpTxt, "y = %g %c %g * x",dres[1],(dres[0] < 0.0 ? '-' : '+'), fabs(dres[0]));
+ else sprintf(TmpTxt, "y = %g * x", fabs(dres[0]));
+#endif
+ rep_DrawText(graph, (graph->GetSize(SIZE_DRECT_LEFT) + graph->GetSize(SIZE_DRECT_RIGHT))/2.0,
+ graph->GetSize(SIZE_DRECT_TOP)+txtdef1.fSize/2.0, true, TXA_HCENTER, &txtdef1, TmpTxt);
+ page = new Page(parent, data); page->Command(CMD_DROP_GRAPH, graph, 0L);
+ graph->moveable = 0;
+ graph->GRect.Xmin += (txtdef1.fSize*5.0); graph->GRect.Xmax += (txtdef1.fSize*5.0);
+ graph->GRect.Ymin += (txtdef1.fSize*10.0); graph->GRect.Ymax += (txtdef1.fSize*10.0);
+ mk_header(page, "<b>Linear Regression Analysis</b>", data);
+ res_tab[0][0] = 1; res_tab[1][0] = df;
+ res_tab[2][0] = df+1.0; res_tab[0][1] = sxy*sxy/sxx;
+ res_tab[1][1] = syy-res_tab[0][1]; res_tab[2][1] = syy;
+ res_tab[0][2] = res_tab[0][1]; res_tab[1][2] = res_tab[1][1]/df;
+ res_tab[0][3] = dres[8]; res_tab[0][4] = dres[9];
+ dres[12] = res_tab[0][1]/res_tab[2][1];
+ c_y = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*3.0;
+ c_x = graph->GRect.Xmin;
+ c_y = mk_regr_summary(page, c_x, c_y, dres, ci, n);
+ rep_DrawText(page, c_x, c_y, false, TXA_HLEFT, &txtdef1, "<b>Anova:</b>");
+ c_y += txtdef1.fSize*1.5; mk_table(page, c_x, c_y, 2, res_tab);
+ parent->Command(CMD_DROP_GRAPH, page, 0L);
+ }
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg; if(res_tab) {
+ for(i = 0; i < 3; i++) if(res_tab[i]) free(res_tab[i]);
+ free(res_tab);
+ }
+ if(x_desc) free(x_desc); if(y_desc)free(y_desc);
+ if(x) free(x); if(y) free(y);
+ if(rX) delete rX; if(rY) delete rY; free(RegrDlg);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Kendall's robust line-fit
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *RobLineDlg_Tmpl =
+ "1,+,,DEFAULT,PUSHBUTTON,-1,148,10,45,12\n"
+ ".,.,,,PUSHBUTTON,-2,148,25,45,12\n"
+ ".,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "4,10,100,ISPARENT | CHECKED,SHEET,1,5,10,130,78\n"
+ "10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+ "100,+,,,LTEXT,2,10,30,60,8\n"
+ ".,.,,,RANGEINPUT,-15,20,40,100,10\n"
+ ".,.,,,LTEXT,3,10,55,60,8\n"
+ ".,,,LASTOBJ,RANGEINPUT,-16,20,65,100,10";
+
+void
+rep_robustline(GraphObj *parent, DataObj *data)
+{
+ TabSHEET tab1 = {0, 90, 10, "Nonparametric Regression"};
+ DlgInfo *RegrDlg;
+ void *dyndata[] = {(void*)&tab1, (void*)"range for x-data", (void*)"range for y-data"};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, j, k, n, n1, rx, cx, ry, cy, res, align = 0;
+ int x_dtype, y_dtype, nVals, nTxt, nTime;
+ bool bContinue = false, bValid;
+ AccRange *rX = 0L, *rY = 0L;
+ double *x = 0L, *y = 0L, *a = 0L, *b = 0L, c_x, c_y;
+ double dx, dy, slope, intercept;
+ char *txt_obj, *x_desc=0L, *y_desc=0L;
+ scaleINFO scale = {{0.0, 0.45}, {0.0, 0.45}, {0.0, 0.45}};
+ anyResult xRes, yRes;
+ TextValue *x_tv, *y_tv;
+ Plot *plot;
+ Graph *graph;
+ Page *page;
+
+ if(!parent || !data) return;
+ if(!(RegrDlg = CompileDialog(RobLineDlg_Tmpl, dyndata))) return;
+ UseRangeMark(data, 1, TmpTxt, TmpTxt+100);
+ if(!(Dlg = new DlgRoot(RegrDlg, data)))return;
+ hDlg = CreateDlgWnd("Kendall's robust line-fit", 50, 50, 420, 220, Dlg, 0x4L);
+ 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 1:
+ if(rX) delete rX; if(rY) delete rY;
+ rX = rY = 0L;
+ if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) rX = new AccRange(TmpTxt);
+ n = rX ? rX->CountItems() : 0;
+ if(!n) {
+ ErrorBox("Range not specified\nor not valid.");
+ bContinue = true;
+ res = -1;
+ }
+ if(n && Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE) && (rY = new AccRange(TmpTxt))){
+ if(n != rY->CountItems()) {
+ ErrorBox("Both ranges must be given\nand must have the same size");
+ bContinue = true;
+ res = -1;
+ }
+ }
+ }
+ }while (res < 0);
+ for(n1 = n, i = k = 1; i < n; i++) k += i;
+ if(res == 1 && n >1 && rX && rY && (x = (double*)malloc(n*sizeof(double)))
+ && (y = (double*)malloc(n*sizeof(double)))
+ && (a = (double*)malloc(k*sizeof(double)))
+ && (b = (double*)malloc(k*sizeof(double)))){
+ x_desc = rX->RangeDesc(data, 0); y_desc = rY->RangeDesc(data, 0);
+ //analyse data types
+ x_dtype = y_dtype = 0; x_tv = y_tv = 0L;
+ if(rX->DataTypes(data, &nVals, &nTxt, &nTime)){
+ if(!nVals && nTxt > 1 && nTxt > nTime) x_tv = new TextValue();
+ else if(!nVals && nTime > 1 && nTime > nTxt) x_dtype = ET_DATETIME;
+ }
+ if(rY->DataTypes(data, &nVals, &nTxt, &nTime)){
+ if(!nVals && nTxt > 1 && nTxt > nTime) y_tv = new TextValue();
+ else if(!nVals && nTime > 1 && nTime > nTxt) y_dtype = ET_DATETIME;
+ }
+ rX->GetFirst(&cx, &rx); rY->GetFirst(&cy, &ry);
+ rep_init();
+ dBounds.Xmin = dBounds.Ymin = HUGE_VAL; dBounds.Xmax = dBounds.Ymax = -HUGE_VAL;
+ //read data into x[] and y[]
+ for(i = n = 0; i < n1 && rX->GetNext(&cx, &rx) && rY->GetNext(&cy, &ry); i++) {
+ bValid = false;
+ if(data->GetResult(&xRes, rx, cx, false) && data->GetResult(&yRes, ry, cy, false)) {
+ bValid = true;
+ if(x_tv) {
+ if(xRes.type == ET_TEXT) dx = x_tv->GetValue(xRes.text);
+ else bValid = false;
+ }
+ else if(x_dtype == ET_DATETIME) {
+ if(xRes.type == ET_DATE || xRes.type == ET_TIME || xRes.type == ET_DATETIME) dx = xRes.value;
+ else bValid = false;
+ }
+ else {
+ if(xRes.type == ET_VALUE) dx = xRes.value;
+ else bValid = false;
+ }
+ if(y_tv) {
+ if(yRes.type == ET_TEXT) dy = y_tv->GetValue(yRes.text);
+ else bValid = false;
+ }
+ else if(y_dtype == ET_DATETIME) {
+ if(yRes.type == ET_DATE || yRes.type == ET_TIME || yRes.type == ET_DATETIME) dy = yRes.value;
+ else bValid = false;
+ }
+ else {
+ if(yRes.type == ET_VALUE) dy = yRes.value;
+ else bValid = false;
+ }
+ }
+ if(bValid){
+ x[n] = dx; y[n] = dy;
+ if(dBounds.Xmin > x[n]) dBounds.Xmin = x[n];
+ if(dBounds.Xmax < x[n]) dBounds.Xmax = x[n];
+ if(dBounds.Ymin > y[n]) dBounds.Ymin = y[n];
+ if(dBounds.Ymax < y[n]) dBounds.Ymax = y[n];
+ n++;
+ }
+ }
+ SortArray2(n, x, y);
+ for(i = k = 0; i < (n-1); i++) for(j = i+1; j < n; j++) {
+ if(x[i] != x[j]) {
+ b[k] = (y[j] - y[i])/(x[j] - x[i]);
+ a[k] = y[i] - b[k]*x[i]; k++;
+ }
+ }
+ d_quartile(k, b, 0L, &slope, 0L); d_quartile(k, a, 0L, &intercept, 0L);
+ slope = slope; intercept = intercept;
+ if (n && (graph = new Graph(parent, data, 0L, 0))) {
+ if(txt_obj = mk_scatt(0, x, y, 0L, 0L, n, "Data", x_desc, y_desc)){
+ OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+ free(txt_obj);
+ if(LastOpenGO && LastOpenGO->Id >= GO_PLOT && LastOpenGO ->Id < GO_GRAPH) {
+ ((Plot*)LastOpenGO)->x_dtype = x_dtype; ((Plot*)LastOpenGO)->y_dtype = y_dtype;
+ ((Plot*)LastOpenGO)->x_tv = x_tv; ((Plot*)LastOpenGO)->y_tv = y_tv;
+ }
+ }
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "[1=Function]\nx1= %g\nx2= %g\nxstep= %g\nLine= %g 1 0x000000ff 0x0\n",
+ dBounds.Xmin, dBounds.Xmax, (dBounds.Xmax -dBounds.Xmin)/100.0, defs.GetSize(SIZE_DATA_LINE));
+ i += sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, "f_xy=\"%g+x*%g\\n\"\n", intercept, slope);
+ i += sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, "Desc=\"Fitted Line\"\n");
+ OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "y = %g %c %g * x",intercept,(slope < 0.0 ? '-' : '+'), fabs(slope));
+#else
+ i = sprintf(TmpTxt, "[1=Function]\nx1= %g\nx2= %g\nxstep= %g\nLine= %g 1 0x000000ff 0x0\n",
+ dBounds.Xmin, dBounds.Xmax, (dBounds.Xmax -dBounds.Xmin)/100.0, defs.GetSize(SIZE_DATA_LINE));
+ i += sprintf(TmpTxt+i, "f_xy=\"%g+x*%g\\n\"\n", intercept, slope);
+ i += sprintf(TmpTxt+i, "Desc=\"Fitted Line\"\n");
+ OpenGraph(graph, 0L, (unsigned char*)TmpTxt, false);
+ sprintf(TmpTxt, "y = %g %c %g * x", intercept, (slope < 0.0 ? '-' : '+'), fabs(slope));
+#endif
+ rep_DrawText(graph, (graph->GetSize(SIZE_DRECT_LEFT) + graph->GetSize(SIZE_DRECT_RIGHT))/2.0,
+ graph->GetSize(SIZE_DRECT_TOP)+txtdef1.fSize/2.0, true, TXA_HCENTER, &txtdef1, TmpTxt);
+ page = new Page(parent, data); page->Command(CMD_DROP_GRAPH, graph, 0L);
+ graph->moveable = 0;
+ graph->GRect.Xmin += (txtdef1.fSize*5.0); graph->GRect.Xmax += (txtdef1.fSize*5.0);
+ graph->GRect.Ymin += (txtdef1.fSize*9.0); graph->GRect.Ymax += (txtdef1.fSize*9.0);
+ mk_header(page, "<b>Kendall's Robust Line-Fit</b>", data);
+ c_y = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*2.0;
+ c_x = graph->GRect.Xmin;
+ j = (int)isqr(k); i = (int)((double)k/10.0);
+ if(j < 8) j = 8;
+ else if (j >40) j = 40;
+ scale.sx.fx = (graph->GRect.Xmin + graph->GRect.Xmax)/2.0;
+ scale.sy.fx = c_y;
+ graph = new Graph(parent, data, 0L, 0);
+ if(plot = new FreqDist(graph, data, b+(i>>1), k-i, j)){
+ if(plot->x_info = (char*)malloc(30)) rlp_strcpy(plot->x_info, 30, "90% of all slopes");
+ if(plot->y_info = (char*)malloc(30)) rlp_strcpy(plot->y_info, 30, "No. of observations");
+ if(!(graph->Command(CMD_DROP_PLOT, plot, 0L))) delete(plot);
+ }
+ graph->Command(CMD_SCALE, &scale, 0L);
+ page->Command(CMD_DROP_GRAPH, graph, 0L);
+ mk_median_report(page, c_x, c_y, b, k, .95, "Slope");
+ scale.sy.fx = c_y = graph->GRect.Ymax + txtdef1.fSize;
+ graph = new Graph(parent, data, 0L, 0);
+ if(plot = new FreqDist(graph, data, a+(i>>1), k-i, j)){
+ if(plot->x_info = (char*)malloc(30)) rlp_strcpy(plot->x_info, 30, "90% of all intercepts");
+ if(plot->y_info = (char*)malloc(30)) rlp_strcpy(plot->y_info, 30, "No. of observations");
+ if(!(graph->Command(CMD_DROP_PLOT, plot, 0L))) delete(plot);
+ }
+ graph->Command(CMD_SCALE, &scale, 0L);
+ page->Command(CMD_DROP_GRAPH, graph, 0L);
+ c_y = mk_median_report(page, c_x, c_y, a, k, .95, "Intercept");
+ parent->Command(CMD_DROP_GRAPH, page, 0L);
+ }
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(x_desc) free(x_desc); if(y_desc)free(y_desc);
+ if(x) free(x); if(y) free(y);
+ if(a) free(a); if(b) free(b);
+ if(rX) delete rX; if(rY) delete rY; free(RegrDlg);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Correlation reports
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *RepCorrel_DlgTmpl =
+ "1,2,,DEFAULT,PUSHBUTTON,-1,158,10,45,12\n"
+ "2,3,,,PUSHBUTTON,-2,158,25,45,12\n"
+ "3,,10,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "10,11,152,ISPARENT | CHECKED, SHEET,1,5,10,140,70\n"
+ "11,20,200,ISPARENT | TOUCHEXIT,SHEET,2,5,10,140,70\n"
+ "20,21,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+ "21,22,,CHECKED,CHECKBOX,7,25,85,130,9\n"
+ "22,23,,,LTEXT,8,35,95,50,9\n"
+ "23,24,,,EDVAL1,9,87,95,30,10\n"
+ "24,,,,LTEXT,-10,120,95,10,9\n"
+ "152,153,,ISPARENT | CHECKED,GROUPBOX,3,12,30,128,45\n"
+ "153,154,,,LTEXT,0,25,35,60,8\n"
+ "154,155,,,RANGEINPUT,0,25,45,100,10\n"
+ "155,156,0,,PUSHBUTTON,-8,95,57,30,12\n"
+ "156,,,,PUSHBUTTON,-9,60,57,35,12\n"
+ "200,201,,TOUCHEXIT,RADIO1,4,25,30,60,8\n"
+ "201,202,,TOUCHEXIT,RADIO1,5,25,45,60,8\n"
+ "202,,,TOUCHEXIT,RADIO1,6,25,60,60,8\n"
+ "300,,,LASTOBJ,NONE,0,0,0,0,0";
+static int use_corr = 2;
+static double use_ci = 95.0;
+
+void rep_correl(GraphObj *parent, DataObj *data, int style)
+{
+ TabSHEET tab1 = {0, 25, 10, "Data"};
+ TabSHEET tab2 = {25, 57, 10, "Method"};
+
+ void *dyndata[] = {(void*)&tab1, (void*)&tab2,
+ (void*)" select one range for every variable ", (void*)" Pearsons product moment",
+ (void*)" Spearmans rank correlation", (void*)" Kendalls Tau", (void*)" highlight significant correlations,",
+ (void*)"sigificance level", (void*)&use_ci};
+ DlgInfo *CorrelDlg;
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, j, res, nr, currYR = 0, maxYR = 0, ny, corr;
+ int r1, c1, r2, c2, n, cb;
+ bool updateYR = true, bContinue = false, bMtab = false, bHiLite;
+ double lmarg, line_inc, *v1, *v2, val1, val2, cx, cy, r,dn, p, sf, ra[20], cl;
+ char **rd = 0L, *txt_obj, *info1, *info2;
+ scaleINFO scale = {{0.0, 0.14}, {0.0, 0.14}, {0.0, 0.14}};
+ AccRange *rV1 = 0L, *rV2 = 0L;
+ TextDEF mtext;
+ Plot *plot;
+ Graph *graph;
+ Page *page;
+
+ if(!parent || !data) return;
+ info1 = info2 = 0L;
+ if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
+ TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return;
+ if(!(CorrelDlg = CompileDialog(RepCorrel_DlgTmpl, dyndata))) return;
+ if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
+ for(i=j=0; i <= 1000; i +=100) if(TmpTxt[i])
+ rd[j++] = (char*)memdup(TmpTxt+i, ((int)strlen(TmpTxt+i))+2, 0); maxYR = j-1;
+ }
+ if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return;
+ if(!(Dlg = new DlgRoot(CorrelDlg, data))) return;
+ if(rd && rd[currYR] && *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
+ switch(use_corr) {
+ case 1: Dlg->SetCheck(200, 0L, true); corr = 1; break;
+ default: Dlg->SetCheck(201, 0L, true); corr = 2; break;
+ case 3: Dlg->SetCheck(202, 0L, true); corr = 3; break;
+ }
+ hDlg = CreateDlgWnd(style? (char*)"Create Tiled Correlation Plots" :
+ (char*)"Create a Correlation Matrix", 50, 50, 420, 252, Dlg, 0x4L);
+ do {
+ if(updateYR) {
+ if(currYR >0) Dlg->ShowItem(156, true);
+ else Dlg->ShowItem(156, false);
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "variable # %d/%d", currYR+1, maxYR+1);
+#else
+ sprintf(TmpTxt,"variable # %d/%d", currYR+1, maxYR+1);
+#endif
+ Dlg->SetText(153, 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 11: //select correlation method
+ bMtab = true; res =-1; break;
+ case 200: //select pearson
+ case 201: //select spearman
+ case 202: //select kendall
+ corr = res-199; res =-1; break;
+ case 1:
+ if(!bMtab) {
+ Dlg->SetCheck(11, 0L, true);
+ bMtab = true; res = -1;
+ break;
+ }
+ case 155: case 156:
+ res = com_StackDlg(res, Dlg, 0L, 0L, &rd, &currYR,
+ &rV1, &bContinue, &ny, &maxYR, &updateYR);
+ break;
+ }
+ }while (res < 0);
+
+ if(res ==1) {
+ if(bHiLite = Dlg->GetCheck(21)) {
+ Dlg->GetValue(23, &use_ci); cl = 1.0 - use_ci/100.0;
+ }
+ maxYR++; rep_init(); page = new Page(parent, data);
+ if(rV1) delete rV1; rV1 = 0L; use_corr = corr;
+ switch(corr) {
+ case 1:
+ mk_header(page, "<b>Pearsons product moment correlations</b>", data);
+ break;
+ case 2:
+ mk_header(page, "<b>Spearmans rank correlations</b>", data);
+ break;
+ case 3:
+ mk_header(page, "<b>Kendalls non parametric correlations</b>", data);
+ break;
+ default:
+ mk_header(page, "<b>### Correlation Error ###</b>", data);
+ break;
+ }
+ memcpy(&mtext, &txtdef1, sizeof(TextDEF));
+ if(style == 0) {
+ lmarg = txtdef1.fSize*12.0;
+ cy = txtdef1.fSize*13.0; cx = txtdef1.fSize*6.0;
+ line_inc = linsp1;
+ sf = (page->GetSize(SIZE_GRECT_RIGHT)-lmarg-linsp1)/(cx *(double)maxYR);
+ if(sf< 1.0) {
+ cx *= sf; line_inc *= sf; lmarg *= sf;
+ mtext.fSize *= sf; mtext.iSize = 0;
+ }
+ }
+ else {
+ lmarg = txtdef1.fSize*8.0;
+ cy = txtdef1.fSize*13.0;
+ cx = (page->GetSize(SIZE_GRECT_RIGHT)-txtdef1.fSize*3.0-lmarg)/maxYR;
+ switch(defs.cUnits) {
+ default:
+ scale.sx.fy = scale.sy.fy = scale.sz.fy = cx/165.0; break;
+ case 1:
+ scale.sx.fy = scale.sy.fy = scale.sz.fy = cx/16.50; break;
+ case 2:
+ scale.sx.fy = scale.sy.fy = scale.sz.fy = cx/6.49606; break;
+ }
+ line_inc = cx/1.44;
+ }
+ for(nr = maxYR, i = 0; i < nr; i++) for(j = 0; j < nr; j++) {
+ if(i == 0 &&(rV1 = new AccRange(rd[j]))) { //first row
+ if(info1 = rV1->RangeDesc(data, style == 0 || nr > 5 ? 1 : 2)) {
+ if(style == 0)
+ rep_DrawText(page, lmarg+cx*j, cy-txtdef1.fSize*2.0, false, TXA_HCENTER, &mtext, info1);
+ else if(style == 1)
+ rep_DrawText(page, lmarg+cx*j+cx/2.0, cy-txtdef1.fSize*2.0, false, TXA_HCENTER, &mtext, info1);
+ free(info1); info1 = 0L;
+ }
+ delete rV1; rV1 = 0L;
+ }
+ if(j == 0 &&(rV1 = new AccRange(rd[i]))) { //first column
+ if(info1 = rV1->RangeDesc(data, 1)) {
+ if(style == 0)
+ rep_DrawText(page, lmarg-cx/2.0-txtdef1.fSize, cy+line_inc, false, TXA_HRIGHT, &mtext, info1);
+ else if(style == 1)
+ rep_DrawText(page, lmarg-txtdef1.fSize, cy+line_inc/2.0-mtext.fSize/2.0, false, TXA_HRIGHT, &mtext, info1);
+ free(info1); info1 = 0L;
+ }
+ delete rV1; rV1 = 0L;
+ }
+ if(i == j) { //self correlation: do something else ...
+ if(style == 0) { //correlation matrix
+ rep_DrawText(page, lmarg+cx*j, cy+line_inc, false, TXA_HCENTER, &mtext, "---");
+ }
+ else if(style = 1) { //tiled plots
+ graph = new Graph(parent, data, 0L, 0);
+ scale.sx.fx = lmarg+cx*j; scale.sy.fx = cy;
+ if(plot = new FreqDist(graph, data, rd[i], true)){
+ if(rV1 = new AccRange(rd[i])){
+ plot->x_info = rV1->RangeDesc(data, 2);
+ delete rV1; rV1 = 0L;
+ }
+ if(!(graph->Command(CMD_DROP_PLOT, plot, 0L))) delete(plot);
+ }
+ graph->Command(CMD_SCALE, &scale, 0L);
+ page->Command(CMD_DROP_GRAPH, graph, 0L);
+ }
+ }
+ else {
+ rV1 = new AccRange(rd[i]); rV2 = new AccRange(rd[j]);
+ v1 = (double*)malloc((rV1->CountItems()+1) * sizeof(double));
+ v2 = (double*)malloc((rV2->CountItems()+1) * sizeof(double));
+ dBounds.Xmin = dBounds.Ymin = HUGE_VAL; dBounds.Xmax = dBounds.Ymax = -HUGE_VAL;
+ rV1->GetFirst(&c1, &r1); rV2->GetFirst(&c2, &r2);
+ //copy values into arrays
+ for(n = 0; rV1->GetNext(&c1, &r1) && rV2->GetNext(&c2, &r2); ) {
+ if(data->GetValue(r1, c1, &val1) && data->GetValue(r2, c2, &val2)) {
+ if(dBounds.Xmin > val1) dBounds.Xmin = val1;
+ if(dBounds.Xmax < val1) dBounds.Xmax = val1;
+ if(dBounds.Ymin > val2) dBounds.Ymin = val2;
+ if(dBounds.Ymax < val2) dBounds.Ymax = val2;
+ v1[n] = val1; v2[n] = val2; n++;
+ }
+ }
+ //do correlation
+ dn = n; r = 0.0;
+ if(n) switch(corr) {
+ case 1:
+ d_pearson(v1, v2, n, 0L, 0L, ra);
+ r = ra[0]; p = ra[2]; dn = ra[3];
+ break;
+ case 2:
+ d_spearman(v1, v2, n, 0L, 0L, ra);
+ r = ra[3]; p = ra[4]; dn = ra[5];
+ break;
+ case 3:
+ d_kendall(v1, v2, n, 0L, 0L, ra);
+ r = ra[0]; p = ra[2]; dn = ra[3];
+ break;
+ default:
+ r = 0.0; dn = 0.0; p = 1.0; break;
+ }
+ //process result
+ if(dn > 1.0 && style == 0) { //correlation matrix
+ if(bHiLite && p < cl && (txt_obj = mk_rect(lmarg+cx*j-cx/2.1, cy-line_inc/4.0, lmarg+cx*j+cx/2.1,
+ cy+line_inc*3.25, 0x0000ffffL, 0x0080ffffL))) {
+ OpenGraph(page, 0L, (unsigned char*)txt_obj, false);
+ free(txt_obj);
+ }
+ dbl_to_str1(TmpTxt, 80, "%g", r);
+ rep_DrawText(page, lmarg+cx*j, cy, false, TXA_HCENTER, &mtext, TmpTxt);
+ dbl_to_str1(TmpTxt, 80, "n = %g", dn);
+ rep_DrawText(page, lmarg+cx*j, cy+line_inc, false, TXA_HCENTER, &mtext, TmpTxt);
+ dbl_to_str1(TmpTxt, 80, p < 0.001 ? (char*)"P < 0.0001" : (char*)"P = %.4lf", p);
+ rep_DrawText(page, lmarg+cx*j, cy+line_inc*2.0, false, TXA_HCENTER, &mtext, TmpTxt);
+ if(j == (nr-1)) cy += (line_inc*4.0);
+ }
+ else if(style == 0) { //corr. matrix but no data
+ if(j == (nr-1)) cy += (line_inc*4.0);
+ }
+ else if(style == 1) { //tiled plots
+ graph = new Graph(parent, data, 0L, 0);
+ scale.sx.fx = lmarg+cx*j; scale.sy.fx = cy;
+ info1 = rV1->RangeDesc(data, 2); info2 = rV2->RangeDesc(data, 2);
+ if(txt_obj = mk_scatt(0, v1, v2, 0L, 0L, n, "Data", info1, info2)){
+ OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+ free(txt_obj);
+ }
+ if(info1) free(info1); if(info2) free(info2);
+ info1 = info2 = 0L;
+ if(bHiLite && p < cl) {
+ graph->SetColor(COL_GRECT, 0x0000ffffL); graph->SetColor(COL_DRECT, 0x00c0ffffL);
+ }
+ switch(corr) {
+ case 1:
+ cb = dbl_to_str2(TmpTxt, 80, "r = %.4lf, n = %g, ", r, dn); break;
+ case 2:
+ cb = dbl_to_str2(TmpTxt, 80, "r<sub>S</sub> = %.4lf, n = %g, ", r, dn); break;
+ case 3:
+ cb = dbl_to_str2(TmpTxt, 80, "r<sub>K</sub> = %.4lf, n = %g, ", r, dn); break;
+ default:
+ TmpTxt[0] = 0; cb = 0; break;
+ }
+ dbl_to_str1(TmpTxt+cb, 80, p < 0.001 ? (char*)"P < 0.0001" : (char*)"P = %.4lf", p);
+ rep_DrawText(graph, graph->GetSize(SIZE_DRECT_LEFT)+txtdef1.fSize,
+ graph->GetSize(SIZE_DRECT_TOP)+txtdef1.fSize, false, TXA_HLEFT, &txtdef1, TmpTxt);
+ if(LastOpenGO)LastOpenGO->SetColor(COL_TEXT, 0x00cb0000L);
+ graph->Command(CMD_SCALE, &scale, 0L);
+ if(dn > 1.0) page->Command(CMD_DROP_GRAPH, graph, 0L);
+ if(j == (nr-1)) cy += line_inc;
+ }
+ free(v1); free(v2);
+ if(rV1)delete rV1; if(rV2)delete rV2; rV1 = rV2 = 0L;
+ }
+ }
+ parent->Command(CMD_DROP_GRAPH, page, 0L);
+ }
+ CloseDlgWnd(hDlg);
+ delete Dlg;
+ if(rd) {
+ for (i = 0; i < maxYR; i++) if(rd[i]) free(rd[i]);
+ free(rd);
+ }
+ if(rV2) delete rV2; if(rV1) delete rV1; free(CorrelDlg);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 2x2 table
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *twDlg_Tmpl =
+ "1,2,100,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "2,3,400,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "3,4,600,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+ "4,5,,DEFAULT,PUSHBUTTON,-1,168,10,45,12\n"
+ "5,,,,PUSHBUTTON,2,168,25,45,12\n"
+ "100,101,,,CTEXT,1,35,10,40,8\n"
+ "101,102,,,EDTEXT,0,35,20,40,10\n"
+ "102,103,,,EDTEXT,0,77,20,40,10\n"
+ "103,104,,,EDTEXT,0,35,32,40,10\n"
+ "104,105,,,EDTEXT,0,77,32,40,10\n"
+ "105,106,,,LTEXT,3,10,20,40,8\n"
+ "106,107,,,LTEXT,4,10,32,40,8\n"
+ "107,,,,CTEXT,5,77,10,40,8\n"
+ "400,401,,,EDTEXT,0,119,20,40,10\n"
+ "401,402,,,EDTEXT,0,119,32,40,10\n"
+ "402,403,,,EDTEXT,0,35,44,40,10\n"
+ "403,404,,,EDTEXT,0,77,44,40,10\n"
+ "404,405,,,EDTEXT,0,119,44,40,10\n"
+ "405,406,,,CTEXT,6,119,10,40,8\n"
+ "406,407,,,LTEXT,7,10,44,40,8\n"
+ "407,408,,,LTEXT,2,35,59,40,8\n"
+ "408,409,,,LTEXT,2,35,69,40,8\n"
+ "409,410,,,LTEXT,8,119,59,60,8\n"
+ "410,,,,LTEXT,0,119,69,60,8\n"
+ "600,601,,DEFAULT,PUSHBUTTON,-1,128,10,45,12\n"
+ "601,,,LASTOBJ,PUSHBUTTON,-2,128,25,45,12";
+
+void rep_twowaytable(GraphObj *parent, DataObj *data)
+{
+ DlgInfo *twDlg;
+ void *dyndata[] = {(void*)"Group A", (void*)"Close", (void*)"Case 1", (void*)"Case 2",
+ (void*)"Group B", (void*)"A + B", (void*)"C1+C2", (void*)"Fisher's exact:"};
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, r, c, level, res, wcc;
+ int v_idx[] = {101,102,400,103,104,401,402,403,404};
+ double tmp, v[9], chi2, p, dn, pf, pfa[128];
+ char *rng;
+ AccRange *ar;
+
+ if(!parent || !data) return;
+ if(!(twDlg = CompileDialog(twDlg_Tmpl, dyndata))) return;
+ if(!(Dlg = new DlgRoot(twDlg, data)))return;
+ for(i = 400; i < 405; i++) Dlg->Activate(i, false);
+ if(data->Command(CMD_GETMARK, &rng, 0L) && rng && rng[0] && (ar = new AccRange(rng)) && ar->GetFirst(&c, &r)) {
+ for(i = 0; i < 4 && ar->GetNext(&c, &r); ) {
+ if(data->GetValue(r, c, &tmp)) {
+ Dlg->SetValue(101+i, tmp); i++;
+ }
+ }
+ delete ar;
+ if(i == 4) Dlg->ItemCmd(600, CMD_ENDDIALOG, 0L);
+ }
+ level = wcc = 0;
+ Dlg->ShowItem(2, false); Dlg->ShowItem(4, false);
+ Dlg->ShowItem(5, false);
+ hDlg = CreateDlgWnd("2x2 Table", 50, 50, 450, 200, Dlg, 0x4L);
+ ResizeDlgWnd(hDlg, 370, 150);
+ do {
+ LoopDlgWnd();
+ res = Dlg->GetResult();
+ switch(res) {
+ case 0:
+ res = -1;
+ break;
+ case 600: //level 0 OK
+ Dlg->ShowItem(2, true); Dlg->ShowItem(4, true);
+ Dlg->ShowItem(5, true); Dlg->ShowItem(3, false);
+ ResizeDlgWnd(hDlg, 450, 200); Dlg->Command(CMD_REDRAW, 0L, 0L);
+ level = 1;
+ case 4: //level 1 OK
+ for(i = 0; i < 9; i++) {
+ v[i] = 0.0; Dlg->GetValue(v_idx[i], &v[i]);
+ v[i] = fabs(floor(v[i]));
+ }
+ v[2] = v[0] + v[1]; v[5] = v[3] + v[4];
+ v[6] = v[0] + v[3]; v[7] = v[1] + v[4];
+ v[8] = v[6] + v[7]; chi2 = v[0]*v[4]-v[1]*v[3];
+ for(i = wcc = 0; i < 9; i++) {
+ dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "%g", v[i]);
+ Dlg->SetText(v_idx[i], TmpTxt);
+ }
+ if(v[8] < 128.0) do {
+ pf = factrl((int)v[2])/factrl((int)v[0])*factrl((int)v[5])/factrl((int)v[1])
+ *factrl((int)v[6])/factrl((int)v[3])*factrl((int)v[7])/factrl((int)v[4]);
+ pf /= factrl((int)v[8]);
+ pfa[wcc++] = pf;
+ //worse case correction
+ //RR Sokal & FJ Rohlf: Biometry, 3rd ed., pp. 734 ff.
+ if((v[0]*v[4]- v[1]*v[3]) < 0.0) {
+ v[0]-=1.0; v[4]-=1.0; v[1]+=1.0; v[3]+=1.0;
+ }
+ else if((v[0]*v[4]- v[1]*v[3]) > 0.0) {
+ v[0]+=1.0; v[4]+=1.0; v[1]-=1.0; v[3]-=1.0;
+ }
+ else break;
+ }while(v[0]>=0.0 && v[1]>=0.0 && v[3]>=0.0 && v[4]>=0.0 && wcc < 128);
+ if(wcc){
+ for(i = 1, pf = pfa[0]; i < wcc; i++){
+ pf += pfa[i];
+ }
+ if(pf > 1.0) pf = 1.0;
+ dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "P(one sided) = %.4lf", pf);
+ Dlg->SetText(410, pf >= 0.001 ? TmpTxt : (char*)"P < 0.001");
+ }
+ else Dlg->SetText(410, "- - -");
+ dn = (v[2]*v[5]*v[6]*v[7]);
+ chi2 = dn > 0.0 ? (chi2*chi2*v[8])/dn : 0.0;
+ p = chi_dist(chi2, 1.0, 1.0);
+ dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "Chi2 = %g", chi2);
+ Dlg->SetText(407, TmpTxt);
+ if(p >= 0.001) {
+ dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "P = %g", p);
+ Dlg->SetText(408, TmpTxt);
+ }
+ else Dlg->SetText(408, "P < 0.001");
+ Dlg->Command(CMD_REDRAW, 0L, 0L);
+ res= -1;
+ break;
+ }
+ }while (res < 0);
+ CloseDlgWnd(hDlg);
+ delete Dlg; free(twDlg);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// compare means / medians of two groups
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void rep_compmeans(GraphObj *parent, DataObj *data)
+{
+ TabSHEET tab1 = {0, 42, 10, "Data Input"};
+ double ci = 95.0;
+ DlgInfo *MeanDlg;
+ void *dyndata[] = {(void*)&tab1, (void*)"range for first variable",
+ (void*)"range for second variable", (void*)"confidence interval:",
+ (void*)&ci, (void*)" "};
+ char *ttest[] = {"Student's t = %g", "P = %g", "P(corr.) = %g"};
+ char *utest[] = {"Mann-Whitney U = %g", "z = %g", "P = %g", "z(corr.) = %g", "P(corr.) = %g"};
+ char g1_nam[30], g2_nam[30], *c_name;
+ DlgRoot *Dlg;
+ void *hDlg;
+ int i, j, res, n1, n2, r, c, *ny;
+ bool bContinue = false;
+ double *d1, *d2, dtmp, *rs, cx, cy, min1,max1, min2, max2;
+ scaleINFO scale = {{0.0, 0.9}, {0.0, 0.9}, {0.0, 0.9}};
+ char *txt_obj;
+ anyResult ares;
+ AccRange *rD;
+ Graph *graph;
+ Page *page;
+
+ if(!parent || !data) return;
+ if(!(MeanDlg = CompileDialog(RegrDlg_Tmpl, dyndata))) return;
+ UseRangeMark(data, 1, TmpTxt, TmpTxt+100);
+ if(!(Dlg = new DlgRoot(MeanDlg, data)))return;
+ Dlg->ShowItem(107, false);
+ d1 = d2 = 0L;
+ hDlg = CreateDlgWnd("Compare Means", 50, 50, 420, 260, Dlg, 0x4L);
+ 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 1:
+ if(d1) free(d1); if(d2) free(d2); d1 = d2 = 0L;
+ min1 = min2 = dBounds.Ymin = HUGE_VAL; max1 = max2 = dBounds.Ymax = -HUGE_VAL;
+ if(Dlg->GetText(101,TmpTxt,TMP_TXT_SIZE)&&(rD=new AccRange(TmpTxt))&&(n1=rD->CountItems())&&(d1=(double*)malloc(n1*sizeof(double)))){
+ if(c_name = rD->RangeDesc(data, 2)) {
+ rlp_strcpy(g1_nam, 30, c_name); g1_nam[0] = toupper(g1_nam[0]);
+ free(c_name);
+ }
+ else rlp_strcpy(g1_nam, 30, "Group 1");
+ for(n1 = 0, rD->GetFirst(&c, &r); rD->GetNext(&c, &r); ) {
+ if(data->GetResult(&ares, r, c, false) && ares.type == ET_VALUE){
+ if(dBounds.Ymin > ares.value) dBounds.Ymin = ares.value;
+ if(dBounds.Ymax < ares.value) dBounds.Ymax = ares.value;
+ if(min1 > ares.value) min1 = ares.value; if(max1 < ares.value) max1 = ares.value;
+ d1[n1++] = ares.value;
+ }
+ }
+ delete rD;
+ }
+ if(Dlg->GetText(103,TmpTxt,TMP_TXT_SIZE)&&(rD=new AccRange(TmpTxt))&&(n2=rD->CountItems())&&(d2=(double*)malloc(n2*sizeof(double)))){
+ if(c_name = rD->RangeDesc(data, 2)) {
+ rlp_strcpy(g2_nam, 30, c_name); g2_nam[0] = toupper(g2_nam[0]);
+ free(c_name);
+ }
+ else rlp_strcpy(g2_nam, 30, "Group 2");
+ for(n2 = 0, rD->GetFirst(&c, &r); rD->GetNext(&c, &r); ) {
+ if(data->GetResult(&ares, r, c, false) && ares.type == ET_VALUE){
+ if(dBounds.Ymin > ares.value) dBounds.Ymin = ares.value;
+ if(dBounds.Ymax < ares.value) dBounds.Ymax = ares.value;
+ if(min2 > ares.value) min2 = ares.value; if(max2 < ares.value) max2 = ares.value;
+ d2[n2++] = ares.value;
+ }
+ }
+ delete rD;
+ }
+ if(g1_nam[0] && g2_nam[0] && 0==strcmp(g1_nam, g2_nam)) {
+ rlp_strcpy(g1_nam, 30, "Group 1"); rlp_strcpy(g2_nam, 30, "Group 2");
+ }
+ if(!d1 || !d2 || n1 < 2 || n2 < 2) {
+ InfoBox("Insufficient data to calculate means!");
+ bContinue = true;
+ res = -1;
+ }
+ Dlg->GetValue(105, &ci);
+ break;
+ }
+ }while (res < 0);
+ if(res == 1 && d1 && d2 && n1>1 && n2>1 && (rs = (double*)malloc(40*sizeof(double))) && (ny = (int*)malloc(2*sizeof(int)))) {
+ dBounds.Xmin = 0.5; rs[0] = 1.0; dBounds.Xmax = 2.3; rs[1] = 2.0;
+ dtmp = d_variance(n1, d1, &rs[2], 0L); rs[10] = sqrt(dtmp);
+ dtmp = d_variance(n2, d2, &rs[3], 0L); rs[11] = sqrt(dtmp);
+ rs[12] = (double)n1; rs[13] = (double)n2;
+ rs[6] = rs[10]/sqrt(rs[12]); rs[7] = rs[11]/sqrt(rs[13]);
+ rs[4] = rs[2] - rs[6]; rs[5] = rs[3] - rs[7];
+ rs[6] += rs[2]; rs[7] += rs[3];
+ rs[8] = rs[2] - rs[10]; rs[9] = rs[3] - rs[11];
+ rs[10] += rs[2]; rs[11] += rs[3];
+ ny[0] = n1; ny[1] = n2;
+ rep_init(); page = new Page(parent, data);
+ ci /= 100.0;
+ mk_header(page, "<b>Compare Means of Two Groups</b>", data);
+ if((graph = new Graph(parent, data, 0L, 0)) && (txt_obj = mk_boxplot(0, rs, rs+2, rs+4, rs+6, rs+8, rs+10,
+ ny, 2,"Mean","Std. Err.","Std. Dev."))){
+ scale.sx.fx = (txtdef1.fSize*5.0); scale.sy.fx = (txtdef1.fSize*10.0);
+ graph->GRect.Xmax = defs.GetSize(SIZE_GRECT_BOTTOM);
+ graph->DRect.Xmin *= 0.8; graph->moveable = 0;
+ graph->DRect.Xmax = graph->GRect.Xmax - (txtdef1.fSize*2.0);
+ OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+ if(LastOpenGO && LastOpenGO->Id == GO_BOXPLOT) {
+ if(((BoxPlot*)LastOpenGO)->x_tv = new TextValue()){
+ ((BoxPlot*)LastOpenGO)->x_tv->GetValue(g1_nam);
+ ((BoxPlot*)LastOpenGO)->x_tv->GetValue(g2_nam);
+ }
+ }
+ free(txt_obj); graph->Command(CMD_SCALE, &scale, 0L);
+ cx = graph->GetSize(SIZE_GRECT_RIGHT)+txtdef1.fSize*3.0;
+ cy = mk_mean_report(page, cx, graph->GetSize(SIZE_GRECT_TOP), d1, n1, ci, g1_nam);
+ cy = mk_mean_report(page, cx, cy + txtdef1.fSize, d2, n2, ci, g2_nam);
+ cy += linsp1;
+ rep_DrawText(page, graph->GetSize(SIZE_GRECT_RIGHT)+txtdef1.fSize*3.0, cy, false, TXA_HLEFT, &txtdef1, "<b>t-Test:</b>");
+ cy += linsp1; d_ttest(d1, d2, n1, n2, 0L, 0L, rs+15);
+ for(i = 0; i < 3; i++) {
+ switch(i) {
+ case 0: dtmp = rs[24]; break;
+ case 1: dtmp = rs[21]; break;
+ case 2: dtmp = rs[23]; break;
+ }
+#ifdef USE_WIN_SECURE
+ j = sprintf_s(TmpTxt, 80, ttest[i], dtmp);
+#else
+ j = sprintf(TmpTxt, ttest[i], dtmp);
+#endif
+ if(i && dtmp < 0.0001) {
+ while(TmpTxt[j] != '=' && j) j--;
+ rlp_strcpy(TmpTxt+j, 10, "< 0.0001");
+ }
+ rep_DrawText(page, cx+(txtdef1.fSize*3.0), cy, false, TXA_HLEFT, &txtdef1, TmpTxt);
+ cy += linsp1/1.2;
+ }
+ page->Command(CMD_DROP_GRAPH, graph, 0L);
+ }
+ d_quartile(n1, d1, &rs[6], &rs[2], &rs[4]);
+ d_quartile(n2, d2, &rs[7], &rs[3], &rs[5]);
+ rs[8] = min1; rs[9] = min2; rs[10] = max1; rs[11] = max2;
+ cy = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*3.0;
+ if((graph = new Graph(parent, data, 0L, 0)) && (txt_obj = mk_boxplot(0, rs, rs+2, rs+4, rs+6, rs+8, rs+10,
+ ny, 2,"Median","25-75%","Min./Max."))){
+ scale.sy.fx = cy;
+ graph->GRect.Xmax = defs.GetSize(SIZE_GRECT_BOTTOM);
+ graph->DRect.Xmin *= 0.8; graph->moveable = 0;
+ graph->DRect.Xmax = graph->GRect.Xmax - (txtdef1.fSize*2.0);
+ OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+ if(LastOpenGO && LastOpenGO->Id == GO_BOXPLOT) {
+ if(((BoxPlot*)LastOpenGO)->x_tv = new TextValue()){
+ ((BoxPlot*)LastOpenGO)->x_tv->GetValue(g1_nam);
+ ((BoxPlot*)LastOpenGO)->x_tv->GetValue(g2_nam);
+ }
+ }
+ free(txt_obj); graph->Command(CMD_SCALE, &scale, 0L);
+ cy = mk_median_report(page, cx, graph->GetSize(SIZE_GRECT_TOP), d1, n1, .95, g1_nam);
+ cy = mk_median_report(page, cx, cy + txtdef1.fSize, d2, n2, .95, g2_nam);
+ cy += linsp1;
+ rep_DrawText(page, graph->GetSize(SIZE_GRECT_RIGHT)+txtdef1.fSize*3.0, cy, false, TXA_HLEFT, &txtdef1, "<b>u-Test:</b>");
+ cy += linsp1; d_utest(d1, d2, n1, n2, 0L, 0L, rs+15);
+ for(i = 0; i < 5; i++) {
+ switch(i) {
+ case 0: dtmp = rs[17]; break;
+ case 1: dtmp = rs[18]; break;
+ case 2: dtmp = rs[21]; break;
+ case 3: dtmp = rs[22]; break;
+ case 4: dtmp = rs[23]; break;
+ }
+#ifdef USE_WIN_SECURE
+ j = sprintf_s(TmpTxt, 80, utest[i], dtmp);
+#else
+ j = sprintf(TmpTxt, utest[i], dtmp);
+#endif
+ if(i && dtmp < 0.0001) {
+ while(TmpTxt[j] != '=' && j) j--;
+ rlp_strcpy(TmpTxt+j, 10, "< 0.0001");
+ }
+ rep_DrawText(page, cx+(txtdef1.fSize*3.0), cy, false, TXA_HLEFT, &txtdef1, TmpTxt);
+ cy += linsp1/1.2;
+ }
+ page->Command(CMD_DROP_GRAPH, graph, 0L);
+ }
+ parent->Command(CMD_DROP_GRAPH, page, 0L);
+ free(rs); free(ny);
+ }
+ CloseDlgWnd(hDlg); delete Dlg; free(MeanDlg);
+ if(d1) free(d1); if(d2) free(d2);
+}
diff --git a/rlp_math.cpp b/rlp_math.cpp
index ab5cf56..0b109f1 100755
--- a/rlp_math.cpp
+++ b/rlp_math.cpp
@@ -1,2604 +1,2631 @@
-//rlp_math.cpp, Copyright (c) 2004-2007 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>
-#include <ctype.h>
-#include <string.h>
-#include <time.h>
-
-#define SWAP(a,b) {double temp=(a);(a)=(b);(b)=temp;}
-#define _PREC 1.0e-12
-
-extern Default defs;
-
-static char *MRQ_error = 0L;
-static double sqrt2pi = sqrt(_PI*2.0);
-
-//---------------------------------------------------------------------------
-//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. Press, 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;
-
- if(n < 2 || !vals) return;
- 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;
- }
-}
-
-//sorts array v1 making the corresponding rearrangement of v2
-void SortArray2(int n, double *v1, double *v2)
-{
- int l, j, ir, i;
- double rra, rrb, *ra = v1-1, *rb = v2-1;
-
- if(n < 2 || !v1 || !v2) return;
- l=(n >> 1) + 1; ir = n;
- for( ; ; ) {
- if(l > 1) {
- rra = ra[--l]; rrb = rb[l];
- }
- else {
- rra = ra[ir]; rrb = rb[ir];
- ra[ir] = ra[1]; rb[ir] = rb[1];
- if(--ir == 1) {
- ra[1] = rra; rb[1] = rrb;
- 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]; rb[i] = rb[j];
- j += (i=j);
- }
- else j = ir + 1;
- }
- ra[i] = rra; rb[i] = rrb;
- }
-}
-
-//Use heap sort to sort elements of an xy array
-void SortFpArray(int n, lfPOINT *vals)
-{
- int l, j, ir, i;
- lfPOINT rra, *ra = vals-1;
-
- if(n < 2) return;
- l=(n >> 1) + 1; ir = n;
- for( ; ; ) {
- if(l > 1) {
- rra.fx = ra[--l].fx; rra.fy = ra[l].fy;
- }
- else {
- rra.fx = ra[ir].fx; rra.fy = ra[ir].fy;
- ra[ir].fx = ra[1].fx; ra[ir].fy = ra[1].fy;
- if(--ir == 1) {
- ra[1].fx = rra.fx; ra[1].fy = rra.fy;
- return;
- }
- }
- i = l; j = l << 1;
- while (j <= ir) {
- if (j < ir && ra[j].fx < ra[j+1].fx) ++j;
- if (rra.fx < ra[j].fx) {
- ra[i].fx = ra[j].fx; ra[i].fy = ra[j].fy;
- j += (i=j);
- }
- else j = ir + 1;
- }
- ra[i].fx = rra.fx; ra[i].fy = rra.fy;
- }
-}
-
-//randomize array
-double *randarr(double *v0, int n, long *seed)
-{
- double r, *v, *v_tmp;
- int i, j, l;
-
- if(!(v = (double*)malloc(n *sizeof(double)))) return 0L;
- if(!(v_tmp = (double*)memdup(v0, n *sizeof(double),0))) return 0L;
- for(l = n, i = 0; i < n; ) {
- r = ran2(seed); j = (int)(r *((double)l));
- if(j < l) {
- v[i++] = v_tmp[j];
- if(j < l)memcpy(v_tmp+j, v_tmp+j+1, (l-j)*sizeof(double));
- l--;
- }
- }
- return v;
-}
-
-//resample array
-double *resample(double *v0, int n, long *seed)
-{
- double r, *v;
- int i, j;
-
- if(!(v = (double*)malloc(n *sizeof(double)))) return 0L;
- for(i = 0; i < n; ) {
- r = ran2(seed); j = (int)(r *((double)n));
- if(j < n) v[i++] = v0[j];
- }
- return v;
-}
-
-//---------------------------------------------------------------------------
-// Cubic Spline Interpolation
-// 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. 96 ff.
-void spline(lfPOINT *v, int n, double *y2)
-{
- int i, k;
- double p, qn, sig, un, *u;
-
- u = (double *)malloc(n * sizeof(double));
- y2[0] = u[0] = 0.0;
- for(i = 1; i < (n-1); i++) {
- sig = (v[i].fx-v[i-1].fx)/(v[i+1].fx-v[i-1].fx);
- p = sig*y2[i-1]+2.0; y2[i]=(sig-1.0)/p;
- u[i]=(v[i+1].fy-v[i].fy)/(v[i+1].fx-v[i].fx)-(v[i].fy-v[i-1].fy)/(v[i].fx-v[i-1].fx);
- u[i]=(6.0*u[i]/(v[i+1].fx-v[i-1].fx)-sig*u[i-1])/p;
- }
- qn = un = 0.0;
- y2[n-1] = (un - qn * u[n-2])/(qn*y2[n-2]+1.0);
- for(k = n-2; k >= 0; k--) {
- y2[k] = y2[k]*y2[k+1]+u[k];
- }
- free(u);
-}
-
-//---------------------------------------------------------------------------
-// The Gamma Function: return the ln(G(xx)) for xx > 0
-// Ref: B.W. Brown, J. Lovato, K. Russel (1994)
-// DCDFLIB.C, Library of C Routinesfor Cumulative Distribution Functions,
-// Inverses, and other Parameters.
-
-double devlpl(double a[], int n, double x)
-{
- double term;
- int i;
-
- for(term = a[n-1], i= n-2; i>=0; i--) term = a[i] + term * x;
- return term;
-}
-
-
-double gammln(double x)
-{
- static double coef[] = {0.83333333333333023564e-1,-0.27777777768818808e-2,
- 0.79365006754279e-3, -0.594997310889e-3, 0.8065880899e-3};
-static double scoefd[] = {0.62003838007126989331e2, 0.9822521104713994894e1,
- -0.8906016659497461257e1, 0.1000000000000000000e1};
-static double scoefn[] = {0.62003838007127258804e2, 0.36036772530024836321e2,
- 0.20782472531792126786e2, 0.6338067999387272343e1,0.215994312846059073e1,
- 0.3980671310203570498e0, 0.1093115956710439502e0,0.92381945590275995e-2,
- 0.29737866448101651e-2};
- double offset, prod, xx;
- int i,n;
-
- if(x < 6.0) {
- prod = 1.0e0; xx = x;
- while(xx > 3.0) {
- xx -= 1.0; prod *= xx;
- }
- if(x <= 2.0) while(xx < 2.0) {
- prod /= xx; xx += 1.0;
- }
- // compute rational approximation to gamma(x)
- return log(devlpl(scoefn, 9, xx-2.0) / devlpl(scoefd, 4, xx-2.0) * prod);
- }
- else {
- offset = 0.91893853320467274178; // hln2pi
- // if necessary make x at least 12 and carry correction in offset
- if(n = 13.0 >= x ? (int)(12.0 - x) : 0) xx = x;
- else {
- for(i=1, prod = 1.0; i<= n; i++) prod *= (x+(double)(i-1));
- offset -= log(prod); xx = x+(double)n;
- }
- // compute power series
- return devlpl(coef, 5, 1.0/(xx*xx)) / xx + (offset+(xx-0.5)*log(xx)-xx);
- }
-}
-
-//---------------------------------------------------------------------------
-// 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 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];
-}
-
-//returns the incomplete gamma function evaluated by its series representation
-void gser(double *gamser, double a, double x, double *gln)
-{
- int n;
- double sum, del, ap;
-
- *gln = gammln(a);
- if(x <= 0) {
- *gamser = 0.0; return;
- }
- else {
- ap = a; del = sum = 1.0/a;
- for(n = 1; n <= 100; n++) {
- ap += 1.0; del *= x/ap; sum += del;
- if(fabs(del) <= fabs(sum) * _PREC) {
- *gamser = sum * exp(-x + a * log(x)-(*gln));
- return;
- }
- }
- // maximum number of iterations exceeded
- *gamser = sum * exp(-x + a * log(x)-(*gln));
- }
-
-}
-
-//returns the incomplete gamma function evaluated by its continued fraction representation
-void gcf(double *gammcf, double a, double x, double *gln)
-{
- int n;
- double gold=0.0, g, fac=1.0, b1=1.0, b0=0.0, anf, ana, an, a1, a0=1.0;
-
- *gln=gammln(a); a1=x;
- for(n=1; n <= 100; n++) {
- an = (double)n; ana = an -a; a0 = (a1 + a0 * ana) * fac;
- b0 = (b1 + b0 * ana) *fac; anf = an * fac;
- a1 = x * a0 + anf * a1; b1 = x * b0 + anf * b1;
- if(a1) {
- fac = 1.0 / a1; g = b1 * fac;
- if(fabs((g-gold)/g) <= _PREC) {
- *gammcf = exp(-x + a * log(x) -(*gln)) * g;
- return;
- }
- gold = g;
- }
- }
- // maximum number of iterations exceeded
- *gammcf = exp(-x + a * log(x) -(*gln)) * gold;
-}
-
-//returns the incomplete gamma function P(a,x)
-double gammp(double a, double x)
-{
- double gamser, gammcf, gln;
-
- if(x < 0.0 || a <= 0.0) return 0.0;
- if(x < (a+1.0)) {
- gser(&gamser, a, x, &gln); return gamser;
- }
- else {
- gcf(&gammcf, a, x, &gln); return 1.0-gammcf;
- }
- return 0.0;
-}
-
-//returns the complementary incomplete gamma function Q(a,x)
-double gammq(double a, double x)
-{
- double gamser, gammcf, gln;
-
- if(x < 0.0 || a <= 0.0) return 0.0;
- if(x < (a+1.0)) {
- gser(&gamser, a, x, &gln); return 1.0-gamser;
- }
- else {
- gcf(&gammcf, a, x, &gln); return gammcf;
- }
- return 0.0;
-}
-
-//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) <= (_PREC * 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;
-}
-
-//The following relations are obviously based on:
-// Abramowitz, M. & Stegun I.A. (1964): Hanbook of Mathematical Functions.
-// Applied Mathematics Series, vol. 55 (Washington: National Bureau
-// of Standards).
-
-//the binomial coefficient
-double bincof(double n, double k)
-{
- if(n<0 || k<0 || k > n) return 0.0;
- return exp(gammln(n+1.0) - gammln(k+1.0) - gammln(n-k+1.0));
-}
-
-//the cumulative binomial distribution
-double binomdistf(double k, double n, double p)
-{
- if(k > n || n < 0.0 || p < 0.0 || p >1.0) return 0.0;
- return betai(n-k, k+1, p);
-}
-
-//the beta function
-double betaf(double z, double w)
-{
- return exp(gammln(z)+gammln(w)-gammln(z+w));
-}
-
-//the error function: not all compilers have a built in erf()
-double errf(double x)
-{
- return x < 0.0 ? -gammp(0.5, x*x) : gammp(0.5, x*x);
-}
-
-//the complementary error function
-double errfc(double x)
-{
-// return x < 0.0 ? 2.0 - gammq(0.5, x*x) : gammq(0.5, x*x);
- return x < 0.0 ? 1.0 + gammp(0.5, x*x) : gammq(0.5, x*x);
-}
-
-//cumulative normal distribution
-double norm_dist(double x, double m, double s)
-{
- return 0.5 + errf((x - m)/(s * _SQRT2))/2.0;
-}
-
-//normal distribution
-double norm_freq(double x, double m, double s)
-{
- double ex;
-
- ex = (x-m)/s; ex = exp(-0.5*ex*ex);
- return ex/(s*sqrt2pi);
-}
-
-//cumulative exponential distribution
-double exp_dist(double x, double l, double s)
-{
- if(x >= 0.0 && l > 0.0) return 1.0-exp(-x*l);
- else return 0.0;
-}
-
-//inverse exponential distribution
-double exp_inv(double p, double l, double s)
-{
- if(p >= 1.0) return HUGE_VAL;
- if(l <= 0.0) return 0.0;
- return -log(1.0-p)/l;
-}
-
-//exponential distribution
-double exp_freq(double x, double l, double s)
-{
- if(x >= 0.0 && l > 0.0) return l*exp(-x*l);
- else return fabs(l);
-}
-
-//cumulative lognormal distribution
-double lognorm_dist(double x, double m, double s)
-{
- return 0.5 + errf((log(x) - m)/(s * _SQRT2))/2.0;
-}
-
-//lognormal distribution
-double lognorm_freq(double x, double m, double s)
-{
- double tmp;
-
- if(x > 0.0 && m > 0.0 && s > 0.0) {
- tmp = (log(x)-m)/s;
- return exp(-0.5*tmp*tmp)/(x*s*sqrt2pi);
- }
- return 0.0;
-}
-
-//chi square distribution
-double chi_dist(double x, double df, double)
-{
- if(x <= 0.0) return 1.0;
- return gammq(df/2.0, x/2.0);
-}
-
-double chi_freq(double x, double df)
-{
- if(x < 0.0 || df <= 0.0) return 0.0;
- if(x < 1.0e-32) x = 1.0e-32;
-//formula by Wikipedia
-// return exp(log(2.0)*(1.0-df/2.0)+log(x)*(df-1.0)+x*x/-2.0-gammln(df/2.0));
-//formula by StatSoft's STATISTICA documentation
- return exp(-x/2.0+log(x)*(df/2.0-1.0)-log(2.0)*df/2.0-gammln(df/2.0));
-}
-
-//t-distribution
-double t_dist(double t, double df, double)
-{
- return betai(df/2.0, 0.5, (df/(df+t*t)));
-}
-
-double t_freq(double t, double df)
-{
- double a, b, c, d;
-
- a = gammln((df+1.0)/2.0); b = log(sqrt(df * _PI));
- c = gammln(df/2.0); d = log(1.0+t*t/df) * (df+1)/2.0;
- return exp(a-b-c-d);
-}
-
-//poisson distribution
-double pois_dist(double x, double m, double)
-{
- return gammq(x+1.0, m);
-}
-
-//f-distribution
-double f_dist(double f, double df1, double df2)
-{
- return f > 0.0 ? betai(df2/2.0, df1/2.0, df2/(df2+df1*f)): 1.0;
-}
-
-double f_freq(double x, double df1, double df2)
-{
- double a, b, c, d;
-
- a = gammln((df1+df2)/2.0); b = gammln(df1/2.0) + gammln(df2/2.0);
- c = log(df1/df2) * df1/2.0 + log(x) * (df1/2.0-1.0);
- d = log(1+(df1/df2)*x) * (-(df1+df2)/2.0);
- return exp(a-b+c+d);
-}
-
-//---------------------------------------------------------------------------
-// The Weibull distribution
-//---------------------------------------------------------------------------
-double weib_dist(double x, double shape, double scale)
-{
- double dn=1.0, sum, term, tmp;
-
- if(shape <= 0.0 || scale <= 0.0) return HUGE_VAL;
- if(x <= 0.0) return 0.0;
- term = -pow(x/scale, shape); tmp = fabs(term);
- if(tmp < 2.22e-16) return tmp;
- if (tmp > 0.697) return -exp(term)+1.0;
- x = sum = term;
- do { //do taylor series
- dn += 1.0 ; term *= x/dn; sum += term;
- }while (fabs(term) > fabs(sum) * 2.22e-16) ;
- return -sum;
-}
-
-double weib_freq(double x, double shape, double scale)
-{
- double tmp1, tmp2;
-
- if (shape <= 0.0 || scale <= 0.0) return HUGE_VAL;
- if (x < 0) return 0.0;
- if(x > -HUGE_VAL && x < HUGE_VAL) {
- if(x == 0.0 && shape < 1.0) return HUGE_VAL;
- tmp1 = pow(x / scale, shape - 1.0);
- tmp2 = tmp1 * (x / scale);
- return shape * tmp1 * exp(-tmp2) / scale;
- }
- return HUGE_VAL;
-}
-
-//---------------------------------------------------------------------------
-// The Cauchy (Lorentz) distribution
-//---------------------------------------------------------------------------
-double cauch_dist(double x, double loc, double scale)
-{
- double y;
-
- if(scale < 0.0) return HUGE_VAL;
- x = (x - loc) / scale;
- if(x > -HUGE_VAL && x < HUGE_VAL) {
- if (fabs(x) > 1.0) {
- y = atan(1.0/x)/_PI; return (x > 0) ? 1.0-y : -y;
- }
- else return 0.5 + atan(x)/_PI;
- }
- return HUGE_VAL;
-}
-
-double cauch_freq(double x, double loc, double scale)
-{
- double y;
-
- if(scale < 0.0) return HUGE_VAL;
- if(x > -HUGE_VAL && x < HUGE_VAL) {
- y = (x - loc) / scale;
- return 1.0 / (_PI * scale * (1.0 + y*y));
- }
- return HUGE_VAL;
-}
-
-//---------------------------------------------------------------------------
-// The Logistic distribution
-//---------------------------------------------------------------------------
-double logis_dist(double x, double loc, double scale)
-{
- if(scale < 0.0) return HUGE_VAL;
- x = exp(-(x - loc) / scale);
- if(x > -HUGE_VAL && x < HUGE_VAL) {
- return 1.0/(1.0 + x);
- }
- return HUGE_VAL;
-}
-
-double logis_freq(double x, double loc, double scale)
-{
- double e, f;
-
- x = fabs((x - loc) / scale);
- if(x > -HUGE_VAL && x < HUGE_VAL) {
- e = exp(-x); f = 1.0 + e;
- return e / (scale * f*f);
- }
- return HUGE_VAL;
-}
-
-//---------------------------------------------------------------------------
-// Shapiro-Wilk W test and its significance level
-// Algorithm AS 394, 1995, Appl. Statist. 44(4), 547-551
-//
-static int do_swilk(double (*func)(double, double, double), double p1, double p2,
- double *x, int n, int n1, int n2, double *a, double *w, double *pw)
-{
-
-//initialized data
-const static double z90 = 1.2816; //tinv(0.2, inf)
-const static double z95 = 1.6449; //tinv(0.1, inf)
-const static double z99 = 2.3263; //tinv(.05, inf)
-const static double zm = 1.7509; //(z90 + z95 + z99)/3
-const static double zss = 0.56268;
-const static double bf1 = 0.8378;
-const static double xx90 = 0.556;
-const static double xx95 = 0.622;
-const static double sqrth = 0.70711; //sqrt(0.5)
-const static double smal = 1.0e-19; //small value
-const static double pi6 = 1.909859;
-const static double stqr = 1.047198; //pi / 3
-
-//polynomial coefficients
-static double g[2] = {-2.273, 0.459};
-static double c1[6] = {0.0, 0.221157, -0.147981, -2.07119, 4.434685, -2.706056};
-static double c2[6] = {0.0, 0.042981, -0.293762, -1.752461, 5.682633, -3.582633};
-static double c3[4] = {0.544, -0.39978, 0.025054, -6.714e-4};
-static double c4[4] = {1.3822, -0.77857, 0.062767, -0.0020322};
-static double c5[4] = {-1.5861, -0.31082, -0.083751, 0.0038915};
-static double c6[3] = {-0.4803, -0.082676, 0.0030302};
-static double c7[2] = {0.164, 0.533};
-static double c8[2] = {0.1736, 0.315};
-static double c9[2] = {0.256, -0.00635};
-
- //local variables
- int i, j, ncens, i1, nn2;
- double zbar, ssassx, summ2, ssumm2, gamma, delta, range;
- double a1, a2, an, bf, ld, m, s, sa, xi, sx, xx, y, w1;
- double fac, asa, an25, ssa, z90f, sax, zfm, z95f, zsd, z99f, rsn, ssx, xsx;
-
- //parameter adjustment
- --a;
-
- *pw = 1.0;
- if(*w >= 0.0) *w = 1.0;
- an = (double)(n); nn2 = n>>1;
- if(n2 < nn2) return 3;
- if(n < 3) return 1;
- // calculate coefficients a[]
- if(true) {
- if(n == 3) a[1] = sqrth;
- else {
- for(i = 1, summ2 = 0.0, an25 = an + 0.25; i <= n2; ++i) {
- a[i] = distinv(func, p1, p2, (i-0.375)/an25, 0);
- summ2 += (a[i] * a[i]);
- }
- summ2 *= 2.0; ssumm2 = sqrt(summ2);
- rsn = 1.0 / sqrt(an); a1 = devlpl(c1, 6, rsn) -a[1]/ssumm2;
- //normalize a[]
- if(n > 5) {
- i1 = 3;
- a2 = -a[2] / ssumm2 + devlpl(c2, 6, rsn);
- fac = sqrt((summ2 - 2.0*a[1]*a[1] - 2.0*a[2]*a[2])
- / (1.0 - 2.0*a1*a1 - 2.0*a2*a2));
- a[2] = a2;
- }
- else {
- i1 = 2;
- fac = sqrt((summ2 -2.0*a[1]*a[1]) / (1.0 - 2.0*a1*a1));
- }
- a[1] = a1;
- for(i = i1; i <= nn2; ++i) a[i] /= -fac;
- }
- }
- if(n1 < 3) return 1;
- ncens = n - n1;
- if(ncens < 0 || (ncens > 0 && n < 20)) return 4;
- delta = (double)ncens / an;
- if(delta > 0.8) return 5;
- //if w input as negative, calculate significance level of -w
- if(*w < 0.0) {
- w1 = 1.0 + *w;
- goto sw_prob;
- }
- //check for zero range
- if((range = x[n1-1] -x[0]) < smal) return 6;
- //check for sort order
- xx = x[0]/range; sx = xx; sa = -a[1]; j = n -1;
- for(i = 1; i < n1; --j) {
- xi = x[i] / range; sx += xi; ++i;
- if(i != j) sa += i > j ? a[i < j ? i : j] : -a[i < j ? i : j];
- xx = xi;
- }
- //calculate w statistic as squared correlation between data and coefficients
- sa /= n1; sx /= n1; ssa = ssx = sax = 0.0; j = n -1;
- for(i = 0; i < n1; ++i, --j) {
- if(i > j) asa = a[1+j] - sa;
- else if(i < j) asa = -a[1+i] - sa;
- else asa = -sa;
- xsx = x[i] / range - sx; ssa += asa * asa;
- ssx += xsx * xsx; sax += asa * xsx;
- }
- ssassx = sqrt(ssa * ssx);
- w1 = (ssassx - sax) * (ssassx + sax) / (ssa * ssx);
-sw_prob:
- *w = 1.0 - w1; //reduce rounding errors
- if(n == 3) {
- *pw = pi6 * (asin(sqrt(*w)) - stqr);
- return 0;
- }
- y = log(w1);
- xx = log(an);
- if(n <= 11) {
- gamma = devlpl(g, 2, an);
- if(y >= gamma) {
- *pw = smal; return 0;
- }
- y = -log(gamma - y); m = devlpl(c3, 4, an);
- s = exp(devlpl(c4, 4, an));
- }
- else { //n >= 12
- m = devlpl(c5, 4, xx); s = exp(devlpl(c6, 3, xx));
- }
- //Censoring by proportion NCENS/N
- if(ncens > 0) {
- ld = -log(delta); bf = 1.0 + xx * bf1;
- z90f = z90 + bf * pow(devlpl(c7, 2, pow(xx90, xx)), ld);
- z95f = z95 + bf * pow(devlpl(c8, 2, pow(xx95, xx)), ld);
- z99f = z99 + bf * pow(devlpl(c9, 2, xx), ld);
- //Regress z90f ... z99f on normal deviates z90 ... z99
- // to get pseudo-mean and pseudo-sd of z as the slope and intercept
- zfm = (z90f + z95f + z99f)/3.0;
- zsd = (z90 * (z90f - zfm) + z95 * (z95f - zfm) + z99 * (z99f - zfm)) / zss;
- zbar = zfm - zsd * zm; m += zbar * s; s *= zsd;
- }
- *pw = 1.0 - norm_dist(y, m, s);
- return 0;
-}
-
-void swilk1(int n, double *v0, double (*func)(double, double, double), double p1, double p2,
- bool bsorted, double *w, double *p)
-{
- double *v, *a;
-
- if(!n || !w || !p) return; *w = *p = 1.0;
- if(!(a = (double*)malloc(n *sizeof(double)))) return;
- if(!bsorted && (v = (double*)memdup(v0, n*sizeof(double), 0)))SortArray(n, v);
- else if(bsorted) v = v0;
- else return;
- if(do_swilk(func, p1, p2, v, n, n, n>>1, a, w, p)){
- //an error occured
- *w = *p = -1.0;
- }
- free(a); if(v != v0) free(v);
-}
-
-//Kolmogorov-Smirnov's test and distribution of D
-// (1) Miller L. (1956) Journal of the American Statistical Association. 51: 111-121
-// (2) Mises R. (1964) Mathematical Theory of Probability and Statistics (New York: Academic Press)
-// Chapters IX(C) and IX(E)
-// (3) Press W.H., Flannery B.P.,Teukolsky S.A., Vetterling W.T. (1988/1989)
-// Numerical Recipes in C, Cambridge University Press, ISBN 0-521-35465-X, pp. 490 ff.
-//
-double ks_dist(int n, double d)
-{
- double j, jn, sum, las, q, r, s, dn = (double)n;
-
- las = floor(dn - dn * d);
- for (j = sum = 0.0; j <= las; j += 1.0) {
- jn = j / dn; q = gammln(dn+1) - gammln(j+1) - gammln(dn-j+1.0);
- r = (dn - j) * log( 1 - d - jn ); s = (j - 1.0) * log( d + jn );
- sum += exp(q + r + s);
- }
- return(d*sum);
-}
-
-void KolSmir(int n, double *v0, double (*func)(double, double, double), double p1, double p2,
- bool bsorted, double *d, double *p)
-{
- int i;
- double *v, *dev, *x, ff, dt, dt1, dt2;
- double dn = (double)n, f0 = 0.0;
-
- if(!n || !d || !p) return; *d = *p = 0.0;
- if(!(dev = (double*)malloc(n*sizeof(double)))) return;
- if(!(x = (double*)malloc(n*sizeof(double)))){
- free(dev); return;
- }
- if(!bsorted && (v = (double*)memdup(v0, n*sizeof(double), 0)))SortArray(n, v);
- else if(bsorted) v = v0;
- else return;
- for(i = 0, *d = 0.0; i < n; i++) {
- x[i] = (double)(i+1)/dn; ff = (*func)(v[i], p1, p2);
- dt1 = fabs(f0-ff); dt2 = fabs(dev[i] = (f0 = x[i])-ff);
- dt = dt1 > dt2 ? dt1 : dt2; if(dt > *d) *d = dt;
- }
- free(dev); free(x);
- *p = ks_dist(n, *d);
- if(v != v0) free(v);
-}
-
-//---------------------------------------------------------------------------
-// Inverse of statitistical functions:
-// funcd supplies the function value fn and the derivative df of the function sf at x
-void funcd(double x, double *fn, double *df, double (*sf)(double, double, double),
- double df1, double df2, double p)
-{
- double y1, y2;
-
- *fn = (sf)(x, df1, df2);
- if(sf == norm_dist) *df = norm_freq(x, df1,df2);
- else if(sf == chi_dist) *df = -chi_freq(x, df1);
- else if(sf == t_dist) *df = -2.0 * t_freq(x, df1);
- else if(sf == f_dist) *df = -1.0 * f_freq(x, df1, df2);
- else if(sf == lognorm_dist) *df = lognorm_freq(x, df1, df2);
- else if(sf == weib_dist) *df = weib_freq(x, df1, df2);
- else if(sf == cauch_dist) *df = cauch_freq(x, df1, df2);
- else if(sf == logis_dist) *df = logis_freq(x, df1, df2);
- else { //numerical differentiation
- y1 = (sf)(x * 0.995, df1, df2); y2 = (sf)(x * 1.005, df1, df2);
- *df = (y2-y1)*100.0/x;
- }
- *fn = *fn - p;
-}
-
-//distinv does actual Newton-Raphson root finding
-double distinv(double (*sf)(double, double, double), double df1, double df2, double p, double x0)
-{
- int i, j;
- double df, df0, adf, dx, f, rtn;
-
- for(j = 0, rtn = dx = x0; j < 200; j++) {
- for(i = 0, df0 = 0.0; i < 20; i++) {
- funcd(rtn, &f, &df, sf, df1, df2, p);
- if((adf=fabs(df)) > 1.0e-12 || df0 > adf) break;
- rtn += (dx = dx/2.0); df0 = adf;
- if(i >= 19) return HUGE_VAL;
- }
- dx = f/df*(0.01*(double)(100-j)); rtn -= dx;
- if(fabs(dx) < _PREC && j > 3)return rtn;
- }
- return HUGE_VAL;
-}
-
-//---------------------------------------------------------------------------
-//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;
- }
-}
-
-// statistical basics partly based on
-// Davies, J. and Gogh, B. (2000), GSL-1.7 - The GNU scientific library
-//
-//do variance
-double d_variance(int n, double *v, double *mean, double *ss)
-{
- int i;
- double d, m, va, e;
-
- for(i = 0, m = 0.0, d = 1.0; i < n; i++, d += 1.0) {
- m += (v[i] - m)/d;
- }
- if (mean) *mean = m;
- for(i = 0, va = 0.0, d = 1.0; i < n; i++, d += 1.0) {
- e = v[i] - m; va += (e * e - va)/d;
- }
- if (ss) *ss = va * (double)n;
- return va * ((double)n/((double)(n-1)));
-}
-
-//do arithmethic mean
-double d_amean(int n, double *v)
-{
- int i;
- double d, mean;
-
- for(i = 0, mean = 0.0, d = 1.0; i < n; i++, d += 1.0) {
- mean += (v[i] - mean)/d;
- }
- return mean;
-}
-
-
-//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);
-}
-
-//kurtosis
-double d_kurt(int n, double *v)
-{
- double sum, avg, sd, tmp, dn = n;
- int i;
-
- for(i = 0, sum = 0.0; i < n; i++) sum += v[i];
- for(i = 0, avg = sum/dn, sum = 0.0; i < n; i++) sum += (tmp = v[i]-avg) * tmp;
- for(i = 0, sd = sqrt(sum/(dn-1.0)), sum=0.0; i < n; i++) sum += ((tmp = (v[i]-avg)/sd)*tmp*tmp*tmp);
- sum *= ((dn*(dn+1.0))/((dn-1.0)*(dn-2.0)*(dn-3.0)));
- tmp = (3.0 * (dn-1.0) * (dn-1.0))/((dn-2.0)*(dn-3.0));
- return sum - tmp;
-}
-
-//skewness
-double d_skew(int n, double *v)
-{
- double sum, avg, sd, tmp, dn = n;
- int i;
-
- for(i = 0, avg = 0.0; i < n; i++) avg += ((v[i]-avg)/((double)(i+1)));
- for(i = 0, sum = 0.0; i < n; i++) sum += (tmp = v[i]-avg) * tmp;
- for(i = 0, sd = sqrt(sum/(dn-1.0)), sum=0.0; i < n; i++) sum += ((tmp = (v[i]-avg)/sd)*tmp*tmp);
- return sum * dn/((dn-1.0)*(dn-2.0));
-}
-
-//---------------------------------------------------------------------------
-// Create a frequency distribution by counting the elements which may be
-// assigned to a bin
-double d_classes(DataObj *d, double start, double step, double *v, int nv, char *range)
-{
- int i, j, r, c, nc, *f;
- AccRange *ar;
-
- if(!range || !nv || !v || step <= 0.0 || !(ar = new AccRange(range))) return 0.0;
- if(!(nc = ar->CountItems()) || !ar->GetFirst(&c, &r) || !(f=(int*)calloc(nc, sizeof(int)))) {
- delete ar; return 0.0;
- }
- for(i = 0; i < nv; i++) {
- j = (int)(floor((v[i] - start)/step));
- if(j < 0) j = 0; if(j >= nc) j = (nc-1);
- f[j]++;
- }
- for( ; nc > 0 && !(f[nc-1]); nc--);
- for(i = 0; ar->GetNext(&c, &r) && i < nc; i++) {
- d->SetValue(r, c, (double)f[i]);
- }
- free(f); return ((double)nv);
-}
-
-//---------------------------------------------------------------------------
-// Pearsons linear correlation
-// (1) 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. 503 ff.
-// (2) B. Gough (2000), linear.c, gsl-1.7 the GNU scientific library
-double d_pearson(double *x, double *y, int n, char *dest, DataObj *data, double *ra)
-{
- int j, r, c;
- double yt, xt, t, df, res[4];
- double syy=0.0, sxy=0.0, sxx=0.0, ay=0.0, ax=0.0;
- AccRange *rD;
-
-
- for(j = 0; j < n; j++) { // find means
- ax += (x[j] - ax) / (j+1); ay += (y[j] - ay) / (j+1);
- }
- for(j = 0; j < n; j++) { // correlation
- xt = x[j] - ax; yt = y[j] - ay;
- sxx += (xt*xt-sxx) / (j+1); syy += (yt*yt-syy) / (j+1);
- sxy += (xt*yt-sxy) / (j+1);
- }
- res[0] = sxy/sqrt(sxx*syy); //pearsons r
- if(dest || ra) {
- res[1] = 0.5 * log((1.0+res[0]+_PREC)/(1.0-res[0]+_PREC)); //Fishers z-transform
- df = n-2;
- t = res[0]*sqrt(df/((1.0-res[0]+_PREC)*(1.0+res[0]+_PREC))); //Student's t
- res[2] = betai(0.5*df, 0.5, df/(df+t*t)); //probability
- res[3] = n;
- }
- if((dest) && (data) && (rD = new AccRange(dest))) {
- rD->GetFirst(&c, &r);
- for(j = 0; j < 4 && rD->GetNext(&c, &r); j++) {
- data->SetValue(r, c, res[j]);
- }
- data->Command(CMD_UPDATE, 0L, 0L);
- delete rD;
- }
- if (ra){
- memcpy(ra, res, 4 * sizeof(double));
- }
- return res[0];
-}
-
-//---------------------------------------------------------------------------
-// Given an array w, rank returns the rank of v1 in v
-// if v1 is not found in v 0 is returned
-double d_rank(int n, double *v, double v1)
-{
- double *sv;
- int i, j;
-
- if(!n || !v) return 0.0; if(n < 2) return 1.0;
- if(!(sv = (double*)memdup(v, n * sizeof(double), 0))) return 0.0;
- SortArray(n, sv);
- for(i = j = 0; i < n; i++) {
- if(v1 == sv[i]) {
- for( ;(i+j)<n; j++) if(sv[i+j] > v1) break;
- free(sv); return (double)i + 1.0 + (((double)j-1.0)/2.0);
- }
- }
- free(sv); return 0.0;
-}
-
-//---------------------------------------------------------------------------
-// Spearman rank-order correlation
-// Ref.: W.H. Press, B.P. Flannery, S.A. Teukolsky, W.T. Vetterling (1989),
-// Numerical Recipies in C. The Art of Scientific Computing,
-// Cambridge University Press, ISBN 0-521-35465, pp. 507 ff.
-
-//Given a sorted array w, crank replaces the elements by their rank
-void crank(int n, double *w0, double *s)
-{
- int j=1, ji, jt;
- double t, rank, *w = w0-1;
-
- *s = 0.0;
- while (j < n) {
- if(w[j+1] != w[j]) {
- w[j] = j; ++j;
- }
- else {
- for(jt = j+1; jt <= n; jt++) if(w[jt] != w[j]) break;
- rank = 0.5 * (j+jt-1);
- for(ji = j; ji <= (jt-1); ji++) w[ji] = rank;
- t = jt -j; *s += t*t*t -t; j = jt;
- }
- }
- if(j == n) w[n] = n;
-}
-
-//the actual rank correlation
-double d_spearman(double *sx, double *sy, int n, char *dest, DataObj *data, double *ra)
-{
- int j, r, c;
- double *x, *y, vard, t, sg, sf, fac, en3n, en, df, aved, tmp;
- double res[6];
- AccRange *rD;
-
- if(!(x = (double*)memdup(sx, n*sizeof(double), 0))
- || !(y = (double*)memdup(sy, n*sizeof(double), 0)))return 0.0;
- SortArray2(n, x, y); crank(n, x, &sf);
- SortArray2(n, y, x); crank(n, y, &sg);
- for(j = 0, res[0] = 0.0; j < n; j++) res[0] += ((tmp = (x[j]-y[j]))*tmp);
- en = n; en3n = en*en*en -en;
- aved = en3n/6.0 - (sf+sg)/12.0;
- fac = (1.0-sf/en3n)*(1.0-sg/en3n);
- vard = ((en-1.0)*en*en*((tmp = (en+1.0))*tmp)/36.0)*fac;
- res[1] = (res[0]-aved)/sqrt(vard);
- res[2] = errfc(fabs(res[1])/_SQRT2);
- res[3] = (1.0-(6.0/en3n)*(res[0]+0.5*(sf+sg)))/fac;
- t = res[3]*sqrt((en-2.0)/((res[3]+1.0)*(1.0-res[3])));
- df = en-2.0; res[5] = (double)n;
- res[4] = betai(0.5*df, 0.5, df/(df+t*t));
- if((dest) && (data) && (rD = new AccRange(dest))) {
- rD->GetFirst(&c, &r);
- for(j = 0; j < 6 && rD->GetNext(&c, &r); j++) {
- data->SetValue(r, c, res[j]);
- }
- data->Command(CMD_UPDATE, 0L, 0L);
- delete rD;
- }
- if(ra) {
- memcpy(ra, res, 6 * sizeof(double));
- }
- free(x); free(y);
- return res[3];
-}
-
-//---------------------------------------------------------------------------
-// Kendal's non-parametric correlation
-// Ref.: W.H. Press, B.P. Flannery, S.A. Teukolsky, W.T. Vetterling (1989),
-// Numerical Recipies in C. The Art of Scientific Computing,
-// Cambridge University Press, ISBN 0-521-35465, pp. 510 ff.
-
-double d_kendall(double *x, double *y, int n, char *dest, DataObj *data, double *ra)
-{
- int j, k, n1, n2, is, r, c;
- double aa, a1, a2, sv, res[4];
- AccRange *rD;
-
- for (j = n1 = n2 = is = 0; j < (n-1); j++) {
- for(k = j+1; k < n; k++) {
- a1 = x[j] - x[k]; a2 = y[j] - y[k]; aa = a1*a2;
- if(aa != 0.0) {
- n1++; n2++;
- if (aa > 0.0) is++;
- else is--;
- }
- else {
- if(a1 != 0.0) n1++; if(a2 != 0.0) n2++;
- }
- }
- }
- res[0] = ((double)is)/(sqrt((double)n1) * sqrt((double)n2));
- sv = (4.0 * ((double)n) + 10.0)/(9.0*((double)n)*((double)(n-1)));
- res[1] = res[0]/sqrt(sv); res[2] = errfc(fabs(res[1])/_SQRT2);
- res[3] = n;
- if((dest) && (data) && (rD = new AccRange(dest))) {
- rD->GetFirst(&c, &r);
- for(j = 0; j < 4 && rD->GetNext(&c, &r); j++) {
- data->SetValue(r, c, res[j]);
- }
- data->Command(CMD_UPDATE, 0L, 0L);
- delete rD;
- }
- if (ra){
- memcpy(ra, res, 4 * sizeof(double));
- }
- return res[0];
-}
-
-
-//linear regression
-double d_regression(double *x, double *y, int n, char *dest, DataObj *data, double *ra)
-{
- double sx, sy, dx, dy, sxy, sxx, syy, sdy, df;
- double res[10]; // slope, intercept, mean x, mean y, SE of slope,
- // variance(x), variance(y), variance(fit), F of regression, significance
- int i, j, r, c;
- AccRange *rD;
-
- if(n < 2) return 0.0;
- for(i = 0, sx = sy = 0.0; i < n; i++) {
- sx += x[i]; sy += y[i];
- }
- res[2] = sx /n; res[3] = sy/n;
- sxy = sxx = syy = 0.0;
- for(i = 0; i < n; i++) {
- dx = x[i]-res[2]; dy = y[i]-res[3];
- sxx += (dx*dx); syy += (dy*dy); sxy += (dx*dy);
- }
- res[0] = sxy / sxx; res[1] = res[3] - res[0] * res[2];
- for(i = 0, sdy = 0.0; i < n; i++) {
- dy = y[i] - (res[1] + x[i] *res[0]);
- sdy += (dy * dy);
- }
- sdy = sdy/(n-2); res[4] = sqrt(sdy/sxx); df = (n-2);
- res[5] = sxx/(n-1); res[6] = syy/(n-1); res[7] = sdy;
- res[8] = sxy/sdy*sxy/sxx;
- res[9] = betai(df/2.0, 0.5, df/(df+res[8]));
- if((dest) && (data) && (rD = new AccRange(dest))) {
- rD->GetFirst(&c, &r);
- for(j = 0; j < 10 && rD->GetNext(&c, &r); j++) {
- data->SetValue(r, c, res[j]);
- }
- data->Command(CMD_UPDATE, 0L, 0L);
- delete rD;
- }
- if (ra) memcpy(ra, res, 10 * sizeof(double));
- return n;
-}
-
-//covariance
-double d_covar(double *x, double *y, int n, char *dest, DataObj *data)
-{
- int i;
- double sx, sy, dx, dy, sxy;
-
- if(n < 2) return 0.0;
- for(i = 0, sx = sy = 0.0; i < n; i++) {
- sx += x[i]; sy += y[i];
- }
- sx /= n; sy /= n; sxy = 0.0;
- for(i = 0; i < n; i++) {
- dx = x[i]-sx; dy = y[i]-sy;
- sxy += (dx*dy - sxy) / (i+1);
- }
- return sxy;
-}
-
-//Mann-Whitney U Test
-double d_utest(double *x, double *y, int n1, int n2, char *dest, DataObj *data, double *ra)
-{
- double *da, *ta, u1, u2, su, su1, ts, dn1 = n1, dn2 = n2;
- double res[9];
- AccRange *rD;
- int i, j, n, r, c;
-
- if(!x || !y || n1 < 2 || n2 < 2) return 0.0;
- da = (double*)malloc((n = (n1+n2)) * sizeof(double));
- ta = (double*)malloc(n * sizeof(double));
- if(!da || !ta) {
- if(da) free(da); if(ta) free(ta); return 0.0;
- }
- for(i = 0; i < n1; i++) {
- da[i] = x[i]; ta[i] = 1.0;
- }
- for(j = 0; j < n2; j++) {
- da[i] = y[j]; ta[i++] = 2.0;
- }
- SortArray2(n, da, ta); crank(n, da, &ts);
- for(i = 0, res[0] = res[1] = 0.0; i < n; i++) {
- if(ta[i] == 1.0) res[0] += da[i];
- else res[1] += da[i];
- }
- free(da); free(ta);
- u1 = (dn1*dn2 + (dn1*(dn1+1))/2.0) - res[0]; u2 = (dn1*dn2 + ((dn2+1)*dn2)/2.0) - res[1];
- su = sqrt((dn1*dn2*(dn1+dn2+1))/12.0); res[2] = u2 > u1 ? u2 : u1;
- su1 = ((dn1*dn2)/((dn1+dn2)*(dn1+dn2-1))) * (((dn1+dn2)*(dn1+dn2)*(dn1+dn2)-(dn1+dn2)-ts)/12.0);
- su1 = sqrt(su1);
- res[3] = (res[2] - (n1*n2)/2.0)/su; res[6] = errfc(res[3]/_SQRT2);
- res[4] = n1; res[5] = n2;
- res[7] = (res[2] - (n1*n2)/2.0)/su1; res[8] = errfc(res[7]/_SQRT2);
- if((dest) && (data) && (rD = new AccRange(dest))) {
- rD->GetFirst(&c, &r);
- for(i = 0; i < 9 && rD->GetNext(&c, &r); i++) {
- data->SetValue(r, c, res[i]);
- }
- data->Command(CMD_UPDATE, 0L, 0L);
- delete rD;
- }
- if (ra) memcpy(ra, res, 9 * sizeof(double));
- return res[8];
-}
-
-//t-test
-double d_ttest(double *x, double *y, int n1, int n2, char *dest, DataObj *data, double *results)
-{
- int i, r, c;
- double sx, sy, mx, my, d, df, p;
- double res[9]; // mean1, SD1, n1, mean2, SD2, n2, p if variances equal,
- AccRange *rD; // corrected df, corrected p
-
- d_variance(n1, x, &mx, &sx); d_variance(n2, y, &my, &sy);
- d = ((sx+sy)/(n1+n2-2)) * ((double)(n1+n2)/(double)(n1*n2));
- d = (mx-my)/sqrt(d); //Student's t
-
- //Welch's correction for differences in variance
- df = (sx/(double)n1)*(sx/(double)n1)/(double)(n1+1)+(sy/(double)n2)*(sy/(double)n2)/(double)(n2+1);
- df = (sx/(double)n1+sy/(double)n2)*(sx/(double)n1+sy/(double)n2)/df;
- df -= 2.0; df = floor(df);
-
-// an alternative formula for correction
-// p = (sx/(double)n1)*(sx/(double)n1)/(double)(n1-1) + (sy/(double)n2)*(sy/(double)n2)/(double)(n2-1);
-// df = (sx/(double)n1 + sy/(double)n2) * (sx/(double)n1 + sy/(double)n2) / p;
-
- p = betai(df/2.0, 0.5, (df/(df+d*d)));
- if((dest) && (data) && (rD = new AccRange(dest))) {
- res[0] = mx; res[1] = sqrt(sx/(double)(n1-1)); res[2] = n1;
- res[3] = my; res[4] = sqrt(sy/(double)(n2-1)); res[5] = n2;
- res[7] = df; df = (n1-1) + (n2-1); res[6] = betai(df/2.0, 0.5, (df/(df+d*d)));
- res[8] = p;
- rD->GetFirst(&c, &r);
- for(i = 0; i < 9 && rD->GetNext(&c, &r); i++) {
- data->SetValue(r, c, res[i]);
- }
- data->Command(CMD_UPDATE, 0L, 0L);
- delete rD;
- }
- if(results) {
- results[0] = mx; results[1] = sqrt(sx/(double)(n1-1)); results[2] = n1;
- results[3] = my; results[4] = sqrt(sy/(double)(n2-1)); results[5] = n2;
- results[7] = df; df = (n1-1) + (n2-1); results[6] = betai(df/2.0, 0.5, (df/(df+d*d)));
- results[8] = p; results[9] = d;
- }
- return p;
-}
-
-//t-test for paired samples
-double d_ttest2(double *x, double *y, int n, char *dest, DataObj *data, double *ra)
-{
- double sx, sy, mx, my, df, cov, sd, t, p;
- int i, r, c;
- double res[6]; // mean1, SD1, mean2, SD2, n, p
- AccRange *rD;
-
- d_variance(n, x, &mx, &sx); d_variance(n, y, &my, &sy);
- sx = d_variance(n, x, &mx); sy = d_variance(n, y, &my);
- cov = d_covar(x, y, n, 0L, 0L) * ((double)n/(double)(n-1));
- sd = sqrt((sx+sy-2*cov)/n);
- t = (mx-my)/sd; df = (n-1);
- p = betai(0.5*df, 0.5, df/(df+t*t));
- res[0] = mx; res[1] = sqrt(sx); res[5] = p;
- res[2] = my; res[3] = sqrt(sy); res[4] = n;
- if((dest) && (data) && (rD = new AccRange(dest))) {
- rD->GetFirst(&c, &r);
- for(i = 0; i < 6 && rD->GetNext(&c, &r); i++) {
- data->SetValue(r, c, res[i]);
- }
- data->Command(CMD_UPDATE, 0L, 0L);
- delete rD;
- }
- if (ra) memcpy(ra, res, 6 * sizeof(double));
- return p;
-}
-
-//f-test
-double d_ftest(double *x, double *y, int n1, int n2, char *dest, DataObj *data, double *ra)
-{
- int i, r, c;
- double sx, sy, mx, my, d, df1, df2, p;
- double res[6]; // mean1, SD1, n1, mean2, SD2, n2
- AccRange *rD;
-
- for(i=0, sx = 0.0; i < n1; sx += x[i], i++); mx = sx/n1;
- for(i=0, sy = 0.0; i < n2; sy += y[i], i++); my = sy/n2;
- for(i=0, sx = 0.0; i < n1; sx += ((d=(x[i]-mx))*d), i++); sx /= (n1-1);
- for(i=0, sy = 0.0; i < n2; sy += ((d=(y[i]-my))*d), i++); sy /= (n2-1);
- if(sx > sy) {
- d = sx/sy; df1 = n1-1; df2 = n2-1;
- }
- else {
- d = sy/sx; df1 = n2-1; df2 = n1-1;
- }
- p = 2.0 * betai(df2/2.0, df1/2.0, df2/(df2+df1*d));
- if(p > 1.0) p = 2.0-p;
- res[0] = mx; res[1] = sqrt(sx); res[2] = n1;
- res[3] = my; res[4] = sqrt(sy); res[5] = n2;
- if((dest) && (data) && (rD = new AccRange(dest))) {
- rD->GetFirst(&c, &r);
- for(i = 0; i < 6 && rD->GetNext(&c, &r); i++) {
- data->SetValue(r, c, res[i]);
- }
- data->Command(CMD_UPDATE, 0L, 0L);
- delete rD;
- }
- if (ra) memcpy(ra, res, 6 * sizeof(double));
- return p;
-}
-//---------------------------------------------------------------------------
-// Simple one way anova
-//---------------------------------------------------------------------------
-bool do_anova1(int n, int *nv, double **vals, double **res_tab, double *gm, double **means, double **ss)
-{
- int i, j, ntot;
- double tmp, *csums, *css, ssa, ssw, sst, mtot, d;
-
- if(!(csums = (double*)calloc(n+1, sizeof(double)))
- || !(css = (double*)calloc(n+1, sizeof(double)))) return false;
-
- for(i = ntot = 0, mtot = 0.0, d = 1.0; i< n; i++){
- for(j = 0, csums[i] = 0.0, tmp = 1.0; j < nv[i]; j++, d+=1.0, tmp +=1.0) {
- mtot += (vals[i][j] - mtot)/d;
- csums[i] += (vals[i][j] -csums[i])/tmp;
- }
- ntot += nv[i];
- }
- for(i = 0; i < n; i++) {
- for(j = 0, css[i] = 0.0; j < nv[i]; j++) {
- tmp = vals[i][j] - csums[i]; css[i] += (tmp*tmp);
- }
- }
- for(i = 0, ssa = ssw = sst = 0.0; i < n; i++) {
- tmp =(csums[i] - mtot); ssa += (tmp*tmp) * ((double)nv[i]);
- ssw += css[i];
- }
- sst = ssa + ssw;
- res_tab[0][0] = n - 1; res_tab[1][0] = ntot - n;
- res_tab[2][0] = ntot -1; res_tab[0][1] = ssa;
- res_tab[1][1] = ssw; res_tab[2][1] = sst;
- res_tab[0][2] = ssa/res_tab[0][0]; res_tab[1][2] = ssw/res_tab[1][0];
- res_tab[0][3] = res_tab[0][2]/res_tab[1][2];
- res_tab[0][4] = f_dist(res_tab[0][3], res_tab[0][0], res_tab[1][0]);
- if(gm) *gm = mtot;
- if(means) *means = csums; else free(csums);
- if(ss) *ss = css; else free(css);
- return true;
-}
-
-//---------------------------------------------------------------------------
-// Bartlett's Test for homogeneity of variances
-// RR Sokal & FJ Rohlf: Biometry, 3rd ed., pp. 398 ff.
-//---------------------------------------------------------------------------
-bool bartlett(int n, int *nc, double *ss, double *chi2)
-{
- int i, sdf, df;
- double mss, mlss, *lnss, cf;
-
- if(!n || !nc || !ss || !chi2) return false;
- if(!(lnss = (double*)malloc(n * sizeof(double))))return false;
- for(i = sdf = 0, mss = mlss = cf = 0.0; i < n; i++) {
- sdf += (df = nc[i]-1); lnss[i] = log(ss[i]);
- mss += (ss[i] * ((double)df)); mlss += (lnss[i] * ((double)df));
- cf += (1.0/((double)df));
- }
- *chi2 = ((double)sdf) * log(mss/((double)sdf)) - mlss;
- cf -= (1.0/((double)sdf)); cf = 1.0 + cf/(3.0 * ((double)(n-1)));
- *chi2 /= cf;
- // P = chi_dist(*chi2, n-1, 0);
- free(lnss); return true;
-}
-//---------------------------------------------------------------------------
-// Leven's Test for homogeneity of variances
-//---------------------------------------------------------------------------
-bool levene(int type, int n, int *nv, double *means, double **vals, double *F, double *P)
-{
- int i, j;
- bool bRet = false;
- double cm, **res_tab, **cols;
-
- if(!n || !nv || !means || !vals) return false;
- //setup matrix for results
- if((res_tab = (double**)calloc(3, sizeof(double*)))
- && (res_tab[0] = (double*) malloc(5*sizeof(double)))
- && (res_tab[1] = (double*) malloc(5*sizeof(double)))
- && (res_tab[2] = (double*) malloc(5*sizeof(double)))
- && (cols = (double**)calloc(n+1, sizeof(double*)))) bRet = true;
- //allocate mem for data
- for(i = 0; bRet && i<n; i++) {
- if(!(cols[i]=(double*)malloc((nv[i]+1)*sizeof(double)))) bRet = false;
- }
- //data are absolute differences to mean ...
- for(i = 0, cm = 0.0; bRet && i < n; i++) {
- switch(type) {
- case 1: //use means
- cm = means[i]; break;
- case 2: //use medians
- d_quartile(nv[i], vals[i], 0L, &cm, 0L); break;
- }
- for(j = 0; j < nv[i]; j++) {
- cols[i][j] = vals[i][j] > cm ? vals[i][j] - cm : cm - vals[i][j];
- }
- }
- //Levene's test statistic is based on ANOVA of the differences
- if(bRet && (bRet = do_anova1(n, nv, cols, res_tab, 0L, 0L, 0L))){
- if(F) *F = res_tab[0][3]; if(P) *P = res_tab[0][4];
- }
- //clean up
- if(bRet) {
- for(i = 0; i < n; i++) if(cols[i]) free(cols[i]);
- for(i = 0; i < 3; i++) if(res_tab[i]) free(res_tab[i]);
- free(cols); free(res_tab);
- }
- return bRet;
-}
-
-//---------------------------------------------------------------------------
-// Modules from the R-project
-//
-//---------------------------------------------------------------------------
-#define M_1_SQRT_2PI 0.398942280401432677939946059934 /* 1/sqrt(2pi) */
-/*
- * Copyright (C) 1998 Ross Ihaka
- * Copyright (C) 2000--2005 The R Development Core Team
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * DESCRIPTION
- * Computes the probability that the maximum of rr studentized
- * ranges, each based on cc means and with df degrees of freedom
- * for the standard error, is less than q.
- * The algorithm is based on that of the reference.
- *
- * REFERENCE
- * Copenhaver, Margaret Diponzio & Holland, Burt S.
- * Multiple comparisons of simple effects in
- * the two-way analysis of variance with fixed effects.
- * Journal of Statistical Computation and Simulation,
- * Vol.30, pp.1-15, 1988.
- */
-
-double wprob(double w, double rr, double cc)
-{
-/* wprob() :
-
- This function calculates probability integral of Hartley's
- form of the range.
-
- w = value of range
- rr = no. of rows or groups
- cc = no. of columns or treatments
- ir = error flag = 1 if pr_w probability > 1
- pr_w = returned probability integral from (0, w)
-
- program will not terminate if ir is raised.
-
- bb = upper limit of legendre integration
- iMax = maximum acceptable value of integral
- nleg = order of legendre quadrature
- ihalf = int ((nleg + 1) / 2)
- wlar = value of range above which wincr1 intervals are used to
- calculate second part of integral,
- else wincr2 intervals are used.
- C1, C2, C3 = values which are used as cutoffs for terminating
- or modifying a calculation.
- xleg = legendre 12-point nodes
- aleg = legendre 12-point coefficients
- */
-#define nleg 12
-#define ihalf 6
-
- /* looks like this is suboptimal for double precision.
- (see how C1-C3 are used) <MM> */
- /* const double iMax = 1.; not used if = 1*/
- const static double C1 = -30.0, C2 = -50.0, C3 = 60.;
- const static double bb = 8.0, wlar = 3.0, wincr1 = 2.0, wincr2 = 3.;
- const static double xleg[ihalf] = { 0.981560634246719250690549090149,
- 0.904117256370474856678465866119, 0.769902674194304687036893833213,
- 0.587317954286617447296702418941, 0.367831498998180193752691536644,
- 0.125233408511468915472441369464};
- const static double aleg[ihalf] = { 0.047175336386511827194615961485,
- 0.106939325995318430960254718194, 0.160078328543346226334652529543,
- 0.203167426723065921749064455810, 0.233492536538354808760849898925,
- 0.249147045813402785000562436043};
- double a, ac, pr_w, b, binc, blb, bub, c, cc1, einsum, elsum,
- pminus, pplus, qexpo, qsqz, rinsum, wi, wincr, xx;
- int j, jj;
-
- qsqz = w * 0.5;
-
- // if w >= 16 then the integral lower bound (occurs for c=20)
- // is 0.99999999999995 so return a value of 1
- if (qsqz >= bb) return 1.0;
-
- // find (f(w/2) - 1) ^ cc
- // (first term in integral of hartley's form).
- pr_w = 2.0 * norm_dist(qsqz, 0.0, 1.0) -1.0;
- // if pr_w ^ cc < 2e-22 then set pr_w = 0
- if (pr_w >= exp(C2 / cc)) pr_w = pow(pr_w, cc);
- else pr_w = 0.0;
- // if w is large then the second component of the
- // integral is small, so fewer intervals are needed.
- if (w > wlar) wincr = wincr1;
- else wincr = wincr2;
-
- /* find the integral of second term of hartley's form */
- /* for the integral of the range for equal-length */
- /* intervals using legendre quadrature. limits of */
- /* integration are from (w/2, 8). two or three */
- /* equal-length intervals are used. */
- /* blb and bub are lower and upper limits of integration. */
- blb = qsqz; binc = (bb - qsqz) / wincr;
- bub = blb + binc; einsum = 0.0;
-
- // integrate over each interval
- cc1 = cc - 1.0;
- for (wi = 1; wi <= wincr; wi++) {
- elsum = 0.0; a = 0.5 * (bub + blb);
- // legendre quadrature with order = nleg
- b = 0.5 * (bub - blb);
- for (jj = 1; jj <= nleg; jj++) {
- if (ihalf < jj) {
- j = (nleg - jj) + 1; xx = xleg[j-1];
- }
- else {
- j = jj; xx = -xleg[j-1];
- }
- c = b * xx; ac = a + c;
- // if exp(-qexpo/2) < 9e-14, then doesn't contribute to integral
- if ((qexpo = ac * ac) > C3) break;
- pplus = 2.0 * norm_dist(ac, 0.0, 1.0); pminus= 2.0 * norm_dist(ac, w, 1.0);
- // if rinsum ^ (cc-1) < 9e-14, then doesn't contribute to integral
- rinsum = (pplus * 0.5) - (pminus * 0.5);
- if (rinsum >= exp(C1 / cc1)) {
- rinsum = (aleg[j-1] * exp(-(0.5 * qexpo))) * pow(rinsum, cc1);
- elsum += rinsum;
- }
- }
- elsum *= (((2.0 * b) * cc) * M_1_SQRT_2PI);
- einsum += elsum; blb = bub; bub += binc;
- }
- // if pr_w ^ rr < 9e-14, then return 0 */
- pr_w = einsum + pr_w;
- if (pr_w <= exp(C1 / rr))return 0.;
- pr_w = pow(pr_w, rr);
- return pr_w < 1.0 ? pr_w : 1.0;
-}
-
-double ptukey(double q, double rr, double cc, double df, int lower_tail, int log_p)
-{
-/* q = value of studentized range
- rr = no. of rows or groups
- cc = no. of columns or treatments
- df = degrees of freedom of error term
- ir[0] = error flag = 1 if wprob probability > 1
- ir[1] = error flag = 1 if qprob probability > 1
-
- All references in wprob to Abramowitz and Stegun
- are from the following reference:
- Abramowitz, Milton and Stegun, Irene A.
- Handbook of Mathematical Functions.
- New York: Dover publications, Inc. (1970).
- All constants taken from this text are given to 25 significant digits.
-
- nlegq = order of legendre quadrature
- ihalfq = int ((nlegq + 1) / 2)
- eps = max. allowable value of integral
- eps1 & eps2 = values below which there is no contribution to integral.
-
- d.f. <= dhaf: integral is divided into ulen1 length intervals. else
- d.f. <= dquar: integral is divided into ulen2 length intervals. else
- d.f. <= deigh: integral is divided into ulen3 length intervals. else
- d.f. <= dlarg: integral is divided into ulen4 length intervals.
-
- d.f. > dlarg: the range is used to calculate integral.
-
- xlegq = legendre 16-point nodes
- alegq = legendre 16-point coefficients
-
- The coefficients and nodes for the legendre quadrature used in
- qprob and wprob were calculated using the algorithms found in:
- Stroud, A. H. and Secrest, D., Gaussian Quadrature Formulas.
- Englewood Cliffs, New Jersey: Prentice-Hall, Inc, 1966.
-
- All values matched the tables (provided in same reference)
- to 30 significant digits.
-
- f(x) = .5 + erf(x / sqrt(2)) / 2 for x > 0
- f(x) = erfc( -x / sqrt(2)) / 2 for x < 0
- where f(x) is standard normal c. d. f.
-
- if degrees of freedom large, approximate integral with range distribution.
- */
-#define nlegq 16
-#define ihalfq 8
-
-/* const double eps = 1.0; not used if = 1 */
- const static double eps1 = -30.0, eps2 = 1.0e-14;
- const static double dhaf = 100.0, dquar = 800.0, deigh = 5000.0, dlarg = 25000.0;
- const static double ulen1 = 1.0, ulen2 = 0.5, ulen3 = 0.25, ulen4 = 0.125;
- const static double xlegq[ihalfq] = { 0.989400934991649932596154173450,
- 0.944575023073232576077988415535, 0.865631202387831743880467897712,
- 0.755404408355003033895101194847, 0.617876244402643748446671764049,
- 0.458016777657227386342419442984, 0.281603550779258913230460501460,
- 0.950125098376374401853193354250e-1};
- const static double alegq[ihalfq] = {0.271524594117540948517805724560e-1,
- 0.622535239386478928628438369944e-1, 0.951585116824927848099251076022e-1,
- 0.124628971255533872052476282192, 0.149595988816576732081501730547,
- 0.169156519395002538189312079030, 0.182603415044923588866763667969,
- 0.189450610455068496285396723208};
- double ans, f2, f21, f2lf, ff4, otsum, qsqz, rotsum, t1, twa1, ulen, wprb;
- int i, j, jj;
-
- if (df > dlarg) return wprob(q, rr, cc);
- f2 = df * 0.5; // calculate leading constant
- f2lf = ((f2 * log(df)) - (df * log(2.0))) - gammln(f2);
- f21 = f2 - 1.0;
- // integral is divided into unit, half-unit, quarter-unit, or eighth-unit length intervals
- // depending on the value of the degrees of freedom.
- ff4 = df * 0.25;
- if (df <= dhaf) ulen = ulen1;
- else if (df <= dquar) ulen = ulen2;
- else if (df <= deigh) ulen = ulen3;
- else ulen = ulen4;
- f2lf += log(ulen);
- for (i = 1, ans = 0.0; i <= 50; i++) { // integrate over each subinterval
- otsum = 0.0;
- // legendre quadrature with order = nlegq, nodes (stored in xlegq) are symmetric around zero.
- twa1 = (2 * i - 1) * ulen;
- for (jj = 1; jj <= nlegq; jj++) {
- if (ihalfq < jj) {
- j = jj - ihalfq - 1;
- t1 = (f2lf + (f21 * log(twa1 + (xlegq[j] * ulen)))) - (((xlegq[j] * ulen) + twa1) * ff4);
- }
- else {
- j = jj - 1;
- t1 = (f2lf + (f21 * log(twa1 - (xlegq[j] * ulen)))) + (((xlegq[j] * ulen) - twa1) * ff4);
- }
- if (t1 >= eps1) { // if exp(t1) < 9e-14, then doesn't contribute to integral
- if (ihalfq < jj) qsqz = q * sqrt(((xlegq[j] * ulen) + twa1) * 0.5);
- else qsqz = q * sqrt(((-(xlegq[j] * ulen)) + twa1) * 0.5);
- wprb = wprob(qsqz, rr, cc); // call wprob to find integral of range portion
- rotsum = (wprb * alegq[j]) * exp(t1); otsum += rotsum;
- }
- } // end legendre integral for interval i
- // If integral for interval i < 1e-14, then stop. However, in order to avoid small area
- // under left tail, at least 1 / ulen intervals are calculated.
- if (i * ulen >= 1.0 && otsum <= eps2) break;
- ans += otsum; //end of interval i
- }
- return ans > 1.0 ? 1.0 : ans;
- }
-
- /*
- * Copyright (C) 1998 Ross Ihaka
- * Copyright (C) 2000--2005 The R Development Core Team
- * based in part on AS70 (C) 1974 Royal Statistical Society
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * DESCRIPTION
- * Computes the quantiles of the maximum of rr studentized
- * ranges, each based on cc means and with df degrees of freedom
- * for the standard error, is less than q.
- * The algorithm is based on that of the reference.
- *
- * REFERENCE
- * Copenhaver, Margaret Diponzio & Holland, Burt S., Multiple comparisons of simple
- * effects in the two-way analysis of variance with fixed effects.
- * Journal of Statistical Computation and Simulation, Vol.30, pp.1-15, 1988.
- */
-
-/* qinv() :
- * this function finds percentage point of the studentized range
- * which is used as initial estimate for the secant method.
- * function is adapted from portion of algorithm as 70
- * from applied statistics (1974) ,vol. 23, no. 1
- * by odeh, r. e. and evans, j. o.
- * p = percentage point
- * c = no. of columns or treatments
- * v = degrees of freedom
- * qinv = returned initial estimate
- * vmax is cutoff above which degrees of freedom
- * is treated as infinity.
- */
-
-static double qinv(double p, double c, double v)
-{
- const static double p0 = 0.322232421088, q0 = 0.993484626060e-01;
- const static double p1 = -1.0, q1 = 0.588581570495;
- const static double p2 = -0.342242088547, q2 = 0.531103462366;
- const static double p3 = -0.204231210125, q3 = 0.103537752850;
- const static double p4 = -0.453642210148e-04, q4 = 0.38560700634e-02;
- const static double c1 = 0.8832, c2 = 0.2368, c3 = 1.214, c4 = 1.208, c5 = 1.4142;
- const static double vmax = 120.0;
- double ps, q, t, yi;
-
- ps = 0.5 - 0.5 * p;
- yi = sqrt (log (1.0 / (ps * ps)));
- t = yi + (((( yi * p4 + p3) * yi + p2) * yi + p1) * yi + p0)
- / (((( yi * q4 + q3) * yi + q2) * yi + q1) * yi + q0);
- if (v < vmax) t += (t * t * t + t) / v / 4.0;
- q = c1 - c2 * t;
- if (v < vmax) q += -c3 / v + c4 * t / v;
- return t * (q * log (c - 1.0) + c5);
-}
-
-/*
- * Copenhaver, Margaret Diponzio & Holland, Burt S.
- * Multiple comparisons of simple effects in
- * the two-way analysis of variance with fixed effects.
- * Journal of Statistical Computation and Simulation,
- * Vol.30, pp.1-15, 1988.
- *
- * Uses the secant method to find critical values.
- *
- * p = confidence level (1 - alpha)
- * rr = no. of rows or groups
- * cc = no. of columns or treatments
- * df = degrees of freedom of error term
- *
- */
-double qtukey(double p, double rr, double cc, double df, int lower_tail, int log_p)
-{
- const int maxiter = 50;
- double ans = HUGE_VAL, valx0, valx1, x0, x1;
- int iter;
-
- // df must be > 1 ; there must be at least two values
- if(p >= 1.0 || df < 2 || rr < 1 || cc < 2) return HUGE_VAL;
- if(p < 0.0) p = 0.0;
- x0 = qinv(p, cc, df); // Initial value
- valx0 = ptukey(x0, rr, cc, df, true, false) - p; // Find prob(value < x0)
- // Find the second iterate and prob(value < x1). If the first iterate has probability value
- // exceeding p then second iterate is 1 less than first iterate; otherwise it is 1 greater.
- x1 = valx0 > 0.0 ? (x1 = x0 > 1.0 ? x0-1.0 : 0.0) : (x0 + 1.0);
- valx1 = ptukey(x1, rr, cc, df, true, false) - p;
- for(iter=1; iter < maxiter ; iter++) { // Iterate
- ans = x1 - ((valx1 * (x1 - x0)) / (valx1 - valx0));
- valx0 = valx1; x0 = x1;
- if (ans < 0.0) { // New iterate must be >= 0
- ans = 0.0; valx1 = -p;
- }
- valx1 = ptukey(ans, rr, cc, df, true, false) - p; // Find prob(value < new iterate)
- x1 = ans;
- if (fabs(x1 - x0) < _PREC) return ans; // Convergence ?
- }
- //The process did not converge in 'maxiter' iterations
- return ans;
-}
-//---------------------------------------------------------------------------
-// END Modules from the R-project
-
-
-//---------------------------------------------------------------------------
-// Calendar, Date- and Time functions
-// The following characters are used as format specifiers in a format string,
-// all other characters are either ignored or copyied to the output
-//
-// Y four digits year y two digits year
-// X month's full name x three character month name
-// Z two digits day of month z same as Z but no leading zero
-// V two digit month number v number of month
-// W single letter month
-// D full name of day d three characters for day name
-// E two digits weekday e one or two digits weekday
-// F single character day name
-// H two digits for hours h hours with no leading zero
-// M two digits for minutes m minutes with no leading zero
-// S two digits for seconds s seconds with no leading zero
-// T two digits seconds, two dec. t same as T but no leading zero
-// U full precision seconds
-
-static char *dt_month[] = {"January", "February", "March", "April", "May", "June",
- "July", "August", "September", "October", "November", "December"};
-
-static char *dt_months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
- "Sep", "Oct", "Nov", "Dec"};
-
-static int dt_monthl[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-
-static char *dt_day[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
- "Friday", "Saturday"};
-
-static char *dt_days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
-
-static bool leapyear(int year) {
- return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
-}
-
-int year2aday(int y)
-{
- int aday, y1;
-
- y1 = y - 1900;
- aday = y1 * 365;
- aday += ((y1-1) >> 2 );
- aday -= (y1 / 100);
- aday += ((y/400)-4);
- return aday;
-}
-
-static void set_dow(rlp_datetime *dt)
-{
- dt->dow = (dt->aday %7)+1;
-}
-
-void add_date(rlp_datetime *base, rlp_datetime *inc)
-{
- int i, dom;
-
- if(base) {
- if(base->month < 1) base->month = 1;
- if(inc) {
- base->seconds += inc->seconds;
- if(base->seconds >= 60.0) {
- base->minutes++; base->seconds -= 60.0;
- }
- base->minutes += inc->minutes;
- if(base->minutes >= 60) {
- base->hours++; base->minutes -= 60;
- }
- base->hours += inc->hours;
- if(base->hours >= 24) {
- base->dom++; base->hours -= 24;
- }
- base->year += inc->year; base->dom += inc->dom;
- base->month += inc->month;
- }
- dom = dt_monthl[base->month-1];
- if(leapyear(base->year) && base->month == 2) dom = 29;
- if(base->dom > dom) {
- base->month++; base->dom -= dom;
- }
- if(base->month > 12) {
- base->year++; base->month -= 12;
- }
- base->aday = year2aday(base->year);
- for(i = base->doy = 0; i < (base->month-1); i++) {
- dom = dt_monthl[i];
- if(i == 1 && leapyear(base->year)) dom = 29;
- base->doy += dom;
- }
- base->doy += base->dom;
- base->aday += base->doy; set_dow(base);
- }
-}
-
-static int parse_date (rlp_datetime *dt, char *src, char *fmt)
-{
- int i, j, k;
- char tmp_str[10];
-
- if(!src || !src[0] || !fmt || !fmt[0]) return 0;
- if(*src == '\'') src++;
- for(i = j = 0; fmt[i] && src[j]; i++) {
- switch (fmt[i]) {
- case 'Y': case 'y': // year is numeric
- if(j && src[j] == '-' || src[j] == '/' || src[j] == '.') j++;
-#ifdef USE_WIN_SECURE
- if(sscanf_s(src+j, "%d", &dt->year)) {
-#else
- if(sscanf(src+j, "%d", &dt->year)) {
-#endif
- if(dt->year < 0) return 0;
- while(isdigit(src[j])) j++;
- if(dt->year<60) dt->year += 2000;
- else if(dt->year <99) dt->year += 1900;
- }
- else return 0;
- break;
- case 'X': case 'x': // month can be text
- if(j && src[j] == '-' || src[j] == '/' || src[j] == '.') j++;
- tmp_str[0] = toupper(src[j]);
- tmp_str[1] = tolower(src[j+1]);
- tmp_str[2] = tolower(src[j+2]);
- tmp_str[3] = 0;
- for(k = dt->month = 0; k < 12; k++) {
- if(0 == strcmp(tmp_str,dt_months[k])) {
- dt->month = k+1; break;
- }
- }
- if(dt->month) while(isalpha(src[j])) j++;
- else return 0;
- break;
- case 'V': case 'v': // or numeric
- if(j && src[j] == '-' || src[j] == '/' || src[j] == '.') j++;
-#ifdef USE_WIN_SECURE
- if(sscanf_s(src+j, "%d", &dt->month)) {
-#else
- if(sscanf(src+j, "%d", &dt->month)) {
-#endif
- if(dt->month <= 0 || dt->month > 12) return 0;
- j++; if(isdigit(src[j])) j++;
- }
- else return 0;
- break;
- case 'Z': case 'z': // day of month is numeric
- if(j && src[j] == '-' || src[j] == '/' || src[j] == '.') j++;
-#ifdef USE_WIN_SECURE
- if(sscanf_s(src+j, "%d", &dt->dom)) {
-#else
- if(sscanf(src+j, "%d", &dt->dom)) {
-#endif
- if(dt->dom <= 0 || dt->dom > 31) return 0;
- j++; if(isdigit(src[j])) j++;
- }
- else return 0;
- break;
- case 'H': case 'h': // hours are numeric
-#ifdef USE_WIN_SECURE
- if(sscanf_s(src+j, "%2d", &dt->hours)) {
-#else
- if(sscanf(src+j, "%2d", &dt->hours)) {
-#endif
- if(dt->hours < 0 || dt->hours > 23) return 0;
- j++; if(isdigit(src[j])) j++;
- }
- else return 0;
- break;
- case 'M': case 'm': // minutes are numeric
- if(j && src[j] == ' ' || src[j] == ':') j++;
-#ifdef USE_WIN_SECURE
- if(sscanf_s(src+j, "%2d", &dt->minutes)) {
-#else
- if(sscanf(src+j, "%2d", &dt->minutes)) {
-#endif
- if(dt->minutes < 0 || dt->minutes >= 60) return 0;
- j++; if(isdigit(src[j])) j++;
- }
- else return 0;
- break;
- case 'S': case 's': // seconds are numeric
- case 'T': case 't':
- if(j && src[j] == ' ' || src[j] == ':') j++;
-#ifdef USE_WIN_SECURE
- if(sscanf_s(src+j, "%lf", &dt->seconds)) {
-#else
- if(sscanf(src+j, "%lf", &dt->seconds)) {
-#endif
- if(dt->seconds < 0.0 || dt->seconds >= 60.0) return 0;
- while(isdigit(src[j]) || src[j] == '.') j++;
- }
- else return 0;
- dt->seconds += 1.0e-12;
- break;
- default:
- if(fmt[i] && fmt[i] == src[j]) j++;
- }
- }
- if(dt->year && dt->month && dt->dom) {
- for(dt->doy = 0, i = dt->month-2; i >= 0; i--) {
- if(i == 1) dt->doy += leapyear(dt->year) ? 29 : 28;
- else dt->doy += dt_monthl[i];
- }
- dt->doy += dt->dom;
- if(dt->year >= 1900) dt->aday = year2aday(dt->year);
- dt->aday += dt->doy;
- }
- return j;
-}
-
-char *date2text(rlp_datetime *dt, char *fmt)
-{
- static char res[80];
- int i, pos;
- double secs;
-
- res[0] = 0;
- if(!fmt || !fmt[0] || !dt) return res;
- set_dow(dt);
- secs = dt->seconds;
- if (secs > 59.4999) secs = 59.4999;
- for(pos = i = 0; fmt[i] && pos < 70; i++) {
-#ifdef USE_WIN_SECURE
- switch(fmt[i]) {
- case 'Y':
- if(dt->year) pos+=sprintf_s(res+pos, 80-pos, "%4d", dt->year);
- else pos += sprintf_s(res+pos, 80-pos, "####"); break;
- case 'y':
- if(dt->year) pos+=sprintf_s(res+pos, 80-pos, "%02d", (dt->year %100));
- else pos += sprintf_s(res+pos, 80-pos, "##"); break;
- case 'Z':
- if(dt->dom) pos+=sprintf_s(res+pos, 80-pos, "%02d", dt->dom);
- else pos += sprintf_s(res+pos, 80-pos, "##"); break;
- case 'z':
- if(dt->dom) pos+=sprintf_s(res+pos, 80-pos, "%d", dt->dom);
- else pos += sprintf_s(res+pos, 80-pos, "##"); break;
- case 'X':
- if(dt->month >0 && dt->month < 13) pos+=sprintf_s(res+pos, 80-pos, "%s", dt_month[dt->month-1]);
- else pos += sprintf_s(res+pos, 80-pos, "###"); break;
- case 'x':
- if(dt->month >0 && dt->month < 13) pos+=sprintf_s(res+pos, 80-pos, "%s", dt_months[dt->month-1]);
- else pos += sprintf_s(res+pos, 80-pos, "###"); break;
- case 'V':
- if(dt->month >0 && dt->month < 13) pos+=sprintf_s(res+pos, 80-pos, "%02d", dt->month);
- else pos += sprintf_s(res+pos, 80-pos, "##"); break;
- case 'v':
- if(dt->month >0 && dt->month < 13) pos+=sprintf_s(res+pos, 80-pos, "%d", dt->month);
- else pos += sprintf_s(res+pos, 80-pos, "##"); break;
- case 'W':
- if(dt->month >0 && dt->month < 13) pos+=sprintf_s(res+pos, 80-pos, "%c", dt_month[dt->month-1][0]);
- else pos += sprintf_s(res+pos, 80-pos, "#"); break;
- case 'D':
- if(dt->dow >0 && dt->dow < 8) pos+=sprintf_s(res+pos, 80-pos, "%s", dt_day[dt->dow-1]);
- else pos += sprintf_s(res+pos, 80-pos, "###"); break;
- case 'd':
- if(dt->dow >0 && dt->dow < 8) pos+=sprintf_s(res+pos, 80-pos, "%s", dt_days[dt->dow-1]);
- else pos += sprintf_s(res+pos, 80-pos, "###"); break;
- case 'E':
- if(dt->dow >0 && dt->dow < 8) pos+=sprintf_s(res+pos, 80-pos, "%02d", dt->dow);
- else pos += sprintf_s(res+pos, 80-pos, "##"); break;
- case 'e':
- if(dt->dow >0 && dt->dow < 8) pos+=sprintf_s(res+pos, 80-pos, "%d", dt->dow);
- else pos += sprintf_s(res+pos, 80-pos, "##"); break;
- case 'F':
- if(dt->dow >0 && dt->dow < 8) pos+=sprintf_s(res+pos, 80-pos, "%c", dt_day[dt->dow-1][0]);
- else pos += sprintf_s(res+pos, 80-pos, "#"); break;
- case 'H':
- if(dt->hours >=0 && dt->hours < 24) pos+=sprintf_s(res+pos, 80-pos, "%02d", dt->hours);
- else pos += sprintf_s(res+pos, 80-pos, "##"); break;
- case 'h':
- if(dt->hours >=0 && dt->hours < 24) pos+=sprintf_s(res+pos, 80-pos, "%d", dt->hours);
- else pos += sprintf_s(res+pos, 80-pos, "##"); break;
- case 'M':
- if(dt->minutes >=0 && dt->minutes < 60) pos+=sprintf_s(res+pos, 80-pos, "%02d", dt->minutes);
- else pos += sprintf_s(res+pos, 80-pos, "##"); break;
- case 'm':
- if(dt->minutes >=0 && dt->minutes < 60) pos+=sprintf_s(res+pos, 80-pos, "%d", dt->minutes);
- else pos += sprintf_s(res+pos, 80-pos, "##"); break;
- case 'S':
- if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf_s(res+pos, 80-pos, "%02d", iround(secs));
- else pos += sprintf_s(res+pos, 80-pos, "##"); break;
- case 's':
- if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf_s(res+pos, 80-pos, "%d", iround(secs));
- else pos += sprintf_s(res+pos, 80-pos, "##"); break;
- case 'T':
- if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf_s(res+pos, 80-pos, "%02.2lf", dt->seconds);
- else pos += sprintf_s(res+pos, 80-pos, "##.##"); break;
- case 't':
- if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf_s(res+pos, 80-pos, "%.2lf", dt->seconds);
- else pos += sprintf_s(res+pos, 80-pos, "##.##"); break;
- default:
- pos += sprintf_s(res+pos, 80-pos, "%c", fmt[i]); break;
- }
-#else
- switch(fmt[i]) {
- case 'Y':
- if(dt->year) pos+=sprintf(res+pos, "%4d", dt->year);
- else pos += sprintf(res+pos, "####"); break;
- case 'y':
- if(dt->year) pos+=sprintf(res+pos, "%02d", (dt->year %100));
- else pos += sprintf(res+pos, "##"); break;
- case 'Z':
- if(dt->dom) pos+=sprintf(res+pos, "%02d", dt->dom);
- else pos += sprintf(res+pos, "##"); break;
- case 'z':
- if(dt->dom) pos+=sprintf(res+pos, "%d", dt->dom);
- else pos += sprintf(res+pos, "##"); break;
- case 'X':
- if(dt->month >0 && dt->month < 13) pos+=sprintf(res+pos, "%s", dt_month[dt->month-1]);
- else pos += sprintf(res+pos, "###"); break;
- case 'x':
- if(dt->month >0 && dt->month < 13) pos+=sprintf(res+pos, "%s", dt_months[dt->month-1]);
- else pos += sprintf(res+pos, "###"); break;
- case 'V':
- if(dt->month >0 && dt->month < 13) pos+=sprintf(res+pos, "%02d", dt->month);
- else pos += sprintf(res+pos, "##"); break;
- case 'v':
- if(dt->month >0 && dt->month < 13) pos+=sprintf(res+pos, "%d", dt->month);
- else pos += sprintf(res+pos, "##"); break;
- case 'W':
- if(dt->month >0 && dt->month < 13) pos+=sprintf(res+pos, "%c", dt_month[dt->month-1][0]);
- else pos += sprintf(res+pos, "#"); break;
- case 'D':
- if(dt->dow >0 && dt->dow < 8) pos+=sprintf(res+pos, "%s", dt_day[dt->dow-1]);
- else pos += sprintf(res+pos, "###"); break;
- case 'd':
- if(dt->dow >0 && dt->dow < 8) pos+=sprintf(res+pos, "%s", dt_days[dt->dow-1]);
- else pos += sprintf(res+pos, "###"); break;
- case 'E':
- if(dt->dow >0 && dt->dow < 8) pos+=sprintf(res+pos, "%02d", dt->dow);
- else pos += sprintf(res+pos, "##"); break;
- case 'e':
- if(dt->dow >0 && dt->dow < 8) pos+=sprintf(res+pos, "%d", dt->dow);
- else pos += sprintf(res+pos, "##"); break;
- case 'F':
- if(dt->dow >0 && dt->dow < 8) pos+=sprintf(res+pos, "%c", dt_day[dt->dow-1][0]);
- else pos += sprintf(res+pos, "#"); break;
- case 'H':
- if(dt->hours >=0 && dt->hours < 24) pos+=sprintf(res+pos, "%02d", dt->hours);
- else pos += sprintf(res+pos, "##"); break;
- case 'h':
- if(dt->hours >=0 && dt->hours < 24) pos+=sprintf(res+pos, "%d", dt->hours);
- else pos += sprintf(res+pos, "##"); break;
- case 'M':
- if(dt->minutes >=0 && dt->minutes < 60) pos+=sprintf(res+pos, "%02d", dt->minutes);
- else pos += sprintf(res+pos, "##"); break;
- case 'm':
- if(dt->minutes >=0 && dt->minutes < 60) pos+=sprintf(res+pos, "%d", dt->minutes);
- else pos += sprintf(res+pos, "##"); break;
- case 'S':
- if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf(res+pos, "%02d", iround(secs));
- else pos += sprintf(res+pos, "##"); break;
- case 's':
- if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf(res+pos, "%d", iround(secs));
- else pos += sprintf(res+pos, "##"); break;
- case 'T':
- if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf(res+pos, "%02.2lf", dt->seconds);
- else pos += sprintf(res+pos, "##.##"); break;
- case 't':
- if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf(res+pos, "%.2lf", dt->seconds);
- else pos += sprintf(res+pos, "##.##"); break;
- default:
- pos += sprintf(res+pos, "%c", fmt[i]); break;
- }
-#endif
- }
- res[pos] = 0;
- return res;
-}
-
-double date2value(rlp_datetime *dt)
-{
- double res;
-
- if(!dt) return 0.0;
-
- res = dt->seconds/60.0 + (double)dt->minutes;
- res = res/60.0 + (double)dt->hours;
- res = res/24.0 + (double)dt->aday;
- return res;
-}
-
-void parse_datevalue(rlp_datetime *dt, double dv)
-{
- int i, j, d;
-
- if(!dt || dv < 0.0) return;
- if(dv > 1.0) {
- dt->aday = (int)floor(dv);
- dt->year = (int)(dv/365.2425);
- d = (int)floor(dv);
- do {
- dt->doy = d - 365*dt->year;
- dt->doy -= ((dt->year-1)>>2);
- dt->doy += ((dt->year)/100);
- dt->doy -= ((dt->year+300)/400);
- if(dt->doy < 1) dt->year--;
- }while(dt->doy < 1);
- dt->year += 1900;
- for(i = dt->month = 0, d = dt->doy; i < 12 && d > 0; i++) {
- if(i == 1 && d > (j = (leapyear(dt->year)) ? 29 : 28)) d -= j;
- else if(i != 1 && d > dt_monthl[i]) d -= dt_monthl[i];
- else break;
- }
- dt->month = i+1; dt->dom = d;
- }
- dv -= floor(dv); dv *= 24.0;
- dt->hours = (int)floor(dv); dv -= floor(dv);
- dv *= 60.0; dt->minutes = (int)floor(dv);
- dv -= floor(dv); dt->seconds = dv *60.0 + 1.0e-12;
- if(dt->seconds > 59.9999) {
- dt->seconds = 0.0; dt->minutes++;
- if(dt->minutes == 60) {
- dt->hours++; dt->minutes = 0;
- }
- }
-}
-
-static char *dt_popfmt[] = {"Z.V.Y H:M:S", "Z/V/Y H:M:S", "Z-V-Y H:M:S", "Z.X.Y H:M:S",
- "Y.V.Z H:M:S", "Y-X-Z H:M:S", "H:M:S", 0L};
-
-bool date_value(char *desc, char *fmt, double *value)
-{
- int i;
- rlp_datetime dt;
-
- dt.year = dt.aday = dt.doy = dt.month = dt.dom = dt.dow = dt.hours = dt.minutes = 0;
- dt.seconds = 0.0;
- if(!value || !desc || !desc[0]) return false;
- if(fmt && fmt[0]) {
- if(parse_date(&dt, desc, fmt)) {
- *value = date2value(&dt); return true;
- }
- }
- else {
- if(parse_date(&dt, desc, defs.fmt_datetime)) {
- *value = date2value(&dt); return true;
- }
- }
- for(i=0; dt_popfmt[i]; i++) {
- if(parse_date(&dt, desc, dt_popfmt[i])) {
- *value = date2value(&dt); return true;
- }
- }
- return false;
-}
-
-char *value_date(double dv, char *fmt)
-{
- rlp_datetime dt;
-
- parse_datevalue(&dt, dv);
- return date2text(&dt, fmt ? fmt : defs.fmt_date);
-}
-
-double now_today()
-{
- double res = 0.0;
- time_t ti = time(0L);
-#ifdef USE_WIN_SECURE
- char dtbuff[80];
-
- ctime_s(dtbuff, 80, &ti);
- date_value(dtbuff+4, "x z H:M:S Y", &res);
-#else
- date_value(ctime(&ti)+4, "x z H:M:S Y", &res);
-#endif
- return res;
-}
-
-void split_date(double dv, int *y, int *mo, int *dom, int *dow, int *doy, int *h, int *m, double *s)
-{
- rlp_datetime dt;
-
- parse_datevalue(&dt, dv);
- set_dow(&dt);
- if(y) *y = dt.year; if(mo) *mo = dt.month;
- if(dom) *dom = dt.dom; if(dow) *dow = dt.dow;
- if(doy) *doy = dt.doy; if(h) *h = dt.hours;
- if(m) *m = dt.minutes; if(s) *s = dt.seconds;
-}
-
-//---------------------------------------------------------------------------
-// Use the Delauney triangulation to create a 3D mesh of dispersed data
-//
-Triangle* Triangulate1(char *xr, char *yr, char *zr, DataObj *data)
-{
- AccRange *rX, *rY, *rZ;
- int i, j, n, rx, cx, ry, cy, rz, cz;
- double zMin;
- fPOINT3D *da;
- fRECT lim;
- Triangle *trl, *trn;
- Triangulate *tria;
-
- rX = rY = rZ = 0L; trl = trn = 0L;
- if((rX = new AccRange(xr)) && (rY = new AccRange(yr)) && (rZ = new AccRange(zr))
- && rX->GetFirst(&cx, &rx) && rY->GetFirst(&cy, &ry) && rZ->GetFirst(&cz, &rz)
- && (n = rX->CountItems()) && (da = (fPOINT3D*)malloc(n * sizeof(fPOINT3D)))
- && (trl = new Triangle()) && (trn = new Triangle())) {
- //get minima and maxima
- for(i = j = 0; i < n; i++) {
- if(rX->GetNext(&cx, &rx) && rY->GetNext(&cy, &ry) && rZ->GetNext(&cz, &rz)) {
- data->GetValue(rx, cx, &da[j].fx); data->GetValue(ry, cy, &da[j].fy);
- data->GetValue(rz, cz, &da[j].fz); j++;
- }
- }
- if(!j) {
- free(da); delete rX; delete rY; delete rZ; return trl;
- }
- for(i = 0, j = n; i < n; i++) {
- if(i) {
- if(da[i].fx < lim.Xmin) lim.Xmin = da[i].fx; if(da[i].fx > lim.Xmax) lim.Xmax = da[i].fx;
- if(da[i].fy < lim.Ymin) lim.Ymin = da[i].fy; if(da[i].fy > lim.Ymax) lim.Ymax = da[i].fy;
- if(da[i].fz < zMin) zMin = da[i].fz;
- }
- else {
- lim.Xmax = lim.Xmin = da[i].fx; lim.Ymax = lim.Ymin = da[i].fy; zMin = da[i].fz;
- }
- }
- //setup two super triangles
- trl->pt[0].fz = trl->pt[1].fz = trl->pt[2].fz = zMin;
- trn->pt[0].fz = trn->pt[1].fz = trn->pt[2].fz = zMin;
- trl->pt[0].fx = trn->pt[0].fx = trl->pt[2].fx = lim.Xmin;
- trl->pt[0].fy = trn->pt[0].fy = trn->pt[1].fy = lim.Ymin;
- trl->pt[1].fx = trn->pt[2].fx = trn->pt[1].fx = lim.Xmax;
- trl->pt[1].fy = trn->pt[2].fy = trl->pt[2].fy = lim.Ymax;
- trl->SetRect(); trn->SetRect();
- trl->next = trn; trn->next = 0L;
- //do triangulation
- tria = new Triangulate(trl);
- for(i = 0; i < n; i++) {
- tria->AddVertex(&da[i]);
- }
- free(da);
- }
- if(rX) delete rX; if(rY) delete rY; if(rZ) delete rZ;
- trl = tria->trl; delete tria; return trl;
-}
-
-Ribbon *SurfTria(GraphObj *parent, DataObj *data, char *xr, char *yr, char *zr)
-{
- Triangle *trl, *trc, *trn;
- int i, j, n, npl;
- double tmp;
- Plane3D **planes;
-
- trl = Triangulate1(xr, zr, yr, data);
- for(i = 0, trc = trl; trc; i++) trc = trc->next;
- if((n = i) && (planes = (Plane3D**)malloc(n*sizeof(Plane3D*))))
- for(i = npl = 0, trc = trl; trc && i < n; i++) {
- for(j = 0; j < 4; j++) { //swap y and z values;
- tmp = trc->pt[j].fz; trc->pt[j].fz = trc->pt[j].fy; trc->pt[j].fy = tmp;
- }
- planes[npl++] = new Plane3D(0L, data, trc->pt, 4);
- trn = trc->next; delete trc; trc = trn;
- }
- if(npl) return new Ribbon(parent, data, (GraphObj**)planes, npl);
- return 0L;
-}
+//rlp_math.cpp, Copyright (c) 2004-2008 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>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+
+#define SWAP(a,b) {double temp=(a);(a)=(b);(b)=temp;}
+#define _PREC 1.0e-12
+
+extern Default defs;
+
+static char *MRQ_error = 0L;
+static double sqrt2pi = sqrt(_PI*2.0);
+
+//---------------------------------------------------------------------------
+//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. Press, 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;
+
+ if(n < 2 || !vals) return;
+ 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;
+ }
+}
+
+//sorts array v1 making the corresponding rearrangement of v2
+void SortArray2(int n, double *v1, double *v2)
+{
+ int l, j, ir, i;
+ double rra, rrb, *ra = v1-1, *rb = v2-1;
+
+ if(n < 2 || !v1 || !v2) return;
+ l=(n >> 1) + 1; ir = n;
+ for( ; ; ) {
+ if(l > 1) {
+ rra = ra[--l]; rrb = rb[l];
+ }
+ else {
+ rra = ra[ir]; rrb = rb[ir];
+ ra[ir] = ra[1]; rb[ir] = rb[1];
+ if(--ir == 1) {
+ ra[1] = rra; rb[1] = rrb;
+ 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]; rb[i] = rb[j];
+ j += (i=j);
+ }
+ else j = ir + 1;
+ }
+ ra[i] = rra; rb[i] = rrb;
+ }
+}
+
+//Use heap sort to sort elements of an xy array
+void SortFpArray(int n, lfPOINT *vals)
+{
+ int l, j, ir, i;
+ lfPOINT rra, *ra = vals-1;
+
+ if(n < 2) return;
+ l=(n >> 1) + 1; ir = n;
+ for( ; ; ) {
+ if(l > 1) {
+ rra.fx = ra[--l].fx; rra.fy = ra[l].fy;
+ }
+ else {
+ rra.fx = ra[ir].fx; rra.fy = ra[ir].fy;
+ ra[ir].fx = ra[1].fx; ra[ir].fy = ra[1].fy;
+ if(--ir == 1) {
+ ra[1].fx = rra.fx; ra[1].fy = rra.fy;
+ return;
+ }
+ }
+ i = l; j = l << 1;
+ while (j <= ir) {
+ if (j < ir && ra[j].fx < ra[j+1].fx) ++j;
+ if (rra.fx < ra[j].fx) {
+ ra[i].fx = ra[j].fx; ra[i].fy = ra[j].fy;
+ j += (i=j);
+ }
+ else j = ir + 1;
+ }
+ ra[i].fx = rra.fx; ra[i].fy = rra.fy;
+ }
+}
+
+//randomize array
+double *randarr(double *v0, int n, long *seed)
+{
+ double r, *v, *v_tmp;
+ int i, j, l;
+
+ if(!(v = (double*)malloc(n *sizeof(double)))) return 0L;
+ if(!(v_tmp = (double*)memdup(v0, n *sizeof(double),0))) return 0L;
+ for(l = n, i = 0; i < n; ) {
+ r = ran2(seed); j = (int)(r *((double)l));
+ if(j < l) {
+ v[i++] = v_tmp[j];
+ if(j < l)memcpy(v_tmp+j, v_tmp+j+1, (l-j)*sizeof(double));
+ l--;
+ }
+ }
+ return v;
+}
+
+//resample array
+double *resample(double *v0, int n, long *seed)
+{
+ double r, *v;
+ int i, j;
+
+ if(!(v = (double*)malloc(n *sizeof(double)))) return 0L;
+ for(i = 0; i < n; ) {
+ r = ran2(seed); j = (int)(r *((double)n));
+ if(j < n) v[i++] = v0[j];
+ }
+ return v;
+}
+
+//---------------------------------------------------------------------------
+// Cubic Spline Interpolation
+// 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. 96 ff.
+void spline(lfPOINT *v, int n, double *y2)
+{
+ int i, k;
+ double p, qn, sig, un, *u;
+
+ u = (double *)malloc(n * sizeof(double));
+ y2[0] = u[0] = 0.0;
+ for(i = 1; i < (n-1); i++) {
+ sig = (v[i].fx-v[i-1].fx)/(v[i+1].fx-v[i-1].fx);
+ p = sig*y2[i-1]+2.0; y2[i]=(sig-1.0)/p;
+ u[i]=(v[i+1].fy-v[i].fy)/(v[i+1].fx-v[i].fx)-(v[i].fy-v[i-1].fy)/(v[i].fx-v[i-1].fx);
+ u[i]=(6.0*u[i]/(v[i+1].fx-v[i-1].fx)-sig*u[i-1])/p;
+ }
+ qn = un = 0.0;
+ y2[n-1] = (un - qn * u[n-2])/(qn*y2[n-2]+1.0);
+ for(k = n-2; k >= 0; k--) {
+ y2[k] = y2[k]*y2[k+1]+u[k];
+ }
+ free(u);
+}
+
+//---------------------------------------------------------------------------
+// The Gamma Function: return the ln(G(xx)) for xx > 0
+// Ref: B.W. Brown, J. Lovato, K. Russel (1994)
+// DCDFLIB.C, Library of C Routinesfor Cumulative Distribution Functions,
+// Inverses, and other Parameters.
+
+double devlpl(double a[], int n, double x)
+{
+ double term;
+ int i;
+
+ for(term = a[n-1], i= n-2; i>=0; i--) term = a[i] + term * x;
+ return term;
+}
+
+
+double gammln(double x)
+{
+ static double coef[] = {0.83333333333333023564e-1,-0.27777777768818808e-2,
+ 0.79365006754279e-3, -0.594997310889e-3, 0.8065880899e-3};
+static double scoefd[] = {0.62003838007126989331e2, 0.9822521104713994894e1,
+ -0.8906016659497461257e1, 0.1000000000000000000e1};
+static double scoefn[] = {0.62003838007127258804e2, 0.36036772530024836321e2,
+ 0.20782472531792126786e2, 0.6338067999387272343e1,0.215994312846059073e1,
+ 0.3980671310203570498e0, 0.1093115956710439502e0,0.92381945590275995e-2,
+ 0.29737866448101651e-2};
+ double offset, prod, xx;
+ int i,n;
+
+ if(x < 6.0) {
+ prod = 1.0e0; xx = x;
+ while(xx > 3.0) {
+ xx -= 1.0; prod *= xx;
+ }
+ if(x <= 2.0) while(xx < 2.0) {
+ prod /= xx; xx += 1.0;
+ }
+ // compute rational approximation to gamma(x)
+ return log(devlpl(scoefn, 9, xx-2.0) / devlpl(scoefd, 4, xx-2.0) * prod);
+ }
+ else {
+ offset = 0.91893853320467274178; // hln2pi
+ // if necessary make x at least 12 and carry correction in offset
+ if(n = 13.0 >= x ? (int)(12.0 - x) : 0) xx = x;
+ else {
+ for(i=1, prod = 1.0; i<= n; i++) prod *= (x+(double)(i-1));
+ offset -= log(prod); xx = x+(double)n;
+ }
+ // compute power series
+ return devlpl(coef, 5, 1.0/(xx*xx)) / xx + (offset+(xx-0.5)*log(xx)-xx);
+ }
+}
+
+//---------------------------------------------------------------------------
+// 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 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];
+}
+
+//returns the incomplete gamma function evaluated by its series representation
+void gser(double *gamser, double a, double x, double *gln)
+{
+ int n;
+ double sum, del, ap;
+
+ *gln = gammln(a);
+ if(x <= 0) {
+ *gamser = 0.0; return;
+ }
+ else {
+ ap = a; del = sum = 1.0/a;
+ for(n = 1; n <= 100; n++) {
+ ap += 1.0; del *= x/ap; sum += del;
+ if(fabs(del) <= fabs(sum) * _PREC) {
+ *gamser = sum * exp(-x + a * log(x)-(*gln));
+ return;
+ }
+ }
+ // maximum number of iterations exceeded
+ *gamser = sum * exp(-x + a * log(x)-(*gln));
+ }
+
+}
+
+//returns the incomplete gamma function evaluated by its continued fraction representation
+void gcf(double *gammcf, double a, double x, double *gln)
+{
+ int n;
+ double gold=0.0, g, fac=1.0, b1=1.0, b0=0.0, anf, ana, an, a1, a0=1.0;
+
+ *gln=gammln(a); a1=x;
+ for(n=1; n <= 100; n++) {
+ an = (double)n; ana = an -a; a0 = (a1 + a0 * ana) * fac;
+ b0 = (b1 + b0 * ana) *fac; anf = an * fac;
+ a1 = x * a0 + anf * a1; b1 = x * b0 + anf * b1;
+ if(a1) {
+ fac = 1.0 / a1; g = b1 * fac;
+ if(fabs((g-gold)/g) <= _PREC) {
+ *gammcf = exp(-x + a * log(x) -(*gln)) * g;
+ return;
+ }
+ gold = g;
+ }
+ }
+ // maximum number of iterations exceeded
+ *gammcf = exp(-x + a * log(x) -(*gln)) * gold;
+}
+
+//returns the incomplete gamma function P(a,x)
+double gammp(double a, double x)
+{
+ double gamser, gammcf, gln;
+
+ if(x < 0.0 || a <= 0.0) return 0.0;
+ if(x < (a+1.0)) {
+ gser(&gamser, a, x, &gln); return gamser;
+ }
+ else {
+ gcf(&gammcf, a, x, &gln); return 1.0-gammcf;
+ }
+ return 0.0;
+}
+
+//returns the complementary incomplete gamma function Q(a,x)
+double gammq(double a, double x)
+{
+ double gamser, gammcf, gln;
+
+ if(x < 0.0 || a <= 0.0) return 0.0;
+ if(x < (a+1.0)) {
+ gser(&gamser, a, x, &gln); return 1.0-gamser;
+ }
+ else {
+ gcf(&gammcf, a, x, &gln); return gammcf;
+ }
+ return 0.0;
+}
+
+//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) <= (_PREC * 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;
+}
+
+//The following relations are obviously based on:
+// Abramowitz, M. & Stegun I.A. (1964): Hanbook of Mathematical Functions.
+// Applied Mathematics Series, vol. 55 (Washington: National Bureau
+// of Standards).
+
+//the binomial coefficient
+double bincof(double n, double k)
+{
+ if(n<0 || k<0 || k > n) return 0.0;
+ return exp(gammln(n+1.0) - gammln(k+1.0) - gammln(n-k+1.0));
+}
+
+//the cumulative binomial distribution
+double binomdistf(double k, double n, double p)
+{
+ if(k > n || n < 0.0 || p < 0.0 || p >1.0) return 0.0;
+ return betai(n-k, k+1, p);
+}
+
+//the beta function
+double betaf(double z, double w)
+{
+ return exp(gammln(z)+gammln(w)-gammln(z+w));
+}
+
+//the error function: not all compilers have a built in erf()
+double errf(double x)
+{
+ return x < 0.0 ? -gammp(0.5, x*x) : gammp(0.5, x*x);
+}
+
+//the complementary error function
+double errfc(double x)
+{
+// return x < 0.0 ? 2.0 - gammq(0.5, x*x) : gammq(0.5, x*x);
+ return x < 0.0 ? 1.0 + gammp(0.5, x*x) : gammq(0.5, x*x);
+}
+
+//cumulative normal distribution
+double norm_dist(double x, double m, double s)
+{
+ return 0.5 + errf((x - m)/(s * _SQRT2))/2.0;
+}
+
+//normal distribution
+double norm_freq(double x, double m, double s)
+{
+ double ex;
+
+ ex = (x-m)/s; ex = exp(-0.5*ex*ex);
+ return ex/(s*sqrt2pi);
+}
+
+//cumulative exponential distribution
+double exp_dist(double x, double l, double s)
+{
+ if(x >= 0.0 && l > 0.0) return 1.0-exp(-x*l);
+ else return 0.0;
+}
+
+//inverse exponential distribution
+double exp_inv(double p, double l, double s)
+{
+ if(p >= 1.0) return HUGE_VAL;
+ if(l <= 0.0) return 0.0;
+ return -log(1.0-p)/l;
+}
+
+//exponential distribution
+double exp_freq(double x, double l, double s)
+{
+ if(x >= 0.0 && l > 0.0) return l*exp(-x*l);
+ else return fabs(l);
+}
+
+//cumulative lognormal distribution
+double lognorm_dist(double x, double m, double s)
+{
+ return 0.5 + errf((log(x) - m)/(s * _SQRT2))/2.0;
+}
+
+//lognormal distribution
+double lognorm_freq(double x, double m, double s)
+{
+ double tmp;
+
+ if(x > 0.0 && m > 0.0 && s > 0.0) {
+ tmp = (log(x)-m)/s;
+ return exp(-0.5*tmp*tmp)/(x*s*sqrt2pi);
+ }
+ return 0.0;
+}
+
+//chi square distribution
+double chi_dist(double x, double df, double)
+{
+ if(x <= 0.0) return 1.0;
+ return gammq(df/2.0, x/2.0);
+}
+
+double chi_freq(double x, double df)
+{
+ if(x < 0.0 || df <= 0.0) return 0.0;
+ if(x < 1.0e-32) x = 1.0e-32;
+//formula by Wikipedia
+// return exp(log(2.0)*(1.0-df/2.0)+log(x)*(df-1.0)+x*x/-2.0-gammln(df/2.0));
+//formula by StatSoft's STATISTICA documentation
+ return exp(-x/2.0+log(x)*(df/2.0-1.0)-log(2.0)*df/2.0-gammln(df/2.0));
+}
+
+//t-distribution
+double t_dist(double t, double df, double)
+{
+ return betai(df/2.0, 0.5, (df/(df+t*t)));
+}
+
+double t_freq(double t, double df)
+{
+ double a, b, c, d;
+
+ a = gammln((df+1.0)/2.0); b = log(sqrt(df * _PI));
+ c = gammln(df/2.0); d = log(1.0+t*t/df) * (df+1)/2.0;
+ return exp(a-b-c-d);
+}
+
+//poisson distribution
+double pois_dist(double x, double m, double)
+{
+ return gammq(x+1.0, m);
+}
+
+//f-distribution
+double f_dist(double f, double df1, double df2)
+{
+ return f > 0.0 ? betai(df2/2.0, df1/2.0, df2/(df2+df1*f)): 1.0;
+}
+
+double f_freq(double x, double df1, double df2)
+{
+ double a, b, c, d;
+
+ a = gammln((df1+df2)/2.0); b = gammln(df1/2.0) + gammln(df2/2.0);
+ c = log(df1/df2) * df1/2.0 + log(x) * (df1/2.0-1.0);
+ d = log(1+(df1/df2)*x) * (-(df1+df2)/2.0);
+ return exp(a-b+c+d);
+}
+
+//---------------------------------------------------------------------------
+// The Weibull distribution
+//---------------------------------------------------------------------------
+double weib_dist(double x, double shape, double scale)
+{
+ double dn=1.0, sum, term, tmp;
+
+ if(shape <= 0.0 || scale <= 0.0) return HUGE_VAL;
+ if(x <= 0.0) return 0.0;
+ term = -pow(x/scale, shape); tmp = fabs(term);
+ if(tmp < 2.22e-16) return tmp;
+ if (tmp > 0.697) return -exp(term)+1.0;
+ x = sum = term;
+ do { //do taylor series
+ dn += 1.0 ; term *= x/dn; sum += term;
+ }while (fabs(term) > fabs(sum) * 2.22e-16) ;
+ return -sum;
+}
+
+double weib_freq(double x, double shape, double scale)
+{
+ double tmp1, tmp2;
+
+ if (shape <= 0.0 || scale <= 0.0) return HUGE_VAL;
+ if (x < 0) return 0.0;
+ if(x > -HUGE_VAL && x < HUGE_VAL) {
+ if(x == 0.0 && shape < 1.0) return HUGE_VAL;
+ tmp1 = pow(x / scale, shape - 1.0);
+ tmp2 = tmp1 * (x / scale);
+ return shape * tmp1 * exp(-tmp2) / scale;
+ }
+ return HUGE_VAL;
+}
+
+//---------------------------------------------------------------------------
+// The geometric distribution
+//---------------------------------------------------------------------------
+double geom_freq(double x, double p)
+{
+ if (p <= 0 || p > 1 || x < 0.0) return HUGE_VAL;
+ x = floor(x + 1.0e-16);
+ return pow(1.0 - p, x) * p;
+}
+
+double geom_dist(double x, double p)
+{
+ double sum, x1;
+
+ for(x1 = sum = 0.0; x1 <= x; sum += geom_freq(x1, p), x1 += 1.0);
+ return sum;
+}
+
+//---------------------------------------------------------------------------
+// The hypergeometric distribution
+//---------------------------------------------------------------------------
+double hyper_freq(double k, double n0, double m, double n1)
+{
+ double pr;
+
+ if(k < 0.0 || m < 0.0 || n1 < 0.0 || n1 > n0+m) return HUGE_VAL;
+ k = floor(k + 1.0e-16); n0 = floor(n0 + 1.0e-16);
+ m = floor(m + 1.0e-16); n1 = floor(n1 + 1.0e-16);
+
+ pr = gammln(m+1.0) - gammln(k+1.0) - gammln(m-k+1.0)
+ + gammln(n0-m+1.0) - gammln(n1-k+1.0) - gammln(n0-m-n1+k+1.0)
+ - gammln(n0+1.0) + gammln(n1+1.0) + gammln(n0-n1+1.0);
+ return exp(pr);
+}
+
+double hyper_dist(double k, double n0, double m, double n1)
+{
+ double sum, x1;
+
+ for(x1 = sum = 0.0; x1 <= k; sum += hyper_freq(x1, n0, m, n1), x1 += 1.0);
+ return sum;
+}
+
+//---------------------------------------------------------------------------
+// The Cauchy (Lorentz) distribution
+//---------------------------------------------------------------------------
+double cauch_dist(double x, double loc, double scale)
+{
+ double y;
+
+ if(scale < 0.0) return HUGE_VAL;
+ x = (x - loc) / scale;
+ if(x > -HUGE_VAL && x < HUGE_VAL) {
+ if (fabs(x) > 1.0) {
+ y = atan(1.0/x)/_PI; return (x > 0) ? 1.0-y : -y;
+ }
+ else return 0.5 + atan(x)/_PI;
+ }
+ return HUGE_VAL;
+}
+
+double cauch_freq(double x, double loc, double scale)
+{
+ double y;
+
+ if(scale < 0.0) return HUGE_VAL;
+ if(x > -HUGE_VAL && x < HUGE_VAL) {
+ y = (x - loc) / scale;
+ return 1.0 / (_PI * scale * (1.0 + y*y));
+ }
+ return HUGE_VAL;
+}
+
+//---------------------------------------------------------------------------
+// The Logistic distribution
+//---------------------------------------------------------------------------
+double logis_dist(double x, double loc, double scale)
+{
+ if(scale < 0.0) return HUGE_VAL;
+ x = exp(-(x - loc) / scale);
+ if(x > -HUGE_VAL && x < HUGE_VAL) {
+ return 1.0/(1.0 + x);
+ }
+ return HUGE_VAL;
+}
+
+double logis_freq(double x, double loc, double scale)
+{
+ double e, f;
+
+ x = fabs((x - loc) / scale);
+ if(x > -HUGE_VAL && x < HUGE_VAL) {
+ e = exp(-x); f = 1.0 + e;
+ return e / (scale * f*f);
+ }
+ return HUGE_VAL;
+}
+
+//---------------------------------------------------------------------------
+// Shapiro-Wilk W test and its significance level
+// Algorithm AS 394, 1995, Appl. Statist. 44(4), 547-551
+//
+static int do_swilk(double (*func)(double, double, double), double p1, double p2,
+ double *x, int n, int n1, int n2, double *a, double *w, double *pw)
+{
+
+//initialized data
+const static double z90 = 1.2816; //tinv(0.2, inf)
+const static double z95 = 1.6449; //tinv(0.1, inf)
+const static double z99 = 2.3263; //tinv(.05, inf)
+const static double zm = 1.7509; //(z90 + z95 + z99)/3
+const static double zss = 0.56268;
+const static double bf1 = 0.8378;
+const static double xx90 = 0.556;
+const static double xx95 = 0.622;
+const static double sqrth = 0.70711; //sqrt(0.5)
+const static double smal = 1.0e-19; //small value
+const static double pi6 = 1.909859;
+const static double stqr = 1.047198; //pi / 3
+
+//polynomial coefficients
+static double g[2] = {-2.273, 0.459};
+static double c1[6] = {0.0, 0.221157, -0.147981, -2.07119, 4.434685, -2.706056};
+static double c2[6] = {0.0, 0.042981, -0.293762, -1.752461, 5.682633, -3.582633};
+static double c3[4] = {0.544, -0.39978, 0.025054, -6.714e-4};
+static double c4[4] = {1.3822, -0.77857, 0.062767, -0.0020322};
+static double c5[4] = {-1.5861, -0.31082, -0.083751, 0.0038915};
+static double c6[3] = {-0.4803, -0.082676, 0.0030302};
+static double c7[2] = {0.164, 0.533};
+static double c8[2] = {0.1736, 0.315};
+static double c9[2] = {0.256, -0.00635};
+
+ //local variables
+ int i, j, ncens, i1, nn2;
+ double zbar, ssassx, summ2, ssumm2, gamma, delta, range;
+ double a1, a2, an, bf, ld, m, s, sa, xi, sx, xx, y, w1;
+ double fac, asa, an25, ssa, z90f, sax, zfm, z95f, zsd, z99f, rsn, ssx, xsx;
+
+ //parameter adjustment
+ --a;
+
+ *pw = 1.0;
+ if(*w >= 0.0) *w = 1.0;
+ an = (double)(n); nn2 = n>>1;
+ if(n2 < nn2) return 3;
+ if(n < 3) return 1;
+ // calculate coefficients a[]
+ if(true) {
+ if(n == 3) a[1] = sqrth;
+ else {
+ for(i = 1, summ2 = 0.0, an25 = an + 0.25; i <= n2; ++i) {
+ a[i] = distinv(func, p1, p2, (i-0.375)/an25, 0);
+ summ2 += (a[i] * a[i]);
+ }
+ summ2 *= 2.0; ssumm2 = sqrt(summ2);
+ rsn = 1.0 / sqrt(an); a1 = devlpl(c1, 6, rsn) -a[1]/ssumm2;
+ //normalize a[]
+ if(n > 5) {
+ i1 = 3;
+ a2 = -a[2] / ssumm2 + devlpl(c2, 6, rsn);
+ fac = sqrt((summ2 - 2.0*a[1]*a[1] - 2.0*a[2]*a[2])
+ / (1.0 - 2.0*a1*a1 - 2.0*a2*a2));
+ a[2] = a2;
+ }
+ else {
+ i1 = 2;
+ fac = sqrt((summ2 -2.0*a[1]*a[1]) / (1.0 - 2.0*a1*a1));
+ }
+ a[1] = a1;
+ for(i = i1; i <= nn2; ++i) a[i] /= -fac;
+ }
+ }
+ if(n1 < 3) return 1;
+ ncens = n - n1;
+ if(ncens < 0 || (ncens > 0 && n < 20)) return 4;
+ delta = (double)ncens / an;
+ if(delta > 0.8) return 5;
+ //if w input as negative, calculate significance level of -w
+ if(*w < 0.0) {
+ w1 = 1.0 + *w;
+ goto sw_prob;
+ }
+ //check for zero range
+ if((range = x[n1-1] -x[0]) < smal) return 6;
+ //check for sort order
+ xx = x[0]/range; sx = xx; sa = -a[1]; j = n -1;
+ for(i = 1; i < n1; --j) {
+ xi = x[i] / range; sx += xi; ++i;
+ if(i != j) sa += i > j ? a[i < j ? i : j] : -a[i < j ? i : j];
+ xx = xi;
+ }
+ //calculate w statistic as squared correlation between data and coefficients
+ sa /= n1; sx /= n1; ssa = ssx = sax = 0.0; j = n -1;
+ for(i = 0; i < n1; ++i, --j) {
+ if(i > j) asa = a[1+j] - sa;
+ else if(i < j) asa = -a[1+i] - sa;
+ else asa = -sa;
+ xsx = x[i] / range - sx; ssa += asa * asa;
+ ssx += xsx * xsx; sax += asa * xsx;
+ }
+ ssassx = sqrt(ssa * ssx);
+ w1 = (ssassx - sax) * (ssassx + sax) / (ssa * ssx);
+sw_prob:
+ *w = 1.0 - w1; //reduce rounding errors
+ if(n == 3) {
+ *pw = pi6 * (asin(sqrt(*w)) - stqr);
+ return 0;
+ }
+ y = log(w1);
+ xx = log(an);
+ if(n <= 11) {
+ gamma = devlpl(g, 2, an);
+ if(y >= gamma) {
+ *pw = smal; return 0;
+ }
+ y = -log(gamma - y); m = devlpl(c3, 4, an);
+ s = exp(devlpl(c4, 4, an));
+ }
+ else { //n >= 12
+ m = devlpl(c5, 4, xx); s = exp(devlpl(c6, 3, xx));
+ }
+ //Censoring by proportion NCENS/N
+ if(ncens > 0) {
+ ld = -log(delta); bf = 1.0 + xx * bf1;
+ z90f = z90 + bf * pow(devlpl(c7, 2, pow(xx90, xx)), ld);
+ z95f = z95 + bf * pow(devlpl(c8, 2, pow(xx95, xx)), ld);
+ z99f = z99 + bf * pow(devlpl(c9, 2, xx), ld);
+ //Regress z90f ... z99f on normal deviates z90 ... z99
+ // to get pseudo-mean and pseudo-sd of z as the slope and intercept
+ zfm = (z90f + z95f + z99f)/3.0;
+ zsd = (z90 * (z90f - zfm) + z95 * (z95f - zfm) + z99 * (z99f - zfm)) / zss;
+ zbar = zfm - zsd * zm; m += zbar * s; s *= zsd;
+ }
+ *pw = 1.0 - norm_dist(y, m, s);
+ return 0;
+}
+
+void swilk1(int n, double *v0, double (*func)(double, double, double), double p1, double p2,
+ bool bsorted, double *w, double *p)
+{
+ double *v, *a;
+
+ if(!n || !w || !p) return; *w = *p = 1.0;
+ if(!(a = (double*)malloc(n *sizeof(double)))) return;
+ if(!bsorted && (v = (double*)memdup(v0, n*sizeof(double), 0)))SortArray(n, v);
+ else if(bsorted) v = v0;
+ else return;
+ if(do_swilk(func, p1, p2, v, n, n, n>>1, a, w, p)){
+ //an error occured
+ *w = *p = -1.0;
+ }
+ free(a); if(v != v0) free(v);
+}
+
+//Kolmogorov-Smirnov's test and distribution of D
+// (1) Miller L. (1956) Journal of the American Statistical Association. 51: 111-121
+// (2) Mises R. (1964) Mathematical Theory of Probability and Statistics (New York: Academic Press)
+// Chapters IX(C) and IX(E)
+// (3) Press W.H., Flannery B.P.,Teukolsky S.A., Vetterling W.T. (1988/1989)
+// Numerical Recipes in C, Cambridge University Press, ISBN 0-521-35465-X, pp. 490 ff.
+//
+double ks_dist(int n, double d)
+{
+ double j, jn, sum, las, q, r, s, dn = (double)n;
+
+ las = floor(dn - dn * d);
+ for (j = sum = 0.0; j <= las; j += 1.0) {
+ jn = j / dn; q = gammln(dn+1) - gammln(j+1) - gammln(dn-j+1.0);
+ r = (dn - j) * log( 1 - d - jn ); s = (j - 1.0) * log( d + jn );
+ sum += exp(q + r + s);
+ }
+ return(d*sum);
+}
+
+void KolSmir(int n, double *v0, double (*func)(double, double, double), double p1, double p2,
+ bool bsorted, double *d, double *p)
+{
+ int i;
+ double *v, *dev, *x, ff, dt, dt1, dt2;
+ double dn = (double)n, f0 = 0.0;
+
+ if(!n || !d || !p) return; *d = *p = 0.0;
+ if(!(dev = (double*)malloc(n*sizeof(double)))) return;
+ if(!(x = (double*)malloc(n*sizeof(double)))){
+ free(dev); return;
+ }
+ if(!bsorted && (v = (double*)memdup(v0, n*sizeof(double), 0)))SortArray(n, v);
+ else if(bsorted) v = v0;
+ else return;
+ for(i = 0, *d = 0.0; i < n; i++) {
+ x[i] = (double)(i+1)/dn; ff = (*func)(v[i], p1, p2);
+ dt1 = fabs(f0-ff); dt2 = fabs(dev[i] = (f0 = x[i])-ff);
+ dt = dt1 > dt2 ? dt1 : dt2; if(dt > *d) *d = dt;
+ }
+ free(dev); free(x);
+ *p = ks_dist(n, *d);
+ if(v != v0) free(v);
+}
+
+//---------------------------------------------------------------------------
+// Inverse of statitistical functions:
+// funcd supplies the function value fn and the derivative df of the function sf at x
+void funcd(double x, double *fn, double *df, double (*sf)(double, double, double),
+ double df1, double df2, double p)
+{
+ double y1, y2;
+
+ *fn = (sf)(x, df1, df2);
+ if(sf == norm_dist) *df = norm_freq(x, df1,df2);
+ else if(sf == chi_dist) *df = -chi_freq(x, df1);
+ else if(sf == t_dist) *df = -2.0 * t_freq(x, df1);
+ else if(sf == f_dist) *df = -1.0 * f_freq(x, df1, df2);
+ else if(sf == lognorm_dist) *df = lognorm_freq(x, df1, df2);
+ else if(sf == weib_dist) *df = weib_freq(x, df1, df2);
+ else if(sf == cauch_dist) *df = cauch_freq(x, df1, df2);
+ else if(sf == logis_dist) *df = logis_freq(x, df1, df2);
+ else { //numerical differentiation
+ y1 = (sf)(x * 0.995, df1, df2); y2 = (sf)(x * 1.005, df1, df2);
+ *df = (y2-y1)*100.0/x;
+ }
+ *fn = *fn - p;
+}
+
+//distinv does actual Newton-Raphson root finding
+double distinv(double (*sf)(double, double, double), double df1, double df2, double p, double x0)
+{
+ int i, j;
+ double df, df0, adf, dx, f, rtn;
+
+ for(j = 0, rtn = dx = x0; j < 200; j++) {
+ for(i = 0, df0 = 0.0; i < 20; i++) {
+ funcd(rtn, &f, &df, sf, df1, df2, p);
+ if((adf=fabs(df)) > 1.0e-12 || df0 > adf) break;
+ rtn += (dx = dx/2.0); df0 = adf;
+ if(i >= 19) return HUGE_VAL;
+ }
+ dx = f/df*(0.01*(double)(100-j)); rtn -= dx;
+ if(fabs(dx) < _PREC && j > 3)return rtn;
+ }
+ return HUGE_VAL;
+}
+
+//---------------------------------------------------------------------------
+//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;
+ }
+}
+
+// statistical basics partly based on
+// Davies, J. and Gogh, B. (2000), GSL-1.7 - The GNU scientific library
+//
+//do variance
+double d_variance(int n, double *v, double *mean, double *ss)
+{
+ int i;
+ double d, m, va, e;
+
+ for(i = 0, m = 0.0, d = 1.0; i < n; i++, d += 1.0) {
+ m += (v[i] - m)/d;
+ }
+ if (mean) *mean = m;
+ for(i = 0, va = 0.0, d = 1.0; i < n; i++, d += 1.0) {
+ e = v[i] - m; va += (e * e - va)/d;
+ }
+ if (ss) *ss = va * (double)n;
+ return va * ((double)n/((double)(n-1)));
+}
+
+//do arithmethic mean
+double d_amean(int n, double *v)
+{
+ int i;
+ double d, mean;
+
+ for(i = 0, mean = 0.0, d = 1.0; i < n; i++, d += 1.0) {
+ mean += (v[i] - mean)/d;
+ }
+ return mean;
+}
+
+
+//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);
+}
+
+//kurtosis
+double d_kurt(int n, double *v)
+{
+ double sum, avg, sd, tmp, dn = n;
+ int i;
+
+ for(i = 0, sum = 0.0; i < n; i++) sum += v[i];
+ for(i = 0, avg = sum/dn, sum = 0.0; i < n; i++) sum += (tmp = v[i]-avg) * tmp;
+ for(i = 0, sd = sqrt(sum/(dn-1.0)), sum=0.0; i < n; i++) sum += ((tmp = (v[i]-avg)/sd)*tmp*tmp*tmp);
+ sum *= ((dn*(dn+1.0))/((dn-1.0)*(dn-2.0)*(dn-3.0)));
+ tmp = (3.0 * (dn-1.0) * (dn-1.0))/((dn-2.0)*(dn-3.0));
+ return sum - tmp;
+}
+
+//skewness
+double d_skew(int n, double *v)
+{
+ double sum, avg, sd, tmp, dn = n;
+ int i;
+
+ for(i = 0, avg = 0.0; i < n; i++) avg += ((v[i]-avg)/((double)(i+1)));
+ for(i = 0, sum = 0.0; i < n; i++) sum += (tmp = v[i]-avg) * tmp;
+ for(i = 0, sd = sqrt(sum/(dn-1.0)), sum=0.0; i < n; i++) sum += ((tmp = (v[i]-avg)/sd)*tmp*tmp);
+ return sum * dn/((dn-1.0)*(dn-2.0));
+}
+
+//---------------------------------------------------------------------------
+// Create a frequency distribution by counting the elements which may be
+// assigned to a bin
+double d_classes(DataObj *d, double start, double step, double *v, int nv, char *range)
+{
+ int i, j, r, c, nc, *f;
+ AccRange *ar;
+
+ if(!range || !nv || !v || step <= 0.0 || !(ar = new AccRange(range))) return 0.0;
+ if(!(nc = ar->CountItems()) || !ar->GetFirst(&c, &r) || !(f=(int*)calloc(nc, sizeof(int)))) {
+ delete ar; return 0.0;
+ }
+ for(i = 0; i < nv; i++) {
+ j = (int)(floor((v[i] - start)/step));
+ if(j < 0) j = 0; if(j >= nc) j = (nc-1);
+ f[j]++;
+ }
+ for( ; nc > 0 && !(f[nc-1]); nc--);
+ for(i = 0; ar->GetNext(&c, &r) && i < nc; i++) {
+ d->SetValue(r, c, (double)f[i]);
+ }
+ free(f); return ((double)nv);
+}
+
+//---------------------------------------------------------------------------
+// Pearsons linear correlation
+// (1) 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. 503 ff.
+// (2) B. Gough (2000), linear.c, gsl-1.7 the GNU scientific library
+double d_pearson(double *x, double *y, int n, char *dest, DataObj *data, double *ra)
+{
+ int j, r, c;
+ double yt, xt, t, df, res[4];
+ double syy=0.0, sxy=0.0, sxx=0.0, ay=0.0, ax=0.0;
+ AccRange *rD;
+
+
+ for(j = 0; j < n; j++) { // find means
+ ax += (x[j] - ax) / (j+1); ay += (y[j] - ay) / (j+1);
+ }
+ for(j = 0; j < n; j++) { // correlation
+ xt = x[j] - ax; yt = y[j] - ay;
+ sxx += (xt*xt-sxx) / (j+1); syy += (yt*yt-syy) / (j+1);
+ sxy += (xt*yt-sxy) / (j+1);
+ }
+ res[0] = sxy/sqrt(sxx*syy); //pearsons r
+ if(dest || ra) {
+ res[1] = 0.5 * log((1.0+res[0]+_PREC)/(1.0-res[0]+_PREC)); //Fishers z-transform
+ df = n-2;
+ t = res[0]*sqrt(df/((1.0-res[0]+_PREC)*(1.0+res[0]+_PREC))); //Student's t
+ res[2] = betai(0.5*df, 0.5, df/(df+t*t)); //probability
+ res[3] = n;
+ }
+ if((dest) && (data) && (rD = new AccRange(dest))) {
+ rD->GetFirst(&c, &r);
+ for(j = 0; j < 4 && rD->GetNext(&c, &r); j++) {
+ data->SetValue(r, c, res[j]);
+ }
+ data->Command(CMD_UPDATE, 0L, 0L);
+ delete rD;
+ }
+ if (ra){
+ memcpy(ra, res, 4 * sizeof(double));
+ }
+ return res[0];
+}
+
+//---------------------------------------------------------------------------
+// Given an array w, rank returns the rank of v1 in v
+// if v1 is not found in v 0 is returned
+double d_rank(int n, double *v, double v1)
+{
+ double *sv;
+ int i, j;
+
+ if(!n || !v) return 0.0; if(n < 2) return 1.0;
+ if(!(sv = (double*)memdup(v, n * sizeof(double), 0))) return 0.0;
+ SortArray(n, sv);
+ for(i = j = 0; i < n; i++) {
+ if(v1 == sv[i]) {
+ for( ;(i+j)<n; j++) if(sv[i+j] > v1) break;
+ free(sv); return (double)i + 1.0 + (((double)j-1.0)/2.0);
+ }
+ }
+ free(sv); return 0.0;
+}
+
+//---------------------------------------------------------------------------
+// Spearman rank-order correlation
+// Ref.: W.H. Press, B.P. Flannery, S.A. Teukolsky, W.T. Vetterling (1989),
+// Numerical Recipies in C. The Art of Scientific Computing,
+// Cambridge University Press, ISBN 0-521-35465, pp. 507 ff.
+
+//Given a sorted array w, crank replaces the elements by their rank
+void crank(int n, double *w0, double *s)
+{
+ int j=1, ji, jt;
+ double t, rank, *w = w0-1;
+
+ *s = 0.0;
+ while (j < n) {
+ if(w[j+1] != w[j]) {
+ w[j] = j; ++j;
+ }
+ else {
+ for(jt = j+1; jt <= n; jt++) if(w[jt] != w[j]) break;
+ rank = 0.5 * (j+jt-1);
+ for(ji = j; ji <= (jt-1); ji++) w[ji] = rank;
+ t = jt -j; *s += t*t*t -t; j = jt;
+ }
+ }
+ if(j == n) w[n] = n;
+}
+
+//the actual rank correlation
+double d_spearman(double *sx, double *sy, int n, char *dest, DataObj *data, double *ra)
+{
+ int j, r, c;
+ double *x, *y, vard, t, sg, sf, fac, en3n, en, df, aved, tmp;
+ double res[6];
+ AccRange *rD;
+
+ if(!(x = (double*)memdup(sx, n*sizeof(double), 0))
+ || !(y = (double*)memdup(sy, n*sizeof(double), 0)))return 0.0;
+ SortArray2(n, x, y); crank(n, x, &sf);
+ SortArray2(n, y, x); crank(n, y, &sg);
+ for(j = 0, res[0] = 0.0; j < n; j++){
+ res[0] += ((tmp = (x[j]-y[j]))*tmp);
+ }
+ en = n; en3n = en*en*en -en;
+ aved = en3n/6.0 - (sf+sg)/12.0;
+ fac = (1.0-sf/en3n)*(1.0-sg/en3n);
+ vard = ((en-1.0)*en*en*((tmp = (en+1.0))*tmp)/36.0)*fac;
+ res[1] = (res[0]-aved)/sqrt(vard);
+ res[2] = errfc(fabs(res[1])/_SQRT2);
+ res[3] = (1.0-(6.0/en3n)*(res[0]+0.5*(sf+sg)))/fac;
+ t = res[3]*sqrt((en-2.0)/((res[3]+1.0)*(1.0-res[3])));
+ df = en-2.0; res[5] = (double)n;
+ res[4] = betai(0.5*df, 0.5, df/(df+t*t));
+ if((dest) && (data) && (rD = new AccRange(dest))) {
+ rD->GetFirst(&c, &r);
+ for(j = 0; j < 6 && rD->GetNext(&c, &r); j++) {
+ data->SetValue(r, c, res[j]);
+ }
+ data->Command(CMD_UPDATE, 0L, 0L);
+ delete rD;
+ }
+ if(ra) {
+ memcpy(ra, res, 6 * sizeof(double));
+ }
+ free(x); free(y);
+ return res[3];
+}
+
+//---------------------------------------------------------------------------
+// Kendal's non-parametric correlation
+// Ref.: W.H. Press, B.P. Flannery, S.A. Teukolsky, W.T. Vetterling (1989),
+// Numerical Recipies in C. The Art of Scientific Computing,
+// Cambridge University Press, ISBN 0-521-35465, pp. 510 ff.
+
+double d_kendall(double *x, double *y, int n, char *dest, DataObj *data, double *ra)
+{
+ int j, k, n1, n2, is, r, c;
+ double aa, a1, a2, sv, res[4];
+ AccRange *rD;
+
+ for (j = n1 = n2 = is = 0; j < (n-1); j++) {
+ for(k = j+1; k < n; k++) {
+ a1 = x[j] - x[k]; a2 = y[j] - y[k]; aa = a1*a2;
+ if(aa != 0.0) {
+ n1++; n2++;
+ if (aa > 0.0) is++;
+ else is--;
+ }
+ else {
+ if(a1 != 0.0) n1++; if(a2 != 0.0) n2++;
+ }
+ }
+ }
+ res[0] = ((double)is)/(sqrt((double)n1) * sqrt((double)n2));
+ sv = (4.0 * ((double)n) + 10.0)/(9.0*((double)n)*((double)(n-1)));
+ res[1] = res[0]/sqrt(sv); res[2] = errfc(fabs(res[1])/_SQRT2);
+ res[3] = n;
+ if((dest) && (data) && (rD = new AccRange(dest))) {
+ rD->GetFirst(&c, &r);
+ for(j = 0; j < 4 && rD->GetNext(&c, &r); j++) {
+ data->SetValue(r, c, res[j]);
+ }
+ data->Command(CMD_UPDATE, 0L, 0L);
+ delete rD;
+ }
+ if (ra){
+ memcpy(ra, res, 4 * sizeof(double));
+ }
+ return res[0];
+}
+
+
+//linear regression
+double d_regression(double *x, double *y, int n, char *dest, DataObj *data, double *ra)
+{
+ double sx, sy, dx, dy, sxy, sxx, syy, sdy, df;
+ double res[10]; // slope, intercept, mean x, mean y, SE of slope,
+ // variance(x), variance(y), variance(fit), F of regression, significance
+ int i, j, r, c;
+ AccRange *rD;
+
+ if(n < 2) return 0.0;
+ for(i = 0, sx = sy = 0.0; i < n; i++) {
+ sx += x[i]; sy += y[i];
+ }
+ res[2] = sx /n; res[3] = sy/n;
+ sxy = sxx = syy = 0.0;
+ for(i = 0; i < n; i++) {
+ dx = x[i]-res[2]; dy = y[i]-res[3];
+ sxx += (dx*dx); syy += (dy*dy); sxy += (dx*dy);
+ }
+ res[0] = sxy / sxx; res[1] = res[3] - res[0] * res[2];
+ for(i = 0, sdy = 0.0; i < n; i++) {
+ dy = y[i] - (res[1] + x[i] *res[0]);
+ sdy += (dy * dy);
+ }
+ sdy = sdy/(n-2); res[4] = sqrt(sdy/sxx); df = (n-2);
+ res[5] = sxx/(n-1); res[6] = syy/(n-1); res[7] = sdy;
+ res[8] = sxy/sdy*sxy/sxx;
+ res[9] = betai(df/2.0, 0.5, df/(df+res[8]));
+ if((dest) && (data) && (rD = new AccRange(dest))) {
+ rD->GetFirst(&c, &r);
+ for(j = 0; j < 10 && rD->GetNext(&c, &r); j++) {
+ data->SetValue(r, c, res[j]);
+ }
+ data->Command(CMD_UPDATE, 0L, 0L);
+ delete rD;
+ }
+ if (ra) memcpy(ra, res, 10 * sizeof(double));
+ return n;
+}
+
+//covariance
+double d_covar(double *x, double *y, int n, char *dest, DataObj *data)
+{
+ int i;
+ double sx, sy, dx, dy, sxy;
+
+ if(n < 2) return 0.0;
+ for(i = 0, sx = sy = 0.0; i < n; i++) {
+ sx += x[i]; sy += y[i];
+ }
+ sx /= n; sy /= n; sxy = 0.0;
+ for(i = 0; i < n; i++) {
+ dx = x[i]-sx; dy = y[i]-sy;
+ sxy += (dx*dy - sxy) / (i+1);
+ }
+ return sxy;
+}
+
+//Mann-Whitney U Test
+double d_utest(double *x, double *y, int n1, int n2, char *dest, DataObj *data, double *ra)
+{
+ double *da, *ta, u1, u2, su, su1, ts, dn1 = n1, dn2 = n2;
+ double res[9];
+ AccRange *rD;
+ int i, j, n, r, c;
+
+ if(!x || !y || n1 < 2 || n2 < 2) return 0.0;
+ da = (double*)malloc((n = (n1+n2)) * sizeof(double));
+ ta = (double*)malloc(n * sizeof(double));
+ if(!da || !ta) {
+ if(da) free(da); if(ta) free(ta); return 0.0;
+ }
+ for(i = 0; i < n1; i++) {
+ da[i] = x[i]; ta[i] = 1.0;
+ }
+ for(j = 0; j < n2; j++) {
+ da[i] = y[j]; ta[i++] = 2.0;
+ }
+ SortArray2(n, da, ta); crank(n, da, &ts);
+ for(i = 0, res[0] = res[1] = 0.0; i < n; i++) {
+ if(ta[i] == 1.0) res[0] += da[i];
+ else res[1] += da[i];
+ }
+ free(da); free(ta);
+ u1 = (dn1*dn2 + (dn1*(dn1+1))/2.0) - res[0]; u2 = (dn1*dn2 + ((dn2+1)*dn2)/2.0) - res[1];
+ su = sqrt((dn1*dn2*(dn1+dn2+1))/12.0); res[2] = u2 > u1 ? u2 : u1;
+ su1 = ((dn1*dn2)/((dn1+dn2)*(dn1+dn2-1))) * (((dn1+dn2)*(dn1+dn2)*(dn1+dn2)-(dn1+dn2)-ts)/12.0);
+ su1 = sqrt(su1);
+ res[3] = (res[2] - (n1*n2)/2.0)/su; res[6] = errfc(res[3]/_SQRT2);
+ res[4] = n1; res[5] = n2;
+ res[7] = (res[2] - (n1*n2)/2.0)/su1; res[8] = errfc(res[7]/_SQRT2);
+ if((dest) && (data) && (rD = new AccRange(dest))) {
+ rD->GetFirst(&c, &r);
+ for(i = 0; i < 9 && rD->GetNext(&c, &r); i++) {
+ data->SetValue(r, c, res[i]);
+ }
+ data->Command(CMD_UPDATE, 0L, 0L);
+ delete rD;
+ }
+ if (ra) memcpy(ra, res, 9 * sizeof(double));
+ return res[8];
+}
+
+//t-test
+double d_ttest(double *x, double *y, int n1, int n2, char *dest, DataObj *data, double *results)
+{
+ int i, r, c;
+ double sx, sy, mx, my, d, df, p;
+ double res[9]; // mean1, SD1, n1, mean2, SD2, n2, p if variances equal,
+ AccRange *rD; // corrected df, corrected p
+
+ d_variance(n1, x, &mx, &sx); d_variance(n2, y, &my, &sy);
+ d = ((sx+sy)/(n1+n2-2)) * ((double)(n1+n2)/(double)(n1*n2));
+ d = (mx-my)/sqrt(d); //Student's t
+
+ //Welch's correction for differences in variance
+ df = (sx/(double)n1)*(sx/(double)n1)/(double)(n1+1)+(sy/(double)n2)*(sy/(double)n2)/(double)(n2+1);
+ df = (sx/(double)n1+sy/(double)n2)*(sx/(double)n1+sy/(double)n2)/df;
+ df -= 2.0; df = floor(df);
+
+// an alternative formula for correction
+// p = (sx/(double)n1)*(sx/(double)n1)/(double)(n1-1) + (sy/(double)n2)*(sy/(double)n2)/(double)(n2-1);
+// df = (sx/(double)n1 + sy/(double)n2) * (sx/(double)n1 + sy/(double)n2) / p;
+
+ p = betai(df/2.0, 0.5, (df/(df+d*d)));
+ if((dest) && (data) && (rD = new AccRange(dest))) {
+ res[0] = mx; res[1] = sqrt(sx/(double)(n1-1)); res[2] = n1;
+ res[3] = my; res[4] = sqrt(sy/(double)(n2-1)); res[5] = n2;
+ res[7] = df; df = (n1-1) + (n2-1); res[6] = betai(df/2.0, 0.5, (df/(df+d*d)));
+ res[8] = p;
+ rD->GetFirst(&c, &r);
+ for(i = 0; i < 9 && rD->GetNext(&c, &r); i++) {
+ data->SetValue(r, c, res[i]);
+ }
+ data->Command(CMD_UPDATE, 0L, 0L);
+ delete rD;
+ }
+ if(results) {
+ results[0] = mx; results[1] = sqrt(sx/(double)(n1-1)); results[2] = n1;
+ results[3] = my; results[4] = sqrt(sy/(double)(n2-1)); results[5] = n2;
+ results[7] = df; df = (n1-1) + (n2-1); results[6] = betai(df/2.0, 0.5, (df/(df+d*d)));
+ results[8] = p; results[9] = d;
+ }
+ return p;
+}
+
+//t-test for paired samples
+double d_ttest2(double *x, double *y, int n, char *dest, DataObj *data, double *ra)
+{
+ double sx, sy, mx, my, df, cov, sd, t, p;
+ int i, r, c;
+ double res[6]; // mean1, SD1, mean2, SD2, n, p
+ AccRange *rD;
+
+ d_variance(n, x, &mx, &sx); d_variance(n, y, &my, &sy);
+ sx = d_variance(n, x, &mx); sy = d_variance(n, y, &my);
+ cov = d_covar(x, y, n, 0L, 0L) * ((double)n/(double)(n-1));
+ sd = sqrt((sx+sy-2*cov)/n);
+ t = (mx-my)/sd; df = (n-1);
+ p = betai(0.5*df, 0.5, df/(df+t*t));
+ res[0] = mx; res[1] = sqrt(sx); res[5] = p;
+ res[2] = my; res[3] = sqrt(sy); res[4] = n;
+ if((dest) && (data) && (rD = new AccRange(dest))) {
+ rD->GetFirst(&c, &r);
+ for(i = 0; i < 6 && rD->GetNext(&c, &r); i++) {
+ data->SetValue(r, c, res[i]);
+ }
+ data->Command(CMD_UPDATE, 0L, 0L);
+ delete rD;
+ }
+ if (ra) memcpy(ra, res, 6 * sizeof(double));
+ return p;
+}
+
+//f-test
+double d_ftest(double *x, double *y, int n1, int n2, char *dest, DataObj *data, double *ra)
+{
+ int i, r, c;
+ double sx, sy, mx, my, d, df1, df2, p;
+ double res[6]; // mean1, SD1, n1, mean2, SD2, n2
+ AccRange *rD;
+
+ for(i=0, sx = 0.0; i < n1; sx += x[i], i++); mx = sx/n1;
+ for(i=0, sy = 0.0; i < n2; sy += y[i], i++); my = sy/n2;
+ for(i=0, sx = 0.0; i < n1; sx += ((d=(x[i]-mx))*d), i++); sx /= (n1-1);
+ for(i=0, sy = 0.0; i < n2; sy += ((d=(y[i]-my))*d), i++); sy /= (n2-1);
+ if(sx > sy) {
+ d = sx/sy; df1 = n1-1; df2 = n2-1;
+ }
+ else {
+ d = sy/sx; df1 = n2-1; df2 = n1-1;
+ }
+ p = 2.0 * betai(df2/2.0, df1/2.0, df2/(df2+df1*d));
+ if(p > 1.0) p = 2.0-p;
+ res[0] = mx; res[1] = sqrt(sx); res[2] = n1;
+ res[3] = my; res[4] = sqrt(sy); res[5] = n2;
+ if((dest) && (data) && (rD = new AccRange(dest))) {
+ rD->GetFirst(&c, &r);
+ for(i = 0; i < 6 && rD->GetNext(&c, &r); i++) {
+ data->SetValue(r, c, res[i]);
+ }
+ data->Command(CMD_UPDATE, 0L, 0L);
+ delete rD;
+ }
+ if (ra) memcpy(ra, res, 6 * sizeof(double));
+ return p;
+}
+//---------------------------------------------------------------------------
+// Simple one way anova
+//---------------------------------------------------------------------------
+bool do_anova1(int n, int *nv, double **vals, double **res_tab, double *gm, double **means, double **ss)
+{
+ int i, j, ntot;
+ double tmp, *csums, *css, ssa, ssw, sst, mtot, d;
+
+ if(!(csums = (double*)calloc(n+1, sizeof(double)))
+ || !(css = (double*)calloc(n+1, sizeof(double)))) return false;
+
+ for(i = ntot = 0, mtot = 0.0, d = 1.0; i< n; i++){
+ for(j = 0, csums[i] = 0.0, tmp = 1.0; j < nv[i]; j++, d+=1.0, tmp +=1.0) {
+ mtot += (vals[i][j] - mtot)/d;
+ csums[i] += (vals[i][j] -csums[i])/tmp;
+ }
+ ntot += nv[i];
+ }
+ for(i = 0; i < n; i++) {
+ for(j = 0, css[i] = 0.0; j < nv[i]; j++) {
+ tmp = vals[i][j] - csums[i]; css[i] += (tmp*tmp);
+ }
+ }
+ for(i = 0, ssa = ssw = sst = 0.0; i < n; i++) {
+ tmp =(csums[i] - mtot); ssa += (tmp*tmp) * ((double)nv[i]);
+ ssw += css[i];
+ }
+ sst = ssa + ssw;
+ res_tab[0][0] = n - 1; res_tab[1][0] = ntot - n;
+ res_tab[2][0] = ntot -1; res_tab[0][1] = ssa;
+ res_tab[1][1] = ssw; res_tab[2][1] = sst;
+ res_tab[0][2] = ssa/res_tab[0][0]; res_tab[1][2] = ssw/res_tab[1][0];
+ res_tab[0][3] = res_tab[0][2]/res_tab[1][2];
+ res_tab[0][4] = f_dist(res_tab[0][3], res_tab[0][0], res_tab[1][0]);
+ if(gm) *gm = mtot;
+ if(means) *means = csums; else free(csums);
+ if(ss) *ss = css; else free(css);
+ return true;
+}
+
+//---------------------------------------------------------------------------
+// Bartlett's Test for homogeneity of variances
+// RR Sokal & FJ Rohlf: Biometry, 3rd ed., pp. 398 ff.
+//---------------------------------------------------------------------------
+bool bartlett(int n, int *nc, double *ss, double *chi2)
+{
+ int i, sdf, df;
+ double mss, mlss, *lnss, cf;
+
+ if(!n || !nc || !ss || !chi2) return false;
+ if(!(lnss = (double*)malloc(n * sizeof(double))))return false;
+ for(i = sdf = 0, mss = mlss = cf = 0.0; i < n; i++) {
+ sdf += (df = nc[i]-1); lnss[i] = log(ss[i]);
+ mss += (ss[i] * ((double)df)); mlss += (lnss[i] * ((double)df));
+ cf += (1.0/((double)df));
+ }
+ *chi2 = ((double)sdf) * log(mss/((double)sdf)) - mlss;
+ cf -= (1.0/((double)sdf)); cf = 1.0 + cf/(3.0 * ((double)(n-1)));
+ *chi2 /= cf;
+ // P = chi_dist(*chi2, n-1, 0);
+ free(lnss); return true;
+}
+//---------------------------------------------------------------------------
+// Leven's Test for homogeneity of variances
+//---------------------------------------------------------------------------
+bool levene(int type, int n, int *nv, double *means, double **vals, double *F, double *P)
+{
+ int i, j;
+ bool bRet = false;
+ double cm, **res_tab, **cols;
+
+ if(!n || !nv || !means || !vals) return false;
+ //setup matrix for results
+ if((res_tab = (double**)calloc(3, sizeof(double*)))
+ && (res_tab[0] = (double*) malloc(5*sizeof(double)))
+ && (res_tab[1] = (double*) malloc(5*sizeof(double)))
+ && (res_tab[2] = (double*) malloc(5*sizeof(double)))
+ && (cols = (double**)calloc(n+1, sizeof(double*)))) bRet = true;
+ //allocate mem for data
+ for(i = 0; bRet && i<n; i++) {
+ if(!(cols[i]=(double*)malloc((nv[i]+1)*sizeof(double)))) bRet = false;
+ }
+ //data are absolute differences to mean ...
+ for(i = 0, cm = 0.0; bRet && i < n; i++) {
+ switch(type) {
+ case 1: //use means
+ cm = means[i]; break;
+ case 2: //use medians
+ d_quartile(nv[i], vals[i], 0L, &cm, 0L); break;
+ }
+ for(j = 0; j < nv[i]; j++) {
+ cols[i][j] = vals[i][j] > cm ? vals[i][j] - cm : cm - vals[i][j];
+ }
+ }
+ //Levene's test statistic is based on ANOVA of the differences
+ if(bRet && (bRet = do_anova1(n, nv, cols, res_tab, 0L, 0L, 0L))){
+ if(F) *F = res_tab[0][3]; if(P) *P = res_tab[0][4];
+ }
+ //clean up
+ if(bRet) {
+ for(i = 0; i < n; i++) if(cols[i]) free(cols[i]);
+ for(i = 0; i < 3; i++) if(res_tab[i]) free(res_tab[i]);
+ free(cols); free(res_tab);
+ }
+ return bRet;
+}
+
+//---------------------------------------------------------------------------
+// Modules from the R-project
+//
+//---------------------------------------------------------------------------
+#define M_1_SQRT_2PI 0.398942280401432677939946059934 /* 1/sqrt(2pi) */
+/*
+ * Copyright (C) 1998 Ross Ihaka
+ * Copyright (C) 2000--2005 The R Development Core Team
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * DESCRIPTION
+ * Computes the probability that the maximum of rr studentized
+ * ranges, each based on cc means and with df degrees of freedom
+ * for the standard error, is less than q.
+ * The algorithm is based on that of the reference.
+ *
+ * REFERENCE
+ * Copenhaver, Margaret Diponzio & Holland, Burt S.
+ * Multiple comparisons of simple effects in
+ * the two-way analysis of variance with fixed effects.
+ * Journal of Statistical Computation and Simulation,
+ * Vol.30, pp.1-15, 1988.
+ */
+
+double wprob(double w, double rr, double cc)
+{
+/* wprob() :
+
+ This function calculates probability integral of Hartley's
+ form of the range.
+
+ w = value of range
+ rr = no. of rows or groups
+ cc = no. of columns or treatments
+ ir = error flag = 1 if pr_w probability > 1
+ pr_w = returned probability integral from (0, w)
+
+ program will not terminate if ir is raised.
+
+ bb = upper limit of legendre integration
+ iMax = maximum acceptable value of integral
+ nleg = order of legendre quadrature
+ ihalf = int ((nleg + 1) / 2)
+ wlar = value of range above which wincr1 intervals are used to
+ calculate second part of integral,
+ else wincr2 intervals are used.
+ C1, C2, C3 = values which are used as cutoffs for terminating
+ or modifying a calculation.
+ xleg = legendre 12-point nodes
+ aleg = legendre 12-point coefficients
+ */
+#define nleg 12
+#define ihalf 6
+
+ /* looks like this is suboptimal for double precision.
+ (see how C1-C3 are used) <MM> */
+ /* const double iMax = 1.; not used if = 1*/
+ const static double C1 = -30.0, C2 = -50.0, C3 = 60.;
+ const static double bb = 8.0, wlar = 3.0, wincr1 = 2.0, wincr2 = 3.;
+ const static double xleg[ihalf] = { 0.981560634246719250690549090149,
+ 0.904117256370474856678465866119, 0.769902674194304687036893833213,
+ 0.587317954286617447296702418941, 0.367831498998180193752691536644,
+ 0.125233408511468915472441369464};
+ const static double aleg[ihalf] = { 0.047175336386511827194615961485,
+ 0.106939325995318430960254718194, 0.160078328543346226334652529543,
+ 0.203167426723065921749064455810, 0.233492536538354808760849898925,
+ 0.249147045813402785000562436043};
+ double a, ac, pr_w, b, binc, blb, bub, c, cc1, einsum, elsum,
+ pminus, pplus, qexpo, qsqz, rinsum, wi, wincr, xx;
+ int j, jj;
+
+ qsqz = w * 0.5;
+
+ // if w >= 16 then the integral lower bound (occurs for c=20)
+ // is 0.99999999999995 so return a value of 1
+ if (qsqz >= bb) return 1.0;
+
+ // find (f(w/2) - 1) ^ cc
+ // (first term in integral of hartley's form).
+ pr_w = 2.0 * norm_dist(qsqz, 0.0, 1.0) -1.0;
+ // if pr_w ^ cc < 2e-22 then set pr_w = 0
+ if (pr_w >= exp(C2 / cc)) pr_w = pow(pr_w, cc);
+ else pr_w = 0.0;
+ // if w is large then the second component of the
+ // integral is small, so fewer intervals are needed.
+ if (w > wlar) wincr = wincr1;
+ else wincr = wincr2;
+
+ /* find the integral of second term of hartley's form */
+ /* for the integral of the range for equal-length */
+ /* intervals using legendre quadrature. limits of */
+ /* integration are from (w/2, 8). two or three */
+ /* equal-length intervals are used. */
+ /* blb and bub are lower and upper limits of integration. */
+ blb = qsqz; binc = (bb - qsqz) / wincr;
+ bub = blb + binc; einsum = 0.0;
+
+ // integrate over each interval
+ cc1 = cc - 1.0;
+ for (wi = 1; wi <= wincr; wi++) {
+ elsum = 0.0; a = 0.5 * (bub + blb);
+ // legendre quadrature with order = nleg
+ b = 0.5 * (bub - blb);
+ for (jj = 1; jj <= nleg; jj++) {
+ if (ihalf < jj) {
+ j = (nleg - jj) + 1; xx = xleg[j-1];
+ }
+ else {
+ j = jj; xx = -xleg[j-1];
+ }
+ c = b * xx; ac = a + c;
+ // if exp(-qexpo/2) < 9e-14, then doesn't contribute to integral
+ if ((qexpo = ac * ac) > C3) break;
+ pplus = 2.0 * norm_dist(ac, 0.0, 1.0); pminus= 2.0 * norm_dist(ac, w, 1.0);
+ // if rinsum ^ (cc-1) < 9e-14, then doesn't contribute to integral
+ rinsum = (pplus * 0.5) - (pminus * 0.5);
+ if (rinsum >= exp(C1 / cc1)) {
+ rinsum = (aleg[j-1] * exp(-(0.5 * qexpo))) * pow(rinsum, cc1);
+ elsum += rinsum;
+ }
+ }
+ elsum *= (((2.0 * b) * cc) * M_1_SQRT_2PI);
+ einsum += elsum; blb = bub; bub += binc;
+ }
+ // if pr_w ^ rr < 9e-14, then return 0 */
+ pr_w = einsum + pr_w;
+ if (pr_w <= exp(C1 / rr))return 0.;
+ pr_w = pow(pr_w, rr);
+ return pr_w < 1.0 ? pr_w : 1.0;
+}
+
+double ptukey(double q, double rr, double cc, double df, int lower_tail, int log_p)
+{
+/* q = value of studentized range
+ rr = no. of rows or groups
+ cc = no. of columns or treatments
+ df = degrees of freedom of error term
+ ir[0] = error flag = 1 if wprob probability > 1
+ ir[1] = error flag = 1 if qprob probability > 1
+
+ All references in wprob to Abramowitz and Stegun
+ are from the following reference:
+ Abramowitz, Milton and Stegun, Irene A.
+ Handbook of Mathematical Functions.
+ New York: Dover publications, Inc. (1970).
+ All constants taken from this text are given to 25 significant digits.
+
+ nlegq = order of legendre quadrature
+ ihalfq = int ((nlegq + 1) / 2)
+ eps = max. allowable value of integral
+ eps1 & eps2 = values below which there is no contribution to integral.
+
+ d.f. <= dhaf: integral is divided into ulen1 length intervals. else
+ d.f. <= dquar: integral is divided into ulen2 length intervals. else
+ d.f. <= deigh: integral is divided into ulen3 length intervals. else
+ d.f. <= dlarg: integral is divided into ulen4 length intervals.
+
+ d.f. > dlarg: the range is used to calculate integral.
+
+ xlegq = legendre 16-point nodes
+ alegq = legendre 16-point coefficients
+
+ The coefficients and nodes for the legendre quadrature used in
+ qprob and wprob were calculated using the algorithms found in:
+ Stroud, A. H. and Secrest, D., Gaussian Quadrature Formulas.
+ Englewood Cliffs, New Jersey: Prentice-Hall, Inc, 1966.
+
+ All values matched the tables (provided in same reference)
+ to 30 significant digits.
+
+ f(x) = .5 + erf(x / sqrt(2)) / 2 for x > 0
+ f(x) = erfc( -x / sqrt(2)) / 2 for x < 0
+ where f(x) is standard normal c. d. f.
+
+ if degrees of freedom large, approximate integral with range distribution.
+ */
+#define nlegq 16
+#define ihalfq 8
+
+/* const double eps = 1.0; not used if = 1 */
+ const static double eps1 = -30.0, eps2 = 1.0e-14;
+ const static double dhaf = 100.0, dquar = 800.0, deigh = 5000.0, dlarg = 25000.0;
+ const static double ulen1 = 1.0, ulen2 = 0.5, ulen3 = 0.25, ulen4 = 0.125;
+ const static double xlegq[ihalfq] = { 0.989400934991649932596154173450,
+ 0.944575023073232576077988415535, 0.865631202387831743880467897712,
+ 0.755404408355003033895101194847, 0.617876244402643748446671764049,
+ 0.458016777657227386342419442984, 0.281603550779258913230460501460,
+ 0.950125098376374401853193354250e-1};
+ const static double alegq[ihalfq] = {0.271524594117540948517805724560e-1,
+ 0.622535239386478928628438369944e-1, 0.951585116824927848099251076022e-1,
+ 0.124628971255533872052476282192, 0.149595988816576732081501730547,
+ 0.169156519395002538189312079030, 0.182603415044923588866763667969,
+ 0.189450610455068496285396723208};
+ double ans, f2, f21, f2lf, ff4, otsum, qsqz, rotsum, t1, twa1, ulen, wprb;
+ int i, j, jj;
+
+ if (df > dlarg) return wprob(q, rr, cc);
+ f2 = df * 0.5; // calculate leading constant
+ f2lf = ((f2 * log(df)) - (df * log(2.0))) - gammln(f2);
+ f21 = f2 - 1.0;
+ // integral is divided into unit, half-unit, quarter-unit, or eighth-unit length intervals
+ // depending on the value of the degrees of freedom.
+ ff4 = df * 0.25;
+ if (df <= dhaf) ulen = ulen1;
+ else if (df <= dquar) ulen = ulen2;
+ else if (df <= deigh) ulen = ulen3;
+ else ulen = ulen4;
+ f2lf += log(ulen);
+ for (i = 1, ans = 0.0; i <= 50; i++) { // integrate over each subinterval
+ otsum = 0.0;
+ // legendre quadrature with order = nlegq, nodes (stored in xlegq) are symmetric around zero.
+ twa1 = (2 * i - 1) * ulen;
+ for (jj = 1; jj <= nlegq; jj++) {
+ if (ihalfq < jj) {
+ j = jj - ihalfq - 1;
+ t1 = (f2lf + (f21 * log(twa1 + (xlegq[j] * ulen)))) - (((xlegq[j] * ulen) + twa1) * ff4);
+ }
+ else {
+ j = jj - 1;
+ t1 = (f2lf + (f21 * log(twa1 - (xlegq[j] * ulen)))) + (((xlegq[j] * ulen) - twa1) * ff4);
+ }
+ if (t1 >= eps1) { // if exp(t1) < 9e-14, then doesn't contribute to integral
+ if (ihalfq < jj) qsqz = q * sqrt(((xlegq[j] * ulen) + twa1) * 0.5);
+ else qsqz = q * sqrt(((-(xlegq[j] * ulen)) + twa1) * 0.5);
+ wprb = wprob(qsqz, rr, cc); // call wprob to find integral of range portion
+ rotsum = (wprb * alegq[j]) * exp(t1); otsum += rotsum;
+ }
+ } // end legendre integral for interval i
+ // If integral for interval i < 1e-14, then stop. However, in order to avoid small area
+ // under left tail, at least 1 / ulen intervals are calculated.
+ if (i * ulen >= 1.0 && otsum <= eps2) break;
+ ans += otsum; //end of interval i
+ }
+ return ans > 1.0 ? 1.0 : ans;
+ }
+
+ /*
+ * Copyright (C) 1998 Ross Ihaka
+ * Copyright (C) 2000--2005 The R Development Core Team
+ * based in part on AS70 (C) 1974 Royal Statistical Society
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * DESCRIPTION
+ * Computes the quantiles of the maximum of rr studentized
+ * ranges, each based on cc means and with df degrees of freedom
+ * for the standard error, is less than q.
+ * The algorithm is based on that of the reference.
+ *
+ * REFERENCE
+ * Copenhaver, Margaret Diponzio & Holland, Burt S., Multiple comparisons of simple
+ * effects in the two-way analysis of variance with fixed effects.
+ * Journal of Statistical Computation and Simulation, Vol.30, pp.1-15, 1988.
+ */
+
+/* qinv() :
+ * this function finds percentage point of the studentized range
+ * which is used as initial estimate for the secant method.
+ * function is adapted from portion of algorithm as 70
+ * from applied statistics (1974) ,vol. 23, no. 1
+ * by odeh, r. e. and evans, j. o.
+ * p = percentage point
+ * c = no. of columns or treatments
+ * v = degrees of freedom
+ * qinv = returned initial estimate
+ * vmax is cutoff above which degrees of freedom
+ * is treated as infinity.
+ */
+
+static double qinv(double p, double c, double v)
+{
+ const static double p0 = 0.322232421088, q0 = 0.993484626060e-01;
+ const static double p1 = -1.0, q1 = 0.588581570495;
+ const static double p2 = -0.342242088547, q2 = 0.531103462366;
+ const static double p3 = -0.204231210125, q3 = 0.103537752850;
+ const static double p4 = -0.453642210148e-04, q4 = 0.38560700634e-02;
+ const static double c1 = 0.8832, c2 = 0.2368, c3 = 1.214, c4 = 1.208, c5 = 1.4142;
+ const static double vmax = 120.0;
+ double ps, q, t, yi;
+
+ ps = 0.5 - 0.5 * p;
+ yi = sqrt (log (1.0 / (ps * ps)));
+ t = yi + (((( yi * p4 + p3) * yi + p2) * yi + p1) * yi + p0)
+ / (((( yi * q4 + q3) * yi + q2) * yi + q1) * yi + q0);
+ if (v < vmax) t += (t * t * t + t) / v / 4.0;
+ q = c1 - c2 * t;
+ if (v < vmax) q += -c3 / v + c4 * t / v;
+ return t * (q * log (c - 1.0) + c5);
+}
+
+/*
+ * Copenhaver, Margaret Diponzio & Holland, Burt S.
+ * Multiple comparisons of simple effects in
+ * the two-way analysis of variance with fixed effects.
+ * Journal of Statistical Computation and Simulation,
+ * Vol.30, pp.1-15, 1988.
+ *
+ * Uses the secant method to find critical values.
+ *
+ * p = confidence level (1 - alpha)
+ * rr = no. of rows or groups
+ * cc = no. of columns or treatments
+ * df = degrees of freedom of error term
+ *
+ */
+double qtukey(double p, double rr, double cc, double df, int lower_tail, int log_p)
+{
+ const int maxiter = 50;
+ double ans = HUGE_VAL, valx0, valx1, x0, x1;
+ int iter;
+
+ // df must be > 1 ; there must be at least two values
+ if(p >= 1.0 || df < 2 || rr < 1 || cc < 2) return HUGE_VAL;
+ if(p < 0.0) p = 0.0;
+ x0 = qinv(p, cc, df); // Initial value
+ valx0 = ptukey(x0, rr, cc, df, true, false) - p; // Find prob(value < x0)
+ // Find the second iterate and prob(value < x1). If the first iterate has probability value
+ // exceeding p then second iterate is 1 less than first iterate; otherwise it is 1 greater.
+ x1 = valx0 > 0.0 ? (x1 = x0 > 1.0 ? x0-1.0 : 0.0) : (x0 + 1.0);
+ valx1 = ptukey(x1, rr, cc, df, true, false) - p;
+ for(iter=1; iter < maxiter ; iter++) { // Iterate
+ ans = x1 - ((valx1 * (x1 - x0)) / (valx1 - valx0));
+ valx0 = valx1; x0 = x1;
+ if (ans < 0.0) { // New iterate must be >= 0
+ ans = 0.0; valx1 = -p;
+ }
+ valx1 = ptukey(ans, rr, cc, df, true, false) - p; // Find prob(value < new iterate)
+ x1 = ans;
+ if (fabs(x1 - x0) < _PREC) return ans; // Convergence ?
+ }
+ //The process did not converge in 'maxiter' iterations
+ return ans;
+}
+//---------------------------------------------------------------------------
+// END Modules from the R-project
+
+
+//---------------------------------------------------------------------------
+// Calendar, Date- and Time functions
+// The following characters are used as format specifiers in a format string,
+// all other characters are either ignored or copyied to the output
+//
+// Y four digits year y two digits year
+// X month's full name x three character month name
+// Z two digits day of month z same as Z but no leading zero
+// V two digit month number v number of month
+// W single letter month
+// D full name of day d three characters for day name
+// E two digits weekday e one or two digits weekday
+// F single character day name
+// H two digits for hours h hours with no leading zero
+// M two digits for minutes m minutes with no leading zero
+// S two digits for seconds s seconds with no leading zero
+// T two digits seconds, two dec. t same as T but no leading zero
+// U full precision seconds
+
+static char *dt_month[] = {"January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December"};
+
+static char *dt_months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
+ "Sep", "Oct", "Nov", "Dec"};
+
+static int dt_monthl[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+static char *dt_day[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
+ "Friday", "Saturday"};
+
+static char *dt_days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+
+static bool leapyear(int year) {
+ return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
+}
+
+int year2aday(int y)
+{
+ int aday, y1;
+
+ y1 = y - 1900;
+ aday = y1 * 365;
+ aday += ((y1-1) >> 2 );
+ aday -= (y1 / 100);
+ aday += ((y/400)-4);
+ return aday;
+}
+
+static void set_dow(rlp_datetime *dt)
+{
+ dt->dow = (dt->aday %7)+1;
+}
+
+void add_date(rlp_datetime *base, rlp_datetime *inc)
+{
+ int i, dom;
+
+ if(base) {
+ if(base->month < 1) base->month = 1;
+ if(inc) {
+ base->seconds += inc->seconds;
+ if(base->seconds >= 60.0) {
+ base->minutes++; base->seconds -= 60.0;
+ }
+ base->minutes += inc->minutes;
+ if(base->minutes >= 60) {
+ base->hours++; base->minutes -= 60;
+ }
+ base->hours += inc->hours;
+ if(base->hours >= 24) {
+ base->dom++; base->hours -= 24;
+ }
+ base->year += inc->year; base->dom += inc->dom;
+ base->month += inc->month;
+ }
+ dom = dt_monthl[base->month-1];
+ if(leapyear(base->year) && base->month == 2) dom = 29;
+ if(base->dom > dom) {
+ base->month++; base->dom -= dom;
+ }
+ if(base->month > 12) {
+ base->year++; base->month -= 12;
+ }
+ base->aday = year2aday(base->year);
+ for(i = base->doy = 0; i < (base->month-1); i++) {
+ dom = dt_monthl[i];
+ if(i == 1 && leapyear(base->year)) dom = 29;
+ base->doy += dom;
+ }
+ base->doy += base->dom;
+ base->aday += base->doy; set_dow(base);
+ }
+}
+
+static int parse_date (rlp_datetime *dt, char *src, char *fmt)
+{
+ int i, j, k;
+ char tmp_str[10];
+
+ if(!src || !src[0] || !fmt || !fmt[0]) return 0;
+ if(*src == '\'') src++;
+ for(i = j = 0; fmt[i] && src[j]; i++) {
+ switch (fmt[i]) {
+ case 'Y': case 'y': // year is numeric
+ if(j && src[j] == '-' || src[j] == '/' || src[j] == '.') j++;
+#ifdef USE_WIN_SECURE
+ if(sscanf_s(src+j, "%d", &dt->year)) {
+#else
+ if(sscanf(src+j, "%d", &dt->year)) {
+#endif
+ if(dt->year < 0) return 0;
+ while(isdigit(src[j])) j++;
+ if(dt->year<60) dt->year += 2000;
+ else if(dt->year <99) dt->year += 1900;
+ }
+ else return 0;
+ break;
+ case 'X': case 'x': // month can be text
+ if(j && src[j] == '-' || src[j] == '/' || src[j] == '.') j++;
+ tmp_str[0] = toupper(src[j]);
+ tmp_str[1] = tolower(src[j+1]);
+ tmp_str[2] = tolower(src[j+2]);
+ tmp_str[3] = 0;
+ for(k = dt->month = 0; k < 12; k++) {
+ if(0 == strcmp(tmp_str,dt_months[k])) {
+ dt->month = k+1; break;
+ }
+ }
+ if(dt->month) while(isalpha(src[j])) j++;
+ else return 0;
+ break;
+ case 'V': case 'v': // or numeric
+ if(j && src[j] == '-' || src[j] == '/' || src[j] == '.') j++;
+#ifdef USE_WIN_SECURE
+ if(sscanf_s(src+j, "%d", &dt->month)) {
+#else
+ if(sscanf(src+j, "%d", &dt->month)) {
+#endif
+ if(dt->month <= 0 || dt->month > 12) return 0;
+ j++; if(isdigit(src[j])) j++;
+ }
+ else return 0;
+ break;
+ case 'Z': case 'z': // day of month is numeric
+ if(j && src[j] == '-' || src[j] == '/' || src[j] == '.') j++;
+#ifdef USE_WIN_SECURE
+ if(sscanf_s(src+j, "%d", &dt->dom)) {
+#else
+ if(sscanf(src+j, "%d", &dt->dom)) {
+#endif
+ if(dt->dom <= 0 || dt->dom > 31) return 0;
+ j++; if(isdigit(src[j])) j++;
+ }
+ else return 0;
+ break;
+ case 'H': case 'h': // hours are numeric
+#ifdef USE_WIN_SECURE
+ if(sscanf_s(src+j, "%2d", &dt->hours)) {
+#else
+ if(sscanf(src+j, "%2d", &dt->hours)) {
+#endif
+ if(dt->hours < 0 || dt->hours > 23) return 0;
+ j++; if(isdigit(src[j])) j++;
+ }
+ else return 0;
+ break;
+ case 'M': case 'm': // minutes are numeric
+ if(j && src[j] == ' ' || src[j] == ':') j++;
+#ifdef USE_WIN_SECURE
+ if(sscanf_s(src+j, "%2d", &dt->minutes)) {
+#else
+ if(sscanf(src+j, "%2d", &dt->minutes)) {
+#endif
+ if(dt->minutes < 0 || dt->minutes >= 60) return 0;
+ j++; if(isdigit(src[j])) j++;
+ }
+ else return 0;
+ break;
+ case 'S': case 's': // seconds are numeric
+ case 'T': case 't':
+ if(j && src[j] == ' ' || src[j] == ':') j++;
+#ifdef USE_WIN_SECURE
+ if(sscanf_s(src+j, "%lf", &dt->seconds)) {
+#else
+ if(sscanf(src+j, "%lf", &dt->seconds)) {
+#endif
+ if(dt->seconds < 0.0 || dt->seconds >= 60.0) return 0;
+ while(isdigit(src[j]) || src[j] == '.') j++;
+ }
+ else return 0;
+ dt->seconds += 1.0e-12;
+ break;
+ default:
+ if(fmt[i] && fmt[i] == src[j]) j++;
+ }
+ }
+ if(dt->year && dt->month && dt->dom) {
+ for(dt->doy = 0, i = dt->month-2; i >= 0; i--) {
+ if(i == 1) dt->doy += leapyear(dt->year) ? 29 : 28;
+ else dt->doy += dt_monthl[i];
+ }
+ dt->doy += dt->dom;
+ if(dt->year >= 1900) dt->aday = year2aday(dt->year);
+ dt->aday += dt->doy;
+ }
+ return j;
+}
+
+char *date2text(rlp_datetime *dt, char *fmt)
+{
+ static char res[80];
+ int i, pos;
+ double secs;
+
+ res[0] = 0;
+ if(!fmt || !fmt[0] || !dt) return res;
+ set_dow(dt);
+ secs = dt->seconds;
+ if (secs > 59.4999) secs = 59.4999;
+ for(pos = i = 0; fmt[i] && pos < 70; i++) {
+#ifdef USE_WIN_SECURE
+ switch(fmt[i]) {
+ case 'Y':
+ if(dt->year) pos+=sprintf_s(res+pos, 80-pos, "%4d", dt->year);
+ else pos += sprintf_s(res+pos, 80-pos, "####"); break;
+ case 'y':
+ if(dt->year) pos+=sprintf_s(res+pos, 80-pos, "%02d", (dt->year %100));
+ else pos += sprintf_s(res+pos, 80-pos, "##"); break;
+ case 'Z':
+ if(dt->dom) pos+=sprintf_s(res+pos, 80-pos, "%02d", dt->dom);
+ else pos += sprintf_s(res+pos, 80-pos, "##"); break;
+ case 'z':
+ if(dt->dom) pos+=sprintf_s(res+pos, 80-pos, "%d", dt->dom);
+ else pos += sprintf_s(res+pos, 80-pos, "##"); break;
+ case 'X':
+ if(dt->month >0 && dt->month < 13) pos+=sprintf_s(res+pos, 80-pos, "%s", dt_month[dt->month-1]);
+ else pos += sprintf_s(res+pos, 80-pos, "###"); break;
+ case 'x':
+ if(dt->month >0 && dt->month < 13) pos+=sprintf_s(res+pos, 80-pos, "%s", dt_months[dt->month-1]);
+ else pos += sprintf_s(res+pos, 80-pos, "###"); break;
+ case 'V':
+ if(dt->month >0 && dt->month < 13) pos+=sprintf_s(res+pos, 80-pos, "%02d", dt->month);
+ else pos += sprintf_s(res+pos, 80-pos, "##"); break;
+ case 'v':
+ if(dt->month >0 && dt->month < 13) pos+=sprintf_s(res+pos, 80-pos, "%d", dt->month);
+ else pos += sprintf_s(res+pos, 80-pos, "##"); break;
+ case 'W':
+ if(dt->month >0 && dt->month < 13) pos+=sprintf_s(res+pos, 80-pos, "%c", dt_month[dt->month-1][0]);
+ else pos += sprintf_s(res+pos, 80-pos, "#"); break;
+ case 'D':
+ if(dt->dow >0 && dt->dow < 8) pos+=sprintf_s(res+pos, 80-pos, "%s", dt_day[dt->dow-1]);
+ else pos += sprintf_s(res+pos, 80-pos, "###"); break;
+ case 'd':
+ if(dt->dow >0 && dt->dow < 8) pos+=sprintf_s(res+pos, 80-pos, "%s", dt_days[dt->dow-1]);
+ else pos += sprintf_s(res+pos, 80-pos, "###"); break;
+ case 'E':
+ if(dt->dow >0 && dt->dow < 8) pos+=sprintf_s(res+pos, 80-pos, "%02d", dt->dow);
+ else pos += sprintf_s(res+pos, 80-pos, "##"); break;
+ case 'e':
+ if(dt->dow >0 && dt->dow < 8) pos+=sprintf_s(res+pos, 80-pos, "%d", dt->dow);
+ else pos += sprintf_s(res+pos, 80-pos, "##"); break;
+ case 'F':
+ if(dt->dow >0 && dt->dow < 8) pos+=sprintf_s(res+pos, 80-pos, "%c", dt_day[dt->dow-1][0]);
+ else pos += sprintf_s(res+pos, 80-pos, "#"); break;
+ case 'H':
+ if(dt->hours >=0 && dt->hours < 24) pos+=sprintf_s(res+pos, 80-pos, "%02d", dt->hours);
+ else pos += sprintf_s(res+pos, 80-pos, "##"); break;
+ case 'h':
+ if(dt->hours >=0 && dt->hours < 24) pos+=sprintf_s(res+pos, 80-pos, "%d", dt->hours);
+ else pos += sprintf_s(res+pos, 80-pos, "##"); break;
+ case 'M':
+ if(dt->minutes >=0 && dt->minutes < 60) pos+=sprintf_s(res+pos, 80-pos, "%02d", dt->minutes);
+ else pos += sprintf_s(res+pos, 80-pos, "##"); break;
+ case 'm':
+ if(dt->minutes >=0 && dt->minutes < 60) pos+=sprintf_s(res+pos, 80-pos, "%d", dt->minutes);
+ else pos += sprintf_s(res+pos, 80-pos, "##"); break;
+ case 'S':
+ if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf_s(res+pos, 80-pos, "%02d", iround(secs));
+ else pos += sprintf_s(res+pos, 80-pos, "##"); break;
+ case 's':
+ if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf_s(res+pos, 80-pos, "%d", iround(secs));
+ else pos += sprintf_s(res+pos, 80-pos, "##"); break;
+ case 'T':
+ if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf_s(res+pos, 80-pos, "%02.2lf", dt->seconds);
+ else pos += sprintf_s(res+pos, 80-pos, "##.##"); break;
+ case 't':
+ if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf_s(res+pos, 80-pos, "%.2lf", dt->seconds);
+ else pos += sprintf_s(res+pos, 80-pos, "##.##"); break;
+ default:
+ pos += sprintf_s(res+pos, 80-pos, "%c", fmt[i]); break;
+ }
+#else
+ switch(fmt[i]) {
+ case 'Y':
+ if(dt->year) pos+=sprintf(res+pos, "%4d", dt->year);
+ else pos += sprintf(res+pos, "####"); break;
+ case 'y':
+ if(dt->year) pos+=sprintf(res+pos, "%02d", (dt->year %100));
+ else pos += sprintf(res+pos, "##"); break;
+ case 'Z':
+ if(dt->dom) pos+=sprintf(res+pos, "%02d", dt->dom);
+ else pos += sprintf(res+pos, "##"); break;
+ case 'z':
+ if(dt->dom) pos+=sprintf(res+pos, "%d", dt->dom);
+ else pos += sprintf(res+pos, "##"); break;
+ case 'X':
+ if(dt->month >0 && dt->month < 13) pos+=sprintf(res+pos, "%s", dt_month[dt->month-1]);
+ else pos += sprintf(res+pos, "###"); break;
+ case 'x':
+ if(dt->month >0 && dt->month < 13) pos+=sprintf(res+pos, "%s", dt_months[dt->month-1]);
+ else pos += sprintf(res+pos, "###"); break;
+ case 'V':
+ if(dt->month >0 && dt->month < 13) pos+=sprintf(res+pos, "%02d", dt->month);
+ else pos += sprintf(res+pos, "##"); break;
+ case 'v':
+ if(dt->month >0 && dt->month < 13) pos+=sprintf(res+pos, "%d", dt->month);
+ else pos += sprintf(res+pos, "##"); break;
+ case 'W':
+ if(dt->month >0 && dt->month < 13) pos+=sprintf(res+pos, "%c", dt_month[dt->month-1][0]);
+ else pos += sprintf(res+pos, "#"); break;
+ case 'D':
+ if(dt->dow >0 && dt->dow < 8) pos+=sprintf(res+pos, "%s", dt_day[dt->dow-1]);
+ else pos += sprintf(res+pos, "###"); break;
+ case 'd':
+ if(dt->dow >0 && dt->dow < 8) pos+=sprintf(res+pos, "%s", dt_days[dt->dow-1]);
+ else pos += sprintf(res+pos, "###"); break;
+ case 'E':
+ if(dt->dow >0 && dt->dow < 8) pos+=sprintf(res+pos, "%02d", dt->dow);
+ else pos += sprintf(res+pos, "##"); break;
+ case 'e':
+ if(dt->dow >0 && dt->dow < 8) pos+=sprintf(res+pos, "%d", dt->dow);
+ else pos += sprintf(res+pos, "##"); break;
+ case 'F':
+ if(dt->dow >0 && dt->dow < 8) pos+=sprintf(res+pos, "%c", dt_day[dt->dow-1][0]);
+ else pos += sprintf(res+pos, "#"); break;
+ case 'H':
+ if(dt->hours >=0 && dt->hours < 24) pos+=sprintf(res+pos, "%02d", dt->hours);
+ else pos += sprintf(res+pos, "##"); break;
+ case 'h':
+ if(dt->hours >=0 && dt->hours < 24) pos+=sprintf(res+pos, "%d", dt->hours);
+ else pos += sprintf(res+pos, "##"); break;
+ case 'M':
+ if(dt->minutes >=0 && dt->minutes < 60) pos+=sprintf(res+pos, "%02d", dt->minutes);
+ else pos += sprintf(res+pos, "##"); break;
+ case 'm':
+ if(dt->minutes >=0 && dt->minutes < 60) pos+=sprintf(res+pos, "%d", dt->minutes);
+ else pos += sprintf(res+pos, "##"); break;
+ case 'S':
+ if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf(res+pos, "%02d", iround(secs));
+ else pos += sprintf(res+pos, "##"); break;
+ case 's':
+ if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf(res+pos, "%d", iround(secs));
+ else pos += sprintf(res+pos, "##"); break;
+ case 'T':
+ if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf(res+pos, "%02.2lf", dt->seconds);
+ else pos += sprintf(res+pos, "##.##"); break;
+ case 't':
+ if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf(res+pos, "%.2lf", dt->seconds);
+ else pos += sprintf(res+pos, "##.##"); break;
+ default:
+ pos += sprintf(res+pos, "%c", fmt[i]); break;
+ }
+#endif
+ }
+ res[pos] = 0;
+ return res;
+}
+
+double date2value(rlp_datetime *dt)
+{
+ double res;
+
+ if(!dt) return 0.0;
+
+ res = dt->seconds/60.0 + (double)dt->minutes;
+ res = res/60.0 + (double)dt->hours;
+ res = res/24.0 + (double)dt->aday;
+ return res;
+}
+
+void parse_datevalue(rlp_datetime *dt, double dv)
+{
+ int i, j, d;
+
+ if(!dt || dv < 0.0) return;
+ if(dv > 1.0) {
+ dt->aday = (int)floor(dv);
+ dt->year = (int)(dv/365.2425);
+ d = (int)floor(dv);
+ do {
+ dt->doy = d - 365*dt->year;
+ dt->doy -= ((dt->year-1)>>2);
+ dt->doy += ((dt->year)/100);
+ dt->doy -= ((dt->year+300)/400);
+ if(dt->doy < 1) dt->year--;
+ }while(dt->doy < 1);
+ dt->year += 1900;
+ for(i = dt->month = 0, d = dt->doy; i < 12 && d > 0; i++) {
+ if(i == 1 && d > (j = (leapyear(dt->year)) ? 29 : 28)) d -= j;
+ else if(i != 1 && d > dt_monthl[i]) d -= dt_monthl[i];
+ else break;
+ }
+ dt->month = i+1; dt->dom = d;
+ }
+ else {
+ dt->aday = dt->year = dt->doy = dt->dom = dt->month = 0;
+ }
+ dv -= floor(dv); dv *= 24.0;
+ dt->hours = (int)floor(dv); dv -= floor(dv);
+ dv *= 60.0; dt->minutes = (int)floor(dv);
+ dv -= floor(dv); dt->seconds = dv *60.0 + 1.0e-12;
+ if(dt->seconds > 59.9999) {
+ dt->seconds = 0.0; dt->minutes++;
+ if(dt->minutes == 60) {
+ dt->hours++; dt->minutes = 0;
+ }
+ }
+}
+
+static char *dt_popfmt[] = {"Z.V.Y H:M:S", "Z/V/Y H:M:S", "Z-V-Y H:M:S", "Z.X.Y H:M:S",
+ "Y.V.Z H:M:S", "Y-X-Z H:M:S", "H:M:S", 0L};
+
+bool date_value(char *desc, char *fmt, double *value)
+{
+ int i;
+ rlp_datetime dt;
+
+ dt.year = dt.aday = dt.doy = dt.month = dt.dom = dt.dow = dt.hours = dt.minutes = 0;
+ dt.seconds = 0.0;
+ if(!value || !desc || !desc[0]) return false;
+ if(fmt && fmt[0]) {
+ if(parse_date(&dt, desc, fmt)) {
+ *value = date2value(&dt); return true;
+ }
+ }
+ else {
+ if(parse_date(&dt, desc, defs.fmt_datetime)) {
+ *value = date2value(&dt); return true;
+ }
+ }
+ for(i=0; dt_popfmt[i]; i++) {
+ if(parse_date(&dt, desc, dt_popfmt[i])) {
+ *value = date2value(&dt); return true;
+ }
+ }
+ return false;
+}
+
+char *value_date(double dv, char *fmt)
+{
+ rlp_datetime dt;
+
+ parse_datevalue(&dt, dv);
+ return date2text(&dt, fmt ? fmt : defs.fmt_date);
+}
+
+double now_today()
+{
+ double res = 0.0;
+ time_t ti = time(0L);
+#ifdef USE_WIN_SECURE
+ char dtbuff[80];
+
+ ctime_s(dtbuff, 80, &ti);
+ date_value(dtbuff+4, "x z H:M:S Y", &res);
+#else
+ date_value(ctime(&ti)+4, "x z H:M:S Y", &res);
+#endif
+ return res;
+}
+
+void split_date(double dv, int *y, int *mo, int *dom, int *dow, int *doy, int *h, int *m, double *s)
+{
+ rlp_datetime dt;
+
+ parse_datevalue(&dt, dv);
+ set_dow(&dt);
+ if(y) *y = dt.year; if(mo) *mo = dt.month;
+ if(dom) *dom = dt.dom; if(dow) *dow = dt.dow;
+ if(doy) *doy = dt.doy; if(h) *h = dt.hours;
+ if(m) *m = dt.minutes; if(s) *s = dt.seconds;
+}
+
+//---------------------------------------------------------------------------
+// Use the Delauney triangulation to create a 3D mesh of dispersed data
+//
+Triangle* Triangulate1(char *xr, char *yr, char *zr, DataObj *data)
+{
+ AccRange *rX, *rY, *rZ;
+ int i, j, n, rx, cx, ry, cy, rz, cz;
+ double zMin;
+ fPOINT3D *da;
+ fRECT lim;
+ Triangle *trl, *trn;
+ Triangulate *tria;
+
+ rX = rY = rZ = 0L; trl = trn = 0L;
+ if((rX = new AccRange(xr)) && (rY = new AccRange(yr)) && (rZ = new AccRange(zr))
+ && rX->GetFirst(&cx, &rx) && rY->GetFirst(&cy, &ry) && rZ->GetFirst(&cz, &rz)
+ && (n = rX->CountItems()) && (da = (fPOINT3D*)malloc(n * sizeof(fPOINT3D)))
+ && (trl = new Triangle()) && (trn = new Triangle())) {
+ //get minima and maxima
+ for(i = j = 0; i < n; i++) {
+ if(rX->GetNext(&cx, &rx) && rY->GetNext(&cy, &ry) && rZ->GetNext(&cz, &rz)) {
+ data->GetValue(rx, cx, &da[j].fx); data->GetValue(ry, cy, &da[j].fy);
+ data->GetValue(rz, cz, &da[j].fz); j++;
+ }
+ }
+ if(!j) {
+ free(da); delete rX; delete rY; delete rZ; return trl;
+ }
+ for(i = 0, j = n; i < n; i++) {
+ if(i) {
+ if(da[i].fx < lim.Xmin) lim.Xmin = da[i].fx; if(da[i].fx > lim.Xmax) lim.Xmax = da[i].fx;
+ if(da[i].fy < lim.Ymin) lim.Ymin = da[i].fy; if(da[i].fy > lim.Ymax) lim.Ymax = da[i].fy;
+ if(da[i].fz < zMin) zMin = da[i].fz;
+ }
+ else {
+ lim.Xmax = lim.Xmin = da[i].fx; lim.Ymax = lim.Ymin = da[i].fy; zMin = da[i].fz;
+ }
+ }
+ //setup two super triangles
+ trl->pt[0].fz = trl->pt[1].fz = trl->pt[2].fz = zMin;
+ trn->pt[0].fz = trn->pt[1].fz = trn->pt[2].fz = zMin;
+ trl->pt[0].fx = trn->pt[0].fx = trl->pt[2].fx = lim.Xmin;
+ trl->pt[0].fy = trn->pt[0].fy = trn->pt[1].fy = lim.Ymin;
+ trl->pt[1].fx = trn->pt[2].fx = trn->pt[1].fx = lim.Xmax;
+ trl->pt[1].fy = trn->pt[2].fy = trl->pt[2].fy = lim.Ymax;
+ trl->SetRect(); trn->SetRect();
+ trl->next = trn; trn->next = 0L;
+ //do triangulation
+ tria = new Triangulate(trl);
+ for(i = 0; i < n; i++) {
+ tria->AddVertex(&da[i]);
+ }
+ free(da);
+ }
+ if(rX) delete rX; if(rY) delete rY; if(rZ) delete rZ;
+ trl = tria->trl; delete tria; return trl;
+}
diff --git a/rlplot.cpp b/rlplot.cpp
index 22cfa15..6d37cc7 100755
--- a/rlplot.cpp
+++ b/rlplot.cpp
@@ -1,10204 +1,10279 @@
-//rlplot.cpp, Copyright 2000-2006 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;
-Axis **CurrAxes = 0L;
-dragHandle *CurrHandle = 0L;
-UndoObj Undo;
-fmtText DrawFmtText;
-
-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)
-{
-}
-
-double
-GraphObj::DefSize(int select)
-{
- if(parent) return parent->DefSize(select);
- else return defs.GetSize(select);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 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 DefSize(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, crx, cry, atype;
- double sc;
- long ncpts;
- lfPOINT fip;
- POINT pts[14], *cpts;
- FillDEF cf;
-
- atype = (type & 0xfff);
- memcpy(&cf, &SymFill, sizeof(FillDEF));
- if(atype == SYM_CIRCLEF || atype == SYM_RECTF || atype == SYM_TRIAUF ||
- atype == SYM_TRIADF || atype == SYM_DIAMONDF || atype == SYM_4STARF ||
- atype == SYM_5GONF || atype == SYM_5STARF || atype == SYM_6STARF) 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
- case SYM_CIRCLEC: //circle with center point
- case SYM_1QUAD: case SYM_2QUAD: case SYM_3QUAD:
- rx = target->un2ix(size/2.0); ry = target->un2iy(size/2.0);
- if(rx < 5) rx = 1; if(ry < 5) ry = 1;
- target->SetFill(&cf);
- target->oCircle(ix-rx, iy-ry, ix+rx+1, iy+ry+1, name);
- if(atype == SYM_CIRCLEC) {
- crx = target->un2ix(size/5.0); cry = target->un2iy(size/5.0);
- cf.color = SymLine.color; target->SetFill(&cf);
- target->oCircle(ix-crx, iy-cry, ix+crx+1, iy+cry+1, name);
- }
- else if(atype == SYM_1QUAD || atype == SYM_2QUAD || atype == SYM_3QUAD) {
- ncpts = 0L; cf.color = SymLine.color; target->SetFill(&cf);
- if(atype == SYM_1QUAD) {
- if(!(cpts = MakeArc(ix, iy, rx, 0x04, &ncpts)) || !ncpts) return;
- cpts[0].x = ix + rx; cpts[0].y = iy;
- }
- else if(atype == SYM_2QUAD) {
- if(!(cpts = MakeArc(ix, iy, rx, 0x06, &ncpts)) || !ncpts) return;
- cpts[0].x = ix; cpts[0].y = iy+rx;
- }
- else if(atype == SYM_3QUAD) {
- if(!(cpts = MakeArc(ix, iy, rx, 0x07, &ncpts)) || !ncpts) return;
- cpts[0].x = ix-rx; cpts[0].y = iy;
- }
- cpts[ncpts-1].x = ix; cpts[ncpts-1].y = iy-rx;
- cpts[ncpts].x = ix; cpts[ncpts].y = iy; ncpts++;
- cpts[ncpts].x = cpts[0].x; cpts[ncpts].y = cpts[0].y; ncpts++;
- target->oPolygon(cpts, ncpts); free(cpts);
- }
- rx--;ry--; //smaller marking rectangle
- break;
- case SYM_RECT: //rectange (square)
- case SYM_RECTF: //filled rectangle
- case SYM_RECTC: //square with center point
- rx = target->un2ix(size/2.25676); ry = target->un2iy(size/2.25676);
- if(rx < 5) rx = 1; if(ry < 5) ry = 1;
- target->SetFill(&cf);
- target->oRectangle(ix-rx, iy-ry, ix+rx+1, iy+ry+1, name);
- if(atype == SYM_RECTC) {
- crx = target->un2ix(size/6.0); cry = target->un2iy(size/6.0);
- cf.color = SymLine.color; target->SetFill(&cf);
- target->oCircle(ix-crx, iy-cry, ix+crx+1, iy+cry+1, name);
- }
- break;
- case SYM_TRIAU: //triangles up and down, open or closed
- case SYM_TRIAUF: case SYM_TRIAD: case SYM_TRIADF: case SYM_TRIADC:
- case SYM_TRIAUC: case SYM_TRIAUL: case SYM_TRIAUR: case SYM_TRIADL:
- case SYM_TRIADR:
- rx = target->un2ix(size/1.48503); ry = target->un2iy(size/1.48503);
- if(rx < 5) rx = 1; if(ry < 5) ry = 1;
- target->SetFill(&cf);
- pts[0].x = pts[3].x = ix - rx; pts[1].x = ix; pts[2].x = ix+rx;
- //patch by anonymous
- if(atype == SYM_TRIAU || atype == SYM_TRIAUF || atype == SYM_TRIAUL
- || atype == SYM_TRIAUR || atype == SYM_TRIAUC) {
- 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);
- if(atype == SYM_TRIAUC || atype == SYM_TRIADC) {
- crx = target->un2ix(size/6.0); cry = target->un2iy(size/6.0);
- cf.color = SymLine.color; target->SetFill(&cf);
- target->oCircle(ix-crx, iy-cry, ix+crx+1, iy+cry+1, name);
- }
- else if(atype == SYM_TRIAUL || atype == SYM_TRIADL) {
- cf.color = SymLine.color; target->SetFill(&cf);
- pts[2].x = pts[1].x; target->oPolygon(pts, 4);
- }
- else if(atype == SYM_TRIAUR || atype == SYM_TRIADR) {
- cf.color = SymLine.color; target->SetFill(&cf);
- pts[0].x = pts[3].x = pts[1].x; target->oPolygon(pts, 4);
- }
- rx--; ry--;
- break;
- case SYM_DIAMOND: case SYM_DIAMONDF: case SYM_DIAMONDC:
- rx = target->un2ix(size/1.59588); ry = target->un2iy(size/1.59588);
- if(rx < 5) rx = 1; if(ry < 5) ry = 1;
- 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);
- if(atype == SYM_DIAMONDC) {
- crx = target->un2ix(size/6.0); cry = target->un2iy(size/6.0);
- cf.color = SymLine.color; target->SetFill(&cf);
- target->oCircle(ix-crx, iy-cry, ix+crx+1, iy+cry+1, name);
- }
- rx--; ry--;
- break;
- case SYM_4STAR: case SYM_4STARF:
- rx = target->un2ix(size/1.4); ry = target->un2iy(size/1.4);
- crx = target->un2ix(size/6.0); cry = target->un2iy(size/6.0);
- pts[0].x = pts[8].x = ix-rx; pts[0].y = pts[4].y = pts[8].y = iy;
- pts[1].x = pts[7].x = ix-crx; pts[1].y = pts[3].y = iy - cry;
- pts[2].x = pts[6].x = ix; pts[2].y = iy - ry;
- pts[3].x = pts[5].x = ix+crx; pts[4].x = ix + rx;
- pts[5].y = pts[7].y = iy+cry; pts[6].y = iy + ry;
- target->SetFill(&cf); target->oPolygon(pts, 9);
- break;
- case SYM_5GON: case SYM_5GONF: case SYM_5GONC:
- sc = 1.4;
- rx = target->un2ix(size/sc); ry = target->un2iy(size/sc);
- crx = target->un2ix(size/sc * 0.951057);
- cry = target->un2iy(size/sc * 0.309017);
- pts[0].x = ix-crx; pts[0].y = pts[2].y = iy-cry; pts[1].x = ix;
- pts[1].y = iy-ry; pts[2].x = ix+crx;
- crx = target->un2ix(size/sc * 0.587785);
- cry = target->un2iy(size/sc * 0.809017);
- pts[3].x = ix + crx; pts[4].x = ix - crx;
- pts[3].y = pts[4].y = iy+cry;
- pts[5].x = pts[0].x; pts[5].y = pts[0].y;
- target->SetFill(&cf); target->oPolygon(pts, 6);
- if(atype == SYM_5GONC) {
- crx = target->un2ix(size/6.0); cry = target->un2iy(size/6.0);
- cf.color = SymLine.color; target->SetFill(&cf);
- target->oCircle(ix-crx, iy-cry, ix+crx+1, iy+cry+1, name);
- }
- break;
- case SYM_5STAR: case SYM_5STARF:
- sc = 1.4;
- rx = target->un2ix(size/sc); ry = target->un2iy(size/sc);
- crx = target->un2ix(size/sc * 0.951057);
- cry = target->un2iy(size/sc * 0.309017);
- pts[0].x = ix-crx; pts[0].y = pts[1].y = pts[3].y = pts[4].y = iy-cry;
- pts[2].x = pts[7].x = ix; pts[2].y = iy-ry; pts[4].x = ix+crx;
- crx = target->un2ix(size/sc * 0.23);
- pts[1].x = ix - crx; pts[3].x = ix + crx;
- crx = target->un2ix(size/sc * 0.36);
- cry = target->un2iy(size/sc * 0.11);
- pts[5].x = ix + crx; pts[5].y = pts[9].y = iy + cry; pts[9].x = ix - crx;
- pts[7].y = iy + target->un2iy(size/sc * 0.38);
- crx = target->un2ix(size/sc * 0.587785);
- cry = target->un2iy(size/sc * 0.809017);
- pts[6].x = ix + crx; pts[8].x = ix - crx;
- pts[6].y = pts[8].y = iy+cry;
- pts[10].x = pts[0].x; pts[10].y = pts[0].y;
- target->SetFill(&cf); target->oPolygon(pts, 11);
- break;
- case SYM_6STAR: case SYM_6STARF:
- sc = 1.4 / 0.86; rx = target->un2ix(size/sc);
- sc = 1.4 / 0.5; ry = target->un2iy(size/sc);
- pts[0].x = pts[10].x = pts[12].x = ix - rx;
- pts[4].x = pts[6].x = ix + rx; pts[2].x = pts[8].x = ix;
- pts[0].y = pts[1].y = pts[3].y = pts[4].y = pts[12].y = iy - ry;
- pts[6].y = pts[7].y = pts[9].y = pts[10].y = iy + ry;
- sc = 1.4 / 0.29; rx = target->un2ix(size/sc);
- pts[1].x = pts[9].x = ix - rx; pts[3].x = pts[7].x = ix + rx;
- sc = 1.4 / 0.52; rx = target->un2ix(size/sc);
- pts[5].x = ix +rx; pts[11].x = ix - rx; pts[5].y = pts[11].y = iy;
- sc = 1.4;
- rx = target->un2ix(size/sc); ry = target->un2iy(size/sc);
- pts[2].y = iy - ry; pts[8].y = iy + ry;
- target->SetFill(&cf); target->oPolygon(pts, 13);
- 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);
- if(rx < 5) rx = 1; if(ry < 5) ry = 1;
- 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(atype != SYM_VLINE) target->oPolyline(pts, 2);
- if(atype == SYM_VLINE){ rx = 2; break;}
- if(atype == SYM_HLINE){ ry = 2; break;}
- if(atype == 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);
- if(rx < 5) rx = 1; if(ry < 5) ry = 1;
- pts[0].x = ix - rx - 2; pts[1].x = ix + rx + 3;
- pts[0].y = iy - ry - 2; pts[1].y = iy + ry + 3;
- target->oPolyline(pts, 2); Swap(pts[0].y, pts[1].y);
- pts[1].y -= 1; pts[0].y -= 1;
- 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);
- DrawFmtText.SetText(target, SymTxt->text, &ix, &iy);
- 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+2;
- rDims.top = iy-ry-1; rDims.bottom = iy+ry+2;
-}
-
-bool
-Symbol::Command(int cmd, void *tmpl, anyOutput *o)
-{
- MouseEvent *mev;
- char *tmptxt;
- AccRange *ac;
- int i, r, c;
-
- switch (cmd) {
- case CMD_SCALE:
- if(!tmpl) return false;
- size *= ((scaleINFO*)tmpl)->sy.fy;
- SymLine.width *= ((scaleINFO*)tmpl)->sy.fy;
- if(SymTxt) {
- SymTxt->fSize *= ((scaleINFO*)tmpl)->sy.fy;
- SymTxt->iSize = 0;
- }
- return true;
- 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) {
- rlp_strcpy((char*)tmpl, 50, SymTxt->text);
- return true;
- }
- return false;
- case CMD_SYMTEXT_UNDO:
- if(SymTxt && SymTxt->text){
- c = Undo.String(this, &SymTxt->text, UNDO_CONTINUE);
- i = (int)strlen((char*)tmpl); i = i > c ? i+2 : c+2;
- if(tmpl) {
- if(SymTxt->text = (char*)realloc(SymTxt->text, i)) rlp_strcpy(SymTxt->text, i, (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) {
- i = (int) strlen((char*)tmpl) + 2;
- if(SymTxt->text = (char*)realloc(SymTxt->text, i)) rlp_strcpy(SymTxt->text, i, (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, tmptxt[0] = 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_SCALE:
- if(!tmpl) return false;
- if((type & 0x0f0)== BUBBLE_UNITS) fs *= ((scaleINFO*)tmpl)->sy.fy;
- BubbleLine.width *= ((scaleINFO*)tmpl)->sy.fy;
- BubbleLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
- BubbleFillLine.width *= ((scaleINFO*)tmpl)->sy.fy;
- BubbleFillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
- BubbleFill.scale *= ((scaleINFO*)tmpl)->sy.fy;
- return true;
- case CMD_LEGEND:
- if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
- ((Legend*)tmpl)->HasFill(&BubbleLine, &BubbleFill, 0L);
- break;
- 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:
- return DoAutoscale(o);
- break;
- }
- return false;
-}
-
-bool
-Bubble::DoAutoscale(anyOutput *o)
-{
- double dx, dy;
-
- switch(type & 0x0f0) {
- case BUBBLE_XAXIS: case BUBBLE_YAXIS:
- dx = dy = fs/2.0; break;
- case BUBBLE_UNITS:
- dx = fPos.fx/20; dy = fPos.fy/20; break;
- }
- ((Plot*)parent)->CheckBounds(fPos.fx+dx, fPos.fy-dy);
- ((Plot*)parent)->CheckBounds(fPos.fx-dx, fPos.fy+dy);
- return true;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Bars are graphic objects
-Bar::Bar(GraphObj *par, DataObj *d, double x, double y, int which,int xc, int xr,
- int yc, int yr, char *desc):GraphObj(par, d)
-{
- FileIO(INIT_VARS);
- fPos.fx = x; fPos.fy = y; type = which;
- if(type & BAR_RELWIDTH) size = 60.0; 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;
- }
- }
- if(desc && desc[0]) name = (char*)memdup(desc, (int)strlen(desc)+1, 0);
-}
-
-Bar::Bar(int src):GraphObj(0L, 0L)
-{
- FileIO(INIT_VARS);
- if(src == FILE_READ) {
- FileIO(FILE_READ);
- }
-}
-
-Bar::~Bar()
-{
- if(mo) DelBitmapClass(mo); mo = 0L;
- 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);
-}
-
-void
-Bar::DoMark(anyOutput *o, bool mark)
-{
- int i;
-
- if(mark){
- if(mo) DelBitmapClass(mo); mo = 0L;
- memcpy(&mrc, &rDims, sizeof(RECT));
- i = 2*o->un2ix(BarLine.width); //increase size of rectangle for marks
- IncrementMinMaxRect(&mrc, i);
- mo = GetRectBitmap(&mrc, o);
- o->CopyBitmap(mrc.left, mrc.top, mo, 0, 0, mrc.right-mrc.left, mrc.bottom - mrc.top, true);
- o->UpdateRect(&mrc, false);
- }
- else RestoreRectBitmap(&mo, &mrc, o);
-}
-
-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_SCALE:
- if(!tmpl) return false;
- if(!(type & BAR_RELWIDTH)) size *= ((scaleINFO*)tmpl)->sy.fy;
- BarLine.width *= ((scaleINFO*)tmpl)->sy.fy;
- BarLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
- HatchLine.width *= ((scaleINFO*)tmpl)->sy.fy;
- HatchLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
- BarFill.scale *= ((scaleINFO*)tmpl)->sy.fy;
- return true;
- case CMD_LEGEND:
- if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
- ((Legend*)tmpl)->HasFill(&BarLine, &BarFill, name);
- break;
- case CMD_MOUSE_EVENT:
- mev = (MouseEvent *) tmpl;
- switch (mev->Action) {
- case MOUSE_LBUP:
- if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
- o->ShowMark(CurrGO = this, MRK_GODRAW);
- 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, char *nam):GraphObj(par, d)
-{
- size_t cb;
-
- FileIO(INIT_VARS);
- Id = GO_DATALINE;
- if(xrange && xrange[0]) {
- cb = strlen(xrange) +2; ssXref = (char*)malloc(cb); rlp_strcpy(ssXref, (int)cb, xrange);
- }
- if(yrange && yrange[0]) {
- cb = strlen(yrange) +2; ssYref = (char*)malloc(cb); rlp_strcpy(ssYref, (int)cb, yrange);
- }
- if(nam && nam[0]) name = (char*)memdup(nam, (int)strlen(nam)+1, 0);
- SetValues();
-}
-
-DataLine::DataLine(GraphObj *par, DataObj *d, lfPOINT *val, long nval, char *na):GraphObj(par, d)
-{
- int cb;
-
- FileIO(INIT_VARS);
- Values = val; nPnt = nval; nPntSet = nPnt-1;
- if(na && na[0] && (name = (char*)malloc((cb = (int)strlen(na))+2))) {
- rlp_strcpy(name, cb+1, na);
- }
- 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(name) free(name); name = 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 (nPntSet >= nPnt) nPntSet = nPnt-1;
- if(mo) DelBitmapClass(mo); mo = 0L;
- if(pts) free(pts); pts = 0L;
- if((type & 0xff) == 9 || (type & 0xff) == 10) //splines
- pts = (POINT *)malloc(sizeof(POINT)*1000);
- else if((type & 0xff) == 11) // curve
- pts = (POINT *) malloc(sizeof(POINT)* (nPntSet+2)*192);
- else 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 & 0x0f) {
- case 0: default:
- 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;
- case 9: case 10:
- DrawSpline(target);
- break;
- case 11:
- DrawCurve(target);
- 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){
- if(mo) DelBitmapClass(mo); mo = 0L;
- 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 <1)
- 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_SCALE:
- LineDef.width *= ((scaleINFO*)tmpl)->sy.fy; LineDef.patlength *= ((scaleINFO*)tmpl)->sy.fy;
- break;
- case CMD_SET_DATAOBJ:
- Id = isPolygon ? GO_DATAPOLYGON : GO_DATALINE;
- data = (DataObj*)tmpl;
- return true;
- case CMD_MRK_DIRTY:
- dirty= true;
- case CMD_REDRAW:
- if(parent) return parent->Command(cmd, tmpl, 0L);
- return false;
- case CMD_LEGEND:
- if(tmpl && ((GraphObj*)tmpl)->Id == GO_LEGEND) {
- if(Id == GO_DATALINE) ((Legend*)tmpl)->HasFill(&LineDef, 0L, name);
- }
- break;
- case CMD_SET_LINE:
- if(tmpl) memcpy(&LineDef, tmpl, sizeof(LineDEF));
- return true;
- case CMD_UPDATE:
- Undo.DataMem(this, (void**)&Values, nPnt * sizeof(lfPOINT), &nPnt, UNDO_CONTINUE);
- Undo.ValLong(this, &nPntSet, UNDO_CONTINUE);
- SetValues();
- return true;
- case CMD_AUTOSCALE:
- if(nPntSet < 1 || !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[500], yref2[500];
- lfPOINT *tmpValues = Values;
-
- if(!ssXref || !ssYref) return;
- if(!rlp_strcpy(yref1, 500, ssYref)) return;
- for(i = 0, yref2[0] = 0; yref1[i]; i++) {
- if(yref1[i] == ';') {
- yref1[i++] = 0;
- while(yref1[i] && yref1[i] < 33) i++;
- rlp_strcpy(yref2, 500, yref1+i);
- }
- }
- nPnt = nPntSet = 0;
- min.fx = min.fy = HUGE_VAL; max.fx = max.fy = -HUGE_VAL;
- rX = new AccRange(ssXref); rY1 = new AccRange(yref1);
- if(!rX || !rY1){
- if(rX) delete(rX); if(rY1) delete(rY1);
- return;
- }
- if(!name) name = rY1->RangeDesc(data, 1);
- if(yref2[0] &&((nPnt = rX->CountItems()) == (rY1->CountItems()))) {
- if(!(Values = (lfPOINT *)realloc(Values, ((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 *)realloc(Values, (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 && Values != tmpValues) Undo.InvalidGO(this);
- if(rX) delete(rX); if(rY1) delete(rY1); if(rY2) delete(rY2);
-}
-
-void
-DataLine::LineData(lfPOINT *val, long nval)
-{
- lfPOINT *ov = Values;
-
- if(!val || nval <2) return;
- if(nval > nPnt && nPnt > 1 && Values){
- if(!(Values = (lfPOINT *)realloc(Values, ((nval*2+2) * sizeof(lfPOINT))))) return;
- if(ov != Values) Undo.InvalidGO(this);
- }
- else if(!Undo.busy) Undo.DataMem(this, (void**)&Values, nPnt * sizeof(lfPOINT), &nPnt, UNDO_CONTINUE);
- memcpy(Values, val, nval * sizeof(lfPOINT));
- if(pts) free(pts); pts = 0L; dirty = true;
- free(val); nPnt = nval; nPntSet = nPnt-1;
-}
-
-void
-DataLine::DrawCurve(anyOutput *target)
-{
- lfPOINT *sdata, *bdata;
- POINT *tmppts;
- int i, j, n;
-
- if(!(sdata = (lfPOINT *)malloc(nPnt * sizeof(lfPOINT))))return;
- sdata[0].fx = Values[0].fx; sdata[0].fy = Values[0].fy;
- for(i = j = 1; i < nPnt; i++) {
- if(Values[i].fx != sdata[j-1].fx || Values[i].fy != sdata[j-1].fy) {
- sdata[j].fx = Values[i].fx; sdata[j++].fy = Values[i].fy;
- }
- }
- n = mkCurve(sdata, j, &bdata, false);
- if(!(tmppts = (POINT*)malloc((n+2)*sizeof(POINT))))return;
- for(i = 0; i < n; i++){
- tmppts[i].x = target->fx2ix(bdata[i].fx); tmppts[i].y = target->fy2iy(bdata[i].fy);
- }
- for(i = cp = 0; i< (n-2); i += 3) {
- DrawBezier(&cp, pts, tmppts[i], tmppts[i+1], tmppts[i+2], tmppts[i+3], 0);
- }
- if(bdata) free(bdata); free(sdata);
-}
-
-void
-DataLine::DrawSpline(anyOutput *target)
-{
- int i, j, k, klo, khi, ptsize = 1000;
- double *y2, min, max, x, y, h, b, a;
- POINT pn;
- lfPOINT *scvals;
-
- if(!(y2 = (double*)malloc(sizeof(double)*(nPnt)))) return;
- if(!(scvals = (lfPOINT*)malloc(sizeof(lfPOINT)*(nPnt)))){
- free(y2);
- return;
- }
- if((type & 0x0f) == 9 || (type & 0x0f) == 10) {
- if((type & 0x0f) == 9) for(i = 0; i < nPnt; i++) {
- scvals[i].fx = target->fx2fix(Values[i].fx);
- scvals[i].fy = target->fy2fiy(Values[i].fy);
- }
- else for(i = 0; i < nPnt; i++) {
- scvals[i].fy = target->fx2fix(Values[i].fx);
- scvals[i].fx = target->fy2fiy(Values[i].fy);
- }
- SortFpArray(nPnt, scvals);
- min = scvals[0].fx; max = scvals[nPnt-1].fx;
- for(i = j = 0; i < (nPnt-1); i++, j++) {
- y = scvals[i].fy; scvals[j].fx = scvals[i].fx;
- for(k = 1; scvals[i+1].fx == scvals[i].fx; k++) {
- y += scvals[i+1].fy; i++;
- }
- scvals[j].fy = y/((double)k);
- }
- if(scvals[i].fx > scvals[i-1].fx) {
- scvals[j].fx = scvals[i].fx; scvals[j].fy = scvals[i].fy;
- j++;
- }
- spline(scvals, j, y2);
- h = scvals[1].fx - scvals[0].fx; // klo and khi bracket the input value of x
- for(x = min, klo = 0, i = khi = 1; x < max && i < j; x += 1.0) {
- while(x > scvals[i].fx) {
- klo++; khi++; i++;
- h = scvals[khi].fx - scvals[klo].fx;
- }
- a = (scvals[khi].fx - x) / h; b = (x - scvals[klo].fx) / h;
- y = a * scvals[klo].fy + b * scvals[khi].fy + ((a*a*a - a) * y2[klo] + (b*b*b - b) * y2[khi]) * (h*h)/6.0;
- if((type & 0x0f) == 9) {
- pn.x = iround(x); pn.y = iround(y);
- }
- else {
- pn.x = iround(y); pn.y = iround(x);
- }
- if(cp >= ptsize) {
- ptsize += 1000;
- pts = (POINT*)realloc(pts, sizeof(POINT)*ptsize);
- }
- AddToPolygon(&cp, pts, &pn);
- }
- }
- free(y2); free(scvals);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// DataPolygon is a graphic object based on DataLine
-DataPolygon::DataPolygon(GraphObj *par, DataObj *d, char *xrange, char *yrange, char *nam):
- DataLine(par, d, xrange, yrange, nam)
-{
- 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(name) free(name); name = 0;
- 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){
- if(mo) DelBitmapClass(mo); mo = 0L;
- 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_SCALE:
- LineDef.width *= ((scaleINFO*)tmpl)->sy.fy; LineDef.patlength *= ((scaleINFO*)tmpl)->sy.fy;
- pgFillLine.width *= ((scaleINFO*)tmpl)->sy.fy; pgFillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
- pgFill.scale *= ((scaleINFO*)tmpl)->sy.fy;
- break;
- case CMD_LEGEND:
- if(tmpl && ((GraphObj*)tmpl)->Id == GO_LEGEND) {
- if(Id == GO_DATAPOLYGON) ((Legend*)tmpl)->HasFill(&LineDef, &pgFill, name);
- }
- 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;
- 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) && (!(pts = (POINT *)malloc(sizeof(POINT)*202))))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
- }
- if(dValid) {
- y = a + b*x1;
- 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(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);
- 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_SCALE:
- LineDef.width *= ((scaleINFO*)tmpl)->sy.fy; LineDef.patlength *= ((scaleINFO*)tmpl)->sy.fy;
- 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, fac, fac2;
- 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);
- switch(type & 0x60000) {
- case 0x20000: fac = 2.0; break;
- case 0x40000: fac = 3.0; break;
- default: fac = 1.0; break;
- }
- fac2 = fac*fac; dx = sd2/100.0*fac;
- for(i = 0, cp = 0, x = -(sd2*fac); i < 2; i++) {
- do {
- fv = (x*x)/(ss2*fac2);
- fv = fv < 0.99999 ? sqrt((1.0-fv)*ss1*fac2) : 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*fac) && x > (-sd2*fac));
- x = sd2*fac;
- 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_SCALE:
- LineDef.width *= ((scaleINFO*)tmpl)->sy.fy; LineDef.patlength *= ((scaleINFO*)tmpl)->sy.fy;
- if(rl) rl->Command(cmd, tmpl, o);
- 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(mo) DelBitmapClass(mo); mo = 0L;
- if(ssRef) free(ssRef); ssRef = 0L;
- if(name) free(name); name = 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.0);
- break;
- default:
- ie = target->un2iy(SizeBar/2.0);
- 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, 2);
-}
-
-void
-ErrorBar::DoMark(anyOutput *o, bool mark)
-{
- int i;
- LineDEF OldLine;
-
- if(mark){
- if(mo) DelBitmapClass(mo); mo = 0L;
- memcpy(&mrc, &rDims, sizeof(RECT));
- memcpy(&OldLine, &ErrLine, sizeof(LineDEF));
- i = 3*o->un2ix(ErrLine.width); //increase size of rectangle for marks
- IncrementMinMaxRect(&mrc, i); mo = GetRectBitmap(&mrc, o);
- ErrLine.width *= 5.0; DoPlot(o);
- ErrLine.width = OldLine.width; ErrLine.color = OldLine.color ^ 0x00ffffffL;
- DoPlot(o); o->UpdateRect(&mrc, false);
- memcpy(&ErrLine, &OldLine, sizeof(LineDEF));
- }
- else if(mo) RestoreRectBitmap(&mo, &mrc, o);
-}
-
-bool
-ErrorBar::Command(int cmd, void *tmpl, anyOutput *o)
-{
- MouseEvent *mev;
- bool bFound;
- int cb;
-
- switch (cmd) {
- case CMD_SCALE:
- ErrLine.width *= ((scaleINFO*)tmpl)->sy.fy; ErrLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
- SizeBar *= ((scaleINFO*)tmpl)->sy.fy;
- return true;
- 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);
- }
- return false;
- case CMD_SET_DATAOBJ:
- Id = GO_ERRBAR;
- data = (DataObj *) tmpl;
- return true;
- case CMD_REDRAW:
- if(parent) return parent->Command(cmd, tmpl, o);
- 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, &ferr);
- return true;
- }
- return false;
- case CMD_LEGEND:
- if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
- switch(type) {
- case ERRBAR_VSYM: case ERRBAR_VUP: case ERRBAR_VDOWN:
- ((Legend*)tmpl)->HasErr(&ErrLine, 1, name);
- break;
- case ERRBAR_HSYM: case ERRBAR_HLEFT: case ERRBAR_HRIGHT:
- ((Legend*)tmpl)->HasErr(&ErrLine, 2, name);
- break;
- }
- break;
- case CMD_ERRDESC:
- if(tmpl && *((char *)tmpl)){
- cb = (int)strlen((char*)tmpl)+2;
- if(name = (char*)realloc(name, cb)) rlp_strcpy(name, cb, (char*)tmpl);
- return true;
- }
- return false;
- case CMD_ERR_TYPE:
- if(tmpl) type = *((int*)tmpl);
- return true;
- 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*o->un2ix(LineDef.width)+3);
- 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;
- }
- if(mark) {
- if(mo) DelBitmapClass(mo); mo = 0L;
- if(dh1 && dh2) {
- memcpy(&mrc, &rDims, sizeof(RECT)); memcpy(&OldLine, &LineDef, sizeof(LineDEF));
- mo = GetRectBitmap(&mrc, o); Redraw(o);
- dh1->DoPlot(o); dh2->DoPlot(o);
- }
- else {
- memcpy(&mrc, &rDims, sizeof(RECT)); memcpy(&OldLine, &LineDef, sizeof(LineDEF));
- mo = GetRectBitmap(&mrc, o); LineDef.color = 0x00000000L;
- LineDef.width = OldLine.width *3.0; Redraw(o);
- LineDef.width = OldLine.width; LineDef.color = OldLine.color ^ 0x00ffffffL;
- Redraw(o); o->UpdateRect(&mrc, false);
- memcpy(&LineDef, &OldLine, sizeof(LineDEF));
- }
- }
- else if(mo) RestoreRectBitmap(&mo, &mrc, o);
-}
-
-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_SCALE:
- LineDef.width *= ((scaleINFO*)tmpl)->sy.fy; LineDef.patlength *= ((scaleINFO*)tmpl)->sy.fy;
- cw *= ((scaleINFO*)tmpl)->sy.fy; cl *= ((scaleINFO*)tmpl)->sy.fy;
- if(type & ARROW_UNITS) {
- pos1.fx = ((scaleINFO*)tmpl)->sx.fx + pos1.fx * ((scaleINFO*)tmpl)->sx.fy;
- pos1.fy = ((scaleINFO*)tmpl)->sy.fx + pos1.fy * ((scaleINFO*)tmpl)->sy.fy;
- pos2.fx = ((scaleINFO*)tmpl)->sx.fx + pos2.fx * ((scaleINFO*)tmpl)->sx.fy;
- pos2.fy = ((scaleINFO*)tmpl)->sy.fx + pos2.fy * ((scaleINFO*)tmpl)->sy.fy;
- }
- return true;
- case CMD_FLUSH:
- if (dh1) DeleteGO(dh1); dh1 = 0L;
- if (dh2) DeleteGO(dh2); dh2 = 0L;
- if(mo) DelBitmapClass(mo); mo = 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::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;
- 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
-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 || (pos1.fy == pos2.fy && pos1.fx == pos2.fx)) 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_SCALE:
- Outline.width *= ((scaleINFO*)tmpl)->sy.fy;
- Hatchline.width *= ((scaleINFO*)tmpl)->sy.fy;
- Fill.scale *= ((scaleINFO*)tmpl)->sy.fy;
- if(!(type & BAR_RELWIDTH) && parent->Id!= GO_DENSDISP)size *= ((scaleINFO*)tmpl)->sy.fy;
- return true;
- 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, name);
- 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(CurrGO = this, MRK_GODRAW);
- return true;
- }
- else {
- p.x = mev->x; p.y = mev->y;
- if(IsInPolygon(&p, pts, 5)) {
- o->ShowMark(CurrGO = 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) {
- if(type & BAR_WIDTHDATA) {
- if(pos1.fy != pos2.fy) {
- ((Plot*)parent)->CheckBounds(pos1.fx+size, pos1.fy);
- ((Plot*)parent)->CheckBounds(pos2.fx-size, pos2.fy);
- }
- else {
- ((Plot*)parent)->CheckBounds(pos1.fx, pos1.fy+size);
- ((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy-size);
- }
- }
- else {
- ((Plot*)parent)->CheckBounds(pos1.fx, pos1.fy);
- ((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy);
- if(parent && (type & BAR_RELWIDTH)) {
- if(pos1.fy == pos2.fy) {
- ((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy + parent->GetSize(SIZE_BOXMINY));
- ((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy - parent->GetSize(SIZE_BOXMINY));
- }
- else if(pos1.fx == pos2.fx) {
- ((Plot*)parent)->CheckBounds(pos2.fx + parent->GetSize(SIZE_BOXMINX), pos2.fy);
- ((Plot*)parent)->CheckBounds(pos2.fx - parent->GetSize(SIZE_BOXMINX), 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;
- }
- }
- Command(CMD_AUTOSCALE, 0L, 0L);
-}
-
-Whisker::Whisker(int src):GraphObj(0L, 0L)
-{
- FileIO(INIT_VARS);
- if(src == FILE_READ) {
- FileIO(FILE_READ);
- }
-}
-
-Whisker::~Whisker()
-{
- if(mo) DelBitmapClass(mo); mo = 0L;
- if(ssRef) free(ssRef); ssRef = 0L;
- if(name) free(name); name = 0L;
-}
-
-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)
-{
- int i;
- LineDEF OldLine;
-
- if(mark){
- if(mo) DelBitmapClass(mo); mo = 0L;
- memcpy(&mrc, &rDims, sizeof(RECT));
- memcpy(&OldLine, &LineDef, sizeof(LineDEF));
- i = 3*o->un2ix(LineDef.width); //increase size of rectangle for marks
- IncrementMinMaxRect(&mrc, i); mo = GetRectBitmap(&mrc, o);
- LineDef.width *= 5.0; DoPlot(o);
- LineDef.width = OldLine.width; LineDef.color = OldLine.color ^ 0x00ffffffL;
- DoPlot(o); o->UpdateRect(&mrc, false);
- memcpy(&LineDef, &OldLine, sizeof(LineDEF));
- }
- else RestoreRectBitmap(&mo, &mrc, o);
-}
-
-bool
-Whisker::Command(int cmd, void *tmpl, anyOutput *o)
-{
- MouseEvent *mev;
- int cb;
-
- switch (cmd) {
- case CMD_SCALE:
- size *= ((scaleINFO*)tmpl)->sy.fy;
- LineDef.width *= ((scaleINFO*)tmpl)->sy.fy;
- LineDef.patlength *= ((scaleINFO*)tmpl)->sy.fy;
- return true;
- 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_ERRDESC:
- if(tmpl && *((char*)tmpl)) {
- cb = (int)strlen((char*)tmpl)+2;
- if(name = (char*)realloc(name, cb)) rlp_strcpy(name, cb, (char*)tmpl);
- return true;
- }
- return false;
- case CMD_LEGEND:
- if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
- switch(type & 0x0f) {
- case 1: ((Legend*)tmpl)->HasErr(&LineDef, 5, name); break;
- case 2: ((Legend*)tmpl)->HasErr(&LineDef, 4, name); break;
- case 3: ((Legend*)tmpl)->HasErr(&LineDef, 3, name); break;
- default:
- if((rDims.right - rDims.left) < (rDims.bottom - rDims.top))
- ((Legend*)tmpl)->HasErr(&LineDef, 1, name);
- else ((Legend*)tmpl)->HasErr(&LineDef, 2, name);
- break;
- }
- break;
- 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 DefSize(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:
- type = 0;
- case 5:
- rx = o->un2ix(size/2.0); ry = o->un2iy(size/2.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_SCALE:
- Line.patlength *= ((scaleINFO*)tmpl)->sy.fy; Line.width *= ((scaleINFO*)tmpl)->sy.fy;
- Fill.scale *= ((scaleINFO*)tmpl)->sy.fy;
- if(!type || type == 5)size *= ((scaleINFO*)tmpl)->sy.fy;;
- return true;
- case CMD_LEGEND:
- if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
- ((Legend*)tmpl)->HasFill(&Line, &Fill, 0L);
- break;
- 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) {
- if(Line.width == 0.0) return;
- //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 && nldata){
- if(Line.width == 0.0) Line.color = Fill.color;
- 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 two planes have the same parent it means they are part of one object
- // do not clip!
- if(co->parent == parent && co->Id == GO_PLANE) return;
- if(co->Id == GO_PLANE && (parent->parent->Id == GO_GRID3D || parent->parent->Id == GO_RIBBON)
- && co->parent->parent == parent->parent) 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;
- if(!(o->ActualSize(&rDims)))return;
- 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_SCALE:
- Line.patlength *= ((scaleINFO*)tmpl)->sy.fy; Line.width *= ((scaleINFO*)tmpl)->sy.fy;
- Fill.scale *= ((scaleINFO*)tmpl)->sy.fy;
- return true;
- case CMD_LEGEND:
- if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
- if(parent && parent->Id > GO_PLOT && parent->Id < GO_GRAPH) {
- ((Legend*)tmpl)->HasFill(&Line, &Fill, ((Plot*)parent)->data_desc);
- }
- else ((Legend*)tmpl)->HasFill(&Line, &Fill, 0L);
- 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){
- if(mo) DelBitmapClass(mo); mo = 0L;
- 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_SCALE:
- Line.patlength *= ((scaleINFO*)tmpl)->sy.fy; Line.width *= ((scaleINFO*)tmpl)->sy.fy;
- Fill.scale *= ((scaleINFO*)tmpl)->sy.fy; depth *= ((scaleINFO*)tmpl)->sz.fy;
- width *= ((scaleINFO*)tmpl)->sx.fy; if(!(flags & 0x800L)) height *= ((scaleINFO*)tmpl)->sx.fy;
- return true;
- case CMD_LEGEND:
- if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
- if(parent && parent->Id > GO_PLOT && parent->Id < GO_GRAPH) {
- ((Legend*)tmpl)->HasFill(&Line, &Fill, ((Plot*)parent)->data_desc);
- }
- else ((Legend*)tmpl)->HasFill(&Line, &Fill, 0L);
- 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) {
- if(mo) DelBitmapClass(mo); mo = 0L;
- 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_SCALE:
- Line.patlength *= ((scaleINFO*)tmpl)->sy.fy; Line.width *= ((scaleINFO*)tmpl)->sy.fy;
- 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_SCALE:
- Line.patlength *= ((scaleINFO*)tmpl)->sy.fy; Line.width *= ((scaleINFO*)tmpl)->sy.fy;
- cw *= ((scaleINFO*)tmpl)->sy.fy; cl *= ((scaleINFO*)tmpl)->sy.fy;
- 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 = (char*)memdup(rx, (int)strlen(rx)+2, 0L);
- if(ry && ry[0]) y_range = (char*)memdup(ry, (int)strlen(ry)+2, 0L);
- if(rz && rz[0]) z_range = (char*)memdup(rz, (int)strlen(rz)+2, 0L);
- DoUpdate();
- Id = GO_LINE3D;
- bModified = false;
-}
-
-Line3D::Line3D(GraphObj *par, DataObj *d, fPOINT3D *pt, int n_pt, 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);
- 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*));
- }
- 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;
- }
- }
- 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; cssRef = 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(ssRef) free(ssRef); ssRef = 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) {
- if(mo) DelBitmapClass(mo); mo = 0L;
- 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_SCALE:
- Line.patlength *= ((scaleINFO*)tmpl)->sy.fy; Line.width *= ((scaleINFO*)tmpl)->sy.fy;
- 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:
- if(parent && parent->Id != GO_GRID3D) {
- Undo.DataMem(this, (void**)&values, nPts * sizeof(fPOINT3D), &nPts, UNDO_CONTINUE);
- }
- if(ssRef && cssRef >5 && data && nPts == 2) {
- data->GetValue(ssRef[0].y, ssRef[0].x, &values[0].fx);
- data->GetValue(ssRef[1].y, ssRef[1].x, &values[0].fy);
- data->GetValue(ssRef[2].y, ssRef[2].x, &values[0].fz);
- data->GetValue(ssRef[3].y, ssRef[3].x, &values[1].fx);
- data->GetValue(ssRef[4].y, ssRef[4].x, &values[1].fy);
- data->GetValue(ssRef[5].y, ssRef[5].x, &values[1].fz);
- return true;
- }
- else 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)
-{
- int cb;
-
- 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 && td->text[0]) {
- cb = (int)strlen(td->text)+1; if(cb < 20) cb = 20;
- TextDef.text = (char*)malloc(cb *sizeof(char));
- rlp_strcpy(TextDef.text, cb, 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()
-{
- HideTextCursor();
- Command(CMD_FLUSH, 0L, 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(this != CurrGO && m1 >=0 && m2 >=0) {
- m1 = m2 = -1;
- }
- 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 if(m1 >= 0 && m2 >= 0) {
- m1 = m2 = -1;
- parent->Command(CMD_REDRAW, 0L, o);
- }
- else {
- HideTextCursor(); m1 = m2 = -1;
- 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;
- scaleINFO *scale;
- int i, cb;
-
- if(cmd != CMD_SET_DATAOBJ && !parent) return false;
- switch (cmd) {
- case CMD_SCALE:
- scale = (scaleINFO*)tmpl;
- if((flags & 0x03)!= LB_X_DATA) fPos.fx *= scale->sx.fy;
- if((flags & 0x30)!= LB_Y_DATA) fPos.fy *= scale->sy.fy;
- fDist.fx *= scale->sx.fy; fDist.fy *= scale->sy.fy;
- TextDef.fSize *= scale->sx.fy; TextDef.iSize = 0;
- return true;
- case CMD_HIDEMARK:
- if(m1 >=0 && m2 >=0 && m1 != m2) {
- m1 = m2 = -1; return true;
- }
- return false;
- 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) ? (int)strlen(TextDef.text) : 0;
- ShowCursor(o);
- return true;
- }
- return false;
- case CMD_SHIFTLEFT: case CMD_CURRLEFT:
- if(o && CursorPos >0 && TextDef.text) {
- Undo.ValInt(this, &CursorPos, 0L);
- DrawFmtText.SetText(0L, TextDef.text, 0L, 0L);
- bModified = true;
- if(cmd == CMD_SHIFTLEFT) {
- if(CursorPos && CursorPos == m1) {
- DrawFmtText.cur_left(&CursorPos);
- m1 = CursorPos; ShowCursor(o);
- }
- else if(CursorPos && CursorPos == m2) {
- DrawFmtText.cur_left(&CursorPos);
- m2 = CursorPos; ShowCursor(o);
- if(parent) parent->Command(CMD_REDRAW, 0L, o);
- }
- else if(CursorPos){
- m2 = CursorPos;
- DrawFmtText.cur_left(&CursorPos);
- m1 = CursorPos; ShowCursor(o);
- }
- }
- else {
- if(m1 >= 0 && m2 >= 0 && parent) {
- m1 = m2 = -1; parent->Command(CMD_REDRAW, 0L, o);
- }
- DrawFmtText.cur_left(&CursorPos); ShowCursor(o);
- }
- if(m1 >=0 && m2 >=0 && m1 != m2) DoPlot(o);
- return true;
- }
- return false;
- case CMD_SHIFTRIGHT: case CMD_CURRIGHT:
- if(o && TextDef.text && CursorPos < (int)strlen(TextDef.text)) {
- Undo.ValInt(this, &CursorPos, 0L);
- DrawFmtText.SetText(0L, TextDef.text, 0L, 0L);
- bModified = true;
- if(cmd == CMD_SHIFTRIGHT) {
- if(CursorPos == m1 && TextDef.text[m1]) {
- DrawFmtText.cur_right(&CursorPos);
- m2 = CursorPos; ShowCursor(o);
- memcpy(&rm2, &Cursor, sizeof(RECT));
- if(parent) parent->Command(CMD_REDRAW, 0L, o);
- }
- else if(CursorPos == m2 && TextDef.text[m2]) {
- DrawFmtText.cur_right(&CursorPos);
- m2 = CursorPos; ShowCursor(o);
- memcpy(&rm2, &Cursor, sizeof(RECT));
- }
- else if(TextDef.text[CursorPos]){
- if(m1 < 0) {
- m1 = CursorPos; ShowCursor(o);
- }
- DrawFmtText.cur_right(&CursorPos);
- m2 = CursorPos; ShowCursor(o);
- }
- else return false;
- }
- else {
- if(m1 >= 0 && m2 >= 0 && parent) {
- m1 = m2 = -1; parent->Command(CMD_REDRAW, 0L, o);
- }
- DrawFmtText.cur_right(&CursorPos); ShowCursor(o);
- }
- if(m1 >=0 && m2 >=0 && m1 != m2) DoPlot(o);
- return true;
- }
- return false;
- case CMD_ADDCHAR: case CMD_ADDCHARW:
- SetModified();
- if(tmpl && 8 != *((int*)tmpl)) return AddChar(*((int*)tmpl), o);
- //value 8 == backspace
- case CMD_BACKSP:
- SetModified();
- if(CursorPos <=0 && o) {
- if(parent && parent->Id == GO_MLABEL) {
- parent->Command(CMD_SETFOCUS, this, o);
- return parent->Command(CMD_BACKSP, tmpl, o);
- }
- RedrawEdit(o);
- return true;
- }
- DrawFmtText.SetText(0L, TextDef.text, 0L, 0L);
- DrawFmtText.cur_left(&CursorPos); //continue as if delete
- case CMD_DELETE:
- SetModified();
- if(TextDef.text && TextDef.text[CursorPos]) {
- Undo.String(this, &TextDef.text, 0L);
- if(cmd == CMD_DELETE) Undo.ValInt(this, &CursorPos, UNDO_CONTINUE);
- if(CheckMark() && m2 < (cb = (int) strlen(TextDef.text))) {
- Undo.ValInt(this, &m1, UNDO_CONTINUE);
- Undo.ValInt(this, &m2, UNDO_CONTINUE);
- rlp_strcpy(TextDef.text + m1, cb, TextDef.text + m2);
- CursorPos = m1; m1 = m2 = -1;
- }
- else {
- DrawFmtText.SetText(0L, TextDef.text, 0L, 0L);
- cb = CursorPos; DrawFmtText.cur_right(&cb);
- cb -= CursorPos; if(cb < 1) cb = 1;
- rlp_strcpy(TextDef.text + CursorPos, TMP_TXT_SIZE, TextDef.text + CursorPos + cb);
- }
- if(o) {
- RedrawEdit(o); ShowCursor(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 && TextDef.text[0] && tmpl) {
- rlp_strcpy((char*)tmpl, TMP_TXT_SIZE, TextDef.text);
- return true;
- }
- return false;
- case CMD_SETTEXT:
- if(TextDef.text) free(TextDef.text); TextDef.text = 0L;
- if(tmpl && *((char*)tmpl)) {
- TextDef.text = (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1, 0);
- }
- return true;
- case CMD_GETTEXTDEF:
- if(!tmpl) return false;
- memcpy(tmpl, &TextDef, sizeof(TextDEF));
- return true;
- case CMD_SETTEXTDEF:
- if(!tmpl)return false;
- memcpy(&TextDef, tmpl, sizeof(TextDEF)-sizeof(char*));
- if(((TextDEF*)tmpl)->text) Command(CMD_SETTEXT, tmpl, o);
- 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)) {
- Undo.String(this, &TextDef.text, UNDO_CONTINUE);
- TextDef.text = (char*)realloc(TextDef.text, cb = (int)strlen(TmpTxt)+2);
- if(TmpTxt[0]) rlp_strcpy(TextDef.text, cb, TmpTxt);
- else TextDef.text[0] = 0;
- }
- 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_MOVE:
- if((mev->StateFlags & 0x01) && ObjThere(mev->x, mev->y)) {
- i = CursorPos; CalcCursorPos(mev->x, mev->y, o);
- if(CurrLabel && CurrLabel != this) {
- CurrLabel->Command(CMD_HIDEMARK, tmpl, o);
- }
- CurrGO = CurrLabel = this;
- if(i == CursorPos) return true;
- if(CursorPos > m1 && CursorPos < m2) {
- if(m1 < 0) m1 = CursorPos;
- else if(m2 != CursorPos)m2 = CursorPos;
- parent->Command(CMD_REDRAW, 0L, o);
- }
- else {
- if(m1 < 0) m1 = CursorPos;
- else if(m2 != CursorPos)m2 = CursorPos;
- if(m1 >=0 && m2 >=0 && m1 != m2) DoPlot(o);
- }
- return true;
- }
- break;
- 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);
- if(o->MrkRect && (void*)o->MrkRect == (void*)this) o->MrkMode = MRK_NONE;
- if(m1 < 0) m1 = CursorPos; ShowCursor(o);
- o->ShowMark(this, MRK_GODRAW);
- }
- else if(m1 >= 0 && m2 >= 0) {
- m1 = m2 = -1; DoPlot(o);
- }
- break;
- }
- break;
- case CMD_TEXTTHERE:
- if(ObjThere(((MouseEvent *)tmpl)->x, ((MouseEvent *)tmpl)->y)) {
- CalcCursorPos(((MouseEvent *)tmpl)->x, ((MouseEvent *)tmpl)->y, o);
- CalcRect(o);
- m1 = m2 = CursorPos; CurrGO = this;
- return true;
- }
- m1 = m2 = -1;
- return false;
- 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(!(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;
- m1 = m2 = -1;
- 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);
- DrawFmtText.SetText(0L, TextDef.text, &ix, &iy);
- if(TextDef.text && TextDef.text[0]) {
- if(!(DrawFmtText.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(DrawFmtText.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::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)
-{
- static LineDEF yLine = {0.0, 1.0, 0x0000ffff, 0x0};
- static FillDEF yFill = {0, 0x0000ffff, 1.0, 0L, 0x0000ffff};
- POINT mpts[5];
- int i;
-
- if(!parent || !o) return;
- if(m1 >= 0 && m2 >= 0 && m1 != m2 && CurrGO == this) {
- i = CursorPos; CursorPos = m1;
- CalcRect(o); memcpy(&rm1, &Cursor, sizeof(RECT));
- CursorPos = m2; CalcRect(o);
- memcpy(&rm2, &Cursor, sizeof(RECT)); CursorPos = i;
- if(CurrGO == this) ShowCursor(o);
- else CalcRect(o);
- if(m2 > m1) {
- mpts[0].x = mpts[4].x = rm1.left; mpts[1].x = rm1.right;
- mpts[0].y = mpts[4].y = rm1.top; mpts[1].y = rm1.bottom;
- mpts[2].x = rm2.right; mpts[2].y = rm2.bottom;
- mpts[3].x = rm2.left; mpts[3].y = rm2.top;
- }
- else {
- mpts[0].x = mpts[4].x = rm2.left; mpts[1].x = rm2.right;
- mpts[0].y = mpts[4].y = rm2.top; mpts[1].y = rm2.bottom;
- mpts[2].x = rm1.right; mpts[2].y = rm1.bottom;
- mpts[3].x = rm1.left; mpts[3].y = rm1.top;
- }
- o->SetLine(&yLine); o->SetFill(&yFill);
- o->oPolygon(mpts, 5, 0L);
- }
- else {
- m1 = m2 = -1;
- if(CurrGO == this) ShowCursor(o);
- }
- 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]){
- DrawFmtText.SetText(o, TextDef.text, &ix, &iy);
- }
- 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);
- if(m1 >= 0 && m2 >= 0 && m1 != m2 && CurrGO == this && fabs(TextDef.RotBL) < 0.01) {
- o->CopyBitmap(mpts[0].x, mpts[0].y, o, mpts[0].x, mpts[0].y,
- mpts[2].x - mpts[0].x, mpts[2].y - mpts[0].y, true);
- }
- if(m1 >= 0 && m2 >= 0) o->UpdateRect(&rDims, false);
-}
-
-bool
-Label::CheckMark()
-{
- int m;
-
- if(m1 < 0 || m2 < 0 || m1 == m2) return false;
- if(m1 < m2) return true;
- //come here on right to left mark: swap m1 and m2
- m = m1; m1 = m2; m2 = m;
- return true;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 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; lspc = 1.0;
- 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; lspc = 1.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;
- case SIZE_LSPC:
- return lspc;
- }
- 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;
- case SIZE_LSPC:
- undo_flags = CheckNewFloat(&lspc, lspc, value, this, undo_flags);
- return 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));
- if(lspc < 0.5 || lspc > 5) lspc = 1.0;
-#ifdef _WINDOWS
- dist.fx = floor(o->un2fix(TextDef.fSize * si * lspc));
- dist.fy = floor(o->un2fiy(TextDef.fSize * csi * lspc));
-#else
- dist.fx = floor(o->un2fix(TextDef.fSize * si * 1.2 * lspc));
- dist.fy = floor(o->un2fiy(TextDef.fSize * csi * 1.2 * lspc));
-#endif
- 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;
- scaleINFO *scale;
-
- switch (cmd) {
- case CMD_MOUSE_EVENT: case CMD_TEXTTHERE:
- 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_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: //used e.g from dialog text boxes
- if(tmpl && Lines && nLines){
- for(i = j = 0; i < nLines; i++) {
- if(Lines[i] && Lines[i]->Command(CMD_GETTEXT, TmpTxt+500, o) && TmpTxt[500]){
- j += rlp_strcpy((char*)tmpl+j, 500-j, TmpTxt+500);
- ((char*)tmpl)[j++] = '\n';
- }
- ((char*)tmpl)[j] = 0;
- }
- if(j >2) return true;
- }
- return false;
- 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;
- if(parent)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;
- 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_SCALE:
- scale = (scaleINFO*)tmpl;
- if((flags & 0x03)!= LB_X_DATA) fPos.fx *= scale->sx.fy;
- if((flags & 0x30)!= LB_Y_DATA) fPos.fy *= scale->sy.fy;
- fDist.fx *= scale->sx.fy; fDist.fy *= scale->sy.fy;
- TextDef.fSize *= scale->sx.fy; TextDef.iSize = 0;
- return true;
- 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
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// a rectangular range to accept any text
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-TextFrame::TextFrame(GraphObj *parent, DataObj *data, lfPOINT *p1, lfPOINT *p2, char *txt)
- :GraphObj(parent, data)
-{
- FileIO(INIT_VARS); lspc = 1.0;
- pos1.fx = p1->fx; pos1.fy = p1->fy; pos2.fx = p2->fx; pos2.fy = p2->fy;
- if(txt && txt[0]) {
- text = (unsigned char*)memdup(txt, (int)strlen(txt)+1, 0);
- }
- else if(lines = (unsigned char**)malloc(sizeof(char*))){
- if(lines[0] = (unsigned char*)malloc(TF_MAXLINE))lines[0][0] = 0;
- nlines = 1;
- }
- Id = GO_TEXTFRAME;
-}
-
-TextFrame::TextFrame(int src):GraphObj(0L, 0L)
-{
- FileIO(INIT_VARS);
- if(src == FILE_READ) {
- FileIO(FILE_READ);
- }
- moveable = 1; bModified = false;
-}
-
-TextFrame::~TextFrame()
-{
- int i;
-
- if(text)free(text); text = 0L;
- if(drc) delete(drc); drc = 0L;
- if(tm_rec) free(tm_rec); tm_rec = 0L;
- if(lines) {
- for(i = 0; i < nlines; i++) if(lines[i]) free(lines[i]);
- free(lines); lines = 0L;
- }
- HideTextCursor();
-}
-double
-TextFrame::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
-TextFrame::SetSize(int select, double value)
-{
- switch(select & 0xfff) {
- case SIZE_XPOS: pos1.fx = value; return bResize = true;
- case SIZE_XPOS+1: pos2.fx = value; return bResize = true;
- case SIZE_YPOS: pos1.fy = value; return bResize = true;
- case SIZE_YPOS+1: pos2.fy = value; return bResize = true;
- }
- return false;
-}
-
-void
-TextFrame::DoMark(anyOutput *o, bool mark)
-{
- RECT upd;
-
- if(has_m1 && has_m2) TextMark(o, 3);
- has_m1 = has_m2 = false;
- if(!drc) drc = new dragRect(this, 0);
- memcpy(&upd, &rDims, sizeof(RECT));
- if(mark){
- if(drc) drc->DoPlot(o); ShowCursor(o);
- }
- else if(parent) parent->DoPlot(o);
- IncrementMinMaxRect(&upd, 6);
- o->UpdateRect(&upd, false);
-}
-
-void
-TextFrame::DoPlot(anyOutput *o)
-{
- int i, j, x1, y1, x2, y2;
- double tmp, dx, dy;
-
- if(!o) return;
- 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);
- x1 = o->co2ix(pos1.fx+dx); y1 = o->co2iy(pos1.fy+dy);
- x2 = o->co2ix(pos2.fx+dx); y2 = o->co2iy(pos2.fy+dy);
- ipad.left = o->un2ix(pad.Xmin); ipad.right = o->un2ix(pad.Xmax);
- ipad.top = o->un2iy(pad.Ymin); ipad.bottom = o->un2iy(pad.Ymax);
- }
- else {
- dx = dy = 0.0;
- x1 = (int)pos1.fx; y1 = (int)pos1.fy; x2 = (int)pos2.fx; y2 = (int)pos2.fy;
- ipad.left = ipad.right = ipad.top = ipad.bottom = 4;
- fmt_txt.EditMode(true);
- }
- if(pos1.fx > pos2.fx) {
- tmp = pos2.fx; pos2.fx = pos1.fx; pos1.fx = tmp;
- }
- if(pos1.fy > pos2.fy) {
- tmp = pos2.fy; pos2.fy = pos1.fy; pos1.fy = tmp;
- }
- o->SetLine(&Line); o->SetFill(&Fill);
- o->oRectangle(x1, y1, x2, y2, name);
- SetMinMaxRect(&rDims, x1, y1, x2, y2);
- x1 += ipad.left; y1 += ipad.top;
- TextDef.iSize = o->un2iy(TextDef.fSize);
-#ifdef _WINDOWS
- linc = o->un2iy(TextDef.fSize*lspc);
-#else
- linc = o->un2iy(TextDef.fSize*lspc*1.2);
-#endif
- o->SetTextSpec(&TextDef); y1 += linc;
- if(text && text[0] && !(lines)) text2lines(o);
- else if(bResize && lines) {
- c_char = lines[cur_pos.y][cur_pos.x]; lines[cur_pos.y][cur_pos.x] = 0x01;
- if(!c_char) lines[cur_pos.y][cur_pos.x+1] = 0x00;
- lines2text(); text2lines(o); bResize = false;
- o->ShowMark(this, MRK_GODRAW);
- return;
- }
- if(has_m1 && has_m2) TextMark(o, 1);
- for(i = 0; i < nlines; i++) {
- if(lines[i] && lines[i][0]){
- j = (int)strlen((char*)lines[i]);
- if(lines[i][j-1] == '\n') {
- lines[i][j-1] = 0;
- fmt_txt.SetText(o, (char*)lines[i], &x1, &y1);
- lines[i][j-1] = '\n';
- }
- else fmt_txt.SetText(o, (char*)lines[i], &x1, &y1);
- }
- y1 += linc;
- }
- if(has_m1 && has_m2) TextMark(o, 2);
- bModified = bResize = false;
-}
-
-bool
-TextFrame::Command(int cmd, void *tmpl, anyOutput *o)
-{
- MouseEvent *mev;
- int i;
-
- switch (cmd) {
- case CMD_SELECT:
- if(!o || !tmpl) return false;
- CalcCursorPos(((POINT*)tmpl)->x, ((POINT*)tmpl)->y, o);
- if(parent)o->ShowMark(this, MRK_GODRAW); ShowCursor(o);
- return true;
- case CMD_COPY:
- return CopyText(o, false);
- case CMD_SAVEPOS:
- bModified = true;
- Undo.SaveLFP(this, &pos1, 0L);
- Undo.SaveLFP(this, &pos2, UNDO_CONTINUE);
- return true;
- case CMD_SCALE:
- if(tmpl) {
- pos1.fx = ((scaleINFO*)tmpl)->sx.fx + pos1.fx * ((scaleINFO*)tmpl)->sx.fy;
- pos1.fy = ((scaleINFO*)tmpl)->sy.fx + pos1.fy * ((scaleINFO*)tmpl)->sy.fy;
- pos2.fx = ((scaleINFO*)tmpl)->sx.fx + pos2.fx * ((scaleINFO*)tmpl)->sx.fy;
- pos2.fy = ((scaleINFO*)tmpl)->sy.fx + pos2.fy * ((scaleINFO*)tmpl)->sy.fy;
- TextDef.fSize *= ((scaleINFO*)tmpl)->sy.fy; TextDef.iSize = 0;
- pad.Xmax *= ((scaleINFO*)tmpl)->sx.fy; pad.Xmin *= ((scaleINFO*)tmpl)->sx.fy;
- pad.Ymax *= ((scaleINFO*)tmpl)->sy.fy; pad.Ymin *= ((scaleINFO*)tmpl)->sy.fy;
- Line.width *= ((scaleINFO*)tmpl)->sy.fy; Line.patlength *= ((scaleINFO*)tmpl)->sy.fy;
- FillLine.width *= ((scaleINFO*)tmpl)->sy.fy; FillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
- Fill.scale *= ((scaleINFO*)tmpl)->sy.fy;
- }
- return true;
- case CMD_GETTEXT: case CMD_ALLTEXT:
- if(lines && lines[0] && lines[0][0] && nlines) {
- lines2text(); i = rlp_strcpy((char*)tmpl, TMP_TXT_SIZE-2, (char*)text);
- while(i && ((char*)tmpl)[i-1] == '\n') i--;
- ((char*)tmpl)[i++] = '\n'; ((char*)tmpl)[i] = 0;
- return true;
- }
- return false;
- case CMD_ADDCHARW: case CMD_ADDCHAR:
- if(tmpl && o) AddChar(o, *((int *)tmpl));
- return true;
- case CMD_DELETE:
- if(o) DelChar(o);
- return true;
- case CMD_SHIFTLEFT:
- if(!has_m1) {
- m1_pos.x = cur_pos.x; m1_pos.y = cur_pos.y;
- }
- has_m1 = has_m2 = true;
- case CMD_CURRLEFT:
- if(!(lines[cur_pos.y]))return false;
- if(cmd == CMD_CURRLEFT && has_m1 && has_m2) TextMark(o, 3);
- if(cur_pos.x > 0) {
- i = 0; fmt_txt.SetText(0L,(char*)lines[cur_pos.y], &i, &i);
- i = cur_pos.x; fmt_txt.cur_left(&i);
- cur_pos.x = i;
- }
- else if(cur_pos.y) {
- cur_pos.y--; cur_pos.x = (int)strlen((char*)lines[cur_pos.y]);
- }
- if(cmd == CMD_SHIFTLEFT){
- m2_pos.x = cur_pos.x; m2_pos.y = cur_pos.y;
- DoPlot(o); o->UpdateRect(&rDims, false);
- }
- ShowCursor(o);
- return false;
- case CMD_SHIFTRIGHT:
- if(!has_m1) {
- m1_pos.x = cur_pos.x; m1_pos.y = cur_pos.y;
- }
- has_m1 = has_m2 = true;
- case CMD_CURRIGHT:
- if(!(lines[cur_pos.y]))return false;
- if(cmd == CMD_CURRIGHT && has_m1 && has_m2) TextMark(o, 3);
- if(cur_pos.x >= (int)strlen((char*)lines[cur_pos.y])) {
- if(cur_pos.y < (nlines-1)) {
- cur_pos.y++; cur_pos.x = 0;
- }
- else if(cur_pos.y == (nlines-1) && lines[cur_pos.y][0]) {
- if(!(lines = (unsigned char**)realloc(lines, (nlines+1)*sizeof(char*))))return false;
- if(!(lines[cur_pos.y+1] = (unsigned char*)malloc(TF_MAXLINE))) return false;
- cur_pos.y++; cur_pos.x = 0; nlines++;
- lines[cur_pos.y][0] = 0;
- }
- }
- else {
- i = 0; fmt_txt.SetText(0L,(char*)lines[cur_pos.y], &i, &i);
- i = cur_pos.x; fmt_txt.cur_right(&i);
- cur_pos.x = i;
- }
- if(cmd == CMD_SHIFTRIGHT){
- m2_pos.x = cur_pos.x; m2_pos.y = cur_pos.y;
- DoPlot(o); o->UpdateRect(&rDims, false);
- }
- ShowCursor(o);
- return false;
- case CMD_SHIFTUP:
- if(!has_m1) {
- m1_pos.x = cur_pos.x; m1_pos.y = cur_pos.y;
- }
- has_m1 = has_m2 = true;
- case CMD_CURRUP:
- if(cmd == CMD_CURRUP && has_m1 && has_m2) TextMark(o, 3);
- if(cur_pos.y && o) {
- i = ((Cursor.bottom + Cursor.top)>>1)-linc;
- CalcCursorPos(Cursor.left, i, o);
- if(cmd == CMD_SHIFTUP){
- m2_pos.x = cur_pos.x; m2_pos.y = cur_pos.y;
- DoPlot(o); o->UpdateRect(&rDims, false);
- }
- ShowCursor(o);
- return true;
- }
- return false;
- case CMD_SHIFTDOWN:
- if(!has_m1) {
- m1_pos.x = cur_pos.x; m1_pos.y = cur_pos.y;
- }
- has_m1 = has_m2 = true;
- case CMD_CURRDOWN:
- if(cmd == CMD_CURRDOWN && has_m1 && has_m2) TextMark(o, 3);
- if(cur_pos.y < (nlines-1) && o && lines[cur_pos.y][0]) {
- i = ((Cursor.bottom + Cursor.top)>>1)+linc;
- if(i >= (rDims.bottom-ipad.bottom)) return false;
- CalcCursorPos(Cursor.left, i, o);
- if(cmd == CMD_SHIFTDOWN){
- m2_pos.x = cur_pos.x; m2_pos.y = cur_pos.y;
- DoPlot(o); o->UpdateRect(&rDims, false);
- }
- ShowCursor(o);
- return true;
- }
- return false;
- case CMD_POS_FIRST:
- if(has_m1 && has_m2) TextMark(o, 3);
- cur_pos.x = 0; ShowCursor(o);
- return true;
- case CMD_POS_LAST:
- if(has_m1 && has_m2) TextMark(o, 3);
- cur_pos.x = (int)strlen((char*)lines[cur_pos.y]);
- ShowCursor(o);
- return true;
- case CMD_TEXTTHERE:
- if(IsInRect(&rDims, ((MouseEvent *)tmpl)->x, ((MouseEvent *)tmpl)->y)) return true;
- return false;
- case CMD_MOUSE_EVENT:
- mev = (MouseEvent *) tmpl;
- switch (mev->Action) {
- case MOUSE_LBUP:
- if(IsInRect(&rDims, mev->x, mev->y) && (!(CurrGO) || !has_m2) && o){
- CalcCursorPos(mev->x, mev->y, o);
- if(has_m1 && has_m2) {
- if(o)DoPlot(o); o->UpdateRect(&rDims, false);
- CurrGO = this; ShowCursor(o);
- return true;
- }
- return o->ShowMark(this, MRK_GODRAW);
- }
- else if(CurrGO == this && o){
- ShowCursor(o);
- return IsInRect(&rDims, mev->x, mev->y);
- }
- break;
- case MOUSE_LBDOWN:
- if(has_m1 && has_m2) {
- has_m1 = has_m2 = false;
- if(o)DoPlot(o); o->UpdateRect(&rDims, false);
- }
- has_m1 = has_m2 = false;
- case MOUSE_MOVE:
- if(!(mev->StateFlags & 0x1)) return false;
- if(!IsInRect(&rDims, mev->x, mev->y))return false;
- if(!CurrGO) CurrGO = this;
- CalcCursorPos(mev->x, mev->y, o);
- if(!has_m1) {
- m1_pos.x = m2_pos.x = cur_pos.x; m1_pos.y = m2_pos.y = cur_pos.y;
- return has_m1 = true;
- }
- else if(cur_pos.x != m2_pos.x || cur_pos.y != m2_pos.y) {
- m2_pos.x = cur_pos.x; m2_pos.y = cur_pos.y;
- has_m2 = true;
- if(o)DoPlot(o); o->UpdateRect(&rDims, false);
- return true;
- }
- return true;
- }
- return false;
- case CMD_SET_DATAOBJ:
- Id = GO_TEXTFRAME;
- return true;
- case CMD_PASTE:
- return DoPaste(o);
- case CMD_MOVE:
- bModified = true;
- Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
- case CMD_UNDO_MOVE:
- pos1.fx += ((lfPOINT*)tmpl)[0].fx; pos1.fy += ((lfPOINT*)tmpl)[0].fy;
- pos2.fx += ((lfPOINT*)tmpl)[0].fx; pos2.fy += ((lfPOINT*)tmpl)[0].fy;
- CurrGO = this;
- case CMD_REDRAW:
- if(parent){
- if(o && cmd == CMD_REDRAW) DoPlot(o); //trickle down ?
- if(!o && cmd == CMD_REDRAW) {
- //coming from Undo
- bModified = true;
- if(lines) {
- for(i = 0; i < nlines; i++) if(lines[i]) free(lines[i]);
- free(lines); lines = 0L;
- }
- HideTextCursor(); cur_pos.x = cur_pos.y = 0;
- parent->Command(CMD_REDRAW, tmpl, o);
- }
- else parent->Command(CMD_REDRAW, tmpl, o);
- }
- return true;
- case CMD_SETSCROLL:
- if(parent) return parent->Command(cmd, tmpl, o);
- case CMD_GETTEXTDEF:
- if(!tmpl) return false;
- memcpy(tmpl, &TextDef, sizeof(TextDEF));
- return true;
- case CMD_SETTEXTDEF:
- if(!tmpl)return false;
- memcpy(&TextDef, tmpl, sizeof(TextDEF));
- TextDef.text = 0L;
- return true;
- case CMD_SETTEXT:
- if(lines) {
- for(i = 0; i < nlines; i++) if(lines[i]) free(lines[i]);
- free(lines); lines = 0L;
- }
- if(text) free(text); text = 0L;
- if(tmpl && *((char*)tmpl)) text = (unsigned char*)memdup(tmpl, (int)strlen(((char*)tmpl))+1, 0);
- return true;
- }
- return false;
-}
-
-void
-TextFrame::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(pos1.fx+dx)+p->x;
- tpts[0].y = tpts[3].y = tpts[4].y = o->co2iy(pos1.fy+dy)+p->y;
- tpts[1].y = tpts[2].y = o->co2iy(pos2.fy+dy)+p->y;
- tpts[2].x = tpts[3].x = o->co2ix(pos2.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);
- }
-}
-
-void *
-TextFrame::ObjThere(int x, int y)
-{
- if(drc) return drc->ObjThere(x, y);
- return 0L;
-}
-
-void
-TextFrame::text2lines(anyOutput *o)
-{
- int i, j, w, h, cl, maxlines, maxw;
- char tmp_line[TF_MAXLINE];
- bool hasMark = false;
-
- if(lines) {
- for(i = 0; i < nlines; i++) if(lines[i]) free(lines[i]);
- free(lines); lines = 0L;
- }
- has_m1 = has_m2 = false;
- nlines = 0;
- if(!text || !text[0]) return;
- maxlines = (rDims.bottom -rDims.top)/linc +1;
- maxw = rDims.right - rDims.left - ipad.left - ipad.right;
- lines = (unsigned char**)calloc(maxlines, sizeof(char*));
- for(cl = cpos = w = h = 0; cl < maxlines && text[cpos]; cl++) {
- if(!(lines[cl] = (unsigned char*)malloc(TF_MAXLINE))) return;
- for(i = 0; text[cpos] && i < TF_MAXLINE; i++) {
- tmp_line[i] = text[cpos++]; tmp_line[i+1] = 0;
- fmt_txt.SetText(0L, tmp_line, &w, &h);
- if(!(fmt_txt.oGetTextExtent(o, &w, &h, i))) break;
- if(tmp_line[i] == '\n'){
- break; //new line character found
- }
- if(tmp_line[i] < ' ') switch(tmp_line[i]) {
- case 0x01:
- if(c_char == 0 && text[cpos]) c_char = text[cpos++]; //cursor at end of line
- hasMark = true; break;
- case 0x02: case 0x03:
- hasMark = true; break;
- }
- else if(w >= maxw){
- for(j = i; j > (i>>1); j--) {
- if(tmp_line[j] == ' ' || tmp_line[j] == '-' || tmp_line[j] < ' ') break;
- }
- if(j == (i>>1)) {
- cpos--; tmp_line[i] = 0;
- }
- else {
- for(tmp_line[j+1] = 0; j < i; j++, cpos--);
- }
- break;
- }
- }
- if(i || tmp_line[i] == '\n') rlp_strcpy((char*)lines[cl], TF_MAXLINE, tmp_line);
- else lines[cl][0] = 0;
- }
- nlines = cl;
- if(hasMark)procTokens();
-}
-
-void
-TextFrame::lines2text()
-{
- int i;
-
- if(text) free(text); cpos = 0;
- text = (unsigned char*)malloc(csize = 1000);
- for(i = 0; i < nlines; i++) {
- if(lines[i] && lines[i][0]) add_to_buff((char**)&text, &cpos, &csize, (char*)lines[i], 0);
- }
-}
-
-void
-TextFrame::AddChar(anyOutput *o, int c)
-{
- int i, j, h, w, maxw;
- bool brd;
- char *txt1;
-
- if(cur_pos.y >= nlines) return;
- if(!lines || !lines[cur_pos.y]) return;
- if(c == '\r') c = '\n';
- if(has_m1 && has_m2){
- TmpTxt[0] = c; TmpTxt[1] = 0;
- if(c == 8) ReplMark(o, "");
- else if(c >= 32 || c == '\n') ReplMark(o, TmpTxt);
- return;
- }
- else if(!text) {
- lines2text();
- Undo.TextBuffer(this, &csize, &cpos, &text, 0L, o);
- }
- maxw = rDims.right - rDims.left - ipad.left - ipad.right;
- i = j = (int)strlen((char*)lines[cur_pos.y])+1;
- has_m1 = has_m2 = false;
- if(c >= 32 || c == '\n') {
- if(c > 254 && (txt1 = (char*)malloc(10))) {
-#ifdef USE_WIN_SECURE
- w = sprintf_s(txt1, 10, "&#%d;", c);
-#else
- w = sprintf(txt1, "&#%d;", c);
-#endif
- for(j = j+w; j>0; j--) {
- lines[cur_pos.y][j] = lines[cur_pos.y][j-w];
- if((j-w) == cur_pos.x){
- for(i = 0; i < w; i++) lines[cur_pos.y][j-w+i] = txt1[i];
- j = 0; cur_pos.x += w;
- }
- }
- free(txt1);
- }
- else while(j) {
- lines[cur_pos.y][j] = lines[cur_pos.y][j-1]; j--;
- if(j == cur_pos.x){
- lines[cur_pos.y][j] = c; j = 0;
- cur_pos.x++;
- }
- }
- fmt_txt.SetText(0L, (char*)lines[cur_pos.y], &j, &j);
- fmt_txt.oGetTextExtent(o, &w, &h, i); brd = false;
- if(cur_pos.x > 2 && (c == '>' || c == ';')) {
- if(c == '>' && fmt_txt.leftTag((char*)lines[cur_pos.y],cur_pos.x-1) >= 0) brd =true;
- if(c == ';' && fmt_txt.ucLeft((char*)lines[cur_pos.y],cur_pos.x-1, 0L, 0L) > 0) brd =true;
- }
- if(brd || w >= maxw || c == '\n' || (c == ' ' && w >=(maxw>>1))) {
- c_char = lines[cur_pos.y][cur_pos.x]; lines[cur_pos.y][cur_pos.x] = 0x01;
- if(!c_char) lines[cur_pos.y][cur_pos.x+1] = 0x00;
- lines2text(); Undo.TextBuffer(this, &csize, &cpos, &text, 0L, o); text2lines(o);
- }
- }
- else if(c == 8 && (cur_pos.x || cur_pos.y)) { //Backspace
- if(!cur_pos.x) Command(CMD_CURRLEFT, 0L, o);
- Command(CMD_CURRLEFT, 0L, o); DelChar(o);
- return;
- }
- else return;
- DoPlot(o); o->UpdateRect(&rDims, false); ShowCursor(o);
-}
-
-void
-TextFrame::DelChar(anyOutput *o)
-{
- int i, cb, x;
-
- if(has_m1 && has_m2){
- ReplMark(o, ""); return;
- }
- if(lines[cur_pos.y][cur_pos.x]) {
- lines2text(); Undo.TextBuffer(this, &csize, &cpos, &text, 0L, o);
- cb = x = cur_pos.x; fmt_txt.cur_right(&x);
- cb = x - cb; if(cb < 1) cb = 1;
- for(i = cur_pos.x; lines[cur_pos.y][i]; i++) {
- if(!(lines[cur_pos.y][i] = lines[cur_pos.y][i+cb])) break;
- }
- c_char = lines[cur_pos.y][cur_pos.x]; lines[cur_pos.y][cur_pos.x] = 0x01;
- if(!c_char) lines[cur_pos.y][cur_pos.x+1] = 0x00;
- lines2text(); text2lines(o);
- DoPlot(o); o->UpdateRect(&rDims, false);
- ShowCursor(o); return;
- }
- else if(cur_pos.y < (nlines-1)){
- cur_pos.y++; cur_pos.x = 0;
- DelChar(o); return;
- }
-}
-
-void
-TextFrame::ReplMark(anyOutput *o, char *ntext)
-{
- int i, j;
-
- if(!has_m1 || !has_m2 || !o || !ntext) return;
- lines2text();
- Undo.TextBuffer(this, &csize, &cpos, &text, 0L, o);
- for(i = cpos = 0; i < nlines && i < m1_cpos.y; i++) {
- if(lines[i] && lines[i][0]) add_to_buff((char**)&text, &cpos, &csize, (char*)lines[i], 0);
- }
- if(m1_cpos.x)add_to_buff((char**)&text, &cpos, &csize, (char*)lines[i], m1_cpos.x);
- add_to_buff((char**)&text, &cpos, &csize, ntext, 0); j = cpos;
- if(m1_cpos.y == m2_cpos.y)add_to_buff((char**)&text, &cpos, &csize, (char*)(lines[i]+m2_cpos.x), 0);
- for( ; i < nlines && i < m2_cpos.y; i++);
- if(i == m2_cpos.y && m2_cpos.y > m1_cpos.y)add_to_buff((char**)&text, &cpos, &csize, (char*)(lines[i]+m2_cpos.x), 0);
- for(i++; i < nlines; i++) {
- if(lines[i] && lines[i][0]) add_to_buff((char**)&text, &cpos, &csize, (char*)lines[i], 0);
- }
- if(tm_rec)free(tm_rec); tm_rec = 0L; has_m1 = has_m2 = false;
- if(text[j]) {
- c_char = text[j]; text[j] = 0x01;
- }
- else if(i < (nlines-1) && lines[i+1] && lines[i+1][0]) {
- c_char = lines[i+1][0]; lines[i+1][0] = 0x01;
- }
- else if(j == cpos){
- c_char = 0; text[cpos++] = 0x01; text[cpos] = 0;
- }
- else cur_pos.x = cur_pos.y = 0;
- text2lines(o); DoPlot(o); o->UpdateRect(&rDims, false);
- ShowCursor(o);
-}
-
-void
-TextFrame::procTokens()
-{
- int i, j;
-
- for(i = 0; i < nlines; i++) {
- if(lines[i] && lines[i][0]){
- for(j = 0; lines[i][j]; j++) switch(lines[i][j]) {
- case 0x01:
- cur_pos.y = i; cur_pos.x = j;
- lines[i][j] = c_char; c_char = '?';
- break;
- case 0x02:
- m1_pos.y = i; m1_pos.x = j;
- if(m1_char == 0x01) {
- lines[i][j] = c_char; c_char = '?';
- cur_pos.y = i; cur_pos.x = j;
- }
- else lines[i][j] = m1_char;
- has_m1 = true; m1_char = '?';
- break;
- case 0x03:
- m2_pos.y = i; m2_pos.x = j;
- if(m2_char == 0x01) {
- lines[i][j] = c_char; c_char = '?';
- cur_pos.y = i; cur_pos.x = j;
- }
- else lines[i][j] = m2_char;
- has_m2 = true; m2_char = '?';
- break;
- }
- }
- }
-}
-
-bool
-TextFrame::DoPaste(anyOutput *o)
-{
- int i, j, k;
- char *ntxt;
- unsigned char *ptxt;
-
- if((ptxt = PasteText()) && ptxt[0]) {
- lines2text(); Undo.TextBuffer(this, &csize, &cpos, &text, 0L, o);
- if(!(ntxt = (char*)malloc(strlen((char*)ptxt)+1))) return false;
- for(i = j = cpos = 0; ptxt[i]; i++) {
- if(ptxt[i] >= ' ' || ptxt[i] == '\n') ntxt[j++] = ptxt[i];
- else if(ptxt[i] == 9)ntxt[j++] = ' '; //convert tab->space
- }
- ntxt[j] = 0;
- if(!ntxt[0]) {
- free(ntxt); return false;
- }
- if(has_m1 && has_m2) {
- ReplMark(o, ntxt); free(ntxt);
- return true;
- }
- m1_char = ntxt[0]; ntxt[0] = 0x02;
- ntxt[j] = 0; if(text) free(text);
- if(!(text = (unsigned char*)malloc(csize = 1000)))return false;
- for(i = k = 0, text[0] = 0; i < nlines; i++) {
- if(lines[i] && lines[i][0]){
- if(i == cur_pos.y) {
- if(cur_pos.x) add_to_buff((char**)&text, &cpos, &csize, (char*)lines[i], cur_pos.x);
- add_to_buff((char**)&text, &cpos, &csize, ntxt, 0); k = cpos;
- add_to_buff((char**)&text, &cpos, &csize, (char*)lines[i]+cur_pos.x, 0);
- free(ntxt); ntxt = 0L;
- }
- else add_to_buff((char**)&text, &cpos, &csize, (char*)lines[i], 0);
- }
- }
- if(ntxt) {
- add_to_buff((char**)&text, &cpos, &csize, ntxt, 0); k = cpos;
- }
- m2_char = 0x01;
- if(text[k]) {
- c_char = text[k]; text[k] = 0x03;
- }
- else if(i < (nlines-1) && lines[i+1] && lines[i+1][0]) {
- c_char = lines[i+1][0]; lines[i+1][0] = 0x03;
- }
- else if(k == cpos){
- c_char = 0; text[cpos++] = 0x03; text[cpos] = 0;
- }
- text2lines(o); DoPlot(o);
- o->UpdateRect(&rDims, false);
- ShowCursor(o); if(ntxt) free(ntxt);
- }
- return false;
-}
-void
-TextFrame::TextMark(anyOutput *o, int mode)
-{
- int i, j, w, h;
- LineDEF ld;
- FillDEF fd;
-
- if(m1_pos.y > m2_pos.y) {
- m1_cpos.y = m2_pos.y; m1_cpos.x = m2_pos.x;
- m2_cpos.y = m1_pos.y; m2_cpos.x = m1_pos.x;
- }
- else if(m1_pos.y == m2_pos.y && m1_pos.x > m2_pos.x) {
- m1_cpos.x = m2_pos.x; m2_cpos.x = m1_pos.x;
- m1_cpos.y = m2_cpos.y = m1_pos.y;
- }
- else {
- m1_cpos.y = m1_pos.y; m1_cpos.x = m1_pos.x;
- m2_cpos.y = m2_pos.y; m2_cpos.x = m2_pos.x;
- }
- if(!has_m1 || !has_m2 || !o) return;
- if(m1_pos.y == m2_pos.y && m1_pos.x == m2_pos.x) return;
- if(mode == 1){ //create background mark
- if(tm_rec)free(tm_rec); tm_rec = 0L;
- if((tm_c = m2_cpos.y - m1_cpos.y +1)<1) return;
- if(!(tm_rec = (RECT*)malloc(tm_c * sizeof(RECT))))return;
- for(i = w = 0, j = m1_cpos.y; j <= m2_cpos.y; i++, j++) {
- h = TextDef.iSize;
- if(j == m1_cpos.y) {
- fmt_txt.SetText(0L, (char*)lines[j], 0L, 0L);
- if(m1_cpos.x) fmt_txt.oGetTextExtent(o, &w, &h, m1_cpos.x);
- else w = 0;
- tm_rec[0].left = w + rDims.left + ipad.left + 1;
- fmt_txt.SetText(0L, (char*)(lines[j]+m1_cpos.x), 0L, 0L);
- fmt_txt.oGetTextExtent(o, &w, &h, 0);
- tm_rec[0].right = tm_rec[0].left + w;
- }
- if(j == m2_cpos.y) {
- fmt_txt.SetText(0L, (char*)lines[j], 0L, 0L);
- if(m2_cpos.x) fmt_txt.oGetTextExtent(o, &w, &h, m2_cpos.x);
- else w = 0;
- tm_rec[i].right = w + rDims.left + ipad.left - 1;
- if(m2_cpos.y > m1_cpos.y) {
- tm_rec[i].left = rDims.left + ipad.left;
- }
- }
- else if(j < m2_cpos.y && j > m1_cpos.y) {
- tm_rec[i].left = rDims.left + ipad.left;
- tm_rec[i].top = j * linc + rDims.top + ipad.top;
- fmt_txt.SetText(0L, (char*)lines[j], 0L, 0L);
- fmt_txt.oGetTextExtent(o, &w, &h, 0);
- tm_rec[i].right = w + rDims.left + ipad.left;
- }
- tm_rec[i].top = j * linc + rDims.top + ipad.top;
- tm_rec[i].bottom = tm_rec[i].top + linc;
- }
- ld.color = 0x0000ffff; ld.patlength = 1.0;
- ld.pattern = 0x0L; ld.width = 0;
- fd.color = fd.color2 = ld.color; fd.hatch = 0L;
- fd.scale = 1.0; fd.type = 0;
- o->SetLine(&ld); o->SetFill(&fd);
- for(i = 0; i < tm_c; i++) {
- o->oRectangle(tm_rec[i].left, tm_rec[i].top, tm_rec[i].right, tm_rec[i].bottom, 0L);
- }
- }
- if(mode == 2){ //invert rectangles
- if(tm_rec) for(i = 0; i < tm_c; i++) {
- o->CopyBitmap(tm_rec[i].left, tm_rec[i].top, o, tm_rec[i].left, tm_rec[i].top,
- tm_rec[i].right - tm_rec[i].left, tm_rec[i].bottom - tm_rec[i].top, true);
- }
- }
- if(mode == 3){ //clear mark
- if(tm_rec)free(tm_rec); tm_rec = 0L;
- tm_c = 0; has_m1 = has_m2 = false;
- DoPlot(o); o->UpdateRect(&rDims, false);
- }
-}
-
-bool
-TextFrame::CopyText(anyOutput *o, bool b_cut)
-{
- int i, csize, pos = 0;
- char *ntxt;
-
- if(!lines || !lines[0][0] || !o) return false;
- if(!has_m1 || !has_m2) {
- m1_pos.x = m1_pos.y = 0; m2_pos.y = nlines-1;
- if(lines[nlines-1]) m2_pos.x = (int)strlen((char*)lines[nlines-1]);
- else m2_pos.x = 0; has_m1 = has_m2 = true;
- DoPlot(o); o->UpdateRect(&rDims, false);
- return CopyText(o, false);
- }
- if(!(ntxt = (char*)malloc(csize = 1000))) return false;
- if(m1_cpos.y == m2_cpos.y) {
- add_to_buff(&ntxt, &pos, &csize, (char*)(lines[m1_cpos.y]) + m1_cpos.x, m2_cpos.x - m1_cpos.x);
- ::CopyText(ntxt, pos); free(ntxt);
- }
- else if(m1_cpos.y < m2_cpos.y){
- add_to_buff(&ntxt, &pos, &csize, (char*)(lines[m1_cpos.y]) + m1_cpos.x, 0);
- for(i = m1_cpos.y; i < m2_cpos.y; i++) {
- add_to_buff(&ntxt, &pos, &csize, (char*)(lines[i]), 0);
- }
- add_to_buff(&ntxt, &pos, &csize, (char*)(lines[i]), m2_pos.x);
- ::CopyText(ntxt, pos); free(ntxt);
- }
- else {
- free(ntxt); return false;
- }
- if(b_cut) ReplMark(o, "");
- return true;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 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_SCALE:
- fCent.fx *= ((scaleINFO*)tmpl)->sx.fy; fCent.fy *= ((scaleINFO*)tmpl)->sx.fy;
- radius1 *= ((scaleINFO*)tmpl)->sx.fy; radius2 *= ((scaleINFO*)tmpl)->sx.fy;
- segLine.width *= ((scaleINFO*)tmpl)->sx.fy; segLine.patlength *= ((scaleINFO*)tmpl)->sx.fy;
- segFillLine.width *= ((scaleINFO*)tmpl)->sx.fy; segFillLine.patlength *= ((scaleINFO*)tmpl)->sx.fy;
- segFill.scale *= ((scaleINFO*)tmpl)->sx.fy; shift *= ((scaleINFO*)tmpl)->sx.fy;
- return true;
- case CMD_LEGEND:
- if(tmpl) {
- leg = new LegItem(this, data, 0L, &segLine, &segFill, 0L);
- 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(cpts && (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);
- if(this == CurrGO) o->ShowMark(this, MRK_GODRAW);
- else switch(type) {
- case 0: //line
- o->SetLine(&pgLine); o->oPolyline(pts, nPts);
- break;
- case 1: //polygon
- o->SetLine(&pgLine); 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);;
- o->UpdateRect(&upd, false);
- }
- else {
- if(parent) parent->DoPlot(o);
- }
-}
-
-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_SCALE:
- if(Values) for(i = 0; i < nPoints; i++){
- Values[i].fx = ((scaleINFO*)tmpl)->sx.fx + Values[i].fx * ((scaleINFO*)tmpl)->sx.fy;
- Values[i].fy = ((scaleINFO*)tmpl)->sy.fx + Values[i].fy * ((scaleINFO*)tmpl)->sy.fy;
- }
- pgLine.patlength *= ((scaleINFO*)tmpl)->sy.fy; pgLine.width *= ((scaleINFO*)tmpl)->sy.fy;
- pgFillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy; pgFillLine.width *= ((scaleINFO*)tmpl)->sy.fy;
- pgFill.scale *= ((scaleINFO*)tmpl)->sy.fy;
- 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;
- return o->ShowMark(CurrGO=this, MRK_GODRAW);
- }
- 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;
- double dx, dy;
- POINT hpts[3];
- LineDEF gl = {0.0, 1.0, 0x00c0c0c0, 0};
-
- if(nPoints >= 200 || !o) return;
- if(!pHandles && (pHandles = (dragHandle**)calloc(nPoints+4, sizeof(dragHandle*)))){
- for(i = 0; i < nPoints; i++) pHandles[i] = new dragHandle(this, DH_DATA+i);
- }
- if(!pHandles) return;
- if(Id == GO_BEZIER && parent && nPoints > 3) {
- dx = parent->GetSize(SIZE_GRECT_LEFT); dy = parent->GetSize(SIZE_GRECT_TOP);
- o->SetLine(&gl);
- hpts[0].x = o->co2ix(Values[0].fx+dx); hpts[0].y = o->co2iy(Values[0].fy+dy);
- hpts[1].x = o->co2ix(Values[1].fx+dx); hpts[1].y = o->co2iy(Values[1].fy+dy);
- o->oPolyline(hpts, 2);
- for(i = 3; i < (nPoints-2); i += 3) {
- hpts[0].x = o->co2ix(Values[i-1].fx+dx); hpts[0].y = o->co2iy(Values[i-1].fy+dy);
- hpts[1].x = o->co2ix(Values[i].fx+dx); hpts[1].y = o->co2iy(Values[i].fy+dy);
- hpts[2].x = o->co2ix(Values[i+1].fx+dx); hpts[2].y = o->co2iy(Values[i+1].fy+dy);
- o->oPolyline(hpts, 3);
- }
- hpts[0].x = o->co2ix(Values[i-1].fx+dx); hpts[0].y = o->co2iy(Values[i-1].fy+dy);
- hpts[1].x = o->co2ix(Values[i].fx+dx); hpts[1].y = o->co2iy(Values[i].fy+dy);
- o->oPolyline(hpts, 2);
- }
- for(i = 0; i < nPoints; i++) if(pHandles[i]) pHandles[i]->DoPlot(o);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Beziers are based on the polyline object
-Bezier::Bezier(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts, int mode, double res):
- polyline(par, d, 0L, 0)
-{
- double dx, dy, merr;
- int i;
-
- type = mode;
- Id = GO_BEZIER;
-
- if(!parent) return;
- dx = parent->GetSize(SIZE_GRECT_LEFT); dy = parent->GetSize(SIZE_GRECT_TOP);
- if(type == 0 && (Values = (lfPOINT*)malloc(4 * cpts * sizeof(lfPOINT)))) {
- merr = 0.01 * res / Units[defs.cUnits].convert;
- FitCurve(fpts, cpts, merr);
- Values[nPoints].fx = fpts[cpts-1].fx; Values[nPoints].fy = fpts[cpts-1].fy;
- for(i = 0; i < nPoints; i++) {
- Values[i].fx -= dx; Values[i].fy -= dy;
- }
- nPoints ++;
- }
- return;
-}
-
-Bezier::Bezier(int src):polyline(0L, 0L, 0L, 0)
-{
- if(src == FILE_READ) {
- FileIO(FILE_READ);
- }
-}
-
-void
-Bezier::DoPlot(anyOutput *o)
-{
- POINT *tmppts;
- double dx, dy;
- int i;
-
- if(!Values || !nPoints || !o || !parent) return;
- if(pts) free(pts); pts = 0L;
- dx = parent->GetSize(SIZE_GRECT_LEFT); dy = parent->GetSize(SIZE_GRECT_TOP);
- if(!(tmppts = (POINT*)malloc((nPoints+2)*sizeof(POINT))))return;
- for(i = 0; i < nPoints; i++){
- tmppts[i].x = o->co2ix(Values[i].fx + dx); tmppts[i].y = o->co2iy(Values[i].fy + dy);
- }
- rDims.left = rDims.right = tmppts[0].x; rDims.top = rDims.bottom = tmppts[0].y;
- for(i = 1; i < nPoints; i++) {
- if(tmppts[i].x < rDims.left) rDims.left = tmppts[i].x;
- else if(tmppts[i].x > rDims.right) rDims.right = tmppts[i].x;
- if(tmppts[i].y < rDims.top) rDims.top = tmppts[i].y;
- else if(tmppts[i].y > rDims.bottom) rDims.bottom = tmppts[i].y;
- }
- //DrawBezier returns not more than 2^MAXDEPTH points
- pts = (POINT*)malloc(nPoints * 64 * sizeof(POINT));
- for(i= nPts = 0; i< (nPoints-2); i += 3) {
- DrawBezier(&nPts, pts, tmppts[i], tmppts[i+1], tmppts[i+2], tmppts[i+3], 0);
- }
- IncrementMinMaxRect(&rDims, 3);
- o->ShowLine(pts, nPts, 0x00c0c0c0L);
- if(this == CurrGO) o->ShowMark(this, MRK_GODRAW);
- else {
- o->SetLine(&pgLine); o->oPolyline(pts, nPts);
- }
-}
-
-bool
-Bezier::Command(int cmd, void *tmpl, anyOutput *o)
-{
- int i, i1, i2;
-
- 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_DELOBJ:
- if(pHandles && tmpl && tmpl == (void*)CurrHandle) {
- i = CurrHandle->type - DH_DATA;
- if (i >= 0 && i < nPoints) {
- i = CurrHandle->type - DH_DATA;
- Undo.DataMem(this, (void**)&Values, nPoints * sizeof(lfPOINT), &nPoints, 0L);
- if (i < 2) {
- i1 = 0; i2 = 3;
- }
- else if (i > (nPoints-3)) {
- i1 = nPoints -3; i2 = nPoints;
- }
- else {
- i -= (((i-2) % 3)-1); i1 = i -1; i2 = i +2;
- RemovePoint(Values, i1+1);
- Values[i2].fx = Values[i1].fx; Values[i2].fy = Values[i1].fy;
- }
- for(i = 0; i < nPoints; i++) if(pHandles[i]) delete(pHandles[i]);
- free(pHandles); pHandles = 0L; CurrHandle = 0L;
- i = i2 - i1;
- for( ; i2 < nPoints; i1++, i2++) {
- Values[i1].fx = Values[i2].fx; Values[i1].fy = Values[i2].fy;
- }
- nPoints -= i; CurrGO = this; bModified = true;
- return true;
- }
- }
- return false;
- case CMD_SET_DATAOBJ:
- Id = GO_BEZIER;
- return true;
- }
- return polyline::Command(cmd, tmpl, o);
-}
-
-void
-Bezier::AddPoints(int n, lfPOINT *p)
-{
- int i;
-
- for(i = 0; i< n; i++) {
- Values[nPoints].fx = p[i].fx; Values[nPoints].fy = p[i].fy;
- nPoints ++;
- }
-}
-
-//Fitting of a Bezier curve to digitized points is based on:
-// P.J. Schneider (1990) An Algorithm for Automatically Fitting Digitized
-// Curves. In: Graphics Gems (Ed. A. Glassner, Academic Press Inc.,
-// ISBN 0-12-286165-5) pp. 612ff
-void
-Bezier::FitCurve(lfPOINT *d, int npt, double error)
-{
- double len;
- lfPOINT tHat1, tHat2;
-
- tHat1.fx = d[1].fx - d[0].fx; tHat1.fy = d[1].fy - d[0].fy;
- if(0.0 != (len = sqrt((tHat1.fx * tHat1.fx) + (tHat1.fy * tHat1.fy)))) {
- tHat1.fx /= len; tHat1.fy /= len;
- }
- tHat2.fx = d[npt-2].fx - d[npt-1].fx; tHat2.fy = d[npt-2].fy - d[npt-1].fy;
- if(0.0 != (len = sqrt((tHat2.fx * tHat2.fx) + (tHat2.fy * tHat2.fy)))) {
- tHat2.fx /= len; tHat2.fy /= len;
- }
- FitCubic(d, 0, npt -1, tHat1, tHat2, error);
-}
-
-void
-Bezier::RemovePoint(lfPOINT *d, int sel)
-{
- lfPOINT tHat1, tHat2;
-
- tHat1.fx = d[sel-2].fx - d[sel-3].fx; tHat1.fy = d[sel-2].fy - d[sel-3].fy;
- tHat2.fx = d[sel+2].fx - d[sel+3].fx; tHat2.fy = d[sel+2].fy - d[sel+3].fy;
- d[sel] = d[sel+3];
- IpolBez(d+sel-3, tHat1, tHat2);
-}
-
-//heuristic interpolation: other methods failed
-void
-Bezier::IpolBez(lfPOINT *d, lfPOINT tHat1, lfPOINT tHat2)
-{
- double b0, b1, b2; //temp variables
-
- b1 = d[3].fx - d[0].fx; b2 = d[3].fy - d[0].fy;
- b0 = sqrt(b1 * b1 + b2 * b2)/3.0;
- b1 = b0/sqrt(tHat1.fx * tHat1.fx + tHat1.fy * tHat1.fy);
- b2 = b0/sqrt(tHat2.fx * tHat2.fx + tHat2.fy * tHat2.fy);
- d[1].fx = d[0].fx + tHat1.fx * b1; d[1].fy = d[0].fy + tHat1.fy * b1;
- d[2].fx = d[3].fx + tHat2.fx * b2; d[2].fy = d[3].fy + tHat2.fy * b2;
-}
-
-//Fit a Bezier curve to a (sub)set of digitized points
-void
-Bezier::FitCubic(lfPOINT *d, int first, int last, lfPOINT tHat1, lfPOINT tHat2, double error)
-{
- lfPOINT bezCurve[4];
- double *u, *uPrime, maxError, iterationError, len;
- int i, splitPoint, npt;
- lfPOINT tHatCenter;
- int maxIterations = 8;
-
- iterationError = error * error;
- npt = last - first +1;
- if(npt == 2) {
- bezCurve[0] = d[first]; bezCurve[3] = d[last];
- IpolBez(bezCurve, tHat1, tHat2);
- AddPoints(3, bezCurve);
- return;
- }
- u = ChordLengthParameterize(d, first, last);
- GenerateBezier(d, first, last, u, tHat1, tHat2, bezCurve);
- maxError = ComputeMaxError(d, first, last, bezCurve, u, &splitPoint);
- if(maxError < error) {
- if(maxError < 0.0) { //Failure fitting curve
- IpolBez(bezCurve, tHat1, tHat2);
- }
- AddPoints(3, bezCurve); return;
- }
- if(maxError < iterationError) {
- for (i = 0; i < maxIterations; i++) {
- uPrime = Reparameterize(d, first, last, u, bezCurve);
- GenerateBezier(d, first, last, uPrime, tHat1, tHat2, bezCurve);
- maxError = ComputeMaxError(d, first, last, bezCurve, uPrime, &splitPoint);
- if (maxError < error) {
- if(maxError < 0.0) IpolBez(bezCurve, tHat1, tHat2);
- AddPoints(3, bezCurve); return;
- }
- free(u); u = uPrime;
- }
- }
- //Fitting failed: split at max error point and recurse
- tHatCenter.fx = d[splitPoint-1].fx - d[splitPoint+1].fx;
- tHatCenter.fy = d[splitPoint-1].fy - d[splitPoint+1].fy;
- if(0.0 != (len = sqrt((tHatCenter.fx * tHatCenter.fx) + (tHatCenter.fy * tHatCenter.fy)))) {
- tHatCenter.fx /= len; tHatCenter.fy /= len;
- }
- FitCubic(d, first, splitPoint, tHat1, tHatCenter, error * _SQRT2);
- tHatCenter.fx = -tHatCenter.fx; tHatCenter.fy = -tHatCenter.fy;
- FitCubic(d, splitPoint, last, tHatCenter, tHat2, error * _SQRT2);
-}
-
-//Use least-squares method to find Bezier control points for region.
-void
-Bezier::GenerateBezier(lfPOINT *d, int first, int last, double *uPrime,
- lfPOINT tHat1, lfPOINT tHat2, lfPOINT *bezCurve)
-{
- int i, npt;
- lfPOINT *A0, *A1, tmp, v1, v2;
- double C[2][2], X[2];
- double det_C0_C1, det_C0_X, det_X_C1, alpha_l, alpha_r;
- double b0, b1, b2, b3; //temp variables
-
- npt = last - first +1;
- A0 = (lfPOINT*) malloc(npt * sizeof(lfPOINT));
- A1 = (lfPOINT*) malloc(npt * sizeof(lfPOINT));
- for (i = 0; i < npt; i++) {
- v1 = tHat1; v2 = tHat2;
- b2 = 1.0 - uPrime[i];
- b1 = 3.0 * uPrime[i] * b2 * b2; b2 = 3.0 * uPrime[i] * uPrime[i] * b2;
- if(0.0 != (b0 = sqrt((v1.fx * v1.fx) + (v1.fy * v1.fy)))) {
- v1.fx *= b1/b0; v1.fy *= b1/b0;
- }
- if(0.0 != (b0 = sqrt((v2.fx * v2.fx) + (v2.fy * v2.fy)))) {
- v2.fx *= b2/b0; v2.fy *= b2/b0;
- }
- A0[i] = v1; A1[i] = v2;
- }
- C[0][0] = C[0][1] = C[1][0] = C[1][1] = X[0] = X[1] = 0.0;
- for (i = 0; i < npt; i++) {
- C[0][0] += ((A0[i].fx * A0[i].fx) + (A0[i].fy * A0[i].fy));
- C[0][1] += ((A0[i].fx * A1[i].fx) + (A0[i].fy * A1[i].fy));
- C[1][0] = C[0][1];
- C[1][1] += ((A1[i].fx * A1[i].fx) + (A1[i].fy * A1[i].fy));
- b2 = 1.0 - uPrime[i]; b0 = b2 * b2 * b2;
- b1 = 3.0 * uPrime[i] * b2 * b2; b2 = 3.0 * uPrime[i] * uPrime[i] * b2;
- b3 = uPrime[i] * uPrime[i] * uPrime[i];
- tmp.fx = d[last].fx * b2 + d[last].fx * b3;
- tmp.fy = d[last].fy * b2 + d[last].fy * b3;
- tmp.fx += d[first].fx * b1; tmp.fy += d[first].fy * b1;
- tmp.fx += d[first].fx * b0; tmp.fy += d[first].fy * b0;
- tmp.fx = d[first+i].fx - tmp.fx; tmp.fy = d[first+i].fy - tmp.fy;
- X[0] += (A0[i].fx * tmp.fx + A0[i].fy * tmp.fy);
- X[1] += (A1[i].fx * tmp.fx + A1[i].fy * tmp.fy);
- }
- det_C0_C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1];
- det_C0_X = C[0][0] * X[1] - C[0][1] * X[0];
- det_X_C1 = X[0] * C[1][1] - X[1] * C[0][1];
- if(det_C0_C1 == 0.0) det_C0_C1 = (C[0][0] * C[1][1]) * 10e-12;
- alpha_l = det_X_C1 / det_C0_C1; alpha_r = det_C0_X / det_C0_C1;
- bezCurve[0] = d[first]; bezCurve[3] = d[last];
- if(alpha_l < 0.0 || alpha_r < 0.0) {
- //use Wu/Barsky heuristic
- b1 = d[last].fx - d[first].fx; b2 = d[last].fy - d[first].fy;
- b0 = sqrt(b1 * b1 + b2 * b2)/3.0;
- b1 = b0/sqrt(tHat1.fx * tHat1.fx + tHat1.fy * tHat1.fy);
- b2 = b0/sqrt(tHat2.fx * tHat2.fx + tHat2.fy * tHat2.fy);
- }
- else {
- b1 = alpha_l/sqrt(tHat1.fx * tHat1.fx + tHat1.fy * tHat1.fy);
- b2 = alpha_r/sqrt(tHat2.fx * tHat2.fx + tHat2.fy * tHat2.fy);
- }
- bezCurve[1].fx = bezCurve[0].fx + tHat1.fx * b1;
- bezCurve[1].fy = bezCurve[0].fy + tHat1.fy * b1;
- bezCurve[2].fx = bezCurve[3].fx + tHat2.fx * b2;
- bezCurve[2].fy = bezCurve[3].fy + tHat2.fy * b2;
- free(A0); free(A1);
-}
-
-//Given set of points and their parameterization, try to find
-// a better parameterization.
-double *
-Bezier::Reparameterize(lfPOINT *d, int first, int last, double *u, lfPOINT *bezCurve)
-{
- int i, j, k, npt = last-first+1;
- double *uPrime, num, den, *pl, *ph, *pq;
- lfPOINT Q1[3], Q2[2], Q_u, Q1_u, Q2_u;
-
- uPrime = (double*)malloc(npt * sizeof(double));
- //Use Newton-Raphson iteration to find better root
- for (i = first, j = 0; i <= last; i++, j++) {
- for(pl=(double*)bezCurve, ph=pl+2, pq=(double*)Q1, k=0; k <= 4; pl++, ph++, pq++, k++) {
- *pq = (*ph - *pl ) * 3.0;
- }
- for(pl=(double*)Q1, ph=pl+2, pq=(double*)Q2, k=0; k <= 2; pl++, ph++, pq++, k++) {
- *pq = (*ph - *pl ) * 2.0;
- }
- Q_u = fBezier(3, bezCurve, u[j]);
- Q1_u = fBezier(2, Q1, u[j]);
- Q2_u = fBezier(1, Q2, u[j]);
- num = (Q_u.fx - d[i].fx) * (Q1_u.fx) + (Q_u.fy - d[i].fy) * (Q1_u.fy);
- den = (Q1_u.fx) * (Q1_u.fx) + (Q1_u.fy) * (Q1_u.fy) +
- (Q_u.fx - d[i].fx) * (Q2_u.fx) + (Q_u.fy - d[i].fy) * (Q2_u.fy);
- uPrime[j] = u[j] - (num/den);
- }
- return uPrime;
-}
-
-//evaluate a Bezier curve at a particular parameter value
-lfPOINT
-Bezier::fBezier(int degree, lfPOINT *V, double t)
-{
- int i, j;
- lfPOINT Q;
- lfPOINT *Vtemp;
-
- Vtemp = (lfPOINT *)malloc((degree+1) * sizeof(lfPOINT));
- for (i = 0; i <= degree; i++) {
- Vtemp[i] = V[i];
- }
- for (i = 1; i <= degree; i++) {
- for (j = 0; j <= degree-i; j++) {
- Vtemp[j].fx = (1.0 -t) * Vtemp[j].fx + t * Vtemp[j+1].fx;
- Vtemp[j].fy = (1.0 -t) * Vtemp[j].fy + t * Vtemp[j+1].fy;
- }
- }
- Q = Vtemp[0];
- free(Vtemp);
- return Q;
-}
-
-double *
-Bezier::ChordLengthParameterize(lfPOINT *d, int first, int last)
-{
- int i;
- double tmp, *u;
-
- u = (double*)malloc((last-first+1) * sizeof(double));
- u[0] = 0.0;
- for(i = first+1; i <= last; i++) {
- u[i-first] = u[i-first-1] +
- sqrt(((tmp=(d[i].fx - d[i-1].fx))*tmp) + ((tmp=(d[i].fy - d[i-1].fy))*tmp));
- }
- for(i = first +1; i <= last; i++) {
- u[i-first] = u[i-first] / u[last-first];
- }
- return u;
-}
-
-double
-Bezier::ComputeMaxError(lfPOINT *d, int first, int last, lfPOINT *bezCurve, double *u, int *splitPoint)
-{
- int i;
- double maxDist, dist;
- lfPOINT P, v;
-
- *splitPoint = (last - first + 1)>>1;
- maxDist = -1.0;
- for(i = first +1; i < last; i++) {
- P = fBezier(3, bezCurve, u[i-first]);
- v.fx = P.fx - d[i].fx; v.fy = P.fy - d[i].fy;
- dist = v.fx * v.fx + v.fy * v.fy;
- if(dist >= maxDist) {
- maxDist = dist; *splitPoint = i;
- }
- }
- return maxDist;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 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);
- if(drc) delete(drc); drc = 0L;
-}
-
-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_SCALE:
- fp1.fx = ((scaleINFO*)tmpl)->sx.fx + fp1.fx * ((scaleINFO*)tmpl)->sx.fy;
- fp2.fx = ((scaleINFO*)tmpl)->sx.fx + fp2.fx * ((scaleINFO*)tmpl)->sx.fy;
- fp1.fy = ((scaleINFO*)tmpl)->sy.fx + fp1.fy * ((scaleINFO*)tmpl)->sy.fy;
- fp2.fy = ((scaleINFO*)tmpl)->sy.fx + fp2.fy * ((scaleINFO*)tmpl)->sy.fy;
- Line.patlength *= ((scaleINFO*)tmpl)->sy.fy; Line.width *= ((scaleINFO*)tmpl)->sy.fy;
- FillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy; FillLine.width *= ((scaleINFO*)tmpl)->sy.fy;
- Fill.scale *= ((scaleINFO*)tmpl)->sy.fy; rad *= ((scaleINFO*)tmpl)->sy.fy;
- 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)){
- return o->ShowMark(this, MRK_GODRAW);
- }
- }
- 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, char *desc)
- :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(desc); Id = GO_LEGITEM; moveable = 1;
-}
-
-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(sy ? sy->name : 0L); Id = GO_LEGITEM; moveable = 1;
-}
-
-LegItem::LegItem(GraphObj *par, DataObj *d, LineDEF *ld, int err, char *desc)
- :GraphObj(par, d)
-{
- FileIO(INIT_VARS); flags |= (0x80 | (err & 0x7f));
- if(ld) {
- memcpy(&OutLine, ld, sizeof(LineDEF));
- }
- DefDesc(desc); Id = GO_LEGITEM; moveable = 1;
-}
-
-LegItem::LegItem(int src):GraphObj(0L, 0L)
-{
- FileIO(INIT_VARS);
- if(src == FILE_READ) {
- FileIO(FILE_READ);
- }
- moveable = 1;
-}
-
-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[3];
- int ie, cy;
-
- if(!parent || !o) return;
- hcr.top = iround(parent->GetSize(SIZE_YPOS));
- hcr.bottom = iround(parent->GetSize(SIZE_YPOS+1));
- if(flags & 0x80) {
- hcr.left = iround(parent->GetSize((flags & 0x40) ? SIZE_XPOS+2 : SIZE_XPOS));
- hcr.right = iround(parent->GetSize((flags & 0x40) ? SIZE_XPOS+3 :SIZE_XPOS+1));
- ie = o->un2ix(DefSize(SIZE_ERRBAR)/2.0);
- o->SetLine(&OutLine); cy = (hcr.top + hcr.bottom)>>1;
- if((flags & 0x3f) == 0x01) {
- pts[0].x = pts[1].x = (hcr.right + hcr.left)>>1;
- pts[0].y = hcr.top; pts[1].y = hcr.bottom;
- o->oPolyline(pts, 2, 0L);
- pts[0].x -= (ie-1); pts[1].x += ie; pts[0].y = pts[1].y = hcr.top;
- o->oPolyline(pts, 2, 0L); pts[0].y = pts[1].y = hcr.bottom;
- o->oPolyline(pts, 2, 0L);
- }
- else if((flags & 0x3f) == 0x02) {
- pts[0].x = pts[1].x = ((hcr.right + hcr.left)>>1);
- pts[0].y = pts[1].y = cy; cy = ((hcr.bottom - hcr.top)>>1);
- pts[0].x -= cy; pts[2].x = (pts[1].x += cy);
- o->oPolyline(pts, 2, 0L); pts[1].x = pts[0].x;
- pts[0].y -= ie; pts[1].y += ie;
- o->oPolyline(pts, 2, 0L);
- pts[0].x = pts[1].x = pts[2].x; o->oPolyline(pts, 2, 0L);
- }
- else if((flags & 0x3f) == 0x03) {
- pts[0].x = pts[1].x = (hcr.right + hcr.left)>>1;
- pts[0].y = hcr.top; pts[1].y = hcr.bottom;
- o->oPolyline(pts, 2, 0L); pts[0].x -= (ie-1);
- pts[0].y = pts[1].y = hcr.top; o->oPolyline(pts, 2, 0L);
- pts[0].y = pts[1].y = hcr.bottom; pts[0].x += (ie + ie -1);
- o->oPolyline(pts, 2, 0L);
- }
- else if((flags & 0x3f) == 0x04) {
- pts[0].x = pts[1].x = (hcr.right + hcr.left)>>1;
- pts[0].y = hcr.top; pts[1].y = hcr.bottom;
- o->oPolyline(pts, 2, 0L); pts[0].x += ie;
- pts[0].y = pts[1].y = hcr.top; o->oPolyline(pts, 2, 0L);
- pts[0].y = pts[1].y = hcr.bottom; pts[0].x -= (ie + ie -1);
- o->oPolyline(pts, 2, 0L);
- }
- else if((flags & 0x3f) == 0x05) {
- pts[0].x = pts[1].x = (hcr.right + hcr.left)>>1;
- pts[0].y = hcr.top; pts[1].y = hcr.bottom;
- o->oPolyline(pts, 2, 0L);
- }
- }
- else {
- 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));
- 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);
- }
- }
- SetMinMaxRect(&rDims, hcr.left, hcr.top, hcr.right, hcr.bottom);
- if(Desc) {
- Desc->moveable = 1; 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_TEXTTHERE:
- if(Desc && Desc->Command(cmd, tmpl, o)) return true;
- return false;
- 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_SCALE:
- DataLine.patlength *= ((scaleINFO*)tmpl)->sy.fy; DataLine.width *= ((scaleINFO*)tmpl)->sy.fy;
- OutLine.patlength *= ((scaleINFO*)tmpl)->sy.fy; OutLine.width *= ((scaleINFO*)tmpl)->sy.fy;
- HatchLine.patlength *= ((scaleINFO*)tmpl)->sy.fy; HatchLine.width *= ((scaleINFO*)tmpl)->sy.fy;
- Fill.scale *= ((scaleINFO*)tmpl)->sy.fy;
- if(Sym) Sym->Command(cmd, tmpl, o);
- if(Desc) Desc->Command(cmd, tmpl, o);
- break;
- 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:
- if(Desc) Desc->Command(cmd, tmpl, o);
- 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, char *desc)
-{
- 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 && (sy->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;
-}
-
-bool
-LegItem::HasErr(LineDEF *ld, int err)
-{
- if((((DWORD)err & 0x1f) | 0x80) != (flags & 0x9f)) return false;
- if(ld && cmpLineDEF(ld, &OutLine)) return false;
- return true;
-}
-
-void
-LegItem::DefDesc(char *txt)
-{
- TextDEF td;
- int cb;
-
- cb = txt && *txt ? (int)strlen(txt) : 20;
- if(cb < 20) cb = 20;
- td.ColTxt = 0x00000000L; td.ColBg = 0x00ffffffL;
- td.fSize = DefSize(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 = (char*)malloc(cb+2);
- rlp_strcpy(td.text, cb+2, txt ? txt : (char*)"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.top = iround(C_Rect.Ymin); rDims.bottom = iround(C_Rect.Ymax);
- rDims.left = rDims.right = iround(C_Rect.Xmin);
- 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]){
- if((Items[i]->flags & 0x11) == 0x01) hasLine = true;
- Items[i]->DoPlot(o);
- 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_TEXTTHERE:
- if(Items) for(i = 0; i< nItems; i++)
- if(Items[i] && Items[i]->Command(cmd, tmpl, o)) return true;
- return false;
- 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_SCALE:
- pos.fx *= ((scaleINFO*)tmpl)->sx.fy; pos.fy *= ((scaleINFO*)tmpl)->sy.fy;
- lb_pos.fx *= ((scaleINFO*)tmpl)->sx.fy; lb_pos.fy *= ((scaleINFO*)tmpl)->sy.fy;
- B_Rect.Xmax *= ((scaleINFO*)tmpl)->sx.fy; B_Rect.Xmin *= ((scaleINFO*)tmpl)->sx.fy;
- B_Rect.Ymax *= ((scaleINFO*)tmpl)->sy.fy; B_Rect.Ymin *= ((scaleINFO*)tmpl)->sy.fy;
- C_Rect.Xmax *= ((scaleINFO*)tmpl)->sx.fy; C_Rect.Xmin *= ((scaleINFO*)tmpl)->sx.fy;
- C_Rect.Ymax *= ((scaleINFO*)tmpl)->sy.fy; C_Rect.Ymin *= ((scaleINFO*)tmpl)->sy.fy;
- D_Rect.Xmax *= ((scaleINFO*)tmpl)->sx.fy; D_Rect.Xmin *= ((scaleINFO*)tmpl)->sx.fy;
- D_Rect.Ymax *= ((scaleINFO*)tmpl)->sy.fy; D_Rect.Ymin *= ((scaleINFO*)tmpl)->sy.fy;
- E_Rect.Xmax *= ((scaleINFO*)tmpl)->sx.fy; E_Rect.Xmin *= ((scaleINFO*)tmpl)->sx.fy;
- E_Rect.Ymax *= ((scaleINFO*)tmpl)->sy.fy; E_Rect.Ymin *= ((scaleINFO*)tmpl)->sy.fy;
- F_Rect.Xmax *= ((scaleINFO*)tmpl)->sx.fy; F_Rect.Xmin *= ((scaleINFO*)tmpl)->sx.fy;
- F_Rect.Ymax *= ((scaleINFO*)tmpl)->sy.fy; F_Rect.Ymin *= ((scaleINFO*)tmpl)->sy.fy;
- if(Items) for(i = 0; i < nItems; i++) if(Items[i]) Items[i]->Command(cmd, tmpl, o);
- return true;
- 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, char *desc)
-{
- int i;
- LegItem *li;
-
- if(Items) for(i = 0; i < nItems; i++) {
- if(Items[i] && Items[i]->HasFill(ld, fd, desc)) return true;
- }
- if(li = new LegItem(this, data, 0L, ld, fd, desc)){
- if(!(Command(CMD_DROP_OBJECT, li, 0L))) DeleteGO(li);
- }
- return false;
-}
-
-bool
-Legend::HasSym(LineDEF *ld, GraphObj *sy, char *desc)
-{
- int i, sym;
- Symbol *ns;
- LegItem *li;
-
- if(!parent || !sy) return true;
- if(ld) hasLine = 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(desc && desc[0]) {
- ns->name = (char*)memdup(desc,(int)strlen(desc)+1, 0);
- }
- else if(sy->name && sy->name[0]) {
- ns->name = (char*)memdup(sy->name,(int)strlen(sy->name)+1, 0);
- }
- else if(sy->parent && sy->parent->Id < GO_GRAPH && sy->parent->Id >= GO_PLOT) {
- if(((Plot*)(sy->parent))->data_desc) ns->name = (char*)memdup(((Plot*)(sy->parent))->data_desc,
- (int)strlen(((Plot*)(sy->parent))->data_desc)+1, 0);
- }
- else if(sy->parent && sy->parent->name && sy->parent->name[0]) {
- ns->name = (char*)memdup(sy->parent->name,(int)strlen(sy->parent->name)+1, 0);
- }
- if(li = new LegItem(this, data, ld, ns)){
- if(!(Command(CMD_DROP_OBJECT, li, 0L))) DeleteGO(li);
- }
- return false;
-}
-
-bool
-Legend::HasErr(LineDEF *ld, int err, char *desc)
-{
- int i;
- LegItem *li;
-
- if(Items) for(i = 0; i < nItems; i++) {
- if(Items[i] && Items[i]->HasErr(ld, err)) return true;
- }
- if(li = new LegItem(this, data, ld, err | (hasLine ? 0x40 : 0), desc)){
- 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, int style):GraphObj(par, d)
-{
- Graph::FileIO(INIT_VARS);
- Disp = o; Id = GO_GRAPH; cGraphs++; bModified = true;
- if(style & 0x10) y_axis.flags |= AXIS_INVERT;
- 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); Plots = 0L; NumPlots = 0;
- }
- if(Axes) {
- for(i = 0; i< NumAxes; i++) if(Axes[i]) DeleteGO(Axes[i]);
- free(Axes); Axes = 0L; NumAxes = 0;
- }
- 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)
-{
- return Graph::DefSize(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;
- case COL_DRECT: return ColDR;
- case COL_GRECT: return ColGR;
- }
- if(parent) return parent->GetColor(select);
- else return defs.Color(select);
-}
-
-bool
-Graph::SetColor(int select, DWORD col)
-{
- switch(select) {
- case COL_DRECT:
- ColDR = col; return true;
- case COL_GRECT:
- ColGR = col; return true;
- }
- return false;
-}
-
-void
-Graph::DoPlot(anyOutput *target)
-{
- int i, cb;
- 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
- //every graph needs axes!
- if(type == GT_STANDARD && !NumAxes) CreateAxes(AxisTempl);
- //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){
-#ifdef USE_WIN_SECURE
- cb = sprintf_s(TmpTxt, TMP_TXT_SIZE, "Graph %d", cGraphs) + 2;
-#else
- cb = sprintf(TmpTxt, "Graph %d", cGraphs) + 2;
-#endif
- name = (char*)realloc(name, cb); rlp_strcpy(name, cb, 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);
- bModified = false; //first graph is not modified!
- Undo.SetDisp(Disp);
- }
- //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(bModified) data->Command(CMD_MRK_DIRTY, 0L, 0L);
- if(parent && parent->Id == GO_GRAPH) {
- parent->Command(CMD_AXIS, 0L, 0L);
- }
- 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 = Disp ? Disp : CurrDisp;
- switch (cmd){
- case CMD_CAN_CLOSE:
- HideTextCursor();
- if(bModified) {
- if (Undo.isEmpty(CurrDisp)) return true;
- bModified = false;
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "%s has not been saved.\nDo you want to save it now?", name);
-#else
- sprintf(TmpTxt, "%s has not been saved.\nDo you want to save it now?", name);
-#endif
- i = YesNoCancelBox(TmpTxt);
- if(i == 2) return false;
- else if(i == 1) if(! SaveGraphAs(this)) return false;
- }
- return true;
- case CMD_SCALE:
- return DoScale((scaleINFO*)tmpl, o);
- 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:
- Undo.SetDisp(o ? o : CurrDisp);
- 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;
- if(Disp) {
- Undo.SetDisp(Disp);
- 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;
- }
- else if(Plots = (GraphObj**)realloc(Plots, sizeof(GraphObj*) * (NumPlots+2))){
- Plots[NumPlots++] = (GraphObj*)tmpl; Plots[NumPlots] = 0L;
- }
- else return false;
- }
- 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);
- if(Disp) Command(CMD_REDRAW, 0L, CurrDisp);
- }
- else if(Id == GO_GRAPH) {
- for(i = 0; i< NumPlots; i++) if(Plots[i]) Plots[i]->Command(cmd, tmpl,o);
- }
- 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_REDRAW:
- if(!CurrDisp) {
- DoPlot(CurrDisp); return true;
- }
- if(Disp)CurrDisp = Disp; bDialogOpen = false;
- if(parent && (parent->Id == GO_PAGE || parent->Id == GO_GRAPH)) 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 == this) CurrGO = 0L;
- 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(o)o->MouseCursor(PasteObj ? MC_PASTE : MC_ARROW, false);
- return true;
- case CMD_AXIS: //one of the plots has changed scaling: reset
- CurrAxes = Axes;
- if(o)o->SetRect(CurrRect, units, &x_axis, &y_axis);
- return true;
- case CMD_REG_AXISPLOT: //notification: plot can handle 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:
- Undo.SetDisp(o ? o : CurrDisp); 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 || Plots[i]->Id == GO_FUNC3D
- || Plots[i]->Id == GO_FITFUNC3D))
- 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); if(CurrGO == this) CurrGO = 0L;
- return Configure();
- case CMD_FILENAME:
- if(tmpl) {
- i = (int)strlen((char*)tmpl)+2;
- filename = (char*)realloc(filename, i );
- rlp_strcpy(filename, i, (char*)tmpl);
- }
- break;
- case CMD_SETNAME:
- if(OwnDisp && CurrDisp && tmpl && *((char*)tmpl)){
- CurrDisp->Caption((char*)tmpl);
- i = (int)strlen((char*)tmpl);
- j = name && name[0] ? (int)strlen(name) : i;
- name = (char*)realloc(name, i > j ? i+2 : j+2);
- rlp_strcpy(name, i+2, (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, false);
- }
- return true;
- case CMD_UPDHISTORY:
- if(data) data->Command(CMD_UPDHISTORY, 0L, 0L);
- return true;
- case CMD_UPDATE:
- Command(CMD_TOOLMODE, 0L, o);
- Undo.SetDisp(CurrDisp);
- if(parent && parent->Id != GO_PAGE && parent->Id != GO_GRAPH){
- 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_CLOSE, 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); HideTextCursor();
- 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 || parent->Id == GO_GRAPH))
- return parent->Command(CMD_DELOBJ_CONT, (void*)this, o);
- return false;
- case CMD_TOOLMODE:
- if(o && tmpl) {
- Undo.SetDisp(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:
- o->MouseCursor(MC_DRAWPEN, false); break;
- case TM_RECTANGLE:
- o->MouseCursor(MC_DRAWREC, false); break;
- case TM_ELLIPSE:
- o->MouseCursor(MC_DRAWELLY, false); break;
- case TM_ROUNDREC:
- o->MouseCursor(MC_DRAWRREC, false); break;
- case TM_ARROW:
- o->MouseCursor(MC_CROSS, false); break;
- default:
- o->MouseCursor(MC_ARROW, true); break;
- }
- if((ToolMode & 0x0f) != TM_TEXT) HideTextCursor();
- return Command(CMD_REDRAW, 0L, CurrDisp);
- case CMD_ADDPLOT:
- Undo.SetDisp(o ? o : CurrDisp);
- 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 || Plots[i]->Id == GO_FUNC3D
- || Plots[i]->Id == GO_FITFUNC3D)) {
- if(Plots[i]->Command(cmd, tmpl, CurrDisp)) return Command(CMD_REDRAW, 0L, o);
- else return false;
- }
- }
- return false;
- }
- else return AddPlot(0x0);
- }
- return false;
- case CMD_MRK_DIRTY:
- return (dirty = true);
- case CMD_CURRLEFT: case CMD_CURRIGHT: case CMD_ADDCHAR: case CMD_ADDCHARW:
- case CMD_BACKSP: case CMD_POS_FIRST: case CMD_POS_LAST:
- defs.SetDisp(o);
- if(tmpl && *((int*)tmpl) == 27) { //Escape
- HideCopyMark();
- if(CurrGO && CurrGO->Id == GO_TEXTFRAME) {
- CurrGO->DoMark(o, false); o->MrkMode = MRK_NONE;
- CurrGO = 0L;
- }
- else o->HideMark();
- CurrLabel = 0L; HideTextCursor();
- }
- if(CurrLabel) return CurrLabel->Command(cmd, tmpl, o);
- if(CurrGO && CurrGO->Id == GO_TEXTFRAME) return CurrGO->Command(cmd, tmpl, o);
- else if(CurrGO && CurrGO->Id != GO_LABEL && 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;
- }
- else if(CurrGO && CurrGO->Id == GO_TEXTFRAME) return CurrGO->Command(cmd, tmpl, o);
- case CMD_SHIFTLEFT: case CMD_SHIFTRIGHT: case CMD_SHIFTUP: case CMD_SHIFTDOWN:
- if(Id == GO_PAGE || (CurrGraph && CurrGraph->parent == this)) {
- if(CurrGraph && CurrGraph->parent == this) return CurrGraph->Command(cmd, tmpl, o);
- else if(CurrGO && CurrGO->Id == GO_TEXTFRAME) return CurrGO->Command(cmd, tmpl, o);
- else if(CurrGO && CurrGO->Id == GO_LABEL) return CurrGO->Command(cmd, tmpl, o);
- }
- else {
- if(type == GT_3D && Plots) {
- for(i = 0; i < NumPlots; i++) {
- if(Plots[i] && (Plots[i]->Id == GO_PLOT3D || Plots[i]->Id == GO_FUNC3D
- || Plots[i]->Id == GO_FITFUNC3D))
- return Plots[i]->Command(cmd, tmpl, CurrDisp);
- }
- }
- else if(CurrGO && CurrGO->Id == GO_TEXTFRAME) return CurrGO->Command(cmd, tmpl, o);
- else if(CurrGO && CurrGO->Id == GO_LABEL) return CurrGO->Command(cmd, tmpl, o);
- }
- 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->Id == GO_TEXTFRAME) return CurrGO->Command(cmd, tmpl, o);
- if(CurrGO == CurrLabel) return CurrLabel->Command(cmd, tmpl, o);
- if(CurrGO->Id == GO_FRAMERECT) if(!(CurrGO = CurrGO->parent))return false;
- if(CurrGO->parent == this) return Command(CMD_DELOBJ, (void*)CurrGO, o);
- if(CurrGO->parent)return CurrGO->parent->Command(CMD_DELOBJ, (void*)CurrGO, o);
- return false;
- case CMD_DROP_GRAPH:
- if(Disp) {
- 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);
- }
- else if(Plots = (GraphObj**)realloc(Plots, sizeof(GraphObj*) * (NumPlots+2))){
- Plots[NumPlots] = (GraphObj*)tmpl; Plots[NumPlots+1] = 0L;
- }
- else return false;
- 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_DROP_PLOT:
- if(!tmpl) return false;
- ((GraphObj*)tmpl)->parent = this;
- if(((GraphObj*)tmpl)->Id < GO_PLOT) {
- if(!NumPlots && Id != GO_PAGE) return false;
- Plots = (GraphObj**)realloc(Plots, (NumPlots+2)*sizeof(GraphObj*));
- Plots[NumPlots] = (GraphObj*)tmpl;
- NumPlots++;
- if(CurrDisp) {
- CurrDisp->StartPage();
- DoPlot(CurrDisp);
- CurrDisp->EndPage();
- }
- return true;
- }
- if(Id == GO_GRAPH) CurrGraph = this; bModified =true;
- if(!NumPlots) {
- Plots = (GraphObj**)calloc(2, sizeof(GraphObj*));
- if(Plots) {
- Plots[0] = (Plot *)tmpl; Plots[0]->parent = this;
- 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: case GO_FUNC3D:
- case GO_FITFUNC3D:
- 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;
- dirty = false;
- return true;
- }
- return false;
- }
- else {
- if(Disp) {
- Undo.SetDisp(Disp);
- 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;
- }
- else if(Plots = (GraphObj**)realloc(Plots, sizeof(GraphObj*) * (NumPlots+2))){
- Plots[NumPlots++] = (Plot*)tmpl; Plots[NumPlots] = 0L;
- }
- else return false;
- 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
- if(CurrDisp) {
- CurrDisp->StartPage();
- DoPlot(CurrDisp);
- CurrDisp->EndPage();
- }
- return true;
- }
- break;
- case CMD_PASTE_OBJ:
- if(!tmpl) return false;
- Undo.SetDisp(o ? o : CurrDisp);
- PasteObj = (GraphObj*)tmpl;
- if(PasteObj->Id == GO_GRAPH || PasteObj->Id == GO_POLYLINE || PasteObj->Id == GO_POLYGON
- || PasteObj->Id == GO_RECTANGLE || PasteObj->Id == GO_ROUNDREC || PasteObj->Id == GO_ELLIPSE
- || PasteObj->Id == GO_BEZIER) {
- ToolMode = TM_PASTE; o->MouseCursor(MC_PASTE, false);
- return true;
- }
- PasteObj = 0L;
- return false;
- case CMD_MOUSE_EVENT:
- mev = (MouseEvent *)tmpl; defs.SetDisp(o);
- if(CurrGO && CurrGO->moveable && mev->Action == MOUSE_LBDOWN &&
- ToolMode == TM_STANDARD && (mev->StateFlags & 24) == 0 &&
- (TrackGO = (GraphObj*)CurrGO->ObjThere(mev->x, mev->y))){
- ToolMode |= TM_MOVE;
- }
- else if(mev->Action == MOUSE_LBDOWN){
- if(CurrGO && (CurrGO->Id == GO_TEXTFRAME || CurrGO->Id == GO_LABEL) && CurrGO->Command(cmd, tmpl, o)) return true;
- CurrGO = 0L; rc_mrk.left = mev->x; rc_mrk.top = mev->y;
- if((ToolMode == TM_TEXT || ToolMode == TM_STANDARD) && Command(CMD_TEXTTHERE, tmpl, o)) {
- o->CheckMenu(TM_TEXT, false); o->CheckMenu(TM_STANDARD, true);
- ToolMode = TM_STANDARD; return true;
- }
- SuspendAnimation(o, true);
- }
- if(ToolMode != TM_STANDARD && ExecTool(mev)) return true;
- switch(mev->Action) {
- case MOUSE_RBUP:
- i = ToolMode; ToolMode = TM_STANDARD;
- mev->Action = MOUSE_LBUP; //fake select
- CurrGO = 0L; Command(cmd, tmpl, o); ToolMode = i;
- if(!CurrGO) CurrGO = this;
- //the default behaviour for right button click is the same as for
- // double click: execute properties dialog, just continue.
- case MOUSE_LBDOUBLECLICK:
- Undo.SetDisp(o); bDialogOpen = true;
- if(!CurrGO){
- mev->Action = MOUSE_LBUP;
- Command(CMD_MOUSE_EVENT, mev, CurrDisp);
- mev->Action = MOUSE_LBDOUBLECLICK;
- if(!CurrGO) CurrGO = this;
- if(CurrGO->Command(CMD_CONFIG, 0L, o)) return Command(CMD_REDRAW, 0L, o);
- }
- else if(CurrGO->Id < GO_PLOT) {
- if(CurrGO->PropertyDlg()) {
- bModified = true; return Command(CMD_REDRAW, 0L, o);
- }
- }
- else if(CurrGO->Command(CMD_CONFIG, 0L, o)) return Command(CMD_REDRAW, 0L, o);
- else o->HideMark();
- TrackGO = 0L; CurrLabel = 0L; bDialogOpen = false;
- if(CurrGO == this) CurrGO = 0L;
- return false;
- case MOUSE_LBUP:
- if(bDialogOpen) {
- bDialogOpen = false; return false;
- }
- Undo.SetDisp(o); SuspendAnimation(o, false);
- if(Id == GO_GRAPH && parent && parent->Id == GO_SPREADDATA){
- CurrGO = TrackGO = 0L;
- CurrGraph = 0L;
- }
- 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 && NumPlots > 0) for(i = NumPlots-1; i>=0; i--){
- if(Plots[i] && Plots[i]->Command(cmd, tmpl, o)){
- if(Plots[i]->Id != GO_GRAPH && Id == GO_GRAPH) CurrGraph = this;
- 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_TEXTTHERE:
- //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;
- break;
- case CMD_SETSCROLL:
- if(o) {
- if(!(o->ActualSize(&rc)))return false;
- 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]->Id == GO_FUNC3D || Plots[i]->Id == GO_FITFUNC3D)
- Plots[i]->Command(cmd, tmpl, o);
- }
- return true;
- }
- return false;
-}
-
-double
-Graph::DefSize(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_SCALE: return scale > 0.0 ? scale : 1.0;
- 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);
- }
- if(scale > 0.0) return scale * defs.GetSize(select);
- else return defs.GetSize(select);
-}
-
-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[500];
- Label *label;
- double ts, lb_ydist, lb_xdist, tlb_dist;
- DWORD ptick, ntick, utick;
- char xa_desc[50], ya_desc[50];
-
- if(Axes && NumAxes) return;
- label_def.ColTxt = defs.Color(COL_AXIS); label_def.ColBg = 0x00ffffffL;
- label_def.fSize = DefSize(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 = DefSize(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 = DefSize(SIZE_AXIS_TICKS);
- rlp_strcpy(xa_desc, 50, (char*)"x-axis"); rlp_strcpy(ya_desc, 50, (char*)"y-axis");
- if(Plots && NumPlots && Plots[0] && Plots[0]->Id >= GO_PLOT && Plots[0]->Id < GO_GRAPH) {
- if(((Plot*)Plots[0])->x_info) rlp_strcpy(xa_desc, 50,((Plot*)Plots[0])->x_info);
- if(((Plot*)Plots[0])->y_info) rlp_strcpy(ya_desc, 50,((Plot*)Plots[0])->y_info);
- }
- 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+DefSize(SIZE_AXIS_TICKS))*2.0);
- lb_xdist = NiceValue((ts+DefSize(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);
- rlp_strcpy(label_text, 500, xa_desc);
- label = new Label(Axes[0], data, (DRect.Xmin+DRect.Xmax)/2.0,
- GRect.Ymin+DRect.Ymax+DefSize(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, y_axis.flags | 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);
- rlp_strcpy(label_text, 500, ya_desc);
- label_def.RotBL = 90.0; label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
- label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - DefSize(SIZE_AXIS_TICKS)*6.0,
- (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);
- rlp_strcpy(label_text, 500, xa_desc);
- label_def.Align = TXA_VTOP | TXA_HRIGHT;
- label = new Label(Axes[0], data, GRect.Xmin + DRect.Xmax - DefSize(SIZE_AXIS_TICKS)*2.0,
- GRect.Ymin+DRect.Ymax+DefSize(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);
- rlp_strcpy(label_text, 500, ya_desc);
- label_def.RotBL = 90.0; label_def.Align = TXA_VBOTTOM | TXA_HRIGHT;
- label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - DefSize(SIZE_AXIS_TICKS)*6.0,
- GRect.Ymin + DRect.Ymin + DefSize(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);
- rlp_strcpy(label_text, 500, xa_desc);
- label = new Label(Axes[0], data, GRect.Xmin + (DRect.Xmin+DRect.Xmax)/2.0f,
- GRect.Ymin+DRect.Ymax+DefSize(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);
- rlp_strcpy(label_text, 500, ya_desc);
- label_def.RotBL = 90.0; label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
- label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - DefSize(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);
- rlp_strcpy(label_text, 500, xa_desc);
- label = new Label(Axes[0], data, GRect.Xmin + (DRect.Xmin+DRect.Xmax)/2.0f,
- GRect.Ymin+DRect.Ymax+DefSize(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);
- rlp_strcpy(label_text, 500, ya_desc);
- label_def.RotBL = 90.0; label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
- label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - DefSize(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);
- rlp_strcpy(label_text, 500, xa_desc);
- label = new Label(Axes[0], data, GRect.Xmin + (DRect.Xmin+DRect.Xmax)/2.0f,
- GRect.Ymin+DRect.Ymax+DefSize(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);
- rlp_strcpy(label_text, 500, ya_desc);
- label_def.RotBL = 90.0; label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
- label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - DefSize(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;
- }
- if(Plots[0] && Plots[0]->Id >= GO_PLOT && Plots[0]->Id < GO_GRAPH && NumAxes > 1) {
- if(((Plot*)Plots[0])->x_tv && Axes[0])Axes[0]->atv = ((Plot*)Plots[0])->x_tv->Copy();
- else if(((Plot*)Plots[0])->x_dtype == ET_DATETIME)x_axis.flags |= AXIS_DATETIME;
- if(((Plot*)Plots[0])->y_tv && Axes[1])Axes[1]->atv = ((Plot*)Plots[0])->y_tv->Copy();
- else if(((Plot*)Plots[0])->y_dtype == ET_DATETIME)y_axis.flags |= AXIS_DATETIME;
- }
-}
-
-bool
-Graph::DoScale(scaleINFO* sc, anyOutput *o)
-{
- int i;
- scaleINFO sc0;
-
- if(sc->sy.fy <= 0.0) return false;
- GRect.Xmax = sc->sx.fx + GRect.Xmax* sc->sx.fy;
- GRect.Xmin = sc->sx.fx + GRect.Xmin * sc->sx.fy;
- GRect.Ymax = sc->sy.fx + GRect.Ymax * sc->sy.fy;
- GRect.Ymin = sc->sy.fx + GRect.Ymin * sc->sy.fy;
- DRect.Xmax *= sc->sx.fy; DRect.Xmin *= sc->sx.fy;
- DRect.Ymax *= sc->sy.fy; DRect.Ymin *= sc->sy.fy;
- if(sc->sx.fy == 1.0 && sc->sx.fy == sc->sy.fy && sc->sx.fy == sc->sz.fy) return true;
- memcpy(&sc0, sc, sizeof(scaleINFO));
- sc0.sx.fx = sc0.sy.fx = sc0.sz.fx = 0.0; sc0.sx.fy = sc0.sz.fy = sc->sy.fy;
- if(Axes) for(i = 0; i< NumAxes; i++) if(Axes[i]) Axes[i]->Command(CMD_SCALE, &sc0, o);
- if(Plots) for(i = 0; i < NumPlots; i++) if(Plots[i]){
- if(Plots[i]->Id == GO_GRAPH || Plots[i]->Id == GO_PAGE) Plots[i]->Command(CMD_SCALE, sc, o);
- else Plots[i]->Command(CMD_SCALE, &sc0, o);
- }
- scale = scale > 0.0 ? scale * sc->sy.fy : sc->sy.fy;
- return true;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Pages are graphic objects containing graphs and drawn objects
-Page::Page(GraphObj *par, DataObj *d):Graph(par, d, 0L, 0)
-{
- 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);
-#ifdef USE_WIN_SECURE
- i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "Page %d", cPages);
-#else
- i = sprintf(TmpTxt, "Page %d", cPages);
-#endif
- if(!name && (name = (char*)malloc(i += 2)))rlp_strcpy(name, i, 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);
- if(PasteObj) {
- ToolMode = TM_PASTE; CurrDisp->MouseCursor(MC_PASTE, false);
- }
-}
-
-bool
-Page::Command(int cmd, void *tmpl, anyOutput *o)
-{
- Graph *g;
-
- switch(cmd) {
- case CMD_MOUSE_EVENT:
- return Graph::Command(cmd, tmpl, o);
- case CMD_REDRAW:
- if(Disp) {
- Disp->StartPage(); DoPlot(Disp); Disp->EndPage();
- }
- return true;
- case CMD_CONFIG:
- return Configure();
- case CMD_NEWGRAPH:
- if((g = new Graph(this, data, Disp, 0)) && 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;
- case CMD_SCALE:
- return true;
- default:
- return Graph::Command(cmd, tmpl, o);
- }
-}
-
-double
-Page::DefSize(int select)
-{
- return defs.GetSize(select);
-}
-
+//rlplot.cpp, Copyright 2000-2008 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;
+Axis **CurrAxes = 0L;
+dragHandle *CurrHandle = 0L;
+UndoObj Undo;
+fmtText DrawFmtText;
+
+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)
+{
+}
+
+double
+GraphObj::DefSize(int select)
+{
+ if(parent) return parent->DefSize(select);
+ else return defs.GetSize(select);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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 DefSize(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, crx, cry, atype;
+ double sc;
+ long ncpts;
+ lfPOINT fip;
+ POINT pts[14], *cpts;
+ FillDEF cf;
+
+ atype = (type & 0xfff);
+ memcpy(&cf, &SymFill, sizeof(FillDEF));
+ if(atype == SYM_CIRCLEF || atype == SYM_RECTF || atype == SYM_TRIAUF ||
+ atype == SYM_TRIADF || atype == SYM_DIAMONDF || atype == SYM_4STARF ||
+ atype == SYM_5GONF || atype == SYM_5STARF || atype == SYM_6STARF) 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
+ case SYM_CIRCLEC: //circle with center point
+ case SYM_1QUAD: case SYM_2QUAD: case SYM_3QUAD:
+ rx = target->un2ix(size/2.0); ry = target->un2iy(size/2.0);
+ if(rx < 5) rx = 1; if(ry < 5) ry = 1;
+ target->SetFill(&cf);
+ target->oCircle(ix-rx, iy-ry, ix+rx+1, iy+ry+1, name);
+ if(atype == SYM_CIRCLEC) {
+ crx = target->un2ix(size/5.0); cry = target->un2iy(size/5.0);
+ cf.color = SymLine.color; target->SetFill(&cf);
+ target->oCircle(ix-crx, iy-cry, ix+crx+1, iy+cry+1, name);
+ }
+ else if(atype == SYM_1QUAD || atype == SYM_2QUAD || atype == SYM_3QUAD) {
+ ncpts = 0L; cf.color = SymLine.color; target->SetFill(&cf);
+ if(atype == SYM_1QUAD) {
+ if(!(cpts = MakeArc(ix, iy, rx, 0x04, &ncpts)) || !ncpts) return;
+ cpts[0].x = ix + rx; cpts[0].y = iy;
+ }
+ else if(atype == SYM_2QUAD) {
+ if(!(cpts = MakeArc(ix, iy, rx, 0x06, &ncpts)) || !ncpts) return;
+ cpts[0].x = ix; cpts[0].y = iy+rx;
+ }
+ else if(atype == SYM_3QUAD) {
+ if(!(cpts = MakeArc(ix, iy, rx, 0x07, &ncpts)) || !ncpts) return;
+ cpts[0].x = ix-rx; cpts[0].y = iy;
+ }
+ cpts[ncpts-1].x = ix; cpts[ncpts-1].y = iy-rx;
+ cpts[ncpts].x = ix; cpts[ncpts].y = iy; ncpts++;
+ cpts[ncpts].x = cpts[0].x; cpts[ncpts].y = cpts[0].y; ncpts++;
+ target->oPolygon(cpts, ncpts); free(cpts);
+ }
+ rx--;ry--; //smaller marking rectangle
+ break;
+ case SYM_RECT: //rectange (square)
+ case SYM_RECTF: //filled rectangle
+ case SYM_RECTC: //square with center point
+ rx = target->un2ix(size/2.25676); ry = target->un2iy(size/2.25676);
+ if(rx < 5) rx = 1; if(ry < 5) ry = 1;
+ target->SetFill(&cf);
+ target->oRectangle(ix-rx, iy-ry, ix+rx+1, iy+ry+1, name);
+ if(atype == SYM_RECTC) {
+ crx = target->un2ix(size/6.0); cry = target->un2iy(size/6.0);
+ cf.color = SymLine.color; target->SetFill(&cf);
+ target->oCircle(ix-crx, iy-cry, ix+crx+1, iy+cry+1, name);
+ }
+ break;
+ case SYM_TRIAU: //triangles up and down, open or closed
+ case SYM_TRIAUF: case SYM_TRIAD: case SYM_TRIADF: case SYM_TRIADC:
+ case SYM_TRIAUC: case SYM_TRIAUL: case SYM_TRIAUR: case SYM_TRIADL:
+ case SYM_TRIADR:
+ rx = target->un2ix(size/1.48503); ry = target->un2iy(size/1.48503);
+ if(rx < 5) rx = 1; if(ry < 5) ry = 1;
+ target->SetFill(&cf);
+ pts[0].x = pts[3].x = ix - rx; pts[1].x = ix; pts[2].x = ix+rx;
+ //patch by anonymous
+ if(atype == SYM_TRIAU || atype == SYM_TRIAUF || atype == SYM_TRIAUL
+ || atype == SYM_TRIAUR || atype == SYM_TRIAUC) {
+ 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);
+ if(atype == SYM_TRIAUC || atype == SYM_TRIADC) {
+ crx = target->un2ix(size/6.0); cry = target->un2iy(size/6.0);
+ cf.color = SymLine.color; target->SetFill(&cf);
+ target->oCircle(ix-crx, iy-cry, ix+crx+1, iy+cry+1, name);
+ }
+ else if(atype == SYM_TRIAUL || atype == SYM_TRIADL) {
+ cf.color = SymLine.color; target->SetFill(&cf);
+ pts[2].x = pts[1].x; target->oPolygon(pts, 4);
+ }
+ else if(atype == SYM_TRIAUR || atype == SYM_TRIADR) {
+ cf.color = SymLine.color; target->SetFill(&cf);
+ pts[0].x = pts[3].x = pts[1].x; target->oPolygon(pts, 4);
+ }
+ rx--; ry--;
+ break;
+ case SYM_DIAMOND: case SYM_DIAMONDF: case SYM_DIAMONDC:
+ rx = target->un2ix(size/1.59588); ry = target->un2iy(size/1.59588);
+ if(rx < 5) rx = 1; if(ry < 5) ry = 1;
+ 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);
+ if(atype == SYM_DIAMONDC) {
+ crx = target->un2ix(size/6.0); cry = target->un2iy(size/6.0);
+ cf.color = SymLine.color; target->SetFill(&cf);
+ target->oCircle(ix-crx, iy-cry, ix+crx+1, iy+cry+1, name);
+ }
+ rx--; ry--;
+ break;
+ case SYM_4STAR: case SYM_4STARF:
+ rx = target->un2ix(size/1.4); ry = target->un2iy(size/1.4);
+ crx = target->un2ix(size/6.0); cry = target->un2iy(size/6.0);
+ pts[0].x = pts[8].x = ix-rx; pts[0].y = pts[4].y = pts[8].y = iy;
+ pts[1].x = pts[7].x = ix-crx; pts[1].y = pts[3].y = iy - cry;
+ pts[2].x = pts[6].x = ix; pts[2].y = iy - ry;
+ pts[3].x = pts[5].x = ix+crx; pts[4].x = ix + rx;
+ pts[5].y = pts[7].y = iy+cry; pts[6].y = iy + ry;
+ target->SetFill(&cf); target->oPolygon(pts, 9);
+ break;
+ case SYM_5GON: case SYM_5GONF: case SYM_5GONC:
+ sc = 1.4;
+ rx = target->un2ix(size/sc); ry = target->un2iy(size/sc);
+ crx = target->un2ix(size/sc * 0.951057);
+ cry = target->un2iy(size/sc * 0.309017);
+ pts[0].x = ix-crx; pts[0].y = pts[2].y = iy-cry; pts[1].x = ix;
+ pts[1].y = iy-ry; pts[2].x = ix+crx;
+ crx = target->un2ix(size/sc * 0.587785);
+ cry = target->un2iy(size/sc * 0.809017);
+ pts[3].x = ix + crx; pts[4].x = ix - crx;
+ pts[3].y = pts[4].y = iy+cry;
+ pts[5].x = pts[0].x; pts[5].y = pts[0].y;
+ target->SetFill(&cf); target->oPolygon(pts, 6);
+ if(atype == SYM_5GONC) {
+ crx = target->un2ix(size/6.0); cry = target->un2iy(size/6.0);
+ cf.color = SymLine.color; target->SetFill(&cf);
+ target->oCircle(ix-crx, iy-cry, ix+crx+1, iy+cry+1, name);
+ }
+ break;
+ case SYM_5STAR: case SYM_5STARF:
+ sc = 1.4;
+ rx = target->un2ix(size/sc); ry = target->un2iy(size/sc);
+ crx = target->un2ix(size/sc * 0.951057);
+ cry = target->un2iy(size/sc * 0.309017);
+ pts[0].x = ix-crx; pts[0].y = pts[1].y = pts[3].y = pts[4].y = iy-cry;
+ pts[2].x = pts[7].x = ix; pts[2].y = iy-ry; pts[4].x = ix+crx;
+ crx = target->un2ix(size/sc * 0.23);
+ pts[1].x = ix - crx; pts[3].x = ix + crx;
+ crx = target->un2ix(size/sc * 0.36);
+ cry = target->un2iy(size/sc * 0.11);
+ pts[5].x = ix + crx; pts[5].y = pts[9].y = iy + cry; pts[9].x = ix - crx;
+ pts[7].y = iy + target->un2iy(size/sc * 0.38);
+ crx = target->un2ix(size/sc * 0.587785);
+ cry = target->un2iy(size/sc * 0.809017);
+ pts[6].x = ix + crx; pts[8].x = ix - crx;
+ pts[6].y = pts[8].y = iy+cry;
+ pts[10].x = pts[0].x; pts[10].y = pts[0].y;
+ target->SetFill(&cf); target->oPolygon(pts, 11);
+ break;
+ case SYM_6STAR: case SYM_6STARF:
+ sc = 1.4 / 0.86; rx = target->un2ix(size/sc);
+ sc = 1.4 / 0.5; ry = target->un2iy(size/sc);
+ pts[0].x = pts[10].x = pts[12].x = ix - rx;
+ pts[4].x = pts[6].x = ix + rx; pts[2].x = pts[8].x = ix;
+ pts[0].y = pts[1].y = pts[3].y = pts[4].y = pts[12].y = iy - ry;
+ pts[6].y = pts[7].y = pts[9].y = pts[10].y = iy + ry;
+ sc = 1.4 / 0.29; rx = target->un2ix(size/sc);
+ pts[1].x = pts[9].x = ix - rx; pts[3].x = pts[7].x = ix + rx;
+ sc = 1.4 / 0.52; rx = target->un2ix(size/sc);
+ pts[5].x = ix +rx; pts[11].x = ix - rx; pts[5].y = pts[11].y = iy;
+ sc = 1.4;
+ rx = target->un2ix(size/sc); ry = target->un2iy(size/sc);
+ pts[2].y = iy - ry; pts[8].y = iy + ry;
+ target->SetFill(&cf); target->oPolygon(pts, 13);
+ 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);
+ if(rx < 5) rx = 1; if(ry < 5) ry = 1;
+ 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(atype != SYM_VLINE) target->oPolyline(pts, 2);
+ if(atype == SYM_VLINE){ rx = 2; break;}
+ if(atype == SYM_HLINE){ ry = 2; break;}
+ if(atype == 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);
+ if(rx < 5) rx = 1; if(ry < 5) ry = 1;
+ pts[0].x = ix - rx - 2; pts[1].x = ix + rx + 3;
+ pts[0].y = iy - ry - 2; pts[1].y = iy + ry + 3;
+ target->oPolyline(pts, 2); Swap(pts[0].y, pts[1].y);
+ pts[1].y -= 1; pts[0].y -= 1;
+ 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);
+ DrawFmtText.SetText(target, SymTxt->text, &ix, &iy);
+ 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+2;
+ rDims.top = iy-ry-1; rDims.bottom = iy+ry+2;
+}
+
+bool
+Symbol::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ char *tmptxt;
+ AccRange *ac;
+ int i, r, c;
+
+ switch (cmd) {
+ case CMD_SCALE:
+ if(!tmpl) return false;
+ size *= ((scaleINFO*)tmpl)->sy.fy;
+ SymLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+ if(SymTxt) {
+ SymTxt->fSize *= ((scaleINFO*)tmpl)->sy.fy;
+ SymTxt->iSize = 0;
+ }
+ return true;
+ 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) {
+ rlp_strcpy((char*)tmpl, 50, SymTxt->text);
+ return true;
+ }
+ return false;
+ case CMD_SYMTEXT_UNDO:
+ if(SymTxt && SymTxt->text){
+ c = Undo.String(this, &SymTxt->text, UNDO_CONTINUE);
+ i = (int)strlen((char*)tmpl); i = i > c ? i+2 : c+2;
+ if(tmpl) {
+ if(SymTxt->text = (char*)realloc(SymTxt->text, i)) rlp_strcpy(SymTxt->text, i, (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) {
+ i = (int) strlen((char*)tmpl) + 2;
+ if(SymTxt->text = (char*)realloc(SymTxt->text, i)) rlp_strcpy(SymTxt->text, i, (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, tmptxt[0] = 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);
+// if(mo) DelBitmapClass(mo); mo = 0L;
+ 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_SCALE:
+ if(!tmpl) return false;
+ if((type & 0x0f0)== BUBBLE_UNITS) fs *= ((scaleINFO*)tmpl)->sy.fy;
+ BubbleLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+ BubbleLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+ BubbleFillLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+ BubbleFillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+ BubbleFill.scale *= ((scaleINFO*)tmpl)->sy.fy;
+ return true;
+ case CMD_LEGEND:
+ if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+ ((Legend*)tmpl)->HasFill(&BubbleLine, &BubbleFill, 0L);
+ break;
+ 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:
+ return DoAutoscale(o);
+ break;
+ }
+ return false;
+}
+
+bool
+Bubble::DoAutoscale(anyOutput *o)
+{
+ double dx, dy;
+
+ switch(type & 0x0f0) {
+ case BUBBLE_XAXIS: case BUBBLE_YAXIS:
+ dx = dy = fs/2.0; break;
+ case BUBBLE_UNITS:
+ dx = fPos.fx/20; dy = fPos.fy/20; break;
+ }
+ ((Plot*)parent)->CheckBounds(fPos.fx+dx, fPos.fy-dy);
+ ((Plot*)parent)->CheckBounds(fPos.fx-dx, fPos.fy+dy);
+ return true;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Bars are graphic objects
+Bar::Bar(GraphObj *par, DataObj *d, double x, double y, int which,int xc, int xr,
+ int yc, int yr, char *desc):GraphObj(par, d)
+{
+ FileIO(INIT_VARS);
+ fPos.fx = x; fPos.fy = y; type = which;
+ if(type & BAR_RELWIDTH) size = 60.0; 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;
+ }
+ }
+ if(desc && desc[0]) name = (char*)memdup(desc, (int)strlen(desc)+1, 0);
+}
+
+Bar::Bar(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+Bar::~Bar()
+{
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ 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);
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ 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);
+}
+
+void
+Bar::DoMark(anyOutput *o, bool mark)
+{
+ POINT mpts[5];
+
+ if(mark){
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ mpts[0].x = mpts[4].x = mpts[3].x = rDims.left;
+ mpts[0].y = mpts[4].y = mpts[1].y = rDims.bottom;
+ mpts[1].x = mpts[2].x = rDims.right; mpts[2].y = mpts[3].y = rDims.top;
+ memcpy(&mrc, &rDims, sizeof(RECT));
+ IncrementMinMaxRect(&mrc, 3*o->un2ix(BarLine.width)+2);
+ mo = GetRectBitmap(&mrc, o);
+ InvertLine(mpts, 5, &BarLine, &mrc, o, mark);
+ }
+ else RestoreRectBitmap(&mo, &mrc, o);
+}
+
+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_SCALE:
+ if(!tmpl) return false;
+ if(!(type & BAR_RELWIDTH)) size *= ((scaleINFO*)tmpl)->sy.fy;
+ BarLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+ BarLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+ HatchLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+ HatchLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+ BarFill.scale *= ((scaleINFO*)tmpl)->sy.fy;
+ return true;
+ case CMD_LEGEND:
+ if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+ ((Legend*)tmpl)->HasFill(&BarLine, &BarFill, name);
+ break;
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
+ o->ShowMark(CurrGO = this, MRK_GODRAW);
+ 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, char *nam):GraphObj(par, d)
+{
+ size_t cb;
+
+ FileIO(INIT_VARS);
+ Id = GO_DATALINE;
+ if(xrange && xrange[0]) {
+ cb = strlen(xrange) +2; ssXref = (char*)malloc(cb); rlp_strcpy(ssXref, (int)cb, xrange);
+ }
+ if(yrange && yrange[0]) {
+ cb = strlen(yrange) +2; ssYref = (char*)malloc(cb); rlp_strcpy(ssYref, (int)cb, yrange);
+ }
+ if(nam && nam[0]) name = (char*)memdup(nam, (int)strlen(nam)+1, 0);
+ SetValues();
+}
+
+DataLine::DataLine(GraphObj *par, DataObj *d, lfPOINT *val, long nval, char *na):GraphObj(par, d)
+{
+ int cb;
+
+ FileIO(INIT_VARS);
+ Values = val; nPnt = nval; nPntSet = nPnt-1;
+ if(na && na[0] && (name = (char*)malloc((cb = (int)strlen(na))+2))) {
+ rlp_strcpy(name, cb+1, na);
+ }
+ 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(name) free(name); name = 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;
+ case COL_POLYGON:
+ pgFill.color = col;
+ LineDef.color = ((col & 0x00fefefeL)>>1);
+ return true;
+ }
+ return false;
+}
+
+void
+DataLine::DoPlot(anyOutput *target)
+{
+ int i;
+ lfPOINT fip;
+ POINT pn, *tmppts;
+
+ if(!Values || nPntSet < 1) return;
+ if (nPntSet >= nPnt) nPntSet = nPnt-1;
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ if(pts) free(pts); pts = 0L;
+ if((type & 0xff) == 9 || (type & 0xff) == 10) //splines
+ pts = (POINT *)malloc(sizeof(POINT)*1000);
+ else if((type & 0xff) == 11 || (type & 0xff) == 12) // curve
+ pts = (POINT *) malloc(sizeof(POINT)* (nPntSet+2)*192);
+ else 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 & 0x0f) {
+ case 0: default:
+ 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;
+ case 9: case 10:
+ DrawSpline(target);
+ break;
+ case 11: case 12:
+ DrawCurve(target);
+ 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){
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ 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 <1)
+ 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_SCALE:
+ LineDef.width *= ((scaleINFO*)tmpl)->sy.fy; LineDef.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+ break;
+ case CMD_SET_DATAOBJ:
+ Id = isPolygon ? GO_DATAPOLYGON : GO_DATALINE;
+ data = (DataObj*)tmpl;
+ return true;
+ case CMD_MRK_DIRTY:
+ dirty= true;
+ case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, 0L);
+ return false;
+ case CMD_LEGEND:
+ if(tmpl && ((GraphObj*)tmpl)->Id == GO_LEGEND) {
+ if(Id == GO_DATALINE) ((Legend*)tmpl)->HasFill(&LineDef, 0L, name);
+ }
+ break;
+ case CMD_SET_LINE:
+ if(tmpl) memcpy(&LineDef, tmpl, sizeof(LineDEF));
+ return true;
+ case CMD_UPDATE:
+ Undo.DataMem(this, (void**)&Values, nPnt * sizeof(lfPOINT), &nPnt, UNDO_CONTINUE);
+ Undo.ValLong(this, &nPntSet, UNDO_CONTINUE);
+ SetValues();
+ return true;
+ case CMD_AUTOSCALE:
+ if(nPntSet < 1 || !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[500], yref2[500];
+ lfPOINT *tmpValues = Values;
+
+ if(!ssXref || !ssYref) return;
+ if(!rlp_strcpy(yref1, 500, ssYref)) return;
+ for(i = 0, yref2[0] = 0; yref1[i]; i++) {
+ if(yref1[i] == ';') {
+ yref1[i++] = 0;
+ while(yref1[i] && yref1[i] < 33) i++;
+ rlp_strcpy(yref2, 500, yref1+i);
+ }
+ }
+ nPnt = nPntSet = 0;
+ min.fx = min.fy = HUGE_VAL; max.fx = max.fy = -HUGE_VAL;
+ rX = new AccRange(ssXref); rY1 = new AccRange(yref1);
+ if(!rX || !rY1){
+ if(rX) delete(rX); if(rY1) delete(rY1);
+ return;
+ }
+ if(!name) name = rY1->RangeDesc(data, 1);
+ if(yref2[0] &&((nPnt = rX->CountItems()) == (rY1->CountItems()))) {
+ if(!(Values = (lfPOINT *)realloc(Values, ((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 *)realloc(Values, (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 && Values != tmpValues) Undo.InvalidGO(this);
+ if(rX) delete(rX); if(rY1) delete(rY1); if(rY2) delete(rY2);
+}
+
+void
+DataLine::LineData(lfPOINT *val, long nval)
+{
+ lfPOINT *ov = Values;
+
+ if(!val || nval <2) return;
+ if(nval > nPnt && nPnt > 1 && Values){
+ if(!(Values = (lfPOINT *)realloc(Values, ((nval*2+2) * sizeof(lfPOINT))))) return;
+ if(ov != Values) Undo.InvalidGO(this);
+ }
+ else if(!Undo.busy) Undo.DataMem(this, (void**)&Values, nPnt * sizeof(lfPOINT), &nPnt, UNDO_CONTINUE);
+ memcpy(Values, val, nval * sizeof(lfPOINT));
+ if(pts) free(pts); pts = 0L; dirty = true;
+ free(val); nPnt = nval; nPntSet = nPnt-1;
+}
+
+void
+DataLine::DrawCurve(anyOutput *target)
+{
+ lfPOINT *sdata, *bdata;
+ POINT *tmppts;
+ int i, j, n;
+
+ if(!(sdata = (lfPOINT *)malloc(nPnt * sizeof(lfPOINT))))return;
+ sdata[0].fx = Values[0].fx; sdata[0].fy = Values[0].fy;
+ for(i = j = 1; i < nPnt; i++) {
+ if(Values[i].fx != sdata[j-1].fx || Values[i].fy != sdata[j-1].fy) {
+ sdata[j].fx = Values[i].fx; sdata[j++].fy = Values[i].fy;
+ }
+ }
+ n = mkCurve(sdata, j, &bdata, (type&0x0f) != 11);
+// if(!(tmppts = (POINT*)malloc((n+2)*sizeof(POINT))))return;
+ if(!(tmppts = (POINT*)malloc((n*64+2)*sizeof(POINT))))return;
+ for(i = 0; i < n; i++){
+ tmppts[i].x = target->fx2ix(bdata[i].fx); tmppts[i].y = target->fy2iy(bdata[i].fy);
+ }
+ for(i = cp = 0; i< (n-2); i += 3) {
+ if(parent->Id == GO_TICK) ClipBezier(&cp, pts, tmppts[i], tmppts[i+1], tmppts[i+2], tmppts[i+3], 0L, 0L);
+ else DrawBezier(&cp, pts, tmppts[i], tmppts[i+1], tmppts[i+2], tmppts[i+3], 0);
+ }
+ if(bdata) free(bdata); free(sdata);
+}
+
+void
+DataLine::DrawSpline(anyOutput *target)
+{
+ int i, j, k, klo, khi, ptsize = 1000;
+ double *y2, min, max, x, y, h, b, a;
+ POINT pn;
+ lfPOINT *scvals;
+
+ if(!(y2 = (double*)malloc(sizeof(double)*(nPnt)))) return;
+ if(!(scvals = (lfPOINT*)malloc(sizeof(lfPOINT)*(nPnt)))){
+ free(y2);
+ return;
+ }
+ if((type & 0x0f) == 9 || (type & 0x0f) == 10) {
+ if((type & 0x0f) == 9) for(i = 0; i < nPnt; i++) {
+ scvals[i].fx = target->fx2fix(Values[i].fx);
+ scvals[i].fy = target->fy2fiy(Values[i].fy);
+ }
+ else for(i = 0; i < nPnt; i++) {
+ scvals[i].fy = target->fx2fix(Values[i].fx);
+ scvals[i].fx = target->fy2fiy(Values[i].fy);
+ }
+ SortFpArray(nPnt, scvals);
+ min = scvals[0].fx; max = scvals[nPnt-1].fx;
+ for(i = j = 0; i < (nPnt-1); i++, j++) {
+ y = scvals[i].fy; scvals[j].fx = scvals[i].fx;
+ for(k = 1; scvals[i+1].fx == scvals[i].fx; k++) {
+ y += scvals[i+1].fy; i++;
+ }
+ scvals[j].fy = y/((double)k);
+ }
+ if(scvals[i].fx > scvals[i-1].fx) {
+ scvals[j].fx = scvals[i].fx; scvals[j].fy = scvals[i].fy;
+ j++;
+ }
+ spline(scvals, j, y2);
+ h = scvals[1].fx - scvals[0].fx; // klo and khi bracket the input value of x
+ for(x = min, klo = 0, i = khi = 1; x < max && i < j; x += 1.0) {
+ while(x > scvals[i].fx) {
+ klo++; khi++; i++;
+ h = scvals[khi].fx - scvals[klo].fx;
+ }
+ a = (scvals[khi].fx - x) / h; b = (x - scvals[klo].fx) / h;
+ y = a * scvals[klo].fy + b * scvals[khi].fy + ((a*a*a - a) * y2[klo] + (b*b*b - b) * y2[khi]) * (h*h)/6.0;
+ if((type & 0x0f) == 9) {
+ pn.x = iround(x); pn.y = iround(y);
+ }
+ else {
+ pn.x = iround(y); pn.y = iround(x);
+ }
+ if(cp >= ptsize) {
+ ptsize += 1000;
+ pts = (POINT*)realloc(pts, sizeof(POINT)*ptsize);
+ }
+ AddToPolygon(&cp, pts, &pn);
+ }
+ }
+ free(y2); free(scvals);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// DataPolygon is a graphic object based on DataLine
+DataPolygon::DataPolygon(GraphObj *par, DataObj *d, char *xrange, char *yrange, char *nam):
+ DataLine(par, d, xrange, yrange, nam)
+{
+ lfPOINT *fp = Values;
+ char *rx = ssXref;
+ char *ry = ssYref;
+ long np = nPnt;
+
+ FileIO(INIT_VARS);
+ Values = fp; //FileIO will just set Values to 0L !
+ ssXref = rx; ssYref = ry;
+ nPnt = np;
+ Id = GO_DATAPOLYGON;
+}
+
+DataPolygon::DataPolygon(GraphObj *par, DataObj *d, lfPOINT *val, long nval, char *na):
+ DataLine(par, d, val, nval, 0L)
+{
+ int cb;
+
+ FileIO(INIT_VARS);
+ Values = val; nPnt = nval; nPntSet = nPnt-1;
+ if(na && na[0] && (name = (char*)malloc((cb = (int)strlen(na))+2))) {
+ rlp_strcpy(name, cb+1, na);
+ }
+ 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(name) free(name); name = 0;
+ if(parent)parent->Command(CMD_MRK_DIRTY, 0L, 0L);
+}
+
+void
+DataPolygon::DoPlot(anyOutput *o)
+{
+ LineDEF currLine;
+
+ if(!Values || !o || nPntSet < 2) return;
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ if((type & 0x0f) != 12 && (type & 0x0f)) { //close polygon if necessary
+ if(Values[nPntSet].fx != Values[0].fx || Values[nPntSet].fy != Values[0].fy) {
+ Values = (lfPOINT*)realloc(Values, (nPntSet+2) * sizeof(lfPOINT));
+ Values[nPntSet+1].fx = Values[0].fx; Values[nPntSet+1].fy = Values[0].fy;
+ nPntSet++; nPnt++;
+ }
+ }
+ DataLine::DoPlot(o); //no drawing but fill pts only
+ memcpy(&currLine, &LineDef, sizeof(LineDEF));
+ if(currLine.width < 1.0e-10) currLine.color = pgFill.color;
+ o->SetLine(&currLine); o->SetFill(&pgFill);
+ o->oPolygon(pts, cp);
+}
+
+void
+DataPolygon::DoMark(anyOutput *o, bool mark)
+{
+ if(pts && cp && o){
+ if(mark){
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ memcpy(&mrc, &rDims, sizeof(RECT));
+ IncrementMinMaxRect(&mrc, 6 + o->un2ix(LineDef.width));
+ mo = GetRectBitmap(&mrc, o);
+ InvertLine(pts, cp, &LineDef, &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_SCALE:
+ LineDef.width *= ((scaleINFO*)tmpl)->sy.fy; LineDef.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+ pgFillLine.width *= ((scaleINFO*)tmpl)->sy.fy; pgFillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+ pgFill.scale *= ((scaleINFO*)tmpl)->sy.fy;
+ break;
+ case CMD_LEGEND:
+ if(tmpl && ((GraphObj*)tmpl)->Id == GO_LEGEND) {
+ if(Id == GO_DATAPOLYGON) ((Legend*)tmpl)->HasFill(&LineDef, &pgFill, name);
+ }
+ 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;
+ 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) && (!(pts = (POINT *)malloc(sizeof(POINT)*202))))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
+ }
+ if(dValid) {
+ y = a + b*x1;
+ 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(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);
+ 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_SCALE:
+ LineDef.width *= ((scaleINFO*)tmpl)->sy.fy; LineDef.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+ 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, fac, fac2;
+ 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);
+ switch(type & 0x60000) {
+ case 0x20000: fac = 2.0; break;
+ case 0x40000: fac = 3.0; break;
+ default: fac = 1.0; break;
+ }
+ fac2 = fac*fac; dx = sd2/100.0*fac;
+ for(i = 0, cp = 0, x = -(sd2*fac); i < 2; i++) {
+ do {
+ fv = (x*x)/(ss2*fac2);
+ fv = fv < 0.99999 ? sqrt((1.0-fv)*ss1*fac2) : 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*fac) && x > (-sd2*fac));
+ x = sd2*fac;
+ 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_SCALE:
+ LineDef.width *= ((scaleINFO*)tmpl)->sy.fy; LineDef.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+ if(rl) rl->Command(cmd, tmpl, o);
+ 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(mo) DelBitmapClass(mo); mo = 0L;
+ if(ssRef) free(ssRef); ssRef = 0L;
+ if(name) free(name); name = 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.0);
+ break;
+ default:
+ ie = target->un2iy(SizeBar/2.0);
+ 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, 2);
+}
+
+void
+ErrorBar::DoMark(anyOutput *o, bool mark)
+{
+ int i;
+ LineDEF OldLine;
+
+ if(mark){
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ memcpy(&mrc, &rDims, sizeof(RECT));
+ memcpy(&OldLine, &ErrLine, sizeof(LineDEF));
+ i = 3*o->un2ix(ErrLine.width); //increase size of rectangle for marks
+ IncrementMinMaxRect(&mrc, i); mo = GetRectBitmap(&mrc, o);
+ ErrLine.width *= 5.0; DoPlot(o);
+ ErrLine.width = OldLine.width; ErrLine.color = OldLine.color ^ 0x00ffffffL;
+ DoPlot(o); o->UpdateRect(&mrc, false);
+ memcpy(&ErrLine, &OldLine, sizeof(LineDEF));
+ }
+ else if(mo) RestoreRectBitmap(&mo, &mrc, o);
+}
+
+bool
+ErrorBar::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ bool bFound;
+ int cb;
+
+ switch (cmd) {
+ case CMD_SCALE:
+ ErrLine.width *= ((scaleINFO*)tmpl)->sy.fy; ErrLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+ SizeBar *= ((scaleINFO*)tmpl)->sy.fy;
+ return true;
+ 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);
+ }
+ return false;
+ case CMD_SET_DATAOBJ:
+ Id = GO_ERRBAR;
+ data = (DataObj *) tmpl;
+ return true;
+ case CMD_REDRAW:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ 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, &ferr);
+ return true;
+ }
+ return false;
+ case CMD_LEGEND:
+ if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+ switch(type) {
+ case ERRBAR_VSYM: case ERRBAR_VUP: case ERRBAR_VDOWN:
+ ((Legend*)tmpl)->HasErr(&ErrLine, 1, name);
+ break;
+ case ERRBAR_HSYM: case ERRBAR_HLEFT: case ERRBAR_HRIGHT:
+ ((Legend*)tmpl)->HasErr(&ErrLine, 2, name);
+ break;
+ }
+ break;
+ case CMD_ERRDESC:
+ if(tmpl && *((char *)tmpl)){
+ cb = (int)strlen((char*)tmpl)+2;
+ if(name = (char*)realloc(name, cb)) rlp_strcpy(name, cb, (char*)tmpl);
+ return true;
+ }
+ return false;
+ case CMD_ERR_TYPE:
+ if(tmpl) type = *((int*)tmpl);
+ return true;
+ 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*o->un2ix(LineDef.width)+3);
+ 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;
+ }
+ if(mark) {
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ if(dh1 && dh2) {
+ memcpy(&mrc, &rDims, sizeof(RECT)); memcpy(&OldLine, &LineDef, sizeof(LineDEF));
+ mo = GetRectBitmap(&mrc, o); Redraw(o);
+ dh1->DoPlot(o); dh2->DoPlot(o);
+ }
+ else {
+ memcpy(&mrc, &rDims, sizeof(RECT)); memcpy(&OldLine, &LineDef, sizeof(LineDEF));
+ mo = GetRectBitmap(&mrc, o); LineDef.color = 0x00000000L;
+ LineDef.width = OldLine.width *3.0; Redraw(o);
+ LineDef.width = OldLine.width; LineDef.color = OldLine.color ^ 0x00ffffffL;
+ Redraw(o); o->UpdateRect(&mrc, false);
+ memcpy(&LineDef, &OldLine, sizeof(LineDEF));
+ }
+ }
+ else if(mo) RestoreRectBitmap(&mo, &mrc, o);
+}
+
+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_SCALE:
+ LineDef.width *= ((scaleINFO*)tmpl)->sy.fy; LineDef.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+ cw *= ((scaleINFO*)tmpl)->sy.fy; cl *= ((scaleINFO*)tmpl)->sy.fy;
+ if(type & ARROW_UNITS) {
+ pos1.fx = ((scaleINFO*)tmpl)->sx.fx + pos1.fx * ((scaleINFO*)tmpl)->sx.fy;
+ pos1.fy = ((scaleINFO*)tmpl)->sy.fx + pos1.fy * ((scaleINFO*)tmpl)->sy.fy;
+ pos2.fx = ((scaleINFO*)tmpl)->sx.fx + pos2.fx * ((scaleINFO*)tmpl)->sx.fy;
+ pos2.fy = ((scaleINFO*)tmpl)->sy.fx + pos2.fy * ((scaleINFO*)tmpl)->sy.fy;
+ }
+ return true;
+ case CMD_FLUSH:
+ if (dh1) DeleteGO(dh1); dh1 = 0L;
+ if (dh2) DeleteGO(dh2); dh2 = 0L;
+ if(mo) DelBitmapClass(mo); mo = 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::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;
+ 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
+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);
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ //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 || (pos1.fy == pos2.fy && pos1.fx == pos2.fx)) 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);
+ IncrementMinMaxRect(&rDims, o->un2ix(Outline.width*6)+3);
+}
+
+void
+Box::DoMark(anyOutput *o, bool mark)
+{
+ if(mark){
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ memcpy(&mrc, &rDims, sizeof(RECT));
+ IncrementMinMaxRect(&mrc, o->un2ix(Outline.width*6)+3);
+ mo = GetRectBitmap(&mrc, o);
+ InvertLine(pts, 5, &Outline, &rDims, o, mark);
+ }
+ else if(mo) RestoreRectBitmap(&mo, &mrc, o);
+}
+
+bool
+Box::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ POINT p;
+
+ switch (cmd) {
+ case CMD_SCALE:
+ Outline.width *= ((scaleINFO*)tmpl)->sy.fy;
+ Hatchline.width *= ((scaleINFO*)tmpl)->sy.fy;
+ Fill.scale *= ((scaleINFO*)tmpl)->sy.fy;
+ if(!(type & BAR_RELWIDTH) && parent->Id!= GO_DENSDISP)size *= ((scaleINFO*)tmpl)->sy.fy;
+ return true;
+ case CMD_FLUSH:
+ if(ssRef) free(ssRef); ssRef = 0L;
+ if(name)free(name); name = 0L;
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ return true;
+ case CMD_LEGEND:
+ if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+ ((Legend*)tmpl)->HasFill(&Outline, &Fill, name);
+ 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, p.x = mev->x, p.y = mev->y) && !CurrGO) {
+ if(IsInPolygon(&p, pts, 5)) {
+ o->ShowMark(CurrGO = 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) {
+ if(type & BAR_WIDTHDATA) {
+ if(pos1.fy != pos2.fy) {
+ ((Plot*)parent)->CheckBounds(pos1.fx+size, pos1.fy);
+ ((Plot*)parent)->CheckBounds(pos2.fx-size, pos2.fy);
+ }
+ else {
+ ((Plot*)parent)->CheckBounds(pos1.fx, pos1.fy+size);
+ ((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy-size);
+ }
+ }
+ else {
+ ((Plot*)parent)->CheckBounds(pos1.fx, pos1.fy);
+ ((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy);
+ if(parent && (type & BAR_RELWIDTH)) {
+ if(pos1.fy == pos2.fy) {
+ ((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy + parent->GetSize(SIZE_BOXMINY));
+ ((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy - parent->GetSize(SIZE_BOXMINY));
+ }
+ else if(pos1.fx == pos2.fx) {
+ ((Plot*)parent)->CheckBounds(pos2.fx + parent->GetSize(SIZE_BOXMINX), pos2.fy);
+ ((Plot*)parent)->CheckBounds(pos2.fx - parent->GetSize(SIZE_BOXMINX), 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;
+ }
+ }
+ Command(CMD_AUTOSCALE, 0L, 0L);
+}
+
+Whisker::Whisker(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+Whisker::~Whisker()
+{
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ if(ssRef) free(ssRef); ssRef = 0L;
+ if(name) free(name); name = 0L;
+}
+
+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)
+{
+ int i;
+ LineDEF OldLine;
+
+ if(mark){
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ memcpy(&mrc, &rDims, sizeof(RECT));
+ memcpy(&OldLine, &LineDef, sizeof(LineDEF));
+ i = 3*o->un2ix(LineDef.width); //increase size of rectangle for marks
+ IncrementMinMaxRect(&mrc, i); mo = GetRectBitmap(&mrc, o);
+ LineDef.width *= 5.0; DoPlot(o);
+ LineDef.width = OldLine.width; LineDef.color = OldLine.color ^ 0x00ffffffL;
+ DoPlot(o); o->UpdateRect(&mrc, false);
+ memcpy(&LineDef, &OldLine, sizeof(LineDEF));
+ }
+ else RestoreRectBitmap(&mo, &mrc, o);
+}
+
+bool
+Whisker::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ int cb;
+
+ switch (cmd) {
+ case CMD_SCALE:
+ size *= ((scaleINFO*)tmpl)->sy.fy;
+ LineDef.width *= ((scaleINFO*)tmpl)->sy.fy;
+ LineDef.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+ return true;
+ 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_ERRDESC:
+ if(tmpl && *((char*)tmpl)) {
+ cb = (int)strlen((char*)tmpl)+2;
+ if(name = (char*)realloc(name, cb)) rlp_strcpy(name, cb, (char*)tmpl);
+ return true;
+ }
+ return false;
+ case CMD_LEGEND:
+ if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+ switch(type & 0x0f) {
+ case 1: ((Legend*)tmpl)->HasErr(&LineDef, 5, name); break;
+ case 2: ((Legend*)tmpl)->HasErr(&LineDef, 4, name); break;
+ case 3: ((Legend*)tmpl)->HasErr(&LineDef, 3, name); break;
+ default:
+ if((rDims.right - rDims.left) < (rDims.bottom - rDims.top))
+ ((Legend*)tmpl)->HasErr(&LineDef, 1, name);
+ else ((Legend*)tmpl)->HasErr(&LineDef, 2, name);
+ break;
+ }
+ break;
+ 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 DefSize(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:
+ type = 0;
+ case 5:
+ rx = o->un2ix(size/2.0); ry = o->un2iy(size/2.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_SCALE:
+ Line.patlength *= ((scaleINFO*)tmpl)->sy.fy; Line.width *= ((scaleINFO*)tmpl)->sy.fy;
+ Fill.scale *= ((scaleINFO*)tmpl)->sy.fy;
+ if(!type || type == 5)size *= ((scaleINFO*)tmpl)->sy.fy;;
+ return true;
+ case CMD_LEGEND:
+ if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+ ((Legend*)tmpl)->HasFill(&Line, &Fill, 0L);
+ break;
+ 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; bSigPol = false;
+ 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) {
+ if(Line.width == 0.0) return;
+ //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 && nldata){
+ if(Line.width == 0.0) Line.color = Fill.color;
+ o->SetLine(&Line); o->SetFill(&Fill);
+
+//FILE *dbg;
+//dbg = fopen("c:/test2.txt", "a");
+//fprintf(dbg, "\nplane with %d parts\n", nli);
+ for(i = 0; i < nli; i++){
+//fprintf(dbg, "\n");
+ if(nldata[i] > 2 && (pt = (POINT*)malloc(nldata[i]*sizeof(POINT)))){
+ for(j = 0; j < nldata[i]; j++) {
+//fprintf(dbg, " %d %d\n", ldata[i][j].x, ldata[i][j].y);
+ pt[j].x = ldata[i][j].x; pt[j].y = ldata[i][j].y;
+ }
+ o->oPolygon(pt, nldata[i]);
+ free(pt);
+ }
+ }
+//fclose(dbg);
+ }
+ 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(bSigPol) {
+ n_linept = 1; bSigPol = false;
+ }
+// else n_linept = 0;
+ 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_SIGNAL_POL: //signal: next point is on outline
+ bSigPol = 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].z == ap->z){
+ //probably nothing to add
+ 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]++;
+ if(bSigPol) n_linept++;
+ bSigPol = false;
+ return true;
+ }
+ case CMD_CLIP:
+ bSigPol = false;
+ if(co = (GraphObj*)tmpl){
+ switch(co->Id) {
+ case GO_PLANE:
+ 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){
+ if(bSigPol) {
+ nldata[i]--;
+ }
+ else 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;
+ double *co_vec, d;
+
+ //if two planes have the same parent it means they are part of one object
+ // do not clip!
+ if(co->parent == parent && co->Id == GO_PLANE) return;
+ //test if two planes are part of the same superplane
+#define TOL3D 1.0e-12
+ if(co->Id == GO_PLANE && (co_vec = ((plane*)co)->GetVec()) && PlaneVec && fabs(co_vec[0] - PlaneVec[0]) < TOL3D
+ && fabs(co_vec[1]-PlaneVec[1]) < TOL3D && fabs(co_vec[2]-PlaneVec[2]) < TOL3D && ldata && nldata) {
+ d = (ldata[0][0].x * co_vec[0] + ldata[0][0].y * co_vec[1] - co_vec[3])/co_vec[2] - ldata[0][0].z;
+ if(fabs(d) < 2) return;
+ }
+#undef TOL3D
+ 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++) {
+ n_linept = 0;
+ 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){
+ if(bSigPol) nldata[nli-1]--;
+ 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, ratio;
+
+ //if all points on an edge: not valid
+ if(n_linept >= npg) return false;
+ //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 < 25) return false;
+ ratio = totalArea/area;
+ if(ratio > 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;
+ if(!(o->ActualSize(&rDims)))return;
+ 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_SCALE:
+ Line.patlength *= ((scaleINFO*)tmpl)->sy.fy; Line.width *= ((scaleINFO*)tmpl)->sy.fy;
+ Fill.scale *= ((scaleINFO*)tmpl)->sy.fy;
+ return true;
+ case CMD_LEGEND:
+ if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+ if(parent && parent->Id > GO_PLOT && parent->Id < GO_GRAPH) {
+ ((Legend*)tmpl)->HasFill(&Line, &Fill, ((Plot*)parent)->data_desc);
+ }
+ else ((Legend*)tmpl)->HasFill(&Line, &Fill, 0L);
+ 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){
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ 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_SCALE:
+ Line.patlength *= ((scaleINFO*)tmpl)->sy.fy; Line.width *= ((scaleINFO*)tmpl)->sy.fy;
+ Fill.scale *= ((scaleINFO*)tmpl)->sy.fy; depth *= ((scaleINFO*)tmpl)->sz.fy;
+ width *= ((scaleINFO*)tmpl)->sx.fy; if(!(flags & 0x800L)) height *= ((scaleINFO*)tmpl)->sx.fy;
+ return true;
+ case CMD_LEGEND:
+ if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+ if(parent && parent->Id > GO_PLOT && parent->Id < GO_GRAPH) {
+ ((Legend*)tmpl)->HasFill(&Line, &Fill, ((Plot*)parent)->data_desc);
+ }
+ else ((Legend*)tmpl)->HasFill(&Line, &Fill, 0L);
+ 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) {
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ 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_SCALE:
+ Line.patlength *= ((scaleINFO*)tmpl)->sy.fy; Line.width *= ((scaleINFO*)tmpl)->sy.fy;
+ 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_SCALE:
+ Line.patlength *= ((scaleINFO*)tmpl)->sy.fy; Line.width *= ((scaleINFO*)tmpl)->sy.fy;
+ cw *= ((scaleINFO*)tmpl)->sy.fy; cl *= ((scaleINFO*)tmpl)->sy.fy;
+ 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 = (char*)memdup(rx, (int)strlen(rx)+2, 0L);
+ if(ry && ry[0]) y_range = (char*)memdup(ry, (int)strlen(ry)+2, 0L);
+ if(rz && rz[0]) z_range = (char*)memdup(rz, (int)strlen(rz)+2, 0L);
+ DoUpdate();
+ Id = GO_LINE3D;
+ bModified = false;
+}
+
+Line3D::Line3D(GraphObj *par, DataObj *d, fPOINT3D *pt, int n_pt, 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);
+ 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*));
+ }
+ 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;
+ }
+ }
+ 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; cssRef = 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(ssRef) free(ssRef); ssRef = 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) {
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ 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_SCALE:
+ Line.patlength *= ((scaleINFO*)tmpl)->sy.fy; Line.width *= ((scaleINFO*)tmpl)->sy.fy;
+ 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:
+ if(parent && parent->Id != GO_GRID3D) {
+ Undo.DataMem(this, (void**)&values, nPts * sizeof(fPOINT3D), &nPts, UNDO_CONTINUE);
+ }
+ if(ssRef && cssRef >5 && data && nPts == 2) {
+ data->GetValue(ssRef[0].y, ssRef[0].x, &values[0].fx);
+ data->GetValue(ssRef[1].y, ssRef[1].x, &values[0].fy);
+ data->GetValue(ssRef[2].y, ssRef[2].x, &values[0].fz);
+ data->GetValue(ssRef[3].y, ssRef[3].x, &values[1].fx);
+ data->GetValue(ssRef[4].y, ssRef[4].x, &values[1].fy);
+ data->GetValue(ssRef[5].y, ssRef[5].x, &values[1].fz);
+ return true;
+ }
+ else 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)
+{
+ int cb;
+
+ 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 && td->text[0]) {
+ cb = (int)strlen(td->text)+1; if(cb < 20) cb = 20;
+ TextDef.text = (char*)malloc(cb *sizeof(char));
+ rlp_strcpy(TextDef.text, cb, 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()
+{
+ HideTextCursor();
+ Command(CMD_FLUSH, 0L, 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;
+ case SIZE_TEXT: TextDef.fSize = value; return 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(this != CurrGO && m1 >=0 && m2 >=0) {
+ m1 = m2 = -1;
+ }
+ 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 if(m1 >= 0 && m2 >= 0) {
+ m1 = m2 = -1;
+ parent->Command(CMD_REDRAW, 0L, o);
+ }
+ else {
+ HideTextCursor(); m1 = m2 = -1;
+ 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;
+ scaleINFO *scale;
+ int i, cb;
+
+ if(cmd != CMD_SET_DATAOBJ && !parent) return false;
+ switch (cmd) {
+ case CMD_SCALE:
+ scale = (scaleINFO*)tmpl;
+ if((flags & 0x03)!= LB_X_DATA) fPos.fx *= scale->sx.fy;
+ if((flags & 0x30)!= LB_Y_DATA) fPos.fy *= scale->sy.fy;
+ fDist.fx *= scale->sx.fy; fDist.fy *= scale->sy.fy;
+ TextDef.fSize *= scale->sx.fy; TextDef.iSize = 0;
+ return true;
+ case CMD_HIDEMARK:
+ if(m1 >=0 && m2 >=0 && m1 != m2) {
+ m1 = m2 = -1; return true;
+ }
+ return false;
+ 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) ? (int)strlen(TextDef.text) : 0;
+ ShowCursor(o);
+ return true;
+ }
+ return false;
+ case CMD_SHIFTLEFT: case CMD_CURRLEFT:
+ if(o && CursorPos >0 && TextDef.text) {
+ Undo.ValInt(this, &CursorPos, 0L);
+ DrawFmtText.SetText(0L, TextDef.text, 0L, 0L);
+ bModified = true;
+ if(cmd == CMD_SHIFTLEFT) {
+ if(CursorPos && CursorPos == m1) {
+ DrawFmtText.cur_left(&CursorPos);
+ m1 = CursorPos; ShowCursor(o);
+ }
+ else if(CursorPos && CursorPos == m2) {
+ DrawFmtText.cur_left(&CursorPos);
+ m2 = CursorPos; ShowCursor(o);
+ if(parent) parent->Command(CMD_REDRAW, 0L, o);
+ }
+ else if(CursorPos){
+ m2 = CursorPos;
+ DrawFmtText.cur_left(&CursorPos);
+ m1 = CursorPos; ShowCursor(o);
+ }
+ }
+ else {
+ if(m1 >= 0 && m2 >= 0 && parent) {
+ m1 = m2 = -1; parent->Command(CMD_REDRAW, 0L, o);
+ }
+ DrawFmtText.cur_left(&CursorPos); ShowCursor(o);
+ }
+ if(m1 >=0 && m2 >=0 && m1 != m2) DoPlot(o);
+ return true;
+ }
+ return false;
+ case CMD_SHIFTRIGHT: case CMD_CURRIGHT:
+ if(o && TextDef.text && CursorPos < (int)strlen(TextDef.text)) {
+ Undo.ValInt(this, &CursorPos, 0L);
+ DrawFmtText.SetText(0L, TextDef.text, 0L, 0L);
+ bModified = true;
+ if(cmd == CMD_SHIFTRIGHT) {
+ if(CursorPos == m1 && TextDef.text[m1]) {
+ DrawFmtText.cur_right(&CursorPos);
+ m2 = CursorPos; ShowCursor(o);
+ memcpy(&rm2, &Cursor, sizeof(RECT));
+ if(parent) parent->Command(CMD_REDRAW, 0L, o);
+ }
+ else if(CursorPos == m2 && TextDef.text[m2]) {
+ DrawFmtText.cur_right(&CursorPos);
+ m2 = CursorPos; ShowCursor(o);
+ memcpy(&rm2, &Cursor, sizeof(RECT));
+ }
+ else if(TextDef.text[CursorPos]){
+ if(m1 < 0) {
+ m1 = CursorPos; ShowCursor(o);
+ }
+ DrawFmtText.cur_right(&CursorPos);
+ m2 = CursorPos; ShowCursor(o);
+ }
+ else return false;
+ }
+ else {
+ if(m1 >= 0 && m2 >= 0 && parent) {
+ m1 = m2 = -1; parent->Command(CMD_REDRAW, 0L, o);
+ }
+ DrawFmtText.cur_right(&CursorPos); ShowCursor(o);
+ }
+ if(m1 >=0 && m2 >=0 && m1 != m2) DoPlot(o);
+ return true;
+ }
+ return false;
+ case CMD_ADDCHAR: case CMD_ADDCHARW:
+ SetModified();
+ if(tmpl && 8 != *((int*)tmpl)) return AddChar(*((int*)tmpl), o);
+ //value 8 == backspace
+ case CMD_BACKSP:
+ SetModified();
+ if(CursorPos <=0 && o) {
+ if(parent && parent->Id == GO_MLABEL) {
+ parent->Command(CMD_SETFOCUS, this, o);
+ return parent->Command(CMD_BACKSP, tmpl, o);
+ }
+ RedrawEdit(o);
+ return true;
+ }
+ DrawFmtText.SetText(0L, TextDef.text, 0L, 0L);
+ DrawFmtText.cur_left(&CursorPos); //continue as if delete
+ case CMD_DELETE:
+ SetModified();
+ if(TextDef.text && TextDef.text[CursorPos]) {
+ Undo.String(this, &TextDef.text, 0L);
+ if(cmd == CMD_DELETE) Undo.ValInt(this, &CursorPos, UNDO_CONTINUE);
+ if(CheckMark() && m2 < (cb = (int) strlen(TextDef.text))) {
+ Undo.ValInt(this, &m1, UNDO_CONTINUE);
+ Undo.ValInt(this, &m2, UNDO_CONTINUE);
+ rlp_strcpy(TextDef.text + m1, cb, TextDef.text + m2);
+ CursorPos = m1; m1 = m2 = -1;
+ }
+ else {
+ DrawFmtText.SetText(0L, TextDef.text, 0L, 0L);
+ cb = CursorPos; DrawFmtText.cur_right(&cb);
+ cb -= CursorPos; if(cb < 1) cb = 1;
+ rlp_strcpy(TextDef.text + CursorPos, TMP_TXT_SIZE, TextDef.text + CursorPos + cb);
+ }
+ if(o) {
+ RedrawEdit(o); ShowCursor(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 && TextDef.text[0] && tmpl) {
+ rlp_strcpy((char*)tmpl, TMP_TXT_SIZE, TextDef.text);
+ return true;
+ }
+ return false;
+ case CMD_SETTEXT:
+ if(TextDef.text) free(TextDef.text); TextDef.text = 0L;
+ if(tmpl && *((char*)tmpl)) {
+ TextDef.text = (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1, 0);
+ }
+ return true;
+ case CMD_GETTEXTDEF:
+ if(!tmpl) return false;
+ memcpy(tmpl, &TextDef, sizeof(TextDEF));
+ return true;
+ case CMD_SETTEXTDEF:
+ if(!tmpl)return false;
+ memcpy(&TextDef, tmpl, sizeof(TextDEF)-sizeof(char*));
+ if(((TextDEF*)tmpl)->text) Command(CMD_SETTEXT, tmpl, o);
+ 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)) {
+ Undo.String(this, &TextDef.text, UNDO_CONTINUE);
+ TextDef.text = (char*)realloc(TextDef.text, cb = (int)strlen(TmpTxt)+2);
+ if(TmpTxt[0]) rlp_strcpy(TextDef.text, cb, TmpTxt);
+ else TextDef.text[0] = 0;
+ }
+ 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_MOVE:
+ if((mev->StateFlags & 0x01) && ObjThere(mev->x, mev->y)) {
+ i = CursorPos; CalcCursorPos(mev->x, mev->y, o);
+ if(CurrLabel && CurrLabel != this) {
+ CurrLabel->Command(CMD_HIDEMARK, tmpl, o);
+ }
+ CurrGO = CurrLabel = this;
+ if(i == CursorPos) return true;
+ if(CursorPos > m1 && CursorPos < m2) {
+ if(m1 < 0) m1 = CursorPos;
+ else if(m2 != CursorPos)m2 = CursorPos;
+ parent->Command(CMD_REDRAW, 0L, o);
+ }
+ else {
+ if(m1 < 0) m1 = CursorPos;
+ else if(m2 != CursorPos)m2 = CursorPos;
+ if(m1 >=0 && m2 >=0 && m1 != m2) DoPlot(o);
+ }
+ return true;
+ }
+ break;
+ 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);
+ if(o->MrkRect && (void*)o->MrkRect == (void*)this) o->MrkMode = MRK_NONE;
+ if(m1 < 0) m1 = CursorPos; ShowCursor(o);
+ o->ShowMark(this, MRK_GODRAW);
+ }
+ else if(m1 >= 0 && m2 >= 0) {
+ m1 = m2 = -1; DoPlot(o);
+ }
+ break;
+ }
+ break;
+ case CMD_TEXTTHERE:
+ if(ObjThere(((MouseEvent *)tmpl)->x, ((MouseEvent *)tmpl)->y)) {
+ CalcCursorPos(((MouseEvent *)tmpl)->x, ((MouseEvent *)tmpl)->y, o);
+ CalcRect(o);
+ m1 = m2 = CursorPos; CurrGO = this;
+ return true;
+ }
+ m1 = m2 = -1;
+ return false;
+ 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(!(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 || !TextDef.text || !TextDef.text[0]) return;
+ m1 = m2 = -1;
+ 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));
+ defs.UpdRect(o, rDims.left, rDims.top, rDims.right, rDims.bottom);
+ for(i = 0; i < 5; i++) {
+ tpts[i].x = pts[i].x+p->x; tpts[i].y = pts[i].y+p->y;
+ defs.UpdAdd(o, tpts[i].x, tpts[i].y);
+ }
+ o->ShowLine(tpts, 5, TextDef.ColTxt);
+ free(tpts);
+ }
+}
+
+bool
+Label::CalcRect(anyOutput *o)
+{
+ int rx1, rx, ry;
+ fRECT rc, rcc;
+
+ if(parent && parent->Id != GO_MLABEL) o->SetTextSpec(&TextDef);
+ DrawFmtText.SetText(0L, TextDef.text, &ix, &iy);
+ if(TextDef.text && TextDef.text[0]) {
+ if(!(DrawFmtText.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(DrawFmtText.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;
+ 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);
+ UpdateMinMaxRect(&rDims, pts[4].x, pts[4].y);
+ 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::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)
+{
+ static LineDEF yLine = {0.0, 1.0, 0x0000ffff, 0x0};
+ static FillDEF yFill = {0, 0x0000ffff, 1.0, 0L, 0x0000ffff};
+ POINT mpts[5];
+ int i;
+
+ if(!parent || !o) return;
+ if(m1 >= 0 && m2 >= 0 && m1 != m2 && CurrGO == this) {
+ i = CursorPos; CursorPos = m1;
+ CalcRect(o); memcpy(&rm1, &Cursor, sizeof(RECT));
+ CursorPos = m2; CalcRect(o);
+ memcpy(&rm2, &Cursor, sizeof(RECT)); CursorPos = i;
+ if(CurrGO == this) ShowCursor(o);
+ else CalcRect(o);
+ if(m2 > m1) {
+ mpts[0].x = mpts[4].x = rm1.left; mpts[1].x = rm1.right;
+ mpts[0].y = mpts[4].y = rm1.top; mpts[1].y = rm1.bottom;
+ mpts[2].x = rm2.right; mpts[2].y = rm2.bottom;
+ mpts[3].x = rm2.left; mpts[3].y = rm2.top;
+ }
+ else {
+ mpts[0].x = mpts[4].x = rm2.left; mpts[1].x = rm2.right;
+ mpts[0].y = mpts[4].y = rm2.top; mpts[1].y = rm2.bottom;
+ mpts[2].x = rm1.right; mpts[2].y = rm1.bottom;
+ mpts[3].x = rm1.left; mpts[3].y = rm1.top;
+ }
+ o->SetLine(&yLine); o->SetFill(&yFill);
+ o->oPolygon(mpts, 5, 0L);
+ }
+ else {
+ m1 = m2 = -1;
+ if(CurrGO == this) ShowCursor(o);
+ }
+ 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]){
+ DrawFmtText.SetText(o, TextDef.text, &ix, &iy);
+ }
+ if(!(CalcRect(o))) return;
+ if(m1 >= 0 && m2 >= 0 && m1 != m2 && CurrGO == this && fabs(TextDef.RotBL) < 0.01) {
+ o->CopyBitmap(mpts[0].x, mpts[0].y, o, mpts[0].x, mpts[0].y,
+ mpts[2].x - mpts[0].x, mpts[2].y - mpts[0].y, true);
+ }
+ if(m1 >= 0 && m2 >= 0) o->UpdateRect(&rDims, false);
+}
+
+bool
+Label::CheckMark()
+{
+ int m;
+
+ if(m1 < 0 || m2 < 0 || m1 == m2) return false;
+ if(m1 < m2) return true;
+ //come here on right to left mark: swap m1 and m2
+ m = m1; m1 = m2; m2 = m;
+ return true;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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; lspc = 1.0;
+ 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; lspc = 1.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;
+ case SIZE_LSPC:
+ return lspc;
+ }
+ 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;
+ case SIZE_LSPC:
+ undo_flags = CheckNewFloat(&lspc, lspc, value, this, undo_flags);
+ return 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));
+ if(lspc < 0.5 || lspc > 5) lspc = 1.0;
+#ifdef _WINDOWS
+ dist.fx = floor(o->un2fix(TextDef.fSize * si * lspc));
+ dist.fy = floor(o->un2fiy(TextDef.fSize * csi * lspc));
+#else
+ dist.fx = floor(o->un2fix(TextDef.fSize * si * 1.2 * lspc));
+ dist.fy = floor(o->un2fiy(TextDef.fSize * csi * 1.2 * lspc));
+#endif
+ 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;
+ scaleINFO *scale;
+
+ switch (cmd) {
+ case CMD_MOUSE_EVENT: case CMD_TEXTTHERE:
+ 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_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: //used e.g from dialog text boxes
+ if(tmpl && Lines && nLines){
+ for(i = j = 0; i < nLines; i++) {
+ if(Lines[i] && Lines[i]->Command(CMD_GETTEXT, TmpTxt+500, o) && TmpTxt[500]){
+ j += rlp_strcpy((char*)tmpl+j, 500-j, TmpTxt+500);
+ ((char*)tmpl)[j++] = '\n';
+ }
+ ((char*)tmpl)[j] = 0;
+ }
+ if(j >2) return true;
+ }
+ return false;
+ 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;
+ if(parent)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;
+ 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_SCALE:
+ scale = (scaleINFO*)tmpl;
+ if((flags & 0x03)!= LB_X_DATA) fPos.fx *= scale->sx.fy;
+ if((flags & 0x30)!= LB_Y_DATA) fPos.fy *= scale->sy.fy;
+ fDist.fx *= scale->sx.fy; fDist.fy *= scale->sy.fy;
+ TextDef.fSize *= scale->sx.fy; TextDef.iSize = 0;
+ return true;
+ 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);
+ }
+ }
+ defs.UpdRect(o, rDims.left, rDims.top, rDims.right, rDims.bottom);
+ 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
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// a rectangular range to accept any text
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+TextFrame::TextFrame(GraphObj *parent, DataObj *data, lfPOINT *p1, lfPOINT *p2, char *txt)
+ :GraphObj(parent, data)
+{
+ FileIO(INIT_VARS); lspc = 1.0;
+ pos1.fx = p1->fx; pos1.fy = p1->fy; pos2.fx = p2->fx; pos2.fy = p2->fy;
+ if(txt && txt[0]) {
+ text = (unsigned char*)memdup(txt, (int)strlen(txt)+1, 0);
+ }
+ else if(lines = (unsigned char**)malloc(sizeof(char*))){
+ if(lines[0] = (unsigned char*)malloc(TF_MAXLINE))lines[0][0] = 0;
+ nlines = 1;
+ }
+ Id = GO_TEXTFRAME;
+}
+
+TextFrame::TextFrame(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+ moveable = 1; bModified = false;
+}
+
+TextFrame::~TextFrame()
+{
+ int i;
+
+ if(text)free(text); text = 0L;
+ if(drc) delete(drc); drc = 0L;
+ if(tm_rec) free(tm_rec); tm_rec = 0L;
+ if(lines) {
+ for(i = 0; i < nlines; i++) if(lines[i]) free(lines[i]);
+ free(lines); lines = 0L;
+ }
+ HideTextCursor();
+}
+double
+TextFrame::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
+TextFrame::SetSize(int select, double value)
+{
+ switch(select & 0xfff) {
+ case SIZE_XPOS: pos1.fx = value; return bResize = true;
+ case SIZE_XPOS+1: pos2.fx = value; return bResize = true;
+ case SIZE_YPOS: pos1.fy = value; return bResize = true;
+ case SIZE_YPOS+1: pos2.fy = value; return bResize = true;
+ }
+ return false;
+}
+
+void
+TextFrame::DoMark(anyOutput *o, bool mark)
+{
+ RECT upd;
+
+ if(has_m1 && has_m2) TextMark(o, 3);
+ has_m1 = has_m2 = false;
+ if(!drc) drc = new dragRect(this, 0);
+ memcpy(&upd, &rDims, sizeof(RECT));
+ if(mark){
+ if(drc) drc->DoPlot(o); ShowCursor(o);
+ }
+ else if(parent) parent->DoPlot(o);
+ IncrementMinMaxRect(&upd, 6);
+ o->UpdateRect(&upd, false);
+}
+
+void
+TextFrame::DoPlot(anyOutput *o)
+{
+ int i, j, x1, y1, x2, y2;
+ double tmp, dx, dy;
+
+ if(!o) return;
+ 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);
+ x1 = o->co2ix(pos1.fx+dx); y1 = o->co2iy(pos1.fy+dy);
+ x2 = o->co2ix(pos2.fx+dx); y2 = o->co2iy(pos2.fy+dy);
+ ipad.left = o->un2ix(pad.Xmin); ipad.right = o->un2ix(pad.Xmax);
+ ipad.top = o->un2iy(pad.Ymin); ipad.bottom = o->un2iy(pad.Ymax);
+ }
+ else {
+ dx = dy = 0.0;
+ x1 = (int)pos1.fx; y1 = (int)pos1.fy; x2 = (int)pos2.fx; y2 = (int)pos2.fy;
+ ipad.left = ipad.right = ipad.top = ipad.bottom = 4;
+ fmt_txt.EditMode(true);
+ }
+ if(pos1.fx > pos2.fx) {
+ tmp = pos2.fx; pos2.fx = pos1.fx; pos1.fx = tmp;
+ }
+ if(pos1.fy > pos2.fy) {
+ tmp = pos2.fy; pos2.fy = pos1.fy; pos1.fy = tmp;
+ }
+ o->SetLine(&Line); o->SetFill(&Fill);
+ o->oRectangle(x1, y1, x2, y2, name);
+ SetMinMaxRect(&rDims, x1, y1, x2, y2);
+ x1 += ipad.left; y1 += ipad.top;
+ TextDef.iSize = o->un2iy(TextDef.fSize);
+#ifdef _WINDOWS
+ linc = o->un2iy(TextDef.fSize*lspc);
+#else
+ linc = o->un2iy(TextDef.fSize*lspc*1.2);
+#endif
+ o->SetTextSpec(&TextDef); y1 += linc;
+ if(text && text[0] && !(lines)) text2lines(o);
+ else if(bResize && lines) {
+ c_char = lines[cur_pos.y][cur_pos.x]; lines[cur_pos.y][cur_pos.x] = 0x01;
+ if(!c_char) lines[cur_pos.y][cur_pos.x+1] = 0x00;
+ lines2text(); text2lines(o); bResize = false;
+ o->ShowMark(this, MRK_GODRAW);
+ return;
+ }
+ if(has_m1 && has_m2) TextMark(o, 1);
+ for(i = 0; i < nlines; i++) {
+ if(lines[i] && lines[i][0]){
+ j = (int)strlen((char*)lines[i]);
+ if(lines[i][j-1] == '\n') {
+ lines[i][j-1] = 0;
+ fmt_txt.SetText(o, (char*)lines[i], &x1, &y1);
+ lines[i][j-1] = '\n';
+ }
+ else fmt_txt.SetText(o, (char*)lines[i], &x1, &y1);
+ }
+ y1 += linc;
+ }
+ if(has_m1 && has_m2) TextMark(o, 2);
+ bModified = bResize = false;
+}
+
+bool
+TextFrame::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ MouseEvent *mev;
+ int i;
+
+ switch (cmd) {
+ case CMD_SELECT:
+ if(!o || !tmpl) return false;
+ CalcCursorPos(((POINT*)tmpl)->x, ((POINT*)tmpl)->y, o);
+ if(parent)o->ShowMark(this, MRK_GODRAW); ShowCursor(o);
+ return true;
+ case CMD_COPY:
+ return CopyText(o, false);
+ case CMD_SAVEPOS:
+ bModified = true;
+ Undo.SaveLFP(this, &pos1, 0L);
+ Undo.SaveLFP(this, &pos2, UNDO_CONTINUE);
+ return true;
+ case CMD_SCALE:
+ if(tmpl) {
+ pos1.fx = ((scaleINFO*)tmpl)->sx.fx + pos1.fx * ((scaleINFO*)tmpl)->sx.fy;
+ pos1.fy = ((scaleINFO*)tmpl)->sy.fx + pos1.fy * ((scaleINFO*)tmpl)->sy.fy;
+ pos2.fx = ((scaleINFO*)tmpl)->sx.fx + pos2.fx * ((scaleINFO*)tmpl)->sx.fy;
+ pos2.fy = ((scaleINFO*)tmpl)->sy.fx + pos2.fy * ((scaleINFO*)tmpl)->sy.fy;
+ TextDef.fSize *= ((scaleINFO*)tmpl)->sy.fy; TextDef.iSize = 0;
+ pad.Xmax *= ((scaleINFO*)tmpl)->sx.fy; pad.Xmin *= ((scaleINFO*)tmpl)->sx.fy;
+ pad.Ymax *= ((scaleINFO*)tmpl)->sy.fy; pad.Ymin *= ((scaleINFO*)tmpl)->sy.fy;
+ Line.width *= ((scaleINFO*)tmpl)->sy.fy; Line.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+ FillLine.width *= ((scaleINFO*)tmpl)->sy.fy; FillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy;
+ Fill.scale *= ((scaleINFO*)tmpl)->sy.fy;
+ }
+ return true;
+ case CMD_GETTEXT: case CMD_ALLTEXT:
+ if(lines && lines[0] && lines[0][0] && nlines) {
+ lines2text(); i = rlp_strcpy((char*)tmpl, TMP_TXT_SIZE-2, (char*)text);
+ while(i && ((char*)tmpl)[i-1] == '\n') i--;
+ ((char*)tmpl)[i++] = '\n'; ((char*)tmpl)[i] = 0;
+ return true;
+ }
+ return false;
+ case CMD_ADDCHARW: case CMD_ADDCHAR:
+ if(tmpl && o) AddChar(o, *((int *)tmpl));
+ return true;
+ case CMD_DELETE:
+ if(o) DelChar(o);
+ return true;
+ case CMD_SHIFTLEFT:
+ if(!has_m1) {
+ m1_pos.x = cur_pos.x; m1_pos.y = cur_pos.y;
+ }
+ has_m1 = has_m2 = true;
+ case CMD_CURRLEFT:
+ if(!(lines[cur_pos.y]))return false;
+ if(cmd == CMD_CURRLEFT && has_m1 && has_m2) TextMark(o, 3);
+ if(cur_pos.x > 0) {
+ i = 0; fmt_txt.SetText(0L,(char*)lines[cur_pos.y], &i, &i);
+ i = cur_pos.x; fmt_txt.cur_left(&i);
+ cur_pos.x = i;
+ }
+ else if(cur_pos.y) {
+ cur_pos.y--; cur_pos.x = (int)strlen((char*)lines[cur_pos.y]);
+ }
+ if(cmd == CMD_SHIFTLEFT){
+ m2_pos.x = cur_pos.x; m2_pos.y = cur_pos.y;
+ DoPlot(o); o->UpdateRect(&rDims, false);
+ }
+ ShowCursor(o);
+ return false;
+ case CMD_SHIFTRIGHT:
+ if(!has_m1) {
+ m1_pos.x = cur_pos.x; m1_pos.y = cur_pos.y;
+ }
+ has_m1 = has_m2 = true;
+ case CMD_CURRIGHT:
+ if(!(lines[cur_pos.y]))return false;
+ if(cmd == CMD_CURRIGHT && has_m1 && has_m2) TextMark(o, 3);
+ if(cur_pos.x >= (int)strlen((char*)lines[cur_pos.y])) {
+ if(cur_pos.y < (nlines-1)) {
+ cur_pos.y++; cur_pos.x = 0;
+ }
+ else if(cur_pos.y == (nlines-1) && lines[cur_pos.y][0]) {
+ if(!(lines = (unsigned char**)realloc(lines, (nlines+1)*sizeof(char*))))return false;
+ if(!(lines[cur_pos.y+1] = (unsigned char*)malloc(TF_MAXLINE))) return false;
+ cur_pos.y++; cur_pos.x = 0; nlines++;
+ lines[cur_pos.y][0] = 0;
+ }
+ }
+ else {
+ i = 0; fmt_txt.SetText(0L,(char*)lines[cur_pos.y], &i, &i);
+ i = cur_pos.x; fmt_txt.cur_right(&i);
+ cur_pos.x = i;
+ }
+ if(cmd == CMD_SHIFTRIGHT){
+ m2_pos.x = cur_pos.x; m2_pos.y = cur_pos.y;
+ DoPlot(o); o->UpdateRect(&rDims, false);
+ }
+ ShowCursor(o);
+ return false;
+ case CMD_SHIFTUP:
+ if(!has_m1) {
+ m1_pos.x = cur_pos.x; m1_pos.y = cur_pos.y;
+ }
+ has_m1 = has_m2 = true;
+ case CMD_CURRUP:
+ if(cmd == CMD_CURRUP && has_m1 && has_m2) TextMark(o, 3);
+ if(cur_pos.y && o) {
+ i = ((Cursor.bottom + Cursor.top)>>1)-linc;
+ CalcCursorPos(Cursor.left, i, o);
+ if(cmd == CMD_SHIFTUP){
+ m2_pos.x = cur_pos.x; m2_pos.y = cur_pos.y;
+ DoPlot(o); o->UpdateRect(&rDims, false);
+ }
+ ShowCursor(o);
+ return true;
+ }
+ return false;
+ case CMD_SHIFTDOWN:
+ if(!has_m1) {
+ m1_pos.x = cur_pos.x; m1_pos.y = cur_pos.y;
+ }
+ has_m1 = has_m2 = true;
+ case CMD_CURRDOWN:
+ if(cmd == CMD_CURRDOWN && has_m1 && has_m2) TextMark(o, 3);
+ if(cur_pos.y < (nlines-1) && o && lines[cur_pos.y][0]) {
+ i = ((Cursor.bottom + Cursor.top)>>1)+linc;
+ if(i >= (rDims.bottom-ipad.bottom)) return false;
+ CalcCursorPos(Cursor.left, i, o);
+ if(cmd == CMD_SHIFTDOWN){
+ m2_pos.x = cur_pos.x; m2_pos.y = cur_pos.y;
+ DoPlot(o); o->UpdateRect(&rDims, false);
+ }
+ ShowCursor(o);
+ return true;
+ }
+ return false;
+ case CMD_POS_FIRST:
+ if(has_m1 && has_m2) TextMark(o, 3);
+ cur_pos.x = 0; ShowCursor(o);
+ return true;
+ case CMD_POS_LAST:
+ if(has_m1 && has_m2) TextMark(o, 3);
+ cur_pos.x = (int)strlen((char*)lines[cur_pos.y]);
+ ShowCursor(o);
+ return true;
+ case CMD_TEXTTHERE:
+ if(IsInRect(&rDims, ((MouseEvent *)tmpl)->x, ((MouseEvent *)tmpl)->y)) return true;
+ return false;
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *) tmpl;
+ switch (mev->Action) {
+ case MOUSE_LBUP:
+ if(IsInRect(&rDims, mev->x, mev->y) && (!(CurrGO) || !has_m2) && o){
+ CalcCursorPos(mev->x, mev->y, o);
+ if(has_m1 && has_m2) {
+ if(o)DoPlot(o); o->UpdateRect(&rDims, false);
+ CurrGO = this; ShowCursor(o);
+ return true;
+ }
+ return o->ShowMark(this, MRK_GODRAW);
+ }
+ else if(CurrGO == this && o){
+ ShowCursor(o);
+ return IsInRect(&rDims, mev->x, mev->y);
+ }
+ break;
+ case MOUSE_LBDOWN:
+ if(has_m1 && has_m2) {
+ has_m1 = has_m2 = false;
+ if(o)DoPlot(o); o->UpdateRect(&rDims, false);
+ }
+ has_m1 = has_m2 = false;
+ case MOUSE_MOVE:
+ if(!(mev->StateFlags & 0x1)) return false;
+ if(!IsInRect(&rDims, mev->x, mev->y))return false;
+ if(!CurrGO) CurrGO = this;
+ CalcCursorPos(mev->x, mev->y, o);
+ if(!has_m1) {
+ m1_pos.x = m2_pos.x = cur_pos.x; m1_pos.y = m2_pos.y = cur_pos.y;
+ return has_m1 = true;
+ }
+ else if(cur_pos.x != m2_pos.x || cur_pos.y != m2_pos.y) {
+ m2_pos.x = cur_pos.x; m2_pos.y = cur_pos.y;
+ has_m2 = true;
+ if(o)DoPlot(o); o->UpdateRect(&rDims, false);
+ return true;
+ }
+ return true;
+ }
+ return false;
+ case CMD_SET_DATAOBJ:
+ Id = GO_TEXTFRAME;
+ return true;
+ case CMD_PASTE:
+ return DoPaste(o);
+ case CMD_MOVE:
+ bModified = true;
+ Undo.MoveObj(this, (lfPOINT*)tmpl, 0L);
+ case CMD_UNDO_MOVE:
+ pos1.fx += ((lfPOINT*)tmpl)[0].fx; pos1.fy += ((lfPOINT*)tmpl)[0].fy;
+ pos2.fx += ((lfPOINT*)tmpl)[0].fx; pos2.fy += ((lfPOINT*)tmpl)[0].fy;
+ CurrGO = this;
+ case CMD_REDRAW:
+ if(parent){
+ if(o && cmd == CMD_REDRAW) DoPlot(o); //trickle down ?
+ if(!o && cmd == CMD_REDRAW) {
+ //coming from Undo
+ bModified = true;
+ if(lines) {
+ for(i = 0; i < nlines; i++) if(lines[i]) free(lines[i]);
+ free(lines); lines = 0L;
+ }
+ HideTextCursor(); cur_pos.x = cur_pos.y = 0;
+ parent->Command(CMD_REDRAW, tmpl, o);
+ }
+ else parent->Command(CMD_REDRAW, tmpl, o);
+ }
+ return true;
+ case CMD_SETSCROLL:
+ if(parent) return parent->Command(cmd, tmpl, o);
+ case CMD_GETTEXTDEF:
+ if(!tmpl) return false;
+ memcpy(tmpl, &TextDef, sizeof(TextDEF));
+ return true;
+ case CMD_SETTEXTDEF:
+ if(!tmpl)return false;
+ memcpy(&TextDef, tmpl, sizeof(TextDEF));
+ TextDef.text = 0L;
+ return true;
+ case CMD_SETTEXT:
+ if(lines) {
+ for(i = 0; i < nlines; i++) if(lines[i]) free(lines[i]);
+ free(lines); lines = 0L;
+ }
+ if(text) free(text); text = 0L;
+ if(tmpl && *((char*)tmpl)) text = (unsigned char*)memdup(tmpl, (int)strlen(((char*)tmpl))+1, 0);
+ return true;
+ }
+ return false;
+}
+
+void
+TextFrame::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(pos1.fx+dx)+p->x;
+ tpts[0].y = tpts[3].y = tpts[4].y = o->co2iy(pos1.fy+dy)+p->y;
+ tpts[1].y = tpts[2].y = o->co2iy(pos2.fy+dy)+p->y;
+ tpts[2].x = tpts[3].x = o->co2ix(pos2.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);
+ }
+}
+
+void *
+TextFrame::ObjThere(int x, int y)
+{
+ if(drc) return drc->ObjThere(x, y);
+ return 0L;
+}
+
+void
+TextFrame::text2lines(anyOutput *o)
+{
+ int i, j, w, h, cl, maxlines, maxw;
+ char tmp_line[TF_MAXLINE];
+ bool hasMark = false;
+
+ if(lines) {
+ for(i = 0; i < nlines; i++) if(lines[i]) free(lines[i]);
+ free(lines); lines = 0L;
+ }
+ has_m1 = has_m2 = false;
+ nlines = 0;
+ if(!text || !text[0]) return;
+ maxlines = (rDims.bottom -rDims.top)/linc +1;
+ maxw = rDims.right - rDims.left - ipad.left - ipad.right;
+ lines = (unsigned char**)calloc(maxlines, sizeof(char*));
+ for(cl = cpos = w = h = 0; cl < maxlines && text[cpos]; cl++) {
+ if(!(lines[cl] = (unsigned char*)malloc(TF_MAXLINE))) return;
+ for(i = 0; text[cpos] && i < TF_MAXLINE; i++) {
+ tmp_line[i] = text[cpos++]; tmp_line[i+1] = 0;
+ fmt_txt.SetText(0L, tmp_line, &w, &h);
+ if(!(fmt_txt.oGetTextExtent(o, &w, &h, i))) break;
+ if(tmp_line[i] == '\n'){
+ break; //new line character found
+ }
+ if(tmp_line[i] < ' ') switch(tmp_line[i]) {
+ case 0x01:
+ if(c_char == 0 && text[cpos]) c_char = text[cpos++]; //cursor at end of line
+ hasMark = true; break;
+ case 0x02: case 0x03:
+ hasMark = true; break;
+ }
+ else if(w >= maxw){
+ for(j = i; j > (i>>1); j--) {
+ if(tmp_line[j] == ' ' || tmp_line[j] == '-' || tmp_line[j] < ' ') break;
+ }
+ if(j == (i>>1)) {
+ cpos--; tmp_line[i] = 0;
+ }
+ else {
+ for(tmp_line[j+1] = 0; j < i; j++, cpos--);
+ }
+ break;
+ }
+ }
+ if(i || tmp_line[i] == '\n') rlp_strcpy((char*)lines[cl], TF_MAXLINE, tmp_line);
+ else lines[cl][0] = 0;
+ }
+ nlines = cl;
+ if(hasMark)procTokens();
+}
+
+void
+TextFrame::lines2text()
+{
+ int i;
+
+ if(text) free(text); cpos = 0;
+ text = (unsigned char*)malloc(csize = 1000);
+ for(i = 0; i < nlines; i++) {
+ if(lines[i] && lines[i][0]) add_to_buff((char**)&text, &cpos, &csize, (char*)lines[i], 0);
+ }
+}
+
+void
+TextFrame::AddChar(anyOutput *o, int c)
+{
+ int i, j, h, w, maxw;
+ bool brd;
+ char *txt1;
+
+ if(cur_pos.y >= nlines) return;
+ if(!lines || !lines[cur_pos.y]) return;
+ if(c == '\r') c = '\n';
+ if(has_m1 && has_m2){
+ TmpTxt[0] = c; TmpTxt[1] = 0;
+ if(c == 8) ReplMark(o, "");
+ else if(c >= 32 || c == '\n') ReplMark(o, TmpTxt);
+ return;
+ }
+ else if(!text) {
+ lines2text();
+ Undo.TextBuffer(this, &csize, &cpos, &text, 0L, o);
+ }
+ maxw = rDims.right - rDims.left - ipad.left - ipad.right;
+ i = j = (int)strlen((char*)lines[cur_pos.y])+1;
+ has_m1 = has_m2 = false;
+ if(c >= 32 || c == '\n') {
+ if(c > 254 && (txt1 = (char*)malloc(10))) {
+#ifdef USE_WIN_SECURE
+ w = sprintf_s(txt1, 10, "&#%d;", c);
+#else
+ w = sprintf(txt1, "&#%d;", c);
+#endif
+ for(j = j+w; j>0; j--) {
+ lines[cur_pos.y][j] = lines[cur_pos.y][j-w];
+ if((j-w) == cur_pos.x){
+ for(i = 0; i < w; i++) lines[cur_pos.y][j-w+i] = txt1[i];
+ j = 0; cur_pos.x += w;
+ }
+ }
+ free(txt1);
+ }
+ else while(j) {
+ lines[cur_pos.y][j] = lines[cur_pos.y][j-1]; j--;
+ if(j == cur_pos.x){
+ lines[cur_pos.y][j] = c; j = 0;
+ cur_pos.x++;
+ }
+ }
+ fmt_txt.SetText(0L, (char*)lines[cur_pos.y], &j, &j);
+ fmt_txt.oGetTextExtent(o, &w, &h, i); brd = false;
+ if(cur_pos.x > 2 && (c == '>' || c == ';')) {
+ if(c == '>' && fmt_txt.leftTag((char*)lines[cur_pos.y],cur_pos.x-1) >= 0) brd =true;
+ if(c == ';' && fmt_txt.ucLeft((char*)lines[cur_pos.y],cur_pos.x-1, 0L, 0L) > 0) brd =true;
+ }
+ if(brd || w >= maxw || c == '\n' || (c == ' ' && w >=(maxw>>1))) {
+ c_char = lines[cur_pos.y][cur_pos.x]; lines[cur_pos.y][cur_pos.x] = 0x01;
+ if(!c_char) lines[cur_pos.y][cur_pos.x+1] = 0x00;
+ lines2text(); Undo.TextBuffer(this, &csize, &cpos, &text, 0L, o); text2lines(o);
+ }
+ }
+ else if(c == 8 && (cur_pos.x || cur_pos.y)) { //Backspace
+ if(!cur_pos.x) Command(CMD_CURRLEFT, 0L, o);
+ Command(CMD_CURRLEFT, 0L, o); DelChar(o);
+ return;
+ }
+ else return;
+ DoPlot(o); o->UpdateRect(&rDims, false); ShowCursor(o);
+}
+
+void
+TextFrame::DelChar(anyOutput *o)
+{
+ int i, cb, x;
+
+ if(has_m1 && has_m2){
+ ReplMark(o, ""); return;
+ }
+ if(lines[cur_pos.y][cur_pos.x]) {
+ lines2text(); Undo.TextBuffer(this, &csize, &cpos, &text, 0L, o);
+ cb = x = cur_pos.x; fmt_txt.cur_right(&x);
+ cb = x - cb; if(cb < 1) cb = 1;
+ for(i = cur_pos.x; lines[cur_pos.y][i]; i++) {
+ if(!(lines[cur_pos.y][i] = lines[cur_pos.y][i+cb])) break;
+ }
+ c_char = lines[cur_pos.y][cur_pos.x]; lines[cur_pos.y][cur_pos.x] = 0x01;
+ if(!c_char) lines[cur_pos.y][cur_pos.x+1] = 0x00;
+ lines2text(); text2lines(o);
+ DoPlot(o); o->UpdateRect(&rDims, false);
+ ShowCursor(o); return;
+ }
+ else if(cur_pos.y < (nlines-1)){
+ cur_pos.y++; cur_pos.x = 0;
+ DelChar(o); return;
+ }
+}
+
+void
+TextFrame::ReplMark(anyOutput *o, char *ntext)
+{
+ int i, j;
+
+ if(!has_m1 || !has_m2 || !o || !ntext) return;
+ lines2text();
+ Undo.TextBuffer(this, &csize, &cpos, &text, 0L, o);
+ for(i = cpos = 0; i < nlines && i < m1_cpos.y; i++) {
+ if(lines[i] && lines[i][0]) add_to_buff((char**)&text, &cpos, &csize, (char*)lines[i], 0);
+ }
+ if(m1_cpos.x)add_to_buff((char**)&text, &cpos, &csize, (char*)lines[i], m1_cpos.x);
+ add_to_buff((char**)&text, &cpos, &csize, ntext, 0); j = cpos;
+ if(m1_cpos.y == m2_cpos.y)add_to_buff((char**)&text, &cpos, &csize, (char*)(lines[i]+m2_cpos.x), 0);
+ for( ; i < nlines && i < m2_cpos.y; i++);
+ if(i == m2_cpos.y && m2_cpos.y > m1_cpos.y)add_to_buff((char**)&text, &cpos, &csize, (char*)(lines[i]+m2_cpos.x), 0);
+ for(i++; i < nlines; i++) {
+ if(lines[i] && lines[i][0]) add_to_buff((char**)&text, &cpos, &csize, (char*)lines[i], 0);
+ }
+ if(tm_rec)free(tm_rec); tm_rec = 0L; has_m1 = has_m2 = false;
+ if(text[j]) {
+ c_char = text[j]; text[j] = 0x01;
+ }
+ else if(i < (nlines-1) && lines[i+1] && lines[i+1][0]) {
+ c_char = lines[i+1][0]; lines[i+1][0] = 0x01;
+ }
+ else if(j == cpos){
+ c_char = 0; text[cpos++] = 0x01; text[cpos] = 0;
+ }
+ else cur_pos.x = cur_pos.y = 0;
+ text2lines(o); DoPlot(o); o->UpdateRect(&rDims, false);
+ ShowCursor(o);
+}
+
+void
+TextFrame::procTokens()
+{
+ int i, j;
+
+ for(i = 0; i < nlines; i++) {
+ if(lines[i] && lines[i][0]){
+ for(j = 0; lines[i][j]; j++) switch(lines[i][j]) {
+ case 0x01:
+ cur_pos.y = i; cur_pos.x = j;
+ lines[i][j] = c_char; c_char = '?';
+ break;
+ case 0x02:
+ m1_pos.y = i; m1_pos.x = j;
+ if(m1_char == 0x01) {
+ lines[i][j] = c_char; c_char = '?';
+ cur_pos.y = i; cur_pos.x = j;
+ }
+ else lines[i][j] = m1_char;
+ has_m1 = true; m1_char = '?';
+ break;
+ case 0x03:
+ m2_pos.y = i; m2_pos.x = j;
+ if(m2_char == 0x01) {
+ lines[i][j] = c_char; c_char = '?';
+ cur_pos.y = i; cur_pos.x = j;
+ }
+ else lines[i][j] = m2_char;
+ has_m2 = true; m2_char = '?';
+ break;
+ }
+ }
+ }
+}
+
+bool
+TextFrame::DoPaste(anyOutput *o)
+{
+ int i, j, k;
+ char *ntxt;
+ unsigned char *ptxt;
+
+ if((ptxt = PasteText()) && ptxt[0]) {
+ lines2text(); Undo.TextBuffer(this, &csize, &cpos, &text, 0L, o);
+ if(!(ntxt = (char*)malloc(strlen((char*)ptxt)+1))) return false;
+ for(i = j = cpos = 0; ptxt[i]; i++) {
+ if(ptxt[i] >= ' ' || ptxt[i] == '\n') ntxt[j++] = ptxt[i];
+ else if(ptxt[i] == 9)ntxt[j++] = ' '; //convert tab->space
+ }
+ ntxt[j] = 0;
+ if(!ntxt[0]) {
+ free(ntxt); return false;
+ }
+ if(has_m1 && has_m2) {
+ ReplMark(o, ntxt); free(ntxt);
+ return true;
+ }
+ m1_char = ntxt[0]; ntxt[0] = 0x02;
+ ntxt[j] = 0; if(text) free(text);
+ if(!(text = (unsigned char*)malloc(csize = 1000)))return false;
+ for(i = k = 0, text[0] = 0; i < nlines; i++) {
+ if(lines[i] && lines[i][0]){
+ if(i == cur_pos.y) {
+ if(cur_pos.x) add_to_buff((char**)&text, &cpos, &csize, (char*)lines[i], cur_pos.x);
+ add_to_buff((char**)&text, &cpos, &csize, ntxt, 0); k = cpos;
+ add_to_buff((char**)&text, &cpos, &csize, (char*)lines[i]+cur_pos.x, 0);
+ free(ntxt); ntxt = 0L;
+ }
+ else add_to_buff((char**)&text, &cpos, &csize, (char*)lines[i], 0);
+ }
+ }
+ if(ntxt) {
+ add_to_buff((char**)&text, &cpos, &csize, ntxt, 0); k = cpos;
+ }
+ m2_char = 0x01;
+ if(text[k]) {
+ c_char = text[k]; text[k] = 0x03;
+ }
+ else if(i < (nlines-1) && lines[i+1] && lines[i+1][0]) {
+ c_char = lines[i+1][0]; lines[i+1][0] = 0x03;
+ }
+ else if(k == cpos){
+ c_char = 0; text[cpos++] = 0x03; text[cpos] = 0;
+ }
+ text2lines(o); DoPlot(o);
+ o->UpdateRect(&rDims, false);
+ ShowCursor(o); if(ntxt) free(ntxt);
+ }
+ return false;
+}
+void
+TextFrame::TextMark(anyOutput *o, int mode)
+{
+ int i, j, w, h;
+ LineDEF ld;
+ FillDEF fd;
+
+ if(m1_pos.y > m2_pos.y) {
+ m1_cpos.y = m2_pos.y; m1_cpos.x = m2_pos.x;
+ m2_cpos.y = m1_pos.y; m2_cpos.x = m1_pos.x;
+ }
+ else if(m1_pos.y == m2_pos.y && m1_pos.x > m2_pos.x) {
+ m1_cpos.x = m2_pos.x; m2_cpos.x = m1_pos.x;
+ m1_cpos.y = m2_cpos.y = m1_pos.y;
+ }
+ else {
+ m1_cpos.y = m1_pos.y; m1_cpos.x = m1_pos.x;
+ m2_cpos.y = m2_pos.y; m2_cpos.x = m2_pos.x;
+ }
+ if(!has_m1 || !has_m2 || !o) return;
+ if(m1_pos.y == m2_pos.y && m1_pos.x == m2_pos.x) return;
+ if(mode == 1){ //create background mark
+ if(tm_rec)free(tm_rec); tm_rec = 0L;
+ if((tm_c = m2_cpos.y - m1_cpos.y +1)<1) return;
+ if(!(tm_rec = (RECT*)malloc(tm_c * sizeof(RECT))))return;
+ for(i = w = 0, j = m1_cpos.y; j <= m2_cpos.y; i++, j++) {
+ h = TextDef.iSize;
+ if(j == m1_cpos.y) {
+ fmt_txt.SetText(0L, (char*)lines[j], 0L, 0L);
+ if(m1_cpos.x) fmt_txt.oGetTextExtent(o, &w, &h, m1_cpos.x);
+ else w = 0;
+ tm_rec[0].left = w + rDims.left + ipad.left + 1;
+ fmt_txt.SetText(0L, (char*)(lines[j]+m1_cpos.x), 0L, 0L);
+ fmt_txt.oGetTextExtent(o, &w, &h, 0);
+ tm_rec[0].right = tm_rec[0].left + w;
+ }
+ if(j == m2_cpos.y) {
+ fmt_txt.SetText(0L, (char*)lines[j], 0L, 0L);
+ if(m2_cpos.x) fmt_txt.oGetTextExtent(o, &w, &h, m2_cpos.x);
+ else w = 0;
+ tm_rec[i].right = w + rDims.left + ipad.left - 1;
+ if(m2_cpos.y > m1_cpos.y) {
+ tm_rec[i].left = rDims.left + ipad.left;
+ }
+ }
+ else if(j < m2_cpos.y && j > m1_cpos.y) {
+ tm_rec[i].left = rDims.left + ipad.left;
+ tm_rec[i].top = j * linc + rDims.top + ipad.top;
+ fmt_txt.SetText(0L, (char*)lines[j], 0L, 0L);
+ fmt_txt.oGetTextExtent(o, &w, &h, 0);
+ tm_rec[i].right = w + rDims.left + ipad.left;
+ }
+ tm_rec[i].top = j * linc + rDims.top + ipad.top;
+ tm_rec[i].bottom = tm_rec[i].top + linc;
+ }
+ ld.color = 0x0000ffff; ld.patlength = 1.0;
+ ld.pattern = 0x0L; ld.width = 0;
+ fd.color = fd.color2 = ld.color; fd.hatch = 0L;
+ fd.scale = 1.0; fd.type = 0;
+ o->SetLine(&ld); o->SetFill(&fd);
+ for(i = 0; i < tm_c; i++) {
+ o->oRectangle(tm_rec[i].left, tm_rec[i].top, tm_rec[i].right, tm_rec[i].bottom, 0L);
+ }
+ }
+ if(mode == 2){ //invert rectangles
+ if(tm_rec) for(i = 0; i < tm_c; i++) {
+ o->CopyBitmap(tm_rec[i].left, tm_rec[i].top, o, tm_rec[i].left, tm_rec[i].top,
+ tm_rec[i].right - tm_rec[i].left, tm_rec[i].bottom - tm_rec[i].top, true);
+ }
+ }
+ if(mode == 3){ //clear mark
+ if(tm_rec)free(tm_rec); tm_rec = 0L;
+ tm_c = 0; has_m1 = has_m2 = false;
+ DoPlot(o); o->UpdateRect(&rDims, false);
+ }
+}
+
+bool
+TextFrame::CopyText(anyOutput *o, bool b_cut)
+{
+ int i, csize, pos = 0;
+ char *ntxt;
+
+ if(!lines || !lines[0][0] || !o) return false;
+ if(!has_m1 || !has_m2) {
+ m1_pos.x = m1_pos.y = 0; m2_pos.y = nlines-1;
+ if(lines[nlines-1]) m2_pos.x = (int)strlen((char*)lines[nlines-1]);
+ else m2_pos.x = 0; has_m1 = has_m2 = true;
+ DoPlot(o); o->UpdateRect(&rDims, false);
+ return CopyText(o, false);
+ }
+ if(!(ntxt = (char*)malloc(csize = 1000))) return false;
+ if(m1_cpos.y == m2_cpos.y) {
+ add_to_buff(&ntxt, &pos, &csize, (char*)(lines[m1_cpos.y]) + m1_cpos.x, m2_cpos.x - m1_cpos.x);
+ ::CopyText(ntxt, pos); free(ntxt);
+ }
+ else if(m1_cpos.y < m2_cpos.y){
+ add_to_buff(&ntxt, &pos, &csize, (char*)(lines[m1_cpos.y]) + m1_cpos.x, 0);
+ for(i = m1_cpos.y; i < m2_cpos.y; i++) {
+ add_to_buff(&ntxt, &pos, &csize, (char*)(lines[i]), 0);
+ }
+ add_to_buff(&ntxt, &pos, &csize, (char*)(lines[i]), m2_pos.x);
+ ::CopyText(ntxt, pos); free(ntxt);
+ }
+ else {
+ free(ntxt); return false;
+ }
+ if(b_cut) ReplMark(o, "");
+ return true;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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); pts = 0L;
+ if(bModified) Undo.InvalidGO(this);
+ if(mo) DelBitmapClass(mo); mo = 0L;
+}
+
+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;
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ 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){
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ memcpy(&mrc, &rDims, sizeof(RECT));
+ mo = GetRectBitmap(&mrc, o);
+ InvertLine(pts, nPts, &segLine, &rDims, o, mark);
+ }
+ else if(mo) RestoreRectBitmap(&mo, &mrc, o);
+}
+
+bool
+segment::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ FillDEF *TmpFill;
+ LegItem *leg;
+
+ switch (cmd) {
+ case CMD_SCALE:
+ fCent.fx *= ((scaleINFO*)tmpl)->sx.fy; fCent.fy *= ((scaleINFO*)tmpl)->sx.fy;
+ radius1 *= ((scaleINFO*)tmpl)->sx.fy; radius2 *= ((scaleINFO*)tmpl)->sx.fy;
+ segLine.width *= ((scaleINFO*)tmpl)->sx.fy; segLine.patlength *= ((scaleINFO*)tmpl)->sx.fy;
+ segFillLine.width *= ((scaleINFO*)tmpl)->sx.fy; segFillLine.patlength *= ((scaleINFO*)tmpl)->sx.fy;
+ segFill.scale *= ((scaleINFO*)tmpl)->sx.fy; shift *= ((scaleINFO*)tmpl)->sx.fy;
+ return true;
+ case CMD_LEGEND:
+ if(tmpl) {
+ leg = new LegItem(this, data, 0L, &segLine, &segFill, 0L);
+ 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(cpts && (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);
+ if(this == CurrGO) o->ShowMark(this, MRK_GODRAW);
+ else switch(type) {
+ case 0: //line
+ o->SetLine(&pgLine); o->oPolyline(pts, nPts);
+ break;
+ case 1: //polygon
+ o->SetLine(&pgLine); 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);;
+ o->UpdateRect(&upd, false);
+ }
+ else {
+ if(parent) parent->DoPlot(o);
+ }
+}
+
+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_SCALE:
+ if(Values) for(i = 0; i < nPoints; i++){
+ Values[i].fx = ((scaleINFO*)tmpl)->sx.fx + Values[i].fx * ((scaleINFO*)tmpl)->sx.fy;
+ Values[i].fy = ((scaleINFO*)tmpl)->sy.fx + Values[i].fy * ((scaleINFO*)tmpl)->sy.fy;
+ }
+ pgLine.patlength *= ((scaleINFO*)tmpl)->sy.fy; pgLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+ pgFillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy; pgFillLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+ pgFill.scale *= ((scaleINFO*)tmpl)->sy.fy;
+ 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;
+ return o->ShowMark(CurrGO=this, MRK_GODRAW);
+ }
+ 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;
+ double dx, dy;
+ POINT hpts[3];
+ LineDEF gl = {0.0, 1.0, 0x00c0c0c0, 0};
+
+ if(nPoints >= 200 || !o) return;
+ if(!pHandles && (pHandles = (dragHandle**)calloc(nPoints+4, sizeof(dragHandle*)))){
+ for(i = 0; i < nPoints; i++) pHandles[i] = new dragHandle(this, DH_DATA+i);
+ }
+ if(!pHandles) return;
+ if(Id == GO_BEZIER && parent && nPoints > 3) {
+ dx = parent->GetSize(SIZE_GRECT_LEFT); dy = parent->GetSize(SIZE_GRECT_TOP);
+ o->SetLine(&gl);
+ hpts[0].x = o->co2ix(Values[0].fx+dx); hpts[0].y = o->co2iy(Values[0].fy+dy);
+ hpts[1].x = o->co2ix(Values[1].fx+dx); hpts[1].y = o->co2iy(Values[1].fy+dy);
+ o->oPolyline(hpts, 2);
+ for(i = 3; i < (nPoints-2); i += 3) {
+ hpts[0].x = o->co2ix(Values[i-1].fx+dx); hpts[0].y = o->co2iy(Values[i-1].fy+dy);
+ hpts[1].x = o->co2ix(Values[i].fx+dx); hpts[1].y = o->co2iy(Values[i].fy+dy);
+ hpts[2].x = o->co2ix(Values[i+1].fx+dx); hpts[2].y = o->co2iy(Values[i+1].fy+dy);
+ o->oPolyline(hpts, 3);
+ }
+ hpts[0].x = o->co2ix(Values[i-1].fx+dx); hpts[0].y = o->co2iy(Values[i-1].fy+dy);
+ hpts[1].x = o->co2ix(Values[i].fx+dx); hpts[1].y = o->co2iy(Values[i].fy+dy);
+ o->oPolyline(hpts, 2);
+ }
+ for(i = 0; i < nPoints; i++) if(pHandles[i]) pHandles[i]->DoPlot(o);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Beziers are based on the polyline object
+Bezier::Bezier(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts, int mode, double res):
+ polyline(par, d, 0L, 0)
+{
+ double dx, dy, merr;
+ int i;
+
+ type = mode;
+ Id = GO_BEZIER;
+
+ if(!parent) return;
+ dx = parent->GetSize(SIZE_GRECT_LEFT); dy = parent->GetSize(SIZE_GRECT_TOP);
+ if(type == 0 && (Values = (lfPOINT*)malloc(4 * cpts * sizeof(lfPOINT)))) {
+ merr = 0.01 * res / Units[defs.cUnits].convert;
+ FitCurve(fpts, cpts, merr);
+ Values[nPoints].fx = fpts[cpts-1].fx; Values[nPoints].fy = fpts[cpts-1].fy;
+ for(i = 0; i < nPoints; i++) {
+ Values[i].fx -= dx; Values[i].fy -= dy;
+ }
+ nPoints ++;
+ }
+ return;
+}
+
+Bezier::Bezier(int src):polyline(0L, 0L, 0L, 0)
+{
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+}
+
+void
+Bezier::DoPlot(anyOutput *o)
+{
+ POINT *tmppts;
+ double dx, dy;
+ int i;
+
+ if(!Values || !nPoints || !o || !parent) return;
+ if(pts) free(pts); pts = 0L;
+ dx = parent->GetSize(SIZE_GRECT_LEFT); dy = parent->GetSize(SIZE_GRECT_TOP);
+ if(!(tmppts = (POINT*)malloc((nPoints+2)*sizeof(POINT))))return;
+ for(i = 0; i < nPoints; i++){
+ tmppts[i].x = o->co2ix(Values[i].fx + dx); tmppts[i].y = o->co2iy(Values[i].fy + dy);
+ }
+ rDims.left = rDims.right = tmppts[0].x; rDims.top = rDims.bottom = tmppts[0].y;
+ for(i = 1; i < nPoints; i++) {
+ if(tmppts[i].x < rDims.left) rDims.left = tmppts[i].x;
+ else if(tmppts[i].x > rDims.right) rDims.right = tmppts[i].x;
+ if(tmppts[i].y < rDims.top) rDims.top = tmppts[i].y;
+ else if(tmppts[i].y > rDims.bottom) rDims.bottom = tmppts[i].y;
+ }
+ //DrawBezier returns not more than 2^MAXDEPTH points
+ pts = (POINT*)malloc(nPoints * 64 * sizeof(POINT));
+ for(i= nPts = 0; i< (nPoints-2); i += 3) {
+ DrawBezier(&nPts, pts, tmppts[i], tmppts[i+1], tmppts[i+2], tmppts[i+3], 0);
+ }
+ IncrementMinMaxRect(&rDims, 3);
+ o->ShowLine(pts, nPts, 0x00c0c0c0L);
+ if(this == CurrGO) o->ShowMark(this, MRK_GODRAW);
+ else {
+ o->SetLine(&pgLine); o->oPolyline(pts, nPts);
+ }
+}
+
+bool
+Bezier::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i, i1, i2;
+
+ 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_DELOBJ:
+ if(pHandles && tmpl && tmpl == (void*)CurrHandle) {
+ i = CurrHandle->type - DH_DATA;
+ if (i >= 0 && i < nPoints) {
+ i = CurrHandle->type - DH_DATA;
+ Undo.DataMem(this, (void**)&Values, nPoints * sizeof(lfPOINT), &nPoints, 0L);
+ if (i < 2) {
+ i1 = 0; i2 = 3;
+ }
+ else if (i > (nPoints-3)) {
+ i1 = nPoints -3; i2 = nPoints;
+ }
+ else {
+ i -= (((i-2) % 3)-1); i1 = i -1; i2 = i +2;
+ RemovePoint(Values, i1+1);
+ Values[i2].fx = Values[i1].fx; Values[i2].fy = Values[i1].fy;
+ }
+ for(i = 0; i < nPoints; i++) if(pHandles[i]) delete(pHandles[i]);
+ free(pHandles); pHandles = 0L; CurrHandle = 0L;
+ i = i2 - i1;
+ for( ; i2 < nPoints; i1++, i2++) {
+ Values[i1].fx = Values[i2].fx; Values[i1].fy = Values[i2].fy;
+ }
+ nPoints -= i; CurrGO = this; bModified = true;
+ return true;
+ }
+ }
+ return false;
+ case CMD_SET_DATAOBJ:
+ Id = GO_BEZIER;
+ return true;
+ }
+ return polyline::Command(cmd, tmpl, o);
+}
+
+void
+Bezier::AddPoints(int n, lfPOINT *p)
+{
+ int i;
+
+ for(i = 0; i< n; i++) {
+ Values[nPoints].fx = p[i].fx; Values[nPoints].fy = p[i].fy;
+ nPoints ++;
+ }
+}
+
+//Fitting of a Bezier curve to digitized points is based on:
+// P.J. Schneider (1990) An Algorithm for Automatically Fitting Digitized
+// Curves. In: Graphics Gems (Ed. A. Glassner, Academic Press Inc.,
+// ISBN 0-12-286165-5) pp. 612ff
+void
+Bezier::FitCurve(lfPOINT *d, int npt, double error)
+{
+ double len;
+ lfPOINT tHat1, tHat2;
+
+ tHat1.fx = d[1].fx - d[0].fx; tHat1.fy = d[1].fy - d[0].fy;
+ if(0.0 != (len = sqrt((tHat1.fx * tHat1.fx) + (tHat1.fy * tHat1.fy)))) {
+ tHat1.fx /= len; tHat1.fy /= len;
+ }
+ tHat2.fx = d[npt-2].fx - d[npt-1].fx; tHat2.fy = d[npt-2].fy - d[npt-1].fy;
+ if(0.0 != (len = sqrt((tHat2.fx * tHat2.fx) + (tHat2.fy * tHat2.fy)))) {
+ tHat2.fx /= len; tHat2.fy /= len;
+ }
+ FitCubic(d, 0, npt -1, tHat1, tHat2, error);
+}
+
+void
+Bezier::RemovePoint(lfPOINT *d, int sel)
+{
+ lfPOINT tHat1, tHat2;
+
+ tHat1.fx = d[sel-2].fx - d[sel-3].fx; tHat1.fy = d[sel-2].fy - d[sel-3].fy;
+ tHat2.fx = d[sel+2].fx - d[sel+3].fx; tHat2.fy = d[sel+2].fy - d[sel+3].fy;
+ d[sel] = d[sel+3];
+ IpolBez(d+sel-3, tHat1, tHat2);
+}
+
+//heuristic interpolation: other methods failed
+void
+Bezier::IpolBez(lfPOINT *d, lfPOINT tHat1, lfPOINT tHat2)
+{
+ double b0, b1, b2; //temp variables
+
+ b1 = d[3].fx - d[0].fx; b2 = d[3].fy - d[0].fy;
+ b0 = sqrt(b1 * b1 + b2 * b2)/3.0;
+ b1 = b0/sqrt(tHat1.fx * tHat1.fx + tHat1.fy * tHat1.fy);
+ b2 = b0/sqrt(tHat2.fx * tHat2.fx + tHat2.fy * tHat2.fy);
+ d[1].fx = d[0].fx + tHat1.fx * b1; d[1].fy = d[0].fy + tHat1.fy * b1;
+ d[2].fx = d[3].fx + tHat2.fx * b2; d[2].fy = d[3].fy + tHat2.fy * b2;
+}
+
+//Fit a Bezier curve to a (sub)set of digitized points
+void
+Bezier::FitCubic(lfPOINT *d, int first, int last, lfPOINT tHat1, lfPOINT tHat2, double error)
+{
+ lfPOINT bezCurve[4];
+ double *u, *uPrime, maxError, iterationError, len;
+ int i, splitPoint, npt;
+ lfPOINT tHatCenter;
+ int maxIterations = 8;
+
+ iterationError = error * error;
+ npt = last - first +1;
+ if(npt == 2) {
+ bezCurve[0] = d[first]; bezCurve[3] = d[last];
+ IpolBez(bezCurve, tHat1, tHat2);
+ AddPoints(3, bezCurve);
+ return;
+ }
+ u = ChordLengthParameterize(d, first, last);
+ GenerateBezier(d, first, last, u, tHat1, tHat2, bezCurve);
+ maxError = ComputeMaxError(d, first, last, bezCurve, u, &splitPoint);
+ if(maxError < error) {
+ if(maxError < 0.0) { //Failure fitting curve
+ IpolBez(bezCurve, tHat1, tHat2);
+ }
+ AddPoints(3, bezCurve); return;
+ }
+ if(maxError < iterationError) {
+ for (i = 0; i < maxIterations; i++) {
+ uPrime = Reparameterize(d, first, last, u, bezCurve);
+ GenerateBezier(d, first, last, uPrime, tHat1, tHat2, bezCurve);
+ maxError = ComputeMaxError(d, first, last, bezCurve, uPrime, &splitPoint);
+ if (maxError < error) {
+ if(maxError < 0.0) IpolBez(bezCurve, tHat1, tHat2);
+ AddPoints(3, bezCurve); return;
+ }
+ free(u); u = uPrime;
+ }
+ }
+ //Fitting failed: split at max error point and recurse
+ tHatCenter.fx = d[splitPoint-1].fx - d[splitPoint+1].fx;
+ tHatCenter.fy = d[splitPoint-1].fy - d[splitPoint+1].fy;
+ if(0.0 != (len = sqrt((tHatCenter.fx * tHatCenter.fx) + (tHatCenter.fy * tHatCenter.fy)))) {
+ tHatCenter.fx /= len; tHatCenter.fy /= len;
+ }
+ FitCubic(d, first, splitPoint, tHat1, tHatCenter, error * _SQRT2);
+ tHatCenter.fx = -tHatCenter.fx; tHatCenter.fy = -tHatCenter.fy;
+ FitCubic(d, splitPoint, last, tHatCenter, tHat2, error * _SQRT2);
+}
+
+//Use least-squares method to find Bezier control points for region.
+void
+Bezier::GenerateBezier(lfPOINT *d, int first, int last, double *uPrime,
+ lfPOINT tHat1, lfPOINT tHat2, lfPOINT *bezCurve)
+{
+ int i, npt;
+ lfPOINT *A0, *A1, tmp, v1, v2;
+ double C[2][2], X[2];
+ double det_C0_C1, det_C0_X, det_X_C1, alpha_l, alpha_r;
+ double b0, b1, b2, b3; //temp variables
+
+ npt = last - first +1;
+ A0 = (lfPOINT*) malloc(npt * sizeof(lfPOINT));
+ A1 = (lfPOINT*) malloc(npt * sizeof(lfPOINT));
+ for (i = 0; i < npt; i++) {
+ v1 = tHat1; v2 = tHat2;
+ b2 = 1.0 - uPrime[i];
+ b1 = 3.0 * uPrime[i] * b2 * b2; b2 = 3.0 * uPrime[i] * uPrime[i] * b2;
+ if(0.0 != (b0 = sqrt((v1.fx * v1.fx) + (v1.fy * v1.fy)))) {
+ v1.fx *= b1/b0; v1.fy *= b1/b0;
+ }
+ if(0.0 != (b0 = sqrt((v2.fx * v2.fx) + (v2.fy * v2.fy)))) {
+ v2.fx *= b2/b0; v2.fy *= b2/b0;
+ }
+ A0[i] = v1; A1[i] = v2;
+ }
+ C[0][0] = C[0][1] = C[1][0] = C[1][1] = X[0] = X[1] = 0.0;
+ for (i = 0; i < npt; i++) {
+ C[0][0] += ((A0[i].fx * A0[i].fx) + (A0[i].fy * A0[i].fy));
+ C[0][1] += ((A0[i].fx * A1[i].fx) + (A0[i].fy * A1[i].fy));
+ C[1][0] = C[0][1];
+ C[1][1] += ((A1[i].fx * A1[i].fx) + (A1[i].fy * A1[i].fy));
+ b2 = 1.0 - uPrime[i]; b0 = b2 * b2 * b2;
+ b1 = 3.0 * uPrime[i] * b2 * b2; b2 = 3.0 * uPrime[i] * uPrime[i] * b2;
+ b3 = uPrime[i] * uPrime[i] * uPrime[i];
+ tmp.fx = d[last].fx * b2 + d[last].fx * b3;
+ tmp.fy = d[last].fy * b2 + d[last].fy * b3;
+ tmp.fx += d[first].fx * b1; tmp.fy += d[first].fy * b1;
+ tmp.fx += d[first].fx * b0; tmp.fy += d[first].fy * b0;
+ tmp.fx = d[first+i].fx - tmp.fx; tmp.fy = d[first+i].fy - tmp.fy;
+ X[0] += (A0[i].fx * tmp.fx + A0[i].fy * tmp.fy);
+ X[1] += (A1[i].fx * tmp.fx + A1[i].fy * tmp.fy);
+ }
+ det_C0_C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1];
+ det_C0_X = C[0][0] * X[1] - C[0][1] * X[0];
+ det_X_C1 = X[0] * C[1][1] - X[1] * C[0][1];
+ if(det_C0_C1 == 0.0) det_C0_C1 = (C[0][0] * C[1][1]) * 10e-12;
+ alpha_l = det_X_C1 / det_C0_C1; alpha_r = det_C0_X / det_C0_C1;
+ bezCurve[0] = d[first]; bezCurve[3] = d[last];
+ if(alpha_l < 0.0 || alpha_r < 0.0) {
+ //use Wu/Barsky heuristic
+ b1 = d[last].fx - d[first].fx; b2 = d[last].fy - d[first].fy;
+ b0 = sqrt(b1 * b1 + b2 * b2)/3.0;
+ b1 = b0/sqrt(tHat1.fx * tHat1.fx + tHat1.fy * tHat1.fy);
+ b2 = b0/sqrt(tHat2.fx * tHat2.fx + tHat2.fy * tHat2.fy);
+ }
+ else {
+ b1 = alpha_l/sqrt(tHat1.fx * tHat1.fx + tHat1.fy * tHat1.fy);
+ b2 = alpha_r/sqrt(tHat2.fx * tHat2.fx + tHat2.fy * tHat2.fy);
+ }
+ bezCurve[1].fx = bezCurve[0].fx + tHat1.fx * b1;
+ bezCurve[1].fy = bezCurve[0].fy + tHat1.fy * b1;
+ bezCurve[2].fx = bezCurve[3].fx + tHat2.fx * b2;
+ bezCurve[2].fy = bezCurve[3].fy + tHat2.fy * b2;
+ free(A0); free(A1);
+}
+
+//Given set of points and their parameterization, try to find
+// a better parameterization.
+double *
+Bezier::Reparameterize(lfPOINT *d, int first, int last, double *u, lfPOINT *bezCurve)
+{
+ int i, j, k, npt = last-first+1;
+ double *uPrime, num, den, *pl, *ph, *pq;
+ lfPOINT Q1[3], Q2[2], Q_u, Q1_u, Q2_u;
+
+ uPrime = (double*)malloc(npt * sizeof(double));
+ //Use Newton-Raphson iteration to find better root
+ for (i = first, j = 0; i <= last; i++, j++) {
+ for(pl=(double*)bezCurve, ph=pl+2, pq=(double*)Q1, k=0; k <= 4; pl++, ph++, pq++, k++) {
+ *pq = (*ph - *pl ) * 3.0;
+ }
+ for(pl=(double*)Q1, ph=pl+2, pq=(double*)Q2, k=0; k <= 2; pl++, ph++, pq++, k++) {
+ *pq = (*ph - *pl ) * 2.0;
+ }
+ Q_u = fBezier(3, bezCurve, u[j]);
+ Q1_u = fBezier(2, Q1, u[j]);
+ Q2_u = fBezier(1, Q2, u[j]);
+ num = (Q_u.fx - d[i].fx) * (Q1_u.fx) + (Q_u.fy - d[i].fy) * (Q1_u.fy);
+ den = (Q1_u.fx) * (Q1_u.fx) + (Q1_u.fy) * (Q1_u.fy) +
+ (Q_u.fx - d[i].fx) * (Q2_u.fx) + (Q_u.fy - d[i].fy) * (Q2_u.fy);
+ uPrime[j] = u[j] - (num/den);
+ }
+ return uPrime;
+}
+
+//evaluate a Bezier curve at a particular parameter value
+lfPOINT
+Bezier::fBezier(int degree, lfPOINT *V, double t)
+{
+ int i, j;
+ lfPOINT Q;
+ lfPOINT *Vtemp;
+
+ Vtemp = (lfPOINT *)malloc((degree+1) * sizeof(lfPOINT));
+ for (i = 0; i <= degree; i++) {
+ Vtemp[i] = V[i];
+ }
+ for (i = 1; i <= degree; i++) {
+ for (j = 0; j <= degree-i; j++) {
+ Vtemp[j].fx = (1.0 -t) * Vtemp[j].fx + t * Vtemp[j+1].fx;
+ Vtemp[j].fy = (1.0 -t) * Vtemp[j].fy + t * Vtemp[j+1].fy;
+ }
+ }
+ Q = Vtemp[0];
+ free(Vtemp);
+ return Q;
+}
+
+double *
+Bezier::ChordLengthParameterize(lfPOINT *d, int first, int last)
+{
+ int i;
+ double tmp, *u;
+
+ u = (double*)malloc((last-first+1) * sizeof(double));
+ u[0] = 0.0;
+ for(i = first+1; i <= last; i++) {
+ u[i-first] = u[i-first-1] +
+ sqrt(((tmp=(d[i].fx - d[i-1].fx))*tmp) + ((tmp=(d[i].fy - d[i-1].fy))*tmp));
+ }
+ for(i = first +1; i <= last; i++) {
+ u[i-first] = u[i-first] / u[last-first];
+ }
+ return u;
+}
+
+double
+Bezier::ComputeMaxError(lfPOINT *d, int first, int last, lfPOINT *bezCurve, double *u, int *splitPoint)
+{
+ int i;
+ double maxDist, dist;
+ lfPOINT P, v;
+
+ *splitPoint = (last - first + 1)>>1;
+ maxDist = -1.0;
+ for(i = first +1; i < last; i++) {
+ P = fBezier(3, bezCurve, u[i-first]);
+ v.fx = P.fx - d[i].fx; v.fy = P.fy - d[i].fy;
+ dist = v.fx * v.fx + v.fy * v.fy;
+ if(dist >= maxDist) {
+ maxDist = dist; *splitPoint = i;
+ }
+ }
+ return maxDist;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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);
+ if(drc) delete(drc); drc = 0L;
+}
+
+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_SCALE:
+ fp1.fx = ((scaleINFO*)tmpl)->sx.fx + fp1.fx * ((scaleINFO*)tmpl)->sx.fy;
+ fp2.fx = ((scaleINFO*)tmpl)->sx.fx + fp2.fx * ((scaleINFO*)tmpl)->sx.fy;
+ fp1.fy = ((scaleINFO*)tmpl)->sy.fx + fp1.fy * ((scaleINFO*)tmpl)->sy.fy;
+ fp2.fy = ((scaleINFO*)tmpl)->sy.fx + fp2.fy * ((scaleINFO*)tmpl)->sy.fy;
+ Line.patlength *= ((scaleINFO*)tmpl)->sy.fy; Line.width *= ((scaleINFO*)tmpl)->sy.fy;
+ FillLine.patlength *= ((scaleINFO*)tmpl)->sy.fy; FillLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+ Fill.scale *= ((scaleINFO*)tmpl)->sy.fy; rad *= ((scaleINFO*)tmpl)->sy.fy;
+ 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)){
+ return o->ShowMark(this, MRK_GODRAW);
+ }
+ }
+ 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, char *desc)
+ :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(desc); Id = GO_LEGITEM; moveable = 1;
+}
+
+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(sy ? sy->name : 0L); Id = GO_LEGITEM; moveable = 1;
+}
+
+LegItem::LegItem(GraphObj *par, DataObj *d, LineDEF *ld, int err, char *desc)
+ :GraphObj(par, d)
+{
+ FileIO(INIT_VARS); flags |= (0x80 | (err & 0x7f));
+ if(ld) {
+ memcpy(&OutLine, ld, sizeof(LineDEF));
+ }
+ DefDesc(desc); Id = GO_LEGITEM; moveable = 1;
+}
+
+LegItem::LegItem(int src):GraphObj(0L, 0L)
+{
+ FileIO(INIT_VARS);
+ if(src == FILE_READ) {
+ FileIO(FILE_READ);
+ }
+ moveable = 1;
+}
+
+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[3];
+ int ie, cy;
+
+ if(!parent || !o) return;
+ hcr.top = iround(parent->GetSize(SIZE_YPOS));
+ hcr.bottom = iround(parent->GetSize(SIZE_YPOS+1));
+ if(flags & 0x80) {
+ hcr.left = iround(parent->GetSize((flags & 0x40) ? SIZE_XPOS+2 : SIZE_XPOS));
+ hcr.right = iround(parent->GetSize((flags & 0x40) ? SIZE_XPOS+3 :SIZE_XPOS+1));
+ ie = o->un2ix(DefSize(SIZE_ERRBAR)/2.0);
+ o->SetLine(&OutLine); cy = (hcr.top + hcr.bottom)>>1;
+ if((flags & 0x3f) == 0x01) {
+ pts[0].x = pts[1].x = (hcr.right + hcr.left)>>1;
+ pts[0].y = hcr.top; pts[1].y = hcr.bottom;
+ o->oPolyline(pts, 2, 0L);
+ pts[0].x -= (ie-1); pts[1].x += ie; pts[0].y = pts[1].y = hcr.top;
+ o->oPolyline(pts, 2, 0L); pts[0].y = pts[1].y = hcr.bottom;
+ o->oPolyline(pts, 2, 0L);
+ }
+ else if((flags & 0x3f) == 0x02) {
+ pts[0].x = pts[1].x = ((hcr.right + hcr.left)>>1);
+ pts[0].y = pts[1].y = cy; cy = ((hcr.bottom - hcr.top)>>1);
+ pts[0].x -= cy; pts[2].x = (pts[1].x += cy);
+ o->oPolyline(pts, 2, 0L); pts[1].x = pts[0].x;
+ pts[0].y -= ie; pts[1].y += ie;
+ o->oPolyline(pts, 2, 0L);
+ pts[0].x = pts[1].x = pts[2].x; o->oPolyline(pts, 2, 0L);
+ }
+ else if((flags & 0x3f) == 0x03) {
+ pts[0].x = pts[1].x = (hcr.right + hcr.left)>>1;
+ pts[0].y = hcr.top; pts[1].y = hcr.bottom;
+ o->oPolyline(pts, 2, 0L); pts[0].x -= (ie-1);
+ pts[0].y = pts[1].y = hcr.top; o->oPolyline(pts, 2, 0L);
+ pts[0].y = pts[1].y = hcr.bottom; pts[0].x += (ie + ie -1);
+ o->oPolyline(pts, 2, 0L);
+ }
+ else if((flags & 0x3f) == 0x04) {
+ pts[0].x = pts[1].x = (hcr.right + hcr.left)>>1;
+ pts[0].y = hcr.top; pts[1].y = hcr.bottom;
+ o->oPolyline(pts, 2, 0L); pts[0].x += ie;
+ pts[0].y = pts[1].y = hcr.top; o->oPolyline(pts, 2, 0L);
+ pts[0].y = pts[1].y = hcr.bottom; pts[0].x -= (ie + ie -1);
+ o->oPolyline(pts, 2, 0L);
+ }
+ else if((flags & 0x3f) == 0x05) {
+ pts[0].x = pts[1].x = (hcr.right + hcr.left)>>1;
+ pts[0].y = hcr.top; pts[1].y = hcr.bottom;
+ o->oPolyline(pts, 2, 0L);
+ }
+ }
+ else {
+ 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));
+ 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);
+ }
+ }
+ SetMinMaxRect(&rDims, hcr.left, hcr.top, hcr.right, hcr.bottom);
+ if(Desc) {
+ Desc->moveable = 1; 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_TEXTTHERE:
+ if(Desc && Desc->Command(cmd, tmpl, o)) return true;
+ return false;
+ 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_SCALE:
+ DataLine.patlength *= ((scaleINFO*)tmpl)->sy.fy; DataLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+ OutLine.patlength *= ((scaleINFO*)tmpl)->sy.fy; OutLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+ HatchLine.patlength *= ((scaleINFO*)tmpl)->sy.fy; HatchLine.width *= ((scaleINFO*)tmpl)->sy.fy;
+ Fill.scale *= ((scaleINFO*)tmpl)->sy.fy;
+ if(Sym) Sym->Command(cmd, tmpl, o);
+ if(Desc) Desc->Command(cmd, tmpl, o);
+ break;
+ 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:
+ if(Desc) Desc->Command(cmd, tmpl, o);
+ 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, char *desc)
+{
+ 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 && (sy->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;
+}
+
+bool
+LegItem::HasErr(LineDEF *ld, int err)
+{
+ if((((DWORD)err & 0x1f) | 0x80) != (flags & 0x9f)) return false;
+ if(ld && cmpLineDEF(ld, &OutLine)) return false;
+ return true;
+}
+
+void
+LegItem::DefDesc(char *txt)
+{
+ TextDEF td;
+ int cb;
+
+ cb = txt && *txt ? (int)strlen(txt) : 20;
+ if(cb < 20) cb = 20;
+ td.ColTxt = 0x00000000L; td.ColBg = 0x00ffffffL;
+ td.fSize = DefSize(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 = (char*)malloc(cb+2);
+ rlp_strcpy(td.text, cb+2, txt ? txt : (char*)"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.top = iround(C_Rect.Ymin); rDims.bottom = iround(C_Rect.Ymax);
+ rDims.left = rDims.right = iround(C_Rect.Xmin);
+ 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]){
+ if((Items[i]->flags & 0x11) == 0x01) hasLine = true;
+ Items[i]->DoPlot(o);
+ 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_TEXTTHERE:
+ if(Items) for(i = 0; i< nItems; i++)
+ if(Items[i] && Items[i]->Command(cmd, tmpl, o)) return true;
+ return false;
+ 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_SCALE:
+ pos.fx *= ((scaleINFO*)tmpl)->sx.fy; pos.fy *= ((scaleINFO*)tmpl)->sy.fy;
+ lb_pos.fx *= ((scaleINFO*)tmpl)->sx.fy; lb_pos.fy *= ((scaleINFO*)tmpl)->sy.fy;
+ B_Rect.Xmax *= ((scaleINFO*)tmpl)->sx.fy; B_Rect.Xmin *= ((scaleINFO*)tmpl)->sx.fy;
+ B_Rect.Ymax *= ((scaleINFO*)tmpl)->sy.fy; B_Rect.Ymin *= ((scaleINFO*)tmpl)->sy.fy;
+ C_Rect.Xmax *= ((scaleINFO*)tmpl)->sx.fy; C_Rect.Xmin *= ((scaleINFO*)tmpl)->sx.fy;
+ C_Rect.Ymax *= ((scaleINFO*)tmpl)->sy.fy; C_Rect.Ymin *= ((scaleINFO*)tmpl)->sy.fy;
+ D_Rect.Xmax *= ((scaleINFO*)tmpl)->sx.fy; D_Rect.Xmin *= ((scaleINFO*)tmpl)->sx.fy;
+ D_Rect.Ymax *= ((scaleINFO*)tmpl)->sy.fy; D_Rect.Ymin *= ((scaleINFO*)tmpl)->sy.fy;
+ E_Rect.Xmax *= ((scaleINFO*)tmpl)->sx.fy; E_Rect.Xmin *= ((scaleINFO*)tmpl)->sx.fy;
+ E_Rect.Ymax *= ((scaleINFO*)tmpl)->sy.fy; E_Rect.Ymin *= ((scaleINFO*)tmpl)->sy.fy;
+ F_Rect.Xmax *= ((scaleINFO*)tmpl)->sx.fy; F_Rect.Xmin *= ((scaleINFO*)tmpl)->sx.fy;
+ F_Rect.Ymax *= ((scaleINFO*)tmpl)->sy.fy; F_Rect.Ymin *= ((scaleINFO*)tmpl)->sy.fy;
+ if(Items) for(i = 0; i < nItems; i++) if(Items[i]) Items[i]->Command(cmd, tmpl, o);
+ return true;
+ 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, char *desc)
+{
+ int i;
+ LegItem *li;
+
+ if(Items) for(i = 0; i < nItems; i++) {
+ if(Items[i] && Items[i]->HasFill(ld, fd, desc)) return true;
+ }
+ if(li = new LegItem(this, data, 0L, ld, fd, desc)){
+ if(!(Command(CMD_DROP_OBJECT, li, 0L))) DeleteGO(li);
+ }
+ return false;
+}
+
+bool
+Legend::HasSym(LineDEF *ld, GraphObj *sy, char *desc)
+{
+ int i, sym;
+ Symbol *ns;
+ LegItem *li;
+
+ if(!parent || !sy) return true;
+ if(ld) hasLine = 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(desc && desc[0]) {
+ ns->name = (char*)memdup(desc,(int)strlen(desc)+1, 0);
+ }
+ else if(sy->name && sy->name[0]) {
+ ns->name = (char*)memdup(sy->name,(int)strlen(sy->name)+1, 0);
+ }
+ else if(sy->parent && sy->parent->Id < GO_GRAPH && sy->parent->Id >= GO_PLOT) {
+ if(((Plot*)(sy->parent))->data_desc) ns->name = (char*)memdup(((Plot*)(sy->parent))->data_desc,
+ (int)strlen(((Plot*)(sy->parent))->data_desc)+1, 0);
+ }
+ else if(sy->parent && sy->parent->name && sy->parent->name[0]) {
+ ns->name = (char*)memdup(sy->parent->name,(int)strlen(sy->parent->name)+1, 0);
+ }
+ if(li = new LegItem(this, data, ld, ns)){
+ if(!(Command(CMD_DROP_OBJECT, li, 0L))) DeleteGO(li);
+ }
+ return false;
+}
+
+bool
+Legend::HasErr(LineDEF *ld, int err, char *desc)
+{
+ int i;
+ LegItem *li;
+
+ if(Items) for(i = 0; i < nItems; i++) {
+ if(Items[i] && Items[i]->HasErr(ld, err)) return true;
+ }
+ if(li = new LegItem(this, data, ld, err | (hasLine ? 0x40 : 0), desc)){
+ 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, int style):GraphObj(par, d)
+{
+ Graph::FileIO(INIT_VARS);
+ Disp = o; Id = GO_GRAPH; cGraphs++; bModified = true;
+ if(style & 0x10) y_axis.flags |= AXIS_INVERT;
+ 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); Plots = 0L; NumPlots = 0;
+ }
+ if(Axes) {
+ for(i = 0; i< NumAxes; i++) if(Axes[i]) DeleteGO(Axes[i]);
+ free(Axes); Axes = 0L; NumAxes = 0;
+ }
+ 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)
+{
+ return Graph::DefSize(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;
+ case COL_DRECT: return ColDR;
+ case COL_GRECT: return ColGR;
+ }
+ if(parent) return parent->GetColor(select);
+ else return defs.Color(select);
+}
+
+bool
+Graph::SetColor(int select, DWORD col)
+{
+ switch(select) {
+ case COL_DRECT:
+ ColDR = col; return true;
+ case COL_GRECT:
+ ColGR = col; return true;
+ }
+ return false;
+}
+
+void
+Graph::DoPlot(anyOutput *target)
+{
+ int i, cb;
+ AxisDEF *ax;
+
+ if(nscp > 0 && nscp <= NumPlots && Sc_Plots) free(Sc_Plots);
+ nscp = 0; Sc_Plots = 0L;
+ if(target && parent && parent->Id == GO_SPREADDATA) target->OC_type &= ~OC_TRANSPARENT;
+ rc_mrk.left = rc_mrk.right = rc_mrk.top = rc_mrk.bottom = -1;
+ CurrAxes = Axes; defs.Idle(CMD_FLUSH);
+ if(data) do_formula(data, 0L); //init mfcalc
+ //every graph needs axes!
+ if(type == GT_STANDARD && !NumAxes) CreateAxes(AxisTempl);
+ //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){
+#ifdef USE_WIN_SECURE
+ cb = sprintf_s(TmpTxt, TMP_TXT_SIZE, "Graph %d", cGraphs) + 2;
+#else
+ cb = sprintf(TmpTxt, "Graph %d", cGraphs) + 2;
+#endif
+ name = (char*)realloc(name, cb); rlp_strcpy(name, cb, TmpTxt);
+ }
+ if(!target && !Disp) {
+ Disp = NewDispClass(this);
+ Disp->SetMenu(MENU_GRAPH);
+ if(name) Disp->Caption(name, false);
+ Disp->VPorg.fy = (double)Disp->MenuHeight;
+ Disp->CheckMenu(ToolMode, true);
+ OwnDisp = true; defs.SetDisp(Disp);
+ bModified = false; //first graph is not modified!
+ Undo.SetDisp(Disp);
+ }
+ //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(bModified && data) data->Command(CMD_MRK_DIRTY, 0L, 0L);
+ if(parent && parent->Id == GO_GRAPH) {
+ parent->Command(CMD_AXIS, 0L, 0L);
+ }
+ 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 = Disp ? Disp : CurrDisp;
+ switch (cmd){
+ case CMD_CAN_CLOSE:
+ HideTextCursor();
+ if(bModified) {
+ if (Undo.isEmpty(CurrDisp)) return true;
+ bModified = false;
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "%s has not been saved.\nDo you want to save it now?", name);
+#else
+ sprintf(TmpTxt, "%s has not been saved.\nDo you want to save it now?", name);
+#endif
+ i = YesNoCancelBox(TmpTxt);
+ if(i == 2) return false;
+ else if(i == 1) if(! SaveGraphAs(this)) return false;
+ }
+ return true;
+ case CMD_SAVEAS:
+ return SaveGraphAs(this);
+ case CMD_SCALE:
+ return DoScale((scaleINFO*)tmpl, o);
+ 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:
+ Undo.SetDisp(o ? o : CurrDisp);
+ 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;
+ if(Disp) {
+ Undo.SetDisp(Disp);
+ 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;
+ }
+ else if(Plots = (GraphObj**)realloc(Plots, sizeof(GraphObj*) * (NumPlots+2))){
+ Plots[NumPlots++] = (GraphObj*)tmpl; Plots[NumPlots] = 0L;
+ }
+ else return false;
+ }
+ 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);
+ if(Disp) Command(CMD_REDRAW, 0L, CurrDisp);
+ }
+ else if(Id == GO_GRAPH) {
+ for(i = 0; i< NumPlots; i++) if(Plots[i]) Plots[i]->Command(cmd, tmpl,o);
+ }
+ 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_REDRAW:
+ if(!CurrDisp) {
+ DoPlot(CurrDisp); return true;
+ }
+ if(Disp)CurrDisp = Disp; bDialogOpen = false;
+ if(parent && (parent->Id == GO_PAGE || parent->Id == GO_GRAPH)) 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 == this) CurrGO = 0L;
+ 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(o)o->MouseCursor(PasteObj ? MC_PASTE : MC_ARROW, false);
+ return true;
+ case CMD_AXIS: //one of the plots has changed scaling: reset
+ CurrAxes = Axes;
+ if(o)o->SetRect(CurrRect, units, &x_axis, &y_axis);
+ return true;
+ case CMD_REG_AXISPLOT: //notification: plot can handle 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:
+ Undo.SetDisp(o ? o : CurrDisp); 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 || Plots[i]->Id == GO_FUNC3D
+ || Plots[i]->Id == GO_FITFUNC3D))
+ 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); if(CurrGO == this) CurrGO = 0L;
+ return Configure();
+ case CMD_FILENAME:
+ if(tmpl) {
+ i = (int)strlen((char*)tmpl)+2;
+ filename = (char*)realloc(filename, i );
+ rlp_strcpy(filename, i, (char*)tmpl);
+ }
+ break;
+ case CMD_SETNAME:
+ if(OwnDisp && CurrDisp && tmpl && *((char*)tmpl)){
+ CurrDisp->Caption((char*)tmpl, false);
+ i = (int)strlen((char*)tmpl);
+ j = name && name[0] ? (int)strlen(name) : i;
+ name = (char*)realloc(name, i > j ? i+2 : j+2);
+ rlp_strcpy(name, i+2, (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, false);
+ }
+ return true;
+ case CMD_UPDHISTORY:
+ if(data) data->Command(CMD_UPDHISTORY, 0L, 0L);
+ return true;
+ case CMD_UPDATE:
+ Command(CMD_TOOLMODE, 0L, o);
+ Undo.SetDisp(CurrDisp);
+ if(parent && parent->Id != GO_PAGE && parent->Id != GO_GRAPH){
+ 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_CLOSE, 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); HideTextCursor();
+ 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 || parent->Id == GO_GRAPH))
+ return parent->Command(CMD_DELOBJ_CONT, (void*)this, o);
+ return false;
+ case CMD_TOOLMODE:
+ if(o && tmpl) {
+ Undo.SetDisp(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:
+ o->MouseCursor(MC_DRAWPEN, false); break;
+ case TM_RECTANGLE:
+ o->MouseCursor(MC_DRAWREC, false); break;
+ case TM_ELLIPSE:
+ o->MouseCursor(MC_DRAWELLY, false); break;
+ case TM_ROUNDREC:
+ o->MouseCursor(MC_DRAWRREC, false); break;
+ case TM_ARROW:
+ o->MouseCursor(MC_CROSS, false); break;
+ default:
+ o->MouseCursor(MC_ARROW, true); break;
+ }
+ if((ToolMode & 0x0f) != TM_TEXT) HideTextCursor();
+ return Command(CMD_REDRAW, 0L, CurrDisp);
+ case CMD_ADDPLOT:
+ Undo.SetDisp(o ? o : CurrDisp);
+ 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 || Plots[i]->Id == GO_FUNC3D
+ || Plots[i]->Id == GO_FITFUNC3D)) {
+ if(Plots[i]->Command(cmd, tmpl, CurrDisp)) return Command(CMD_REDRAW, 0L, o);
+ else return false;
+ }
+ }
+ return false;
+ }
+ else return AddPlot(0x0);
+ }
+ return false;
+ case CMD_MRK_DIRTY:
+ return (dirty = true);
+ case CMD_CURRLEFT: case CMD_CURRIGHT: case CMD_ADDCHAR: case CMD_ADDCHARW:
+ case CMD_BACKSP: case CMD_POS_FIRST: case CMD_POS_LAST:
+ defs.SetDisp(o);
+ if(tmpl && *((int*)tmpl) == 27) { //Escape
+ HideCopyMark();
+ if(CurrGO && CurrGO->Id == GO_TEXTFRAME) {
+ CurrGO->DoMark(o, false); o->MrkMode = MRK_NONE;
+ CurrGO = 0L;
+ }
+ else o->HideMark();
+ CurrLabel = 0L; HideTextCursor();
+ }
+ if(CurrLabel) return CurrLabel->Command(cmd, tmpl, o);
+ if(CurrGO && CurrGO->Id == GO_TEXTFRAME) return CurrGO->Command(cmd, tmpl, o);
+ else if(CurrGO && CurrGO->Id != GO_LABEL && 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;
+ }
+ else if(CurrGO && CurrGO->Id == GO_TEXTFRAME) return CurrGO->Command(cmd, tmpl, o);
+ case CMD_SHIFTLEFT: case CMD_SHIFTRIGHT: case CMD_SHIFTUP: case CMD_SHIFTDOWN:
+ if(Id == GO_PAGE || (CurrGraph && CurrGraph->parent == this)) {
+ if(CurrGraph && CurrGraph->parent == this) return CurrGraph->Command(cmd, tmpl, o);
+ else if(CurrGO && CurrGO->Id == GO_TEXTFRAME) return CurrGO->Command(cmd, tmpl, o);
+ else if(CurrGO && CurrGO->Id == GO_LABEL) return CurrGO->Command(cmd, tmpl, o);
+ }
+ else {
+ if(type == GT_3D && Plots) {
+ for(i = 0; i < NumPlots; i++) {
+ if(Plots[i] && (Plots[i]->Id == GO_PLOT3D || Plots[i]->Id == GO_FUNC3D
+ || Plots[i]->Id == GO_FITFUNC3D))
+ return Plots[i]->Command(cmd, tmpl, CurrDisp);
+ }
+ }
+ else if(CurrGO && CurrGO->Id == GO_TEXTFRAME) return CurrGO->Command(cmd, tmpl, o);
+ else if(CurrGO && CurrGO->Id == GO_LABEL) return CurrGO->Command(cmd, tmpl, o);
+ }
+ 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->Id == GO_TEXTFRAME) return CurrGO->Command(cmd, tmpl, o);
+ if(CurrGO == CurrLabel) return CurrLabel->Command(cmd, tmpl, o);
+ if(CurrGO->Id == GO_FRAMERECT) if(!(CurrGO = CurrGO->parent))return false;
+ if(CurrGO->parent == this) return Command(CMD_DELOBJ, (void*)CurrGO, o);
+ if(CurrGO->parent)return CurrGO->parent->Command(CMD_DELOBJ, (void*)CurrGO, o);
+ return false;
+ case CMD_DROP_GRAPH:
+ if(Disp) {
+ 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);
+ }
+ else if(Plots = (GraphObj**)realloc(Plots, sizeof(GraphObj*) * (NumPlots+2))){
+ Plots[NumPlots] = (GraphObj*)tmpl; Plots[NumPlots+1] = 0L;
+ }
+ else return false;
+ 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_DROP_PLOT:
+ if(!tmpl) return false;
+ ((GraphObj*)tmpl)->parent = this;
+ if(((GraphObj*)tmpl)->Id < GO_PLOT) {
+ if(!NumPlots && Id != GO_PAGE) return false;
+ Plots = (GraphObj**)realloc(Plots, (NumPlots+2)*sizeof(GraphObj*));
+ Plots[NumPlots] = (GraphObj*)tmpl;
+ NumPlots++;
+ if(CurrDisp) {
+ CurrDisp->StartPage();
+ DoPlot(CurrDisp);
+ CurrDisp->EndPage();
+ }
+ return true;
+ }
+ if(Id == GO_GRAPH) CurrGraph = this; bModified =true;
+ if(!NumPlots) {
+ Plots = (GraphObj**)calloc(2, sizeof(GraphObj*));
+ if(Plots) {
+ Plots[0] = (Plot *)tmpl; Plots[0]->parent = this;
+ 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: case GO_FUNC3D:
+ case GO_FITFUNC3D:
+ 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;
+ dirty = false;
+ return true;
+ }
+ return false;
+ }
+ else {
+ if(Disp) {
+ Undo.SetDisp(Disp);
+ 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;
+ }
+ else if(Plots = (GraphObj**)realloc(Plots, sizeof(GraphObj*) * (NumPlots+2))){
+ Plots[NumPlots++] = (Plot*)tmpl; Plots[NumPlots] = 0L;
+ }
+ else return false;
+ 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
+ if(CurrDisp) {
+ CurrDisp->StartPage();
+ DoPlot(CurrDisp);
+ CurrDisp->EndPage();
+ }
+ return true;
+ }
+ break;
+ case CMD_PASTE_OBJ:
+ if(!tmpl) return false;
+ Undo.SetDisp(o ? o : CurrDisp);
+ PasteObj = (GraphObj*)tmpl;
+ if(PasteObj->Id == GO_GRAPH || PasteObj->Id == GO_POLYLINE || PasteObj->Id == GO_POLYGON
+ || PasteObj->Id == GO_RECTANGLE || PasteObj->Id == GO_ROUNDREC || PasteObj->Id == GO_ELLIPSE
+ || PasteObj->Id == GO_BEZIER) {
+ ToolMode = TM_PASTE; o->MouseCursor(MC_PASTE, false);
+ return true;
+ }
+ PasteObj = 0L;
+ return false;
+ case CMD_MOUSE_EVENT:
+ mev = (MouseEvent *)tmpl; defs.SetDisp(o);
+ if(CurrGO && CurrGO->moveable && mev->Action == MOUSE_LBDOWN &&
+ ToolMode == TM_STANDARD && (mev->StateFlags & 24) == 0 &&
+ (TrackGO = (GraphObj*)CurrGO->ObjThere(mev->x, mev->y))){
+ ToolMode |= TM_MOVE;
+ }
+ else if(mev->Action == MOUSE_LBDOWN){
+ if(CurrGO && (CurrGO->Id == GO_TEXTFRAME || CurrGO->Id == GO_LABEL) && CurrGO->Command(cmd, tmpl, o)) return true;
+ CurrGO = 0L; rc_mrk.left = mev->x; rc_mrk.top = mev->y;
+ if((ToolMode == TM_TEXT || ToolMode == TM_STANDARD) && Command(CMD_TEXTTHERE, tmpl, o)) {
+ o->CheckMenu(TM_TEXT, false); o->CheckMenu(TM_STANDARD, true);
+ ToolMode = TM_STANDARD; return true;
+ }
+ SuspendAnimation(o, true);
+ }
+ if(ToolMode != TM_STANDARD && ExecTool(mev)) return true;
+ switch(mev->Action) {
+ case MOUSE_RBUP:
+ i = ToolMode; ToolMode = TM_STANDARD;
+ mev->Action = MOUSE_LBUP; //fake select
+ CurrGO = 0L; Command(cmd, tmpl, o); ToolMode = i;
+ if(!CurrGO) CurrGO = this;
+ //the default behaviour for right button click is the same as for
+ // double click: execute properties dialog, just continue.
+ case MOUSE_LBDOUBLECLICK:
+ Undo.SetDisp(o); bDialogOpen = true;
+ if(!CurrGO){
+ mev->Action = MOUSE_LBUP;
+ Command(CMD_MOUSE_EVENT, mev, CurrDisp);
+ mev->Action = MOUSE_LBDOUBLECLICK;
+ if(!CurrGO) CurrGO = this;
+ if(CurrGO->Command(CMD_CONFIG, 0L, o)) return Command(CMD_REDRAW, 0L, o);
+ }
+ else if(CurrGO->Id < GO_PLOT) {
+ if(CurrGO->PropertyDlg()) {
+ bModified = true; return Command(CMD_REDRAW, 0L, o);
+ }
+ }
+ else if(CurrGO->Command(CMD_CONFIG, 0L, o)) return Command(CMD_REDRAW, 0L, o);
+ else o->HideMark();
+ TrackGO = 0L; CurrLabel = 0L; bDialogOpen = false;
+ if(CurrGO == this) CurrGO = 0L;
+ return false;
+ case MOUSE_LBUP:
+ if(bDialogOpen) {
+ bDialogOpen = false; return false;
+ }
+ Undo.SetDisp(o); SuspendAnimation(o, false);
+ if(Id == GO_GRAPH && parent && parent->Id == GO_SPREADDATA){
+ CurrGO = TrackGO = 0L;
+ CurrGraph = 0L;
+ }
+ 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 && NumPlots > 0) for(i = NumPlots-1; i>=0; i--){
+ if(Plots[i] && Plots[i]->Command(cmd, tmpl, o)){
+ if(Plots[i]->Id != GO_GRAPH && Id == GO_GRAPH) CurrGraph = this;
+ return true;
+ }
+ }
+ if(frm_d && frm_d->Command(cmd, tmpl, o) || frm_g && frm_g->Command(cmd, tmpl, o)) {
+ if(Id == GO_GRAPH) CurrGraph = this;
+ 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_TEXTTHERE:
+ //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;
+ break;
+ case CMD_SETSCROLL:
+ if(o) {
+ if(!(o->ActualSize(&rc)))return false;
+ 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]->Id == GO_FUNC3D || Plots[i]->Id == GO_FITFUNC3D)
+ Plots[i]->Command(cmd, tmpl, o);
+ }
+ return true;
+ }
+ return false;
+}
+
+double
+Graph::DefSize(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_SCALE: return scale > 0.0 ? scale : 1.0;
+ 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);
+ }
+ if(scale > 0.0) return scale * defs.GetSize(select);
+ else return defs.GetSize(select);
+}
+bool
+Graph::hasTransp()
+{
+ if(OwnDisp && Disp && (Disp->OC_type & OC_TRANSPARENT)) 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[500];
+ Label *label;
+ double ts, lb_ydist, lb_xdist, tlb_dist;
+ DWORD ptick, ntick, utick;
+ char xa_desc[50], ya_desc[50];
+
+ if(Axes && NumAxes) return;
+ label_def.ColTxt = defs.Color(COL_AXIS); label_def.ColBg = 0x00ffffffL;
+ label_def.fSize = DefSize(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 = DefSize(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 = DefSize(SIZE_AXIS_TICKS);
+ rlp_strcpy(xa_desc, 50, (char*)"x-axis"); rlp_strcpy(ya_desc, 50, (char*)"y-axis");
+ if(Plots && NumPlots && Plots[0] && Plots[0]->Id >= GO_PLOT && Plots[0]->Id < GO_GRAPH) {
+ if(((Plot*)Plots[0])->x_info) rlp_strcpy(xa_desc, 50,((Plot*)Plots[0])->x_info);
+ if(((Plot*)Plots[0])->y_info) rlp_strcpy(ya_desc, 50,((Plot*)Plots[0])->y_info);
+ }
+ 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+DefSize(SIZE_AXIS_TICKS))*2.0);
+ lb_xdist = NiceValue((ts+DefSize(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);
+ rlp_strcpy(label_text, 500, xa_desc);
+ label = new Label(Axes[0], data, (DRect.Xmin+DRect.Xmax)/2.0,
+ GRect.Ymin+DRect.Ymax+DefSize(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, y_axis.flags | 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);
+ rlp_strcpy(label_text, 500, ya_desc);
+ label_def.RotBL = 90.0; label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
+ label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - DefSize(SIZE_AXIS_TICKS)*6.0,
+ (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);
+ rlp_strcpy(label_text, 500, xa_desc);
+ label_def.Align = TXA_VTOP | TXA_HRIGHT;
+ label = new Label(Axes[0], data, GRect.Xmin + DRect.Xmax - DefSize(SIZE_AXIS_TICKS)*2.0,
+ GRect.Ymin+DRect.Ymax+DefSize(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);
+ rlp_strcpy(label_text, 500, ya_desc);
+ label_def.RotBL = 90.0; label_def.Align = TXA_VBOTTOM | TXA_HRIGHT;
+ label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - DefSize(SIZE_AXIS_TICKS)*6.0,
+ GRect.Ymin + DRect.Ymin + DefSize(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);
+ rlp_strcpy(label_text, 500, xa_desc);
+ label = new Label(Axes[0], data, GRect.Xmin + (DRect.Xmin+DRect.Xmax)/2.0f,
+ GRect.Ymin+DRect.Ymax+DefSize(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);
+ rlp_strcpy(label_text, 500, ya_desc);
+ label_def.RotBL = 90.0; label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
+ label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - DefSize(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);
+ rlp_strcpy(label_text, 500, xa_desc);
+ label = new Label(Axes[0], data, GRect.Xmin + (DRect.Xmin+DRect.Xmax)/2.0f,
+ GRect.Ymin+DRect.Ymax+DefSize(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);
+ rlp_strcpy(label_text, 500, ya_desc);
+ label_def.RotBL = 90.0; label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
+ label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - DefSize(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);
+ rlp_strcpy(label_text, 500, xa_desc);
+ label = new Label(Axes[0], data, GRect.Xmin + (DRect.Xmin+DRect.Xmax)/2.0f,
+ GRect.Ymin+DRect.Ymax+DefSize(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);
+ rlp_strcpy(label_text, 500, ya_desc);
+ label_def.RotBL = 90.0; label_def.Align = TXA_VBOTTOM | TXA_HCENTER;
+ label = new Label(Axes[1], data, GRect.Xmin + DRect.Xmin - DefSize(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;
+ }
+ if(Plots[0] && Plots[0]->Id >= GO_PLOT && Plots[0]->Id < GO_GRAPH && NumAxes > 1) {
+ if(((Plot*)Plots[0])->x_tv && Axes[0])Axes[0]->atv = ((Plot*)Plots[0])->x_tv->Copy();
+ else if(((Plot*)Plots[0])->x_dtype == ET_DATETIME)x_axis.flags |= AXIS_DATETIME;
+ if(((Plot*)Plots[0])->y_tv && Axes[1])Axes[1]->atv = ((Plot*)Plots[0])->y_tv->Copy();
+ else if(((Plot*)Plots[0])->y_dtype == ET_DATETIME)y_axis.flags |= AXIS_DATETIME;
+ }
+}
+
+bool
+Graph::DoScale(scaleINFO* sc, anyOutput *o)
+{
+ int i;
+ scaleINFO sc0;
+
+ if(sc->sy.fy <= 0.0) return false;
+ GRect.Xmax = sc->sx.fx + GRect.Xmax* sc->sx.fy;
+ GRect.Xmin = sc->sx.fx + GRect.Xmin * sc->sx.fy;
+ GRect.Ymax = sc->sy.fx + GRect.Ymax * sc->sy.fy;
+ GRect.Ymin = sc->sy.fx + GRect.Ymin * sc->sy.fy;
+ DRect.Xmax *= sc->sx.fy; DRect.Xmin *= sc->sx.fy;
+ DRect.Ymax *= sc->sy.fy; DRect.Ymin *= sc->sy.fy;
+ if(sc->sx.fy == 1.0 && sc->sx.fy == sc->sy.fy && sc->sx.fy == sc->sz.fy) return true;
+ memcpy(&sc0, sc, sizeof(scaleINFO));
+ sc0.sx.fx = sc0.sy.fx = sc0.sz.fx = 0.0; sc0.sx.fy = sc0.sz.fy = sc->sy.fy;
+ if(Axes) for(i = 0; i< NumAxes; i++) if(Axes[i]) Axes[i]->Command(CMD_SCALE, &sc0, o);
+ if(Plots) for(i = 0; i < NumPlots; i++) if(Plots[i]){
+ if(Plots[i]->Id == GO_GRAPH || Plots[i]->Id == GO_PAGE) Plots[i]->Command(CMD_SCALE, sc, o);
+ else Plots[i]->Command(CMD_SCALE, &sc0, o);
+ }
+ scale = scale > 0.0 ? scale * sc->sy.fy : sc->sy.fy;
+ return true;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Pages are graphic objects containing graphs and drawn objects
+Page::Page(GraphObj *par, DataObj *d):Graph(par, d, 0L, 0)
+{
+ 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);
+#ifdef USE_WIN_SECURE
+ i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "Page %d", cPages);
+#else
+ i = sprintf(TmpTxt, "Page %d", cPages);
+#endif
+ if(!name && (name = (char*)malloc(i += 2)))rlp_strcpy(name, i, TmpTxt);
+ Disp->Caption(TmpTxt, false);
+ 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);
+ if(PasteObj) {
+ ToolMode = TM_PASTE; CurrDisp->MouseCursor(MC_PASTE, false);
+ }
+}
+
+bool
+Page::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ Graph *g;
+
+ switch(cmd) {
+ case CMD_MOUSE_EVENT:
+ return Graph::Command(cmd, tmpl, o);
+ case CMD_REDRAW:
+ if(Disp) {
+ Disp->StartPage(); DoPlot(Disp); Disp->EndPage();
+ }
+ return true;
+ case CMD_CONFIG:
+ return Configure();
+ case CMD_NEWGRAPH:
+ if((g = new Graph(this, data, Disp, 0)) && 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;
+ case CMD_SCALE:
+ return true;
+ default:
+ return Graph::Command(cmd, tmpl, o);
+ }
+}
+
+double
+Page::DefSize(int select)
+{
+ return defs.GetSize(select);
+}
+
diff --git a/rlplot.h b/rlplot.h
index db6fa4a..3be5468 100755
--- a/rlplot.h
+++ b/rlplot.h
@@ -1,2973 +1,3045 @@
-//RLPlot.h, Copyright (c) 2000-2007 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);}
-
-#define _PI 3.1415926535897932384626433832795028841971693993751
-#define _SQRT2 1.4142135623730950488016887242096980785696718753769
-
-#ifdef _WINDOWS //platform is windows
-#include <windows.h>
-#if _MSC_VER >= 1400
-#define USE_WIN_SECURE
-#endif
-#define w_char WCHAR
-#define _SBINC 1 //scrollbox extra space/line
-#define _TXH 4.0 //graph text default size in mm
-
-#else //platform is *nix
-#include <sys/types.h>
-#define DWORD u_int32_t
-#define w_char wchar_t
-#define _SBINC 8 //scrollbox extra space/line
-#define _TXH 3.0 //graph text default size in mm
-
-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, SIZE_LSPC, SIZE_SCALE};
-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_ADDCHARW, 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_CLOSE, 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_SSV, 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_SAVE_LABELS, CMD_UNLOCK, CMD_SYMTEXT_UNDO,
- CMD_FILLRANGE, CMD_BUSY, CMD_ERROR, CMD_CLEAR_ERROR, CMD_SETPARAM, CMD_SETFUNC,
- CMD_LEGEND, CMD_FILENAME, CMD_LAYERS, CMD_OBJTREE, CMD_TEXTDEF,
- CMD_HASSTACK, CMD_WRITE_GRAPHS, CMD_SETFONT, CMD_SETSTYLE, CMD_COPY, CMD_PASTE,
- CMD_INSROW, CMD_INSCOL, CMD_DELROW, CMD_DELCOL, CMD_ADDTXT, CMD_ETRACC, CMD_SHPGUP,
- CMD_SHPGDOWN, CMD_ERRDESC, CMD_SAVEDATA, CMD_GETMARK, CMD_PASTE_OBJ, CMD_COL_MOUSE,
- CMD_MARKOBJ, CMD_SCALE, CMD_GETFILENAME, CMD_TEXTTHERE, CMD_HIDEMARK};
-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_CIRCLEC, SYM_RECTC, SYM_TRIAUC, SYM_TRIAUL, SYM_TRIAUR,
- SYM_TRIADC, SYM_TRIADL, SYM_TRIADR, SYM_DIAMONDC, SYM_4STAR, SYM_4STARF, SYM_5GON, SYM_5GONF,
- SYM_5GONC, SYM_5STAR, SYM_5STARF, SYM_6STAR, SYM_6STARF, SYM_1QUAD, SYM_2QUAD, SYM_3QUAD,
- SYM_TEXT = 0x004f, 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_BEZIER, GO_TEXTFRAME,
- 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_FUNC3D,
- GO_XYSTAT, GO_FITFUNC3D, GO_NORMQUANT,
- GO_GRAPH = 0x200, GO_PAGE, GO_SPREADDATA = 0x300, GO_DEFRW};
-enum {OC_UNKNOWN, OC_HIMETRIC};
-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,
- FILL_HASH, FILL_WATER, 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,
- TM_PASTE=0x200};
-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, MC_PASTE, MC_DRAWPEN, MC_DRAWREC,
- MC_DRAWRREC, MC_DRAWELLY, MC_TXTFRM, MC_COLWIDTH};
-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, FF_SSV};
-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};
-enum {FE_NONE = 0x1000, FE_PARENT, FE_PLOT, FE_FLUSH, FE_DELOBJ, FE_REPLGO, FE_MUTATE};
-
-//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 {
- lfPOINT sx, sy, sz;
- }scaleINFO;
-
-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;
-
-typedef struct rlp_datetime {
- int aday, year, doy, month, dom, dow, hours, minutes;
- double seconds;
-}rlp_datetime;
-
-// 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_DATETIME 0x4000 // its a date- or time axis
-#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;
- double *a_data;
- int a_count;
- } 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 NextRow(int *y);
- bool NextCol(int *x);
- bool IsInRange(int x, int y);
- bool BoundRec(RECT *rec);
- char *RangeDesc(void *d, int style); //d points to a DataObj class
- int DataTypes(void *d, int *numerical, int *strings, int *datetime);
-
-private:
- char *txt;
- int x1, y1, x2, y2, cx, cy, curridx;
-
- bool Reset();
- bool Parse(int start);
-};
-
-class Triangle {
-public:
- Triangle *next;
- fPOINT3D pt[4];
-
- void SetRect();
- bool TestVertex(double x, double y);
-
-private:
- double cx, cy, r2; //circumcircle
- fRECT rc; //bounding rectangle
- lfPOINT ld[3]; //line eqations
-};
-
-class Triangulate {
-public:
- Triangle *trl;
-
- Triangulate(Triangle *t_list);
- bool AddEdge(fPOINT3D *p1, fPOINT3D *p2);
- bool AddVertex(fPOINT3D *v);
-
-private:
- typedef struct edge {
- edge *next;
- fPOINT3D p1, p2;
- };
- edge *edges;
-};
-
-class anyOutput{
-public:
- int units; //use units mm, inch ...
- int MrkMode; //existing mark on screen
- int OC_type; //specify display, printer clipboard ...
- 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 UseAxis(AxisDEF *ax, int type);
- 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 Focus() {return;};
- 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 oGetTextExtentW(w_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 oTextOutW(int x, int y, w_char *txt, int cb){return false;};
- virtual bool oPolygon(POINT *pts, int cp, char *nam = 0L){return false;};
-};
-
-enum {ET_UNKNOWN, ET_VALUE, ET_TEXT, ET_FORMULA, ET_ERROR, ET_BOOL,
- ET_DATE, ET_TIME, ET_DATETIME, ET_BUSY=0x100, ET_CIRCULAR=0x200, ET_EMPTY=0x400,
- ET_NODRAW=0x800, ET_NODRAW_EMPTY=0xc00};
-
-class EditText {
-public:
- char *text, *ftext;
- int Align, type, row, col;
- void *parent; //points to a data object: defined below
- anyOutput *disp;
- double Value;
-
- EditText(void *par, char *msg, int r, int c);
- ~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 bTranslate);
- bool GetResult(anyResult *r, bool use_last = false);
- bool SetValue(double v);
- bool SetText(char *t);
- void SetRec(RECT *rc);
- int GetX() {return loc.x;};
- int GetY() {return loc.y;};
- int GetRX() {return crb.x;};
- int GetRY() {return crb.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);};
- bool hasMark() {return (m1 != m2 && m1 >= 0 && m2 >= 0);};
-
-private:
- LineDEF *bgLine;
- FillDEF *bgFill;
- int length, CursorPos, m1, m2, mx1, mx2;
- POINT loc, rb, crb;
- DWORD TextCol;
-
- void FindType();
- void set_etracc();
-};
-
-class fmtText {
-
-typedef struct _fmt_txt_info {
- int tag, uc, uc_len;
- char *txt;
-}fmt_txt_info;
-
-typedef struct _fmt_uc_info {
- int tag, cb;
- w_char *uc_txt;
-}fmt_uc_info;
-
-public:
- fmtText();
- 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);
- int ucTag(char *txt, int cb, int *tl, int *ucc);
- int ucLeft(char *txt, int cb, int *tl, int *ucc);
- 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);
- void EditMode(bool bEdit);
-
-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);
- bool DrawFormattedW(anyOutput *o);
- void DrawFormatted(anyOutput *o);
-
- char *src;
- POINT pos;
- int n_split, n_split_W, uc_state;
- DWORD flags;
- fmt_txt_info *split_text;
- fmt_uc_info *split_text_W;
-};
-
-class TextValue {
-
-typedef struct _TxtValItem {
- unsigned int hv1, hv2;
- char *text;
- double val;
-}TextValItem;
-
-public:
- TextValue();
- TextValue(TextValItem **tvi, int ntvi);
- ~TextValue();
- double GetValue(char* txt);
- bool GetItem(int idx, char **text, double *value);
- void Reset();
- TextValue *Copy();
- int Count() {return nitems;};
-
-private:
- TextValItem **items;
- int nitems;
- double next, inc;
-};
-
-class RangeInfo {
-public:
- int col_width, row_height, first_width;
- RangeInfo(int sel, int cw, int rh, int fw, RangeInfo *next);
- RangeInfo(int sel, char *range, RangeInfo *next);
- ~RangeInfo();
- int SetWidth(int w);
- int SetDefWidth(int w);
- int SetHeight(int h);
- int SetFirstWidth(int w);
- int GetWidth(int col);
- int GetHeight(int row);
- int GetFirstWidth();
- int Type(){return r_type;};
- RangeInfo *Next(){return ri_next;};
-
-private:
- int r_type; // 0 default
- // 1 column info
- // 2 row info
- RangeInfo *ri_next;
- AccRange *ar;
-};
-
-class DataObj{
-public:
- int cRows, cCols, c_disp, r_disp;
- RangeInfo *ri;
- EditText ***etRows;
-
- DataObj();
- ~DataObj();
- virtual bool Init(int nRows, int nCols);
- virtual bool mpos2dpos(POINT *mp, POINT *dp, bool can_scroll){return false;};
- 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, bool bTranslate = true);
- char **GetTextPtr(int row, int col);
- virtual bool GetResult(anyResult *r, int row, int col, bool use_last = false);
- virtual bool GetSize(int *width, int *height);
- virtual bool isEmpty(int row, int col);
- 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();
- bool ValueRec(RECT *rc);
-};
-
-class StrData {
-public:
- StrData(DataObj *par, RECT *rc = 0L);
- ~StrData();
- bool GetSize(int *w, int *h);
- void RestoreData(DataObj *dest);
-
-private:
- int pw, ph;
- RECT drc;
- 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(int type);
- void Herringbone();
- void Circles();
- void Grass();
- void Foam();
- void Recs();
- void Hash();
- 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);
- virtual double DefSize(int select);
-};
-
-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, bSelected, bMarked;
- 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:
- bool DoAutoscale(anyOutput *o);
-
- 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, char *desc = 0L);
- Bar(int src);
- ~Bar();
- double GetSize(int select);
- 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:
- anyOutput *mo;
- RECT mrc;
- 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, char *name=0L);
- DataLine(GraphObj *par, DataObj *d, lfPOINT *val, long nval, char *name);
- 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);
- void DrawCurve(anyOutput *target);
- void DrawSpline(anyOutput *target);
-};
-
-class DataPolygon:public DataLine{
-public:
- DataPolygon(GraphObj *par, DataObj *d, char *xrange=0L, char *yrange=0L, char *name=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:
- anyOutput *mo;
- RECT mrc;
- 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:
- anyOutput *mo;
- RECT mrc;
- 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);
- ~Whisker();
- 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:
- anyOutput *mo;
- RECT mrc;
- 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(GraphObj *par, DataObj *d, fPOINT3D *pt, int n_pt, 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);
- 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;
- long nPts, npts;
- char *x_range, *y_range, *z_range;
- POINT *ssRef;
- long cssRef;
- 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);
- bool CheckMark();
- TextDEF *GetTextDef(){return &TextDef;};
-
-private:
- lfPOINT fPos, fDist;
- double si, csi, curr_z;
- DWORD flags, bgcolor;
- TextDEF TextDef;
- LineDEF bgLine;
- int ix, iy, m1, m2, CursorPos;
- bool is3D;
- RECT Cursor, rm1, rm2;
- POINT pts[5];
- POINT *ssRef;
- long cssRef;
- anyOutput *defDisp;
- bool bModified, bBGvalid;
-};
-
-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, lspc;
- DWORD flags, undo_flags;
- TextDEF TextDef;
- long nLines;
- int cli;
- bool is3D;
- Label **Lines;
-};
-
-class TextFrame:public GraphObj{
- enum {TF_MAXLINE=120};
-public:
- TextFrame(GraphObj *parent, DataObj *data, lfPOINT *p1, lfPOINT *p2, char *txt);
- TextFrame(int src);
- ~TextFrame();
- double GetSize(int select);
- bool SetSize(int select, double value);
- 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:
- fRECT pad;
- RECT ipad, Cursor, *tm_rec;
- fmtText fmt_txt;
- int nlines, linc, tm_c, csize, cpos;
- bool bModified, bResize, has_m1, has_m2;
- unsigned char c_char, m1_char, m2_char;
- double lspc;
- lfPOINT pos1, pos2;
- POINT cur_pos, m1_pos, m2_pos, m1_cpos, m2_cpos;
- TextDEF TextDef;
- dragRect *drc;
- unsigned char *text, **lines;
- LineDEF Line, FillLine;
- FillDEF Fill;
-
- void text2lines(anyOutput *o);
- void lines2text();
- void ShowCursor(anyOutput *o);
- void AddChar(anyOutput *o, int c);
- void DelChar(anyOutput *o);
- void CalcCursorPos(int x, int y, anyOutput *o);
- void ReplMark(anyOutput *o, char *ntext);
- void procTokens();
- bool DoPaste(anyOutput *o);
- void TextMark(anyOutput *o, int mode);
- bool CopyText(anyOutput *o, bool b_cut);
-};
-
-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:
- dragHandle **pHandles;
- 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);
- virtual void DoPlot(anyOutput *o);
- void DoMark(anyOutput *o, bool mark);
- bool Command(int cmd, void *tmpl, anyOutput *o);
- virtual bool PropertyDlg();
- virtual bool FileIO(int rw);
- void * ObjThere(int x, int y);
- void Track(POINT *p, anyOutput *o);
-
-private:
- void ShowPoints(anyOutput *o);
-};
-
-class Bezier:public polyline {
-public:
- Bezier(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts, int mode, double res);
- Bezier(int src);
- void DoPlot(anyOutput *o);
- bool Command(int cmd, void *tmpl, anyOutput *o);
- bool FileIO(int rw);
-
-private:
- void AddPoints(int n, lfPOINT *p);
-
- void FitCurve(lfPOINT *d, int npt, double error);
- void IpolBez(lfPOINT *d, lfPOINT tHat1, lfPOINT tHat2);
- void FitCubic(lfPOINT *d, int first, int last, lfPOINT tHat1, lfPOINT tHat2, double error);
- void RemovePoint(lfPOINT *d, int sel);
- void GenerateBezier(lfPOINT *d, int first, int last, double * uPrime, lfPOINT tHat1, lfPOINT tHat2, lfPOINT *bezCurve);
- double *Reparameterize(lfPOINT *d, int first, int last, double *u, lfPOINT *bezCurve);
- lfPOINT fBezier(int degree, lfPOINT *V, double t);
- double *ChordLengthParameterize(lfPOINT *d, int first, int last);
- double ComputeMaxError(lfPOINT *d, int first, int last, lfPOINT *bezCurve, double *u, int *splitPoint);
-};
-
-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:
- DWORD flags;
-
- LegItem(GraphObj *par, DataObj *d, LineDEF *ld, LineDEF *lf, FillDEF *fill, char *desc);
- LegItem(GraphObj *par, DataObj *d, LineDEF *ld, Symbol *sy);
- LegItem(GraphObj *par, DataObj *d, LineDEF *ld, int err, char *desc);
- 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, char *desc);
- bool HasSym(LineDEF *ld, GraphObj *sy);
- bool HasErr(LineDEF *ld, int err);
-
-private:
- LineDEF DataLine, OutLine, HatchLine;
- FillDEF Fill;
- Symbol *Sym;
- Label *Desc;
- 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, char *desc);
- bool HasSym(LineDEF *ld, GraphObj *sy, char *desc);
- bool HasErr(LineDEF *ld, int err, char *desc);
-
-private:
- lfPOINT pos, lb_pos;
- RECT trc;
- anyOutput *to;
- fRECT B_Rect, C_Rect, D_Rect, E_Rect, F_Rect;
- long nItems;
- bool hasLine;
- 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, use_zaxis; //this plot uses its own axes
- lfPOINT xBounds, yBounds, zBounds; //like Bounds but in 3D space
- int hidden; //plot (layer) is not visible
- int x_dtype, y_dtype, z_dtype; //data types
- char *x_info, *y_info, *z_info; //descriptor used e.g. for axis label or legend
- char *data_desc; //descriptor for data, used for legend etc
- TextValue *x_tv, *y_tv; //TextValue object for ordinal axes
-
- 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:
- char *xRange, *yRange;
- long nPoints;
- int DefSym;
- lfPOINT BarDist;
- Bar **Bars;
- Symbol **Symbols;
- DataLine *TheLine;
- ErrorBar **Errors;
- Label **Labels;
-
- PlotScatt(GraphObj *par, DataObj *d, DWORD presel);
- PlotScatt(GraphObj *par, DataObj *d, int cBars, Bar **bars, ErrorBar **errs);
- 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);
- virtual bool Command(int cmd, void *tmpl, anyOutput *o);
- virtual bool PropertyDlg();
- void RegGO(void *n);
- virtual bool FileIO(int rw);
-
- bool ForEach(int cmd, void *tmp, anyOutput *o);
-
-private:
- DWORD DefSel;
- char *ErrRange, *LbRange;
- Arrow **Arrows;
- DropLine **DropLines;
-
- bool CreateBarChart();
-};
-
-class xyStat:public PlotScatt{
-public:
- xyStat(GraphObj *par, DataObj *d);
- xyStat(int src);
- ~xyStat();
- bool Command(int cmd, void *tmpl, anyOutput *o);
- bool PropertyDlg();
- virtual bool FileIO(int rw);
-
- void CreateData();
-
-private:
- double ci;
- DataObj *curr_data;
- char *case_prefix;
-
-};
-
-class BarChart:public PlotScatt{
-public:
- BarChart(GraphObj *par, DataObj *d);
-};
-
-class FreqDist:public Plot {
-public:
- FreqDist(GraphObj *par, DataObj *d);
- FreqDist(GraphObj *par, DataObj *d, char* range, bool bOnce);
- FreqDist(GraphObj *par, DataObj *d, double *vals, int nvals, int nclasses);
- 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 dmin, dmax, 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, char *box_name);
- ~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);
-
- bool ForEach(int cmd, void *tmp, anyOutput *o);
- void CreateData();
-
-private:
- char *xRange, *yRange, *case_prefix;
- long nPoints;
- double ci_box, ci_err;
- DataObj *curr_data;
- lfPOINT BoxDist;
- Box **Boxes;
- Whisker **Whiskers;
- Symbol **Symbols;
- Label **Labels;
- 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, int type):StackBar(par, d){mode = type;};
- bool PropertyDlg();
-
-private:
- int mode;
-};
-
-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:
- long 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, int which, char *xr, char *yr, char *zr);
- Ribbon(GraphObj *par, DataObj *d, GraphObj **go, int ngo);
- 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, int sel, double x1=0.0, double xstep=1.0, double z1=0.0, double zstep=1.0);
- Grid3D(int src);
- ~Grid3D();
- 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);
-
- void CreateObs(bool set_undo);
-
-private:
- long nLines, nPlanes;
- fPOINT3D start, step;
- LineDEF Line;
- FillDEF Fill;
- Line3D **lines;
- Plane3D **planes;
-
- bool Configure();
-};
-
-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, char *desc);
- 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 NormQuant:public Plot{
-public:
- NormQuant(GraphObj *par, DataObj *d, char* range);
- NormQuant(GraphObj *par, DataObj *d, double *data, int ndata);
- NormQuant(int src);
- ~NormQuant();
- void DoPlot(anyOutput *o);
- bool Command(int cmd, void *tmpl, anyOutput *o);
- bool PropertyDlg();
- bool FileIO(int rw);
-
-private:
- char *ssRef;
- int nData, nValidData;
- double *x_vals, *y_vals, *src_data;
- Symbol *sy;
-
- bool ProcessData();
-};
-
-
-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;
- TextValue *atv;
-
- 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 mkTimeAxis();
- 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, **Sc_Plots;
- double *RotDef;
- fPOINT3D cub1, cub2, rotC;
- int nscp;
-
- 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);
- virtual bool Command(int cmd, void *tmpl, anyOutput *o);
- virtual bool PropertyDlg();
- virtual void RegGO(void *n);
- virtual 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);
- bool AddAxis();
-
-private:
- long nObs, nmaxObs;
- DWORD crea_flags;
- Drag3D *drag;
- fPOINT3D 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 Func3D:public Plot3D {
-public:
- Func3D(GraphObj *par, DataObj *d);
- Func3D(int src);
- ~Func3D();
- bool Command(int cmd, void *tmpl, anyOutput *o);
- bool PropertyDlg();
- void RegGO(void *n);
- bool FileIO(int rw);
-
-private:
- bool Update();
-
- double x1, x2, xstep, z1, z2, zstep;
- LineDEF Line;
- FillDEF Fill;
- char *param, *cmdxy;
- DataObj *gda;
- Grid3D *gob;
-};
-
-class FitFunc3D:public Plot3D {
-public:
- FitFunc3D(GraphObj *par, DataObj *d);
- FitFunc3D(int src);
- ~FitFunc3D();
- bool Command(int cmd, void *tmpl, anyOutput *o);
- bool PropertyDlg();
- void RegGO(void *n);
- bool FileIO(int rw);
-
-private:
- bool Update();
-
- double x1, x2, xstep, z1, z2, zstep, conv, chi2;
- char *ssXref, *ssYref, *ssZref;
- int maxiter;
- LineDEF Line;
- FillDEF Fill;
- char *param, *cmdxy;
- DataObj *gda;
- Grid3D *gob;
-};
-
-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, *PasteObj;
- DWORD ColBG, ColAX;
- GraphObj **Sc_Plots;
- Axis **Axes;
- char *filename;
-
- Graph(GraphObj *par, DataObj *d, anyOutput *o, int style);
- Graph(int src);
- ~Graph();
- double GetSize(int select);
- bool SetSize(int select, double value);
- DWORD GetColor(int select);
- bool SetColor(int select, DWORD col);
- 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);
- virtual double DefSize(int select);
-
-private:
- int NumAxes, AxisTempl, tickstyle, zoom_level;
- double scale;
- RECT rcDim, rcUpd, rc_mrk;
- DWORD ColDR, ColGR, ColGRL;
- AxisDEF x_axis, y_axis;
- FrmRect *frm_g, *frm_d;
- bool dirty, bDialogOpen;
- 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);
- bool DoScale(scaleINFO *sc, anyOutput *o);
-};
-
-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);
- double DefSize(int select);
-
-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();
- int RegisterGO(GraphObj *go);
- void AddRegGO(GraphObj *go);
- bool PushGO(unsigned int id, GraphObj *go);
- GraphObj *PopGO(unsigned int id);
- void FreeStack();
-
-private:
- unsigned int 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;
- char *fmt_date, *fmt_time, *fmt_datetime;
- double min4log, ss_txt;
- 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_VALLONG, UNDO_OBJCONF, UNDO_OBJCONF_1,
- UNDO_LFP, UNDO_POINT, UNDO_VOIDPTR, 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, UNDO_TEXTBUF};
- 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;
-
- typedef struct _TextBuff {
- int *psize, size, *ppos, pos;
- unsigned char **pbuff, *buff;
- }TextBuff;
-
-public:
- int *pcb;
- anyOutput *cdisp, *ldisp;
- bool busy;
-
- UndoObj();
- ~UndoObj();
- void Flush();
- bool isEmpty(anyOutput *o);
- void SetDisp(anyOutput *o);
- void KillDisp(anyOutput *o);
- void InvalidGO(GraphObj *go);
- void Pop(anyOutput *o);
- 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 Point(GraphObj *parent, POINT *pt, anyOutput * o, DWORD flags);
- void VoidPtr(GraphObj *parent, void **pptr, void *ptr, anyOutput * o, DWORD flags);
- void ValInt(GraphObj *parent, int *val, DWORD flags);
- void ValLong(GraphObj *parent, long *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);
- int 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, RECT *rc, DWORD flags);
- void TextCell(EditText *et, anyOutput *o, char *text, int *cur, int *m1, int *m2, void* DaO, DWORD flags);
- void TextBuffer(GraphObj *parent, int *psize, int *ppos, unsigned char **pbuff, DWORD flags, anyOutput *o);
-
-private:
- UndoInfo **buff, **buff0;
- int stub1, ndisp;
- 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);
-int YesNoCancelBox(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 InvalidateOutput(anyOutput *o);
-void SuspendAnimation(anyOutput *o, bool bSusp);
-void InitTextCursor(bool init);
-void EmptyClip();
-void CopyText(char *txt, int len);
-unsigned char* PasteText();
-void GetDesktopSize(int *width, int *height);
-void FindBrowser();
-void LoopDlgWnd();
-void CloseDlgWnd(void *hDlg);
-void ShowDlgWnd(void *hDlg);
-void ResizeDlgWnd(void *hDlg, int w, int h);
-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, bool bPaste);
-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, GraphObj *parent);
-bool FillSsRange(DataObj *d, char **range, GraphObj *msg_go);
-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);
-char *str_ltrim(char *str);
-char *str_rtrim(char *str);
-char *str_trim(char *str);
-void rmquot(char *str);
-int strpos(char *needle, char *haystack);
-char *strreplace(char *needle, char *replace, char *haystack);
-char *substr(char *text, int pos1, int pos2);
-int rlp_strcpy(char*dest, int size, char*src);
-void ReshapeFormula(char **text);
-void TranslateResult(anyResult *res);
-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 *NiceTime(double val);
-char *Int2ColLabel(int nr, bool uc);
-char *mkCellRef(int row, int col);
-char *mkRangeRef(int r1, int c1, int r2, int c2);
-char *str2xml(char *str, bool bGreek);
-char **split(char *str, char sep, int *nl);
-char *fit_num_rect(anyOutput *o, int max_width, char *num_str);
-void add_to_buff(char** dest, int *pos, int *csize, char *txt, int len);
-void add_int_to_buff(char** dest, int *pos, int *csize, int value, bool lsp, int ndig);
-void add_dbl_to_buff(char** dest, int *pos, int *csize, double value, bool lsp);
-void add_hex_to_buff(char** dest, int *pos, int *csize, DWORD value, bool lsp);
-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);
-void DrawBezier(long *cp, POINT *pts, POINT p0, POINT p1, POINT p2, POINT p3, int depth=0);
-int mkCurve(lfPOINT *src, int n1, lfPOINT **dst, bool bClosed);
-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 DeleteGOL(GraphObj ***gol, long n, GraphObj *go, anyOutput *o);
-bool BackupFile(char *FileName);
-bool IsRlpFile(char *FileName);
-bool IsXmlFile(char *FileName);
-bool FileExist(char *FileName);
-bool IsPlot3D(GraphObj *g);
-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);
-unsigned int Hash2(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);
-DWORD CheckNewString(char **loc, char *s_old, char *s_new, 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
-void LockData(bool lockExec, bool lockWrite);
-char *yywarn(char *txt, bool bNew);
-bool do_xyfunc(DataObj *, double, double, double, char *, lfPOINT **, long *, char *);
-bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double z2, double zstep,
- char *expr, char *param);
-anyResult *do_formula(DataObj *, char *);
-bool MoveFormula(DataObj *d, char *of, char *nf, int nfsize, int dx, int dy, int r0, int c0);
-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();
-void SortArray(int n, double *vals);
-void SortArray2(int n, double *a1, double *a2);
-void SortFpArray(int n, lfPOINT *vals);
-double *randarr(double *v0, int n, long *seed);
-double *resample(double *v0, int n, long *seed);
-void spline(lfPOINT *v, int n, double *y2);
-double gammln(double x);
-double factrl(int n);
-double gammp(double a, double x);
-double gammq(double a, double x);
-double betai(double a, double b, double x);
-double bincof(double n, double k);
-double binomdistf(double k, double n, double p);
-double betaf(double z, double w);
-double errf(double x);
-double errfc(double x);
-double norm_dist(double x, double m, double s);
-double norm_freq(double x, double m, double s);
-double exp_dist(double x, double l, double s);
-double exp_inv(double p, double l, double s);
-double exp_freq(double x, double l, double s);
-double lognorm_dist(double x, double m, double s);
-double lognorm_freq(double x, double m, double s);
-double chi_dist(double x, double df, double);
-double chi_freq(double x, double df);
-double t_dist(double t, double df, double);
-double t_freq(double t, double df);
-double pois_dist(double x, double m, double);
-double f_dist(double f, double df1, double df2);
-double f_freq(double f, double df1, double df2);
-double weib_dist(double x, double shape, double scale);
-double weib_freq(double x, double shape, double scale);
-double cauch_dist(double x, double loc, double scale);
-double cauch_freq(double x, double loc, double scale);
-double logis_dist(double x, double loc, double scale);
-double logis_freq(double x, double loc, double scale);
-double ks_dist(int n, double d);
-void swilk1(int n, double *v0, double (*func)(double, double, double), double p1, double p2,
- bool bsorted, double *w, double *p);
-void KolSmir(int n, double *v0, double (*func)(double, double, double),
- double p1, double p2, bool bsorted, double *d, double *p);
-double distinv(double (*sf)(double, double, double), double df1, double df2, double p, double x0);
-void d_quartile(int n, double *v, double *q1, double *q2, double *q3);
-double d_variance(int n, double *v, double *mean = 0L, double *ss = 0L);
-double d_amean(int n, double *v);
-double d_kurt(int n, double *v);
-double d_skew(int n, double *v);
-double d_gmean(int n, double *v);
-double d_hmean(int n, double *v);
-double d_classes(DataObj *d, double start, double step, double *v, int nv, char *range);
-double d_pearson(double *x, double *y, int n, char *dest, DataObj *data, double *ra);
-double d_rank(int n, double *v, double v1);
-void crank(int n, double *w0, double *s);
-double d_spearman(double *x, double *y, int n, char *dest, DataObj *data, double *ra);
-double d_kendall(double *x, double *y, int n, char *dest, DataObj *data, double *ra);
-double d_regression(double *x, double *y, int n, char *dest, DataObj *data, double *ra);
-double d_covar(double *x, double *y, int n, char *dest, DataObj *data);
-double d_utest(double *x, double *y, int n1, int n2, char *dest, DataObj *data, double *results);
-double d_ttest(double *x, double *y, int n1, int n2, char *dest, DataObj *data, double *results);
-double d_ttest2(double *x, double *y, int n, char *dest, DataObj *data, double *results);
-double d_ftest(double *x, double *y, int n1, int n2, char *dest, DataObj *data, double *results);
-bool do_anova1(int n, int *nv, double **vals, double **res_tab, double *gm, double **means, double **ss);
-bool bartlett(int n, int *nc, double *ss, double *chi2);
-bool levene(int type, int n, int *nv, double *means, double **vals, double *F, double *P);
-double wprob(double w, double rr, double cc);
-double ptukey(double q, double rr, double cc, double df, int lower_tail, int log_p);
-double qtukey(double p, double rr, double cc, double df, int lower_tail, int log_p);
-int year2aday(int y);
-void add_date(rlp_datetime *base, rlp_datetime *inc);
-char *date2text(rlp_datetime *dt, char *fmt);
-double date2value(rlp_datetime *dt);
-void parse_datevalue(rlp_datetime *dt, double dv);
-bool date_value(char *desc, char *fmt, double *value);
-char *value_date(double dv, char *fmt);
-double now_today();
-void split_date(double dv, int *y, int *mo, int *dom, int *dow, int *doy, int *h, int *m, double *s);
-Triangle* Triangulate1(char *xr, char *yr, char *zr, DataObj *data);
-Ribbon *SurfTria(GraphObj *parent, DataObj *data, char *text1, char *text2, char *text3);
-
-//prototypes reports.cpp
-void rep_anova(GraphObj *parent, DataObj *data);
-void rep_twanova(GraphObj *parent, DataObj *data);
-void rep_fmanova(GraphObj *parent, DataObj *data);
-void rep_twoway_anova(GraphObj *parent, DataObj *data);
-void rep_kruskal(GraphObj *parent, DataObj *data);
-void rep_samplestats(GraphObj *parent, DataObj *data);
-void rep_regression(GraphObj *parent, DataObj *data);
-void rep_robustline(GraphObj *parent, DataObj *data);
-void rep_twowaytable(GraphObj *parent, DataObj *data);
-void rep_compmeans(GraphObj *parent, DataObj *data);
-void rep_correl(GraphObj *parent, DataObj *data, int style);
-
+//RLPlot.h, Copyright (c) 2000-2008 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
+//
+#ifndef _RLPLOT_H
+#define _RLPLOT_H
+#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);}
+
+#define _PI 3.1415926535897932384626433832795028841971693993751
+#define _SQRT2 1.4142135623730950488016887242096980785696718753769
+
+#ifdef _WINDOWS //platform is windows
+#include <windows.h>
+#if _MSC_VER >= 1400
+#define USE_WIN_SECURE
+#endif
+#define w_char WCHAR
+#define _SBINC 1 //scrollbox extra space/line
+#define _TXH 4.0 //graph text default size in mm
+
+#else //platform is *nix
+#include <sys/types.h>
+#define DWORD u_int32_t
+#define w_char wchar_t
+#define _SBINC 8 //scrollbox extra space/line
+#define _TXH 3.0 //graph text default size in mm
+
+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, SIZE_LSPC, SIZE_SCALE};
+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_ADDCHARW, 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_SAVEAS, 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_CLOSE, 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_SSV, 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_SAVE_LABELS, CMD_UNLOCK, CMD_SYMTEXT_UNDO,
+ CMD_FILLRANGE, CMD_BUSY, CMD_ERROR, CMD_CLEAR_ERROR, CMD_SETPARAM, CMD_SETFUNC,
+ CMD_LEGEND, CMD_FILENAME, CMD_LAYERS, CMD_OBJTREE, CMD_TEXTDEF,
+ CMD_HASSTACK, CMD_WRITE_GRAPHS, CMD_SETFONT, CMD_SETSTYLE, CMD_COPY, CMD_PASTE,
+ CMD_INSROW, CMD_INSCOL, CMD_DELROW, CMD_DELCOL, CMD_ADDTXT, CMD_ETRACC, CMD_SHPGUP,
+ CMD_SHPGDOWN, CMD_ERRDESC, CMD_SAVE, CMD_GETMARK, CMD_PASTE_OBJ, CMD_COL_MOUSE,
+ CMD_MARKOBJ, CMD_SCALE, CMD_GETFILENAME, CMD_TEXTTHERE, CMD_HIDEMARK, CMD_MENUHEIGHT,
+ CMD_RECALC, CMD_DRAWPG, CMD_UPDPG, CMD_MINMAX, CMD_STEP, CMD_SIGNAL_POL};
+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_CIRCLEC, SYM_RECTC, SYM_TRIAUC, SYM_TRIAUL, SYM_TRIAUR,
+ SYM_TRIADC, SYM_TRIADL, SYM_TRIADR, SYM_DIAMONDC, SYM_4STAR, SYM_4STARF, SYM_5GON, SYM_5GONF,
+ SYM_5GONC, SYM_5STAR, SYM_5STARF, SYM_6STAR, SYM_6STARF, SYM_1QUAD, SYM_2QUAD, SYM_3QUAD,
+ SYM_TEXT = 0x004f, 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_BEZIER, GO_TEXTFRAME,
+ 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_FUNC3D,
+ GO_XYSTAT, GO_FITFUNC3D, GO_NORMQUANT, GO_CONTOUR,
+ GO_GRAPH = 0x200, GO_PAGE, GO_SPREADDATA = 0x300, GO_DEFRW};
+enum {OC_UNKNOWN, OC_BITMAP, OC_HIMETRIC, OC_TRANSPARENT = 0x100};
+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,
+ FILL_HASH, FILL_WATER, 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,
+ TM_PASTE=0x200};
+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, MC_PASTE, MC_DRAWPEN, MC_DRAWREC,
+ MC_DRAWRREC, MC_DRAWELLY, MC_TXTFRM, MC_COLWIDTH};
+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, FF_SSV};
+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};
+enum {FE_NONE = 0x1000, FE_PARENT, FE_PLOT, FE_FLUSH, FE_DELOBJ, FE_REPLGO, FE_MUTATE};
+
+//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 {
+ lfPOINT sx, sy, sz;
+ }scaleINFO;
+
+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;
+
+typedef struct rlp_datetime {
+ int aday, year, doy, month, dom, dow, hours, minutes;
+ double seconds;
+}rlp_datetime;
+
+// 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_DATETIME 0x4000 // its a date- or time axis
+#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;
+ double *a_data;
+ int a_count;
+ } 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 NextRow(int *y);
+ bool NextCol(int *x);
+ bool IsInRange(int x, int y);
+ bool BoundRec(RECT *rec);
+ char *RangeDesc(void *d, int style); //d points to a DataObj class
+ int DataTypes(void *d, int *numerical, int *strings, int *datetime);
+
+private:
+ char *txt;
+ int x1, y1, x2, y2, cx, cy, curridx;
+
+ bool Reset();
+ bool Parse(int start);
+};
+
+class Triangle {
+public:
+ Triangle *next;
+ fPOINT3D pt[4];
+ int order[3]; //sort order
+
+ Triangle();
+ void SetRect();
+ bool TestVertex(double x, double y);
+ bool Sort();
+ void LinePoint(int i1, int i2, double z, lfPOINT *res);
+ bool IsoLine(double z, void *dest);
+
+private:
+ double cx, cy, r2; //circumcircle
+ fRECT rc; //bounding rectangle
+ lfPOINT ld[3]; //line eqations
+ bool bSorted; //vertices are sorted
+};
+
+class Triangulate {
+public:
+ Triangle *trl;
+
+ Triangulate(Triangle *t_list);
+ bool AddEdge(fPOINT3D *p1, fPOINT3D *p2);
+ bool AddVertex(fPOINT3D *v);
+
+private:
+ typedef struct edge {
+ edge *next;
+ fPOINT3D p1, p2;
+ };
+ edge *edges;
+};
+
+class anyOutput{
+public:
+ int units; //use units mm, inch ...
+ int minLW; //minimum line width in pix
+ int MrkMode; //existing mark on screen
+ int OC_type; //specify display, printer clipboard ...
+ 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 UseAxis(AxisDEF *ax, int type);
+ 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 Focus() {return;};
+ virtual void Caption(char *txt, bool bModified){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();
+ virtual void MouseCapture(bool bgrab){return;};
+ 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 void ShowInvert(RECT *rec){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 oGetTextExtentW(w_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 oTextOutW(int x, int y, w_char *txt, int cb){return false;};
+ virtual bool oPolygon(POINT *pts, int cp, char *nam = 0L){return false;};
+};
+
+enum {ET_UNKNOWN, ET_VALUE, ET_TEXT, ET_FORMULA, ET_ERROR, ET_BOOL,
+ ET_DATE, ET_TIME, ET_DATETIME, ET_BUSY=0x100, ET_CIRCULAR=0x200, ET_EMPTY=0x400,
+ ET_NODRAW=0x800, ET_NODRAW_EMPTY=0xc00};
+
+class EditText {
+public:
+ char *text, *ftext;
+ int Align, type, row, col;
+ void *parent; //points to a data object: defined below
+ anyOutput *disp;
+ double Value;
+
+ EditText(void *par, char *msg, int r, int c);
+ ~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 bTranslate);
+ bool GetResult(anyResult *r, bool use_last = false);
+ bool SetValue(double v);
+ bool SetText(char *t);
+ void SetRec(RECT *rc);
+ int GetX() {return loc.x;};
+ int GetY() {return loc.y;};
+ int GetRX() {return crb.x;};
+ int GetRY() {return crb.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);};
+ bool hasMark() {return (m1 != m2 && m1 >= 0 && m2 >= 0);};
+
+private:
+ LineDEF *bgLine;
+ FillDEF *bgFill;
+ int length, CursorPos, m1, m2, mx1, mx2;
+ POINT loc, rb, crb;
+ DWORD TextCol;
+
+ void FindType();
+ void set_etracc();
+};
+
+class fmtText {
+
+typedef struct _fmt_txt_info {
+ int tag, uc, uc_len;
+ char *txt;
+}fmt_txt_info;
+
+typedef struct _fmt_uc_info {
+ int tag, cb;
+ w_char *uc_txt;
+}fmt_uc_info;
+
+public:
+ fmtText();
+ 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);
+ int ucTag(char *txt, int cb, int *tl, int *ucc);
+ int ucLeft(char *txt, int cb, int *tl, int *ucc);
+ 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);
+ void EditMode(bool bEdit);
+
+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);
+ bool DrawFormattedW(anyOutput *o);
+ void DrawFormatted(anyOutput *o);
+
+ char *src;
+ POINT pos;
+ int n_split, n_split_W, uc_state;
+ DWORD flags;
+ fmt_txt_info *split_text;
+ fmt_uc_info *split_text_W;
+};
+
+class TextValue {
+
+typedef struct _TxtValItem {
+ unsigned int hv1, hv2;
+ char *text;
+ double val;
+}TextValItem;
+
+public:
+ TextValue();
+ TextValue(TextValItem **tvi, int ntvi);
+ ~TextValue();
+ double GetValue(char* txt);
+ bool GetItem(int idx, char **text, double *value);
+ void Reset();
+ TextValue *Copy();
+ int Count() {return nitems;};
+
+private:
+ TextValItem **items;
+ int nitems;
+ double next, inc;
+};
+
+class RangeInfo {
+public:
+ int col_width, row_height, first_width;
+ RangeInfo(int sel, int cw, int rh, int fw, RangeInfo *next);
+ RangeInfo(int sel, char *range, RangeInfo *next);
+ ~RangeInfo();
+ int SetWidth(int w);
+ int SetDefWidth(int w);
+ int SetHeight(int h);
+ int SetFirstWidth(int w);
+ int GetWidth(int col);
+ int GetHeight(int row);
+ int GetFirstWidth();
+ int Type(){return r_type;};
+ RangeInfo *Next(){return ri_next;};
+
+private:
+ int r_type; // 0 default
+ // 1 column info
+ // 2 row info
+ RangeInfo *ri_next;
+ AccRange *ar;
+};
+
+class DataObj{
+public:
+ int cRows, cCols, c_disp, r_disp;
+ RangeInfo *ri;
+ EditText ***etRows;
+
+ DataObj();
+ ~DataObj();
+ virtual bool Init(int nRows, int nCols);
+ virtual bool mpos2dpos(POINT *mp, POINT *dp, bool can_scroll){return false;};
+ 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, bool bTranslate = true);
+ char **GetTextPtr(int row, int col);
+ virtual bool GetResult(anyResult *r, int row, int col, bool use_last = false);
+ virtual bool GetSize(int *width, int *height);
+ virtual bool isEmpty(int row, int col);
+ 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();
+ bool ValueRec(RECT *rc);
+};
+
+class StrData {
+public:
+ StrData(DataObj *par, RECT *rc = 0L);
+ ~StrData();
+ bool GetSize(int *w, int *h);
+ void RestoreData(DataObj *dest);
+
+private:
+ int pw, ph;
+ RECT drc;
+ 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(int type);
+ void Herringbone();
+ void Circles();
+ void Grass();
+ void Foam();
+ void Recs();
+ void Hash();
+ 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);
+ virtual double DefSize(int select);
+ virtual bool hasTransp(){return false;};
+};
+
+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, bSelected, bMarked;
+ 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:
+ bool DoAutoscale(anyOutput *o);
+
+ 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, char *desc = 0L);
+ Bar(int src);
+ ~Bar();
+ double GetSize(int select);
+ 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:
+ anyOutput *mo;
+ RECT mrc;
+ 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;
+ FillDEF pgFill;
+ LineDEF pgFillLine;
+ 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, char *name=0L);
+ DataLine(GraphObj *par, DataObj *d, lfPOINT *val, long nval, char *name);
+ DataLine(int src);
+ virtual ~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);
+ void DrawCurve(anyOutput *target);
+ void DrawSpline(anyOutput *target);
+};
+
+class DataPolygon:public DataLine{
+public:
+ DataPolygon(GraphObj *par, DataObj *d, char *xrange=0L, char *yrange=0L, char *name=0L);
+ DataPolygon(GraphObj *par, DataObj *d, lfPOINT *val, long nval, char *name = 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);
+};
+
+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:
+ anyOutput *mo;
+ RECT mrc;
+ 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:
+ anyOutput *mo;
+ RECT mrc;
+ 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:
+ anyOutput *mo;
+ RECT mrc;
+ 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);
+ ~Whisker();
+ 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:
+ anyOutput *mo;
+ RECT mrc;
+ 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, n_linept;
+ POINT *ipts;
+ lfPOINT xBounds, yBounds, zBounds;
+ bool bDrawDone, bReqPoint, bSigPol;
+ 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(GraphObj *par, DataObj *d, fPOINT3D *pt, int n_pt, 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);
+ 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;
+ long nPts, npts;
+ char *x_range, *y_range, *z_range;
+ POINT *ssRef;
+ long cssRef;
+ 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);
+ bool CheckMark();
+ TextDEF *GetTextDef(){return &TextDef;};
+
+private:
+ lfPOINT fPos, fDist;
+ double si, csi, curr_z;
+ DWORD flags, bgcolor;
+ TextDEF TextDef;
+ LineDEF bgLine;
+ int ix, iy, m1, m2, CursorPos;
+ bool is3D;
+ RECT Cursor, rm1, rm2;
+ POINT pts[5];
+ POINT *ssRef;
+ long cssRef;
+ anyOutput *defDisp;
+ bool bModified, bBGvalid;
+};
+
+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, lspc;
+ DWORD flags, undo_flags;
+ TextDEF TextDef;
+ long nLines;
+ int cli;
+ bool is3D;
+ Label **Lines;
+};
+
+class TextFrame:public GraphObj{
+ enum {TF_MAXLINE=120};
+public:
+ TextFrame(GraphObj *parent, DataObj *data, lfPOINT *p1, lfPOINT *p2, char *txt);
+ TextFrame(int src);
+ ~TextFrame();
+ double GetSize(int select);
+ bool SetSize(int select, double value);
+ 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:
+ fRECT pad;
+ RECT ipad, Cursor, *tm_rec;
+ fmtText fmt_txt;
+ int nlines, linc, tm_c, csize, cpos;
+ bool bModified, bResize, has_m1, has_m2;
+ unsigned char c_char, m1_char, m2_char;
+ double lspc;
+ lfPOINT pos1, pos2;
+ POINT cur_pos, m1_pos, m2_pos, m1_cpos, m2_cpos;
+ TextDEF TextDef;
+ dragRect *drc;
+ unsigned char *text, **lines;
+ LineDEF Line, FillLine;
+ FillDEF Fill;
+
+ void text2lines(anyOutput *o);
+ void lines2text();
+ void ShowCursor(anyOutput *o);
+ void AddChar(anyOutput *o, int c);
+ void DelChar(anyOutput *o);
+ void CalcCursorPos(int x, int y, anyOutput *o);
+ void ReplMark(anyOutput *o, char *ntext);
+ void procTokens();
+ bool DoPaste(anyOutput *o);
+ void TextMark(anyOutput *o, int mode);
+ bool CopyText(anyOutput *o, bool b_cut);
+};
+
+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;
+ anyOutput *mo;
+ RECT mrc;
+};
+
+class polyline:public GraphObj {
+public:
+ dragHandle **pHandles;
+ 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);
+ virtual ~polyline();
+ double GetSize(int select);
+ bool SetSize(int select, double value);
+ DWORD GetColor(int select);
+ virtual void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ virtual bool PropertyDlg();
+ virtual bool FileIO(int rw);
+ void * ObjThere(int x, int y);
+ void Track(POINT *p, anyOutput *o);
+
+private:
+ void ShowPoints(anyOutput *o);
+};
+
+class Bezier:public polyline {
+public:
+ Bezier(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts, int mode, double res);
+ Bezier(int src);
+ void DoPlot(anyOutput *o);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool FileIO(int rw);
+
+private:
+ void AddPoints(int n, lfPOINT *p);
+
+ void FitCurve(lfPOINT *d, int npt, double error);
+ void IpolBez(lfPOINT *d, lfPOINT tHat1, lfPOINT tHat2);
+ void FitCubic(lfPOINT *d, int first, int last, lfPOINT tHat1, lfPOINT tHat2, double error);
+ void RemovePoint(lfPOINT *d, int sel);
+ void GenerateBezier(lfPOINT *d, int first, int last, double * uPrime, lfPOINT tHat1, lfPOINT tHat2, lfPOINT *bezCurve);
+ double *Reparameterize(lfPOINT *d, int first, int last, double *u, lfPOINT *bezCurve);
+ lfPOINT fBezier(int degree, lfPOINT *V, double t);
+ double *ChordLengthParameterize(lfPOINT *d, int first, int last);
+ double ComputeMaxError(lfPOINT *d, int first, int last, lfPOINT *bezCurve, double *u, int *splitPoint);
+};
+
+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);
+ virtual ~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:
+ DWORD flags;
+
+ LegItem(GraphObj *par, DataObj *d, LineDEF *ld, LineDEF *lf, FillDEF *fill, char *desc);
+ LegItem(GraphObj *par, DataObj *d, LineDEF *ld, Symbol *sy);
+ LegItem(GraphObj *par, DataObj *d, LineDEF *ld, int err, char *desc);
+ 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, char *desc);
+ bool HasSym(LineDEF *ld, GraphObj *sy);
+ bool HasErr(LineDEF *ld, int err);
+
+private:
+ LineDEF DataLine, OutLine, HatchLine;
+ FillDEF Fill;
+ Symbol *Sym;
+ Label *Desc;
+ 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, char *desc);
+ bool HasSym(LineDEF *ld, GraphObj *sy, char *desc);
+ bool HasErr(LineDEF *ld, int err, char *desc);
+
+private:
+ lfPOINT pos, lb_pos;
+ RECT trc;
+ anyOutput *to;
+ fRECT B_Rect, C_Rect, D_Rect, E_Rect, F_Rect;
+ long nItems;
+ bool hasLine;
+ 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, use_zaxis; //this plot uses its own axes
+ lfPOINT xBounds, yBounds, zBounds; //like Bounds but in 3D space
+ int hidden; //plot (layer) is not visible
+ int x_dtype, y_dtype, z_dtype; //data types
+ char *x_info, *y_info, *z_info; //descriptor used e.g. for axis label or legend
+ char *data_desc; //descriptor for data, used for legend etc
+ TextValue *x_tv, *y_tv; //TextValue object for ordinal axes
+
+ Plot(GraphObj *par, DataObj *d);
+ ~Plot(){return;};
+ 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;};
+ virtual void RegGO(void *n){return;};
+ virtual bool FileIO(int rw) {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:
+ char *xRange, *yRange;
+ long nPoints;
+ int DefSym;
+ lfPOINT BarDist;
+ Bar **Bars;
+ Symbol **Symbols;
+ DataLine *TheLine;
+ ErrorBar **Errors;
+ Label **Labels;
+
+ PlotScatt(GraphObj *par, DataObj *d, DWORD presel);
+ PlotScatt(GraphObj *par, DataObj *d, int cBars, Bar **bars, ErrorBar **errs);
+ PlotScatt(GraphObj *par, DataObj *d, int nPts, Symbol **sym, DataLine *lin);
+ PlotScatt(int src);
+ virtual ~PlotScatt();
+ double GetSize(int select);
+ bool SetSize(int select, double value);
+ bool SetColor(int select, DWORD col);
+ void DoPlot(anyOutput *target);
+ virtual bool Command(int cmd, void *tmpl, anyOutput *o);
+ virtual bool PropertyDlg();
+ void RegGO(void *n);
+ virtual bool FileIO(int rw);
+
+ bool ForEach(int cmd, void *tmp, anyOutput *o);
+
+private:
+ DWORD DefSel;
+ char *ErrRange, *LbRange;
+ Arrow **Arrows;
+ DropLine **DropLines;
+
+ bool CreateBarChart();
+};
+
+class xyStat:public PlotScatt{
+public:
+ xyStat(GraphObj *par, DataObj *d);
+ xyStat(int src);
+ ~xyStat();
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ virtual bool FileIO(int rw);
+
+ void CreateData();
+
+private:
+ double ci;
+ DataObj *curr_data;
+ char *case_prefix;
+
+};
+
+class BarChart:public PlotScatt{
+public:
+ BarChart(GraphObj *par, DataObj *d);
+};
+
+class FreqDist:public Plot {
+public:
+ FreqDist(GraphObj *par, DataObj *d);
+ FreqDist(GraphObj *par, DataObj *d, char* range, bool bOnce);
+ FreqDist(GraphObj *par, DataObj *d, double *vals, int nvals, int nclasses);
+ 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 dmin, dmax, 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, char *box_name);
+ ~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);
+
+ bool ForEach(int cmd, void *tmp, anyOutput *o);
+ void CreateData();
+
+private:
+ char *xRange, *yRange, *case_prefix;
+ long nPoints;
+ double ci_box, ci_err;
+ DataObj *curr_data;
+ lfPOINT BoxDist;
+ Box **Boxes;
+ Whisker **Whiskers;
+ Symbol **Symbols;
+ Label **Labels;
+ 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);
+ virtual ~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, int type):StackBar(par, d){mode = type;};
+ bool PropertyDlg();
+
+private:
+ int mode;
+};
+
+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);
+ virtual ~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:
+ long 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);
+ virtual ~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, int which, char *xr, char *yr, char *zr);
+ Ribbon(GraphObj *par, DataObj *d, GraphObj **go, int ngo);
+ 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, int sel, double x1=0.0, double xstep=1.0, double z1=0.0, double zstep=1.0);
+ Grid3D(int src);
+ ~Grid3D();
+ 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);
+
+ void CreateObs(bool set_undo);
+
+private:
+ long nLines, nPlanes;
+ fPOINT3D start, step;
+ LineDEF Line;
+ FillDEF Fill;
+ Line3D **lines;
+ Plane3D **planes;
+
+ bool Configure();
+};
+
+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, char *desc);
+ 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 NormQuant:public Plot{
+public:
+ NormQuant(GraphObj *par, DataObj *d, char* range);
+ NormQuant(GraphObj *par, DataObj *d, double *data, int ndata);
+ NormQuant(int src);
+ ~NormQuant();
+ void DoPlot(anyOutput *o);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ bool FileIO(int rw);
+
+private:
+ char *ssRef;
+ int nData, nValidData;
+ double *x_vals, *y_vals, *src_data;
+ Symbol *sy;
+
+ bool ProcessData();
+};
+
+
+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);
+ virtual ~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 Track(POINT *p, anyOutput *o);
+
+ void DoPlot(double six, double csx, anyOutput *o);
+ bool ProcSeg();
+
+private:
+ double value, size, fix, fiy, fiz, lsi, lcsi, angle, lbx, lby;
+ int n_seg, s_seg;
+ double *seg;
+ bool bModified, bValidTick;
+ long numPG;
+ anyOutput *mo;
+ RECT mrc;
+ int gl_type;
+ GridLine *Grid;
+ Label *label;
+ DataPolygon **Polygons;
+ DWORD flags;
+ POINT pts[2];
+ line_segment *ls;
+
+ bool CmpPoints(double x1, double y1, double x2, double y2);
+ bool StoreSeg(lfPOINT *line);
+};
+
+class Axis:public GraphObj{
+public:
+ AxisDEF *axis;
+ LineDEF axline;
+ TextValue *atv;
+ long NumTicks;
+ Tick **Ticks;
+
+ 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);
+ void *ObjThere(int x, int y);
+ void Track(POINT *p, anyOutput *o);
+
+ 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);
+ void CreateTicks();
+ DWORD GradColor(double value);
+
+private:
+ double sizAxLine, sizAxTick, sizAxTickLabel;
+ double si, csi;
+ double brksymsize, brkgap, tick_angle;
+ int brksym, nl_segs, gl_type, tick_type, grad_type;
+ bool bModified;
+ DWORD colAxis, gCol_0, gCol_1, gCol_2, gTrans;
+ LineDEF GridLine;
+ GraphObj *axisLabel;
+ POINT pts[2], gradient_box[5];
+ 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 mkTimeAxis();
+ void ManuTicks(double sa, double st, int n, DWORD flags);
+ void UpdateTicks();
+ bool ssTicks();
+ void GradientBar(anyOutput *o);
+};
+
+class ContourPlot:public Plot {
+public:
+ ContourPlot(GraphObj *par, DataObj *d);
+ ContourPlot(int src);
+ ~ContourPlot();
+ 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:
+ char *ssRefX, *ssRefY, *ssRefZ;
+ Symbol **Symbols;
+ Label **Labels;
+ long nval, nSym, nLab;
+ DWORD flags;
+ double sr_zval;
+ fPOINT3D *val;
+ AxisDEF z_axis;
+ Axis *zAxis;
+
+ bool LoadData(char *xref, char *yref, char *zref);
+ bool DoTriangulate();
+ bool DoAxis(anyOutput *o);
+ void DoSymbols(Triangle *trl);
+};
+
+class Plot3D:public Plot{
+ typedef struct {
+ double Zmin, Zmax;
+ GraphObj *go;
+ }obj_desc;
+public:
+ long nPlots, nAxes;
+ Axis **Axes;
+ GraphObj **plots, **Sc_Plots;
+ double *RotDef;
+ fPOINT3D cub1, cub2, rotC;
+ int nscp;
+
+ Plot3D(GraphObj *par, DataObj *d, DWORD flags);
+ Plot3D(int src);
+ virtual ~Plot3D();
+ double GetSize(int select);
+ bool SetColor(int select, DWORD col);
+ void DoPlot(anyOutput *o);
+ void DoMark(anyOutput *o, bool mark);
+ virtual bool Command(int cmd, void *tmpl, anyOutput *o);
+ virtual bool PropertyDlg();
+ virtual void RegGO(void *n);
+ virtual 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);
+ bool AddAxis();
+
+private:
+ long nObs, nmaxObs;
+ DWORD crea_flags;
+ Drag3D *drag;
+ fPOINT3D cu1, cu2, rc;
+ obj_desc **dispObs;
+
+ bool AddPlot(int family);
+ int cmp_obj_desc(obj_desc *obj1, obj_desc *obj2);
+};
+
+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 Func3D:public Plot3D {
+public:
+ Func3D(GraphObj *par, DataObj *d);
+ Func3D(int src);
+ ~Func3D();
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ void RegGO(void *n);
+ bool FileIO(int rw);
+
+private:
+ bool Update();
+
+ double x1, x2, xstep, z1, z2, zstep;
+ LineDEF Line;
+ FillDEF Fill;
+ char *param, *cmdxy;
+ DataObj *gda;
+ Grid3D *gob;
+};
+
+class FitFunc3D:public Plot3D {
+public:
+ FitFunc3D(GraphObj *par, DataObj *d);
+ FitFunc3D(int src);
+ ~FitFunc3D();
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+ bool PropertyDlg();
+ void RegGO(void *n);
+ bool FileIO(int rw);
+
+private:
+ bool Update();
+
+ double x1, x2, xstep, z1, z2, zstep, conv, chi2;
+ char *ssXref, *ssYref, *ssZref;
+ int maxiter;
+ LineDEF Line;
+ FillDEF Fill;
+ char *param, *cmdxy;
+ DataObj *gda;
+ Grid3D *gob;
+};
+
+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, *PasteObj;
+ DWORD ColBG, ColAX;
+ GraphObj **Sc_Plots;
+ Axis **Axes;
+ char *filename;
+
+ Graph(GraphObj *par, DataObj *d, anyOutput *o, int style);
+ Graph(int src);
+ virtual ~Graph();
+ double GetSize(int select);
+ bool SetSize(int select, double value);
+ DWORD GetColor(int select);
+ bool SetColor(int select, DWORD col);
+ 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);
+ virtual double DefSize(int select);
+ bool hasTransp();
+
+private:
+ int NumAxes, AxisTempl, tickstyle, zoom_level;
+ double scale;
+ RECT rcDim, rcUpd, rc_mrk;
+ DWORD ColDR, ColGR, ColGRL;
+ AxisDEF x_axis, y_axis;
+ FrmRect *frm_g, *frm_d;
+ bool dirty, bDialogOpen;
+ 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);
+ bool DoScale(scaleINFO *sc, anyOutput *o);
+};
+
+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);
+ double DefSize(int select);
+
+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();
+ int RegisterGO(GraphObj *go);
+ void AddRegGO(GraphObj *go);
+ bool PushGO(unsigned int id, GraphObj *go);
+ GraphObj *PopGO(unsigned int id);
+ void FreeStack();
+
+private:
+ unsigned int NextPopGO, NextPushGO, NextRegGO;
+ GraphObj ***gObs;
+ GraphObj ***goStack;
+};
+
+class Default{
+public:
+ int dUnits, cUnits, iMenuHeight;
+ char DecPoint[2], ColSep[2];
+ char *svgAttr, *svgScript, *currPath, *IniFile;
+ char *File1, *File2, *File3, *File4, *File5, *File6;
+ char *fmt_date, *fmt_time, *fmt_datetime;
+ double min4log, ss_txt;
+ 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);
+ void Idle(int cmd);
+ void UpdRect(anyOutput *o, int x1, int y1, int x2, int y2);
+ void UpdAdd(anyOutput * o, int x, int y);
+
+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, *out_upd;
+ RECT rec_upd;
+ bool can_upd;
+ 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_VALLONG, UNDO_OBJCONF, UNDO_OBJCONF_1,
+ UNDO_LFP, UNDO_POINT, UNDO_VOIDPTR, 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, UNDO_TEXTBUF};
+ 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;
+
+ typedef struct _TextBuff {
+ int *psize, size, *ppos, pos;
+ unsigned char **pbuff, *buff;
+ }TextBuff;
+
+public:
+ int *pcb;
+ anyOutput *cdisp, *ldisp;
+ bool busy;
+
+ UndoObj();
+ ~UndoObj();
+ void Flush();
+ bool isEmpty(anyOutput *o);
+ void SetDisp(anyOutput *o);
+ void KillDisp(anyOutput *o);
+ void InvalidGO(GraphObj *go);
+ void Pop(anyOutput *o);
+ 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 Point(GraphObj *parent, POINT *pt, anyOutput * o, DWORD flags);
+ void VoidPtr(GraphObj *parent, void **pptr, void *ptr, anyOutput * o, DWORD flags);
+ void ValInt(GraphObj *parent, int *val, DWORD flags);
+ void ValLong(GraphObj *parent, long *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);
+ int 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, RECT *rc, DWORD flags);
+ void TextCell(EditText *et, anyOutput *o, char *text, int *cur, int *m1, int *m2, void* DaO, DWORD flags);
+ void TextBuffer(GraphObj *parent, int *psize, int *ppos, unsigned char **pbuff, DWORD flags, anyOutput *o);
+
+private:
+ UndoInfo **buff, **buff0;
+ int stub1, ndisp;
+ 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);
+int YesNoCancelBox(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 InvalidateOutput(anyOutput *o);
+void SuspendAnimation(anyOutput *o, bool bSusp);
+void InitTextCursor(bool init);
+void EmptyClip();
+void CopyText(char *txt, int len);
+unsigned char* PasteText();
+void GetDesktopSize(int *width, int *height);
+void FindBrowser();
+void LoopDlgWnd();
+void CloseDlgWnd(void *hDlg);
+void ShowDlgWnd(void *hDlg);
+void ResizeDlgWnd(void *hDlg, int w, int h);
+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, bool bPaste);
+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, GraphObj *parent);
+bool FillSsRange(DataObj *d, char **range, GraphObj *msg_go);
+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);
+char *str_ltrim(char *str);
+char *str_rtrim(char *str);
+char *str_trim(char *str);
+void rmquot(char *str);
+int strpos(char *needle, char *haystack);
+char *strreplace(char *needle, char *replace, char *haystack);
+char *substr(char *text, int pos1, int pos2);
+int rlp_strcpy(char*dest, int size, char*src);
+void ReshapeFormula(char **text);
+void TranslateResult(anyResult *res);
+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 *NiceTime(double val);
+char *Int2ColLabel(int nr, bool uc);
+char *mkCellRef(int row, int col);
+char *mkRangeRef(int r1, int c1, int r2, int c2);
+char *str2xml(char *str, bool bGreek);
+char **split(char *str, char sep, int *nl);
+char *fit_num_rect(anyOutput *o, int max_width, char *num_str);
+void add_to_buff(char** dest, int *pos, int *csize, char *txt, int len);
+void add_int_to_buff(char** dest, int *pos, int *csize, int value, bool lsp, int ndig);
+void add_dbl_to_buff(char** dest, int *pos, int *csize, double value, bool lsp);
+void add_hex_to_buff(char** dest, int *pos, int *csize, DWORD value, bool lsp);
+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);
+void DrawBezier(long *cp, POINT *pts, POINT p0, POINT p1, POINT p2, POINT p3, int depth=0);
+void ClipBezier(long *cp, POINT *pts, POINT p0, POINT p1, POINT p2, POINT p3, POINT *clp1, POINT *clp2);
+int mkCurve(lfPOINT *src, int n1, lfPOINT **dst, bool bClosed);
+POINT *MakeArc(int ix, int iy, int r, int qad, long *npts);
+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 DeleteGOL(GraphObj ***gol, long n, GraphObj *go, anyOutput *o);
+bool BackupFile(char *FileName);
+bool IsRlpFile(char *FileName);
+bool IsXmlFile(char *FileName);
+bool FileExist(char *FileName);
+bool IsPlot3D(GraphObj *g);
+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);
+unsigned int Hash2(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);
+DWORD CheckNewString(char **loc, char *s_old, char *s_new, 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
+void LockData(bool lockExec, bool lockWrite);
+char *yywarn(char *txt, bool bNew);
+bool do_xyfunc(DataObj *, double, double, double, char *, lfPOINT **, long *, char *);
+bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double z2, double zstep,
+ char *expr, char *param);
+anyResult *do_formula(DataObj *, char *);
+bool MoveFormula(DataObj *d, char *of, char *nf, int nfsize, int dx, int dy, int r0, int c0);
+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();
+void SortArray(int n, double *vals);
+void SortArray2(int n, double *a1, double *a2);
+void SortFpArray(int n, lfPOINT *vals);
+double *randarr(double *v0, int n, long *seed);
+double *resample(double *v0, int n, long *seed);
+void spline(lfPOINT *v, int n, double *y2);
+double gammln(double x);
+double factrl(int n);
+double gammp(double a, double x);
+double gammq(double a, double x);
+double betai(double a, double b, double x);
+double bincof(double n, double k);
+double binomdistf(double k, double n, double p);
+double betaf(double z, double w);
+double errf(double x);
+double errfc(double x);
+double norm_dist(double x, double m, double s);
+double norm_freq(double x, double m, double s);
+double exp_dist(double x, double l, double s);
+double exp_inv(double p, double l, double s);
+double exp_freq(double x, double l, double s);
+double lognorm_dist(double x, double m, double s);
+double lognorm_freq(double x, double m, double s);
+double chi_dist(double x, double df, double);
+double chi_freq(double x, double df);
+double t_dist(double t, double df, double);
+double t_freq(double t, double df);
+double pois_dist(double x, double m, double);
+double f_dist(double f, double df1, double df2);
+double f_freq(double f, double df1, double df2);
+double weib_dist(double x, double shape, double scale);
+double weib_freq(double x, double shape, double scale);
+double geom_freq(double x, double p);
+double geom_dist(double x, double p);
+double hyper_freq(double k, double n0, double m, double n1);
+double hyper_dist(double k, double n0, double m, double n1);
+double cauch_dist(double x, double loc, double scale);
+double cauch_freq(double x, double loc, double scale);
+double logis_dist(double x, double loc, double scale);
+double logis_freq(double x, double loc, double scale);
+double ks_dist(int n, double d);
+void swilk1(int n, double *v0, double (*func)(double, double, double), double p1, double p2,
+ bool bsorted, double *w, double *p);
+void KolSmir(int n, double *v0, double (*func)(double, double, double),
+ double p1, double p2, bool bsorted, double *d, double *p);
+double distinv(double (*sf)(double, double, double), double df1, double df2, double p, double x0);
+void d_quartile(int n, double *v, double *q1, double *q2, double *q3);
+double d_variance(int n, double *v, double *mean = 0L, double *ss = 0L);
+double d_amean(int n, double *v);
+double d_kurt(int n, double *v);
+double d_skew(int n, double *v);
+double d_gmean(int n, double *v);
+double d_hmean(int n, double *v);
+double d_classes(DataObj *d, double start, double step, double *v, int nv, char *range);
+double d_pearson(double *x, double *y, int n, char *dest, DataObj *data, double *ra);
+double d_rank(int n, double *v, double v1);
+void crank(int n, double *w0, double *s);
+double d_spearman(double *x, double *y, int n, char *dest, DataObj *data, double *ra);
+double d_kendall(double *x, double *y, int n, char *dest, DataObj *data, double *ra);
+double d_regression(double *x, double *y, int n, char *dest, DataObj *data, double *ra);
+double d_covar(double *x, double *y, int n, char *dest, DataObj *data);
+double d_utest(double *x, double *y, int n1, int n2, char *dest, DataObj *data, double *results);
+double d_ttest(double *x, double *y, int n1, int n2, char *dest, DataObj *data, double *results);
+double d_ttest2(double *x, double *y, int n, char *dest, DataObj *data, double *results);
+double d_ftest(double *x, double *y, int n1, int n2, char *dest, DataObj *data, double *results);
+bool do_anova1(int n, int *nv, double **vals, double **res_tab, double *gm, double **means, double **ss);
+bool bartlett(int n, int *nc, double *ss, double *chi2);
+bool levene(int type, int n, int *nv, double *means, double **vals, double *F, double *P);
+double wprob(double w, double rr, double cc);
+double ptukey(double q, double rr, double cc, double df, int lower_tail, int log_p);
+double qtukey(double p, double rr, double cc, double df, int lower_tail, int log_p);
+int year2aday(int y);
+void add_date(rlp_datetime *base, rlp_datetime *inc);
+char *date2text(rlp_datetime *dt, char *fmt);
+double date2value(rlp_datetime *dt);
+void parse_datevalue(rlp_datetime *dt, double dv);
+bool date_value(char *desc, char *fmt, double *value);
+char *value_date(double dv, char *fmt);
+double now_today();
+void split_date(double dv, int *y, int *mo, int *dom, int *dow, int *doy, int *h, int *m, double *s);
+Triangle* Triangulate1(char *xr, char *yr, char *zr, DataObj *data);
+
+//prototypes reports.cpp
+void rep_anova(GraphObj *parent, DataObj *data);
+void rep_bdanova(GraphObj *parent, DataObj *data);
+void rep_twanova(GraphObj *parent, DataObj *data);
+void rep_fmanova(GraphObj *parent, DataObj *data);
+void rep_twoway_anova(GraphObj *parent, DataObj *data);
+void rep_kruskal(GraphObj *parent, DataObj *data);
+void rep_samplestats(GraphObj *parent, DataObj *data);
+void rep_regression(GraphObj *parent, DataObj *data);
+void rep_robustline(GraphObj *parent, DataObj *data);
+void rep_twowaytable(GraphObj *parent, DataObj *data);
+void rep_compmeans(GraphObj *parent, DataObj *data);
+void rep_correl(GraphObj *parent, DataObj *data, int style);
+#endif //_RLPLOT_H
diff --git a/rlplot.spec b/rlplot.spec
index b1d823b..9d29338 100755
--- a/rlplot.spec
+++ b/rlplot.spec
@@ -1,5 +1,5 @@
Name: rlplot
-Version: 1.4
+Version: 1.5
Release: 1
Summary: A plotting program to create high quality graphs from data.
License: GPL
@@ -41,6 +41,9 @@ rm -rf "$RPM_BUILD_ROOT"
%{_bindir}/exprlp
%changelog
+* Fri May 2 2008 Reinhard Lackner
+- release 1.5
+
* Fri Sep 14 2007 Reinhard Lackner
- release 1.4
diff --git a/rlplot.spec~ b/rlplot.spec~
deleted file mode 100644
index b63355e..0000000
--- a/rlplot.spec~
+++ /dev/null
@@ -1,70 +0,0 @@
-Name: rlplot
-Version: 1.3
-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), 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
-* Sun Feb 25 2007 Reinhard Lackner
-- release 1.3
-
-* Thu Oct 19 2006 Reinhard Lackner
-- release 1.2
-
-* Fri Feb 24 2006 Reinhard Lackner
-- release 1.1
-
-* Wed Sep 07 2005 Reinhard Lackner
-- release 1.0
-
-* 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
index c2f8921..ac47e08 100755
--- a/spreadwi.cpp
+++ b/spreadwi.cpp
@@ -1,2637 +1,2656 @@
-//spreadwin.cpp, (c)2000-2006 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 <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 const LineDEF GrayLine;
-extern GraphObj *CurrGO, *TrackGO; //Selected Graphic Objects
-extern EditText *CurrText;
-extern char *LoadFile;
-extern char TmpTxt[];
-extern Default defs;
-extern UndoObj Undo;
-
-static ReadCache *Cache = 0L;
-static TextDEF ssText;
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 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, ns;
-
- if(ptr) {
- for(i = nt = nl = nc = ns = 0; ptr[i] && nl<100; i++) {
- switch(ptr[i]) {
- case 0x09: //tab
- nt++;
- break;
- case 0x0a: //LF
- nl++;
- break;
- case ',':
- nc++;
- break;
- case ' ':
- ns++;
- break;
- }
- }
- if(dispatch && i && !nt && !nl) {
- if(CurrText){
- g->Command(CMD_SETFOCUS, 0L, 0L);
- for(i = 0; ptr[i]; i++) CurrText->AddChar(ptr[i], i? 0L : Undo.cdisp, 0L);
- g->Command(CMD_REDRAW, 0L, 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 && ns && 0 == (ns % nl)) RetVal = FF_SSV;
- 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_SSV: g->Command(CMD_PASTE_SSV, 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(GraphObj *par, DataObj *Data);
- ~SpreadWin();
- void DoPlot(anyOutput *target);
- bool Command(int cmd, void *tmpl, anyOutput *o);
-
- bool ShowGrid(int CellWidth, int CellHeight, int FirstWidth, POINT *cpos);
- void MarkButtons(char *rng, POINT *cp = 0L);
- bool PrintData(anyOutput *o);
- void WriteGraphXML(unsigned char **ptr, long *cbd);
-
-private:
- bool is_modified, bDoColWidth;
- char *filename;
- ssButton **cButtons, **rButtons;
- ssButton *aButton;
- POINT cpos;
- DataObj *d;
- int NumGraphs, CurrCol;
- Graph **g;
- RECT rc_line;
- POINT line[2];
-};
-
-SpreadWin::SpreadWin(GraphObj *par, DataObj *Data):GraphObj(par, Data)
-{
- d = Data; g = 0L; ssOrg.x = ssOrg.y = 0; NumGraphs = 0;
- filename=0L; aButton = 0L;
- w = 0L; cButtons = rButtons = 0L;
- if(w = NewDispClass(this)){
- w->hasHistMenu = true;
- ssText.RotBL = ssText.RotCHAR = 0.0;
- ssText.fSize = 0.0f;
- ssText.iSize = w->un2iy(defs.GetSize(SIZE_CELLTEXT));
- ssText.Align = TXA_VCENTER | TXA_HLEFT; ssText.Mode = TXM_TRANSPARENT;
- ssText.Style = TXS_NORMAL; ssText.ColBg = 0x00e8e8e8L;
- ssText.ColTxt = 0x00000000L; ssText.text = 0L;
- ssText.Font = FONT_HELVETICA; w->SetTextSpec(&ssText);
- w->SetMenu(MENU_SPREAD); w->FileHistory();
- w->Erase(0x00e8e8e8L); w->Caption("RLPlot data");
- d->ri->SetDefWidth(w->un2ix(defs.GetSize(SIZE_CELLWIDTH)));
- d->ri->SetHeight(w->un2iy(defs.GetSize(SIZE_CELLTEXT)/defs.ss_txt) + 2);
- d->ri->SetFirstWidth(32);
- }
- else if(d && d->ri) {
- d->ri->SetHeight(19); d->ri->SetDefWidth(76); d->ri->SetFirstWidth(32);
- }
- Id = GO_SPREADDATA;
- is_modified = bDoColWidth = false;
-}
-
-SpreadWin::~SpreadWin()
-{
- int i;
-
- if(parent) {
- 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]) delete(g[i]);
- free (g);
- }
- if(filename) free(filename); filename=0L;
- }
-}
-
-void
-SpreadWin::DoPlot(anyOutput *o)
-{
- if(!(o->ActualSize(&currRC)))return;
- o->StartPage();
- d->Command(CMD_DOPLOT, (void*)this, o);
- o->EndPage();
-}
-
-bool
-SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
-{
- char *Name;
- Graph *g2;
- int i, j, k;
- MouseEvent *mev;
- POINT p1, p2;
-
- if(d) {
- if(!o) o = w;
- switch(cmd) {
- case CMD_CURRPOS:
- if(tmpl && cButtons && rButtons) {
- int ac = 1, na = 0;
- RECT urc;
- if(((POINT*)tmpl)->x != cpos.x) {
- for(cpos.x = ((POINT*)tmpl)->x, i = 0; cButtons[i]; i++) {
- cButtons[i]->Command(CMD_SELECT, (cpos.x == (i+ssOrg.x)) ? &ac : &na, w);
- }
- urc.left = cButtons[0]->rDims.left; urc.bottom = cButtons[0]->rDims.bottom;
- urc.top = cButtons[0]->rDims.top; urc.right = urc.left + d->ri->GetWidth(i+ssOrg.x) * (i-1);
- w->UpdateRect(&urc, false);
- }
- if(((POINT*)tmpl)->y != cpos.y) {
- for(cpos.y = ((POINT*)tmpl)->y, i = 0; rButtons[i]; i++) {
- rButtons[i]->Command(CMD_SELECT, (cpos.y == (i+ssOrg.y)) ? &ac : &na, w);
- }
- urc.left = rButtons[0]->rDims.left; urc.right = rButtons[0]->rDims.right;
- urc.top = rButtons[0]->rDims.top; urc.bottom = urc.top + d->ri->GetHeight(i+ssOrg.y) * (i-1);
- w->UpdateRect(&urc, false);
- }
- }
- else return false;
- return true;
- case CMD_CAN_CLOSE:
- HideTextCursor();
- if(is_modified == true) {
- is_modified=false;
- if(Undo.isEmpty(0L)) return true;
- i = YesNoCancelBox("The spreadsheet or a graph has been modified!\n\nDo you want to save it now?");
- if(i == 2) return false;
- else if(i == 1) return Command(CMD_SAVEDATAAS, tmpl, o);
- }
- return true;
- case CMD_MRK_DIRTY:
- return is_modified = true;
- case CMD_WRITE_GRAPHS:
- if (g && NumGraphs) WriteGraphXML((unsigned char**)tmpl, (long*)o);
- return true;
- case CMD_DROP_GRAPH:
- if(!tmpl) return false; if(o) o->FileHistory();
- if(g && NumGraphs) {
- if(g = (Graph**)realloc(g, (NumGraphs+2) * sizeof(Graph*)))
- g[NumGraphs++] = (Graph *)tmpl;
- else return false;
- }
- else {
- if(g = (Graph **)calloc(2, sizeof(Graph*))){
- g[0] = (Graph *)tmpl; NumGraphs = 1;
- }
- }
- for(i = j = 0; i < NumGraphs; i++) {
- if(g[i]) {
- g[j] = g[i]; g[j]->parent = this;
- g[j]->Command(CMD_SET_DATAOBJ, (void*)d, 0L);
- j++;
- }
- }
- NumGraphs = j; g[j-1]->DoPlot(0L);
- return true;
- case CMD_NEWGRAPH:
- if((g2 = new Graph(this, d, 0L, 0)) && g2->PropertyDlg() &&
- Command(CMD_DROP_GRAPH, g2, o))return Command(CMD_REDRAW, 0L, o);
- else if(g2) DeleteGO(g2);
- Undo.SetDisp(w);
- return false;
- case CMD_NEWPAGE:
- if((g2 = new Page(this, d)) &&
- Command(CMD_DROP_GRAPH, g2, o))return Command(CMD_REDRAW, 0L, o);
- else if(g2) DeleteGO(g2);
- Undo.SetDisp(w);
- return false;
- case CMD_DELGRAPH:
- if (g && NumGraphs) {
- for(i = 0; i < NumGraphs; i++) if(g[i]) DeleteGO(g[i]);
- free (g);
- }
- g = 0L; NumGraphs = 0; Undo.Flush();
- return true;
- case CMD_DELOBJ:
- i = j = 0;
- if(g && tmpl) for(; i < NumGraphs; i++) {
- if(g[i] == (Graph*) tmpl) {
- DeleteGO(g[i]);
- }
- else (g[j++] = g[i]);
- }
- if(g && j < i) g[j] = 0L; NumGraphs = j;
- return true;
- case CMD_SAVEDATA:
- if(o) o->MouseCursor(MC_WAIT, false);
- if(d->WriteData(0L)) {
- is_modified=false;
- if(o) o->MouseCursor(MC_ARROW, false);
- return true;
- }
- if(o) o->MouseCursor(MC_ARROW, true);
- 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 = (char*)memdup(Name, (int)strlen(Name)+1, 0);
- }
- else return false;
- }
- else return false;
- return true;
- case CMD_DROPFILE:
- if(!Command(CMD_CAN_CLOSE, 0L, o)) return false;
- if(IsRlpFile((char*)tmpl)) return OpenGraph(this, (char*)tmpl, 0L, false);
- else if(d->ReadData((char*)tmpl, 0L, FF_UNKNOWN)){
- if(filename) free(filename);
- filename = (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1, 0);
- return Command(CMD_SETSCROLL, 0L, w);
- }
- else ErrorBox("The selected file is not valid\nor not accessible!\n");
- return false;
- case CMD_OPEN:
- if(!Command(CMD_CAN_CLOSE, 0L, o)) return false;
- Undo.KillDisp(o); Undo.SetDisp(o);
- if((Name = OpenDataName(filename)) && Name[0]){
- if(o) o->FileHistory();
- if(IsRlpFile(Name)) return OpenGraph(this, Name, 0L, false);
- else if(d->ReadData(Name, 0L, FF_UNKNOWN)){
- if(filename) free(filename);
- filename = (char*)memdup(Name, (int)strlen(Name)+1, 0);
- return Command(CMD_SETSCROLL, 0L, w);
- }
- }
- return false;
- case CMD_ADDROWCOL:
- if(DoSpShSize(d, this)) DoPlot(o);
- return true;
- case CMD_COL_MOUSE:
- if(o && cButtons && rButtons && (mev = (MouseEvent*)tmpl) && mev->y > o->MenuHeight) {
- for(i = 0; cButtons[i]; i++){
- if(bDoColWidth) {
- o->MouseCursor(MC_COLWIDTH, false);
- }
- else if(mev->x > cButtons[i]->rDims.left && mev->x < cButtons[i]->rDims.right+2){
- if(mev->x > cButtons[i]->rDims.right-4) {
- switch(mev->Action) {
- case MOUSE_LBDOWN:
- CurrCol = i; line[0].x = line[1].x = mev->x;
- line[0].y = o->MenuHeight; line[1].y = currRC.bottom;
- d->Command(CMD_TOOLMODE, tmpl, o);
- o->MouseCursor(MC_COLWIDTH, false);
- return bDoColWidth = true;
- }
- o->MouseCursor(MC_COLWIDTH, false);
- }
- else o->MouseCursor(MC_ARROW, false);
- return false;
- }
- else o->MouseCursor(MC_ARROW, false);
- if(mev->Action == MOUSE_MOVE && bDoColWidth && (mev->StateFlags & 0x01)) {
- rc_line.left = line[0].x - 2; rc_line.right = line[1].x + 2;
- rc_line.top = line[0].y - 2; rc_line.bottom = line[1].y +2;
- o->UpdateRect(&rc_line, false);
- if(mev->x < (cButtons[CurrCol]->rDims.left +20))mev->x = cButtons[CurrCol]->rDims.left +20;
- k = mev->x - cButtons[CurrCol]->rDims.right;
- for(j = CurrCol; cButtons[j] && cButtons[j]->rDims.left < (currRC.right-k); j++) {
- cButtons[j]->rDims.right += k; cButtons[j]->rDims.left += j > CurrCol ? k : 0;
- cButtons[j]->DoPlot(o); o->UpdateRect(&cButtons[j]->rDims, false);
- cButtons[j]->rDims.right -= k; cButtons[j]->rDims.left -= j > CurrCol ? k : 0;
- }
- line[0].x = line[1].x = mev->x;
- line[0].y = o->MenuHeight; line[1].y = currRC.bottom;
- o->ShowLine(line, 2, 0x00a0a0a0);
- return true;
- }
- if(mev->Action == MOUSE_LBUP && bDoColWidth) {
- bDoColWidth = false;
- k = line[0].x - cButtons[CurrCol]->rDims.left;
- if(abs(k - cButtons[CurrCol]->rDims.right + cButtons[CurrCol]->rDims.left)>3) {
- rlp_strcpy(TmpTxt, 40, mkRangeRef(0, CurrCol + ssOrg.x, 0, CurrCol + ssOrg.x));
- d->ri = new RangeInfo(1, TmpTxt, d->ri);
- d->ri->SetWidth(k >=20 ? k : 20);
- }
- d->Command(CMD_REDRAW, 0L, o);
- return true;
- }
- else bDoColWidth = false;
- }
- }
- else o->MouseCursor(MC_ARROW, false);
- return false;
- case CMD_MOUSE_EVENT:
- if(!(mev =(MouseEvent*)tmpl)) return false;
- if(bDoColWidth)return Command(CMD_COL_MOUSE, tmpl, o);
- p1.x = mev->x; p1.y = mev->y;
- if(mev->y < o->MenuHeight) o->MouseCursor(MC_ARROW, false);
- else if(o && cButtons && rButtons) {
- if(mev->x < d->ri->GetFirstWidth() && mev->y < (o->MenuHeight + d->ri->GetHeight(-1)) && aButton) {
- aButton->Command(cmd, tmpl, o);
- }
- else if(mev->x < d->ri->GetFirstWidth() && rButtons) {
- if(!(d->mpos2dpos(&p1, &p2, false)))return false;
- p2.x -= ssOrg.x; p2.y -= ssOrg.y;
- if (p2.y < 0 || p2.y >= (d->r_disp-1)) return false;
- if(rButtons[p2.y]) rButtons[p2.y]->Command(cmd, tmpl, o);
- }
- else if(mev->y < (o->MenuHeight + d->ri->GetHeight(-1)) && cButtons) {
- if(!(d->mpos2dpos(&p1, &p2, false)))return false;
- p2.x -= ssOrg.x; p2.y -= ssOrg.y;
- if (p2.x < 0 || p2.x >= (d->c_disp-1)) return false;
- if(cButtons[p2.x]) cButtons[p2.x]->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_CSV: case CMD_PASTE_SSV:
- Undo.DataObject(this, w, d, 0L, 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_PASTE_XML: case CMD_DELROW: case CMD_INSROW:
- case CMD_INSCOL: case CMD_DELCOL: case CMD_UNDO:
- case CMD_SHPGUP: case CMD_SHPGDOWN: case CMD_HIDEMARK:
- bDoColWidth = false;
- return d->Command(cmd, tmpl, o);
- case CMD_REDRAW:
- Undo.SetDisp(w); d->Command(cmd, tmpl, o);
- return true;
- case CMD_MOUSECURSOR:
- if(o)o->MouseCursor(MC_ARROW, false);
- return true;
- case CMD_SETSCROLL:
- HideTextCursor(); if(!(o->ActualSize(&currRC)))return false;
- k = (currRC.bottom-currRC.top)/d->ri->GetHeight(-1);
- d->GetSize(&i, &j); o->MouseCursor(MC_WAIT, true);
- o->SetScroll(true, 0, j, k, ssOrg.y); k = (currRC.right-currRC.left)/d->ri->GetWidth(-1);
- o->SetScroll(false, 0, i, k, ssOrg.x); DoPlot(o);
- o->MouseCursor(MC_ARROW, true);
- return true;
- case CMD_PAGEUP: case CMD_PAGEDOWN:
- k = (currRC.bottom-currRC.top)/d->ri->GetHeight(-1);
- k = k > 3 ? k-2 : 1; p1.x = d->ri->GetFirstWidth() + 2;
- p1.y = d->ri->GetHeight(-1) + 2;
- if(CurrText){
- p1.x = CurrText->GetX()+2; p1.y = CurrText->GetY()+12;
- }
- d->GetSize(&i, &j);
- if(cmd == CMD_PAGEUP) ssOrg.y = ssOrg.y > k ? ssOrg.y-k : 0;
- else ssOrg.y = ssOrg.y < j-k*2 ? ssOrg.y+k : j > k ? j-k : 0;
- Command(CMD_SETSCROLL, tmpl, o);
- CurrText = 0L; d->Select(&p1);
- return true;
- 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:
- Undo.SetDisp(w);
- return true;
- case CMD_KILLFOCUS:
- return true;
- case CMD_TEXTSIZE:
- if(tmpl && *((int*)tmpl) != ssText.iSize) {
- Undo.ValInt(this, &ssText.iSize, UNDO_CONTINUE);
- ssText.iSize = o->un2iy(defs.GetSize(SIZE_CELLTEXT));
- }
- return true;
- case CMD_CONFIG:
- if(defs.PropertyDlg()) return Command(CMD_REDRAW, 0L, o);
- return false;
- case CMD_NONE:
- return true;
- case CMD_PRINT:
- return PrintData(o);
- }
- }
- return false;
-}
-
-bool
-SpreadWin::ShowGrid(int CellWidth, int CellHeight, int FirstWidth, POINT *cp)
-{
- int i, c, nr, nc, cx, cw, ac = 1, na = 0;
- RECT rc;
- char text[20];
- TextDEF ButtText;
- bool redim = bDoColWidth;
-
- w->HideMark();
- cpos.x = cp->x; cpos.y = cp->y;
- if(d->ri->GetHeight(-1) != CellHeight || d->ri->GetWidth(-1) != CellWidth || d->ri->GetFirstWidth() != FirstWidth) redim = true;
- if(redim){
- d->ri->SetHeight(CellHeight); d->ri->SetDefWidth(CellWidth); d->ri->SetFirstWidth(FirstWidth);
- 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 = d->c_disp; if(c < 40 || c > 200) d->c_disp = c = 40;
- cButtons = (ssButton **)calloc(c, sizeof(ssButton*));
- for(i = 0, cx = FirstWidth; i < (c-1); i++) {
- cw = d->ri->GetWidth(i+ssOrg.x);
- cButtons[i] = new ssButton(this, cx, w->MenuHeight, cw+1, CellHeight);
- cx += cw;
- }
- }
- else {
- for(i = 0, cx = FirstWidth; cButtons[i]; i++) {
- cw = d->ri->GetWidth(i+ssOrg.x);
- cButtons[i]->rDims.left = cx; cButtons[i]->rDims.right = cx + cw + 1;
- cx += cw;
- }
- }
- if(!rButtons) {
- c = d->r_disp; if(c < 60 || c > 300) d->c_disp = c = 60;
- 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);
- }
- d->GetSize(&nc, &nr);
- if(rButtons) for(i = 0; rButtons[i]; i++) {
-#ifdef USE_WIN_SECURE
- sprintf_s(text, 20, "%d", i+1+ssOrg.y);
-#else
- sprintf(text, "%d", i+1+ssOrg.y);
-#endif
- if(rButtons[i]) {
- rButtons[i]->Command(CMD_SETTEXTDEF, &ButtText, w);
- rButtons[i]->Command(CMD_SETTEXT, text, w);
- rButtons[i]->Command(CMD_SELECT, (cpos.y == (i+ssOrg.y)) ? &ac : &na, w);
- }
- }
- 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]->Command(CMD_SELECT, (cpos.x == (i+ssOrg.x)) ? &ac : &na, w);
- }
- }
- w->SetTextSpec(&ssText);
- if(aButton) aButton->DoPlot(w);
- return true;
-}
-
-void
-SpreadWin::MarkButtons(char *rng, POINT *cp)
-{
- int i, r, c, ncb, nrb, *r_idx, *c_idx;
- AccRange *mr;
-
- if(!rButtons || !cButtons) return;
- for(ncb = 0; cButtons[ncb]; ncb++); ncb--;
- for(nrb = 0; rButtons[nrb]; nrb++); nrb--;
- if(!nrb || !ncb || !(r_idx=(int*)calloc(nrb,sizeof(int))) || !(c_idx=(int*)calloc(ncb,sizeof(int)))) return;
- if(rng && rng[0] && (mr = new AccRange(rng)) && mr->GetFirst(&c, &r)) {
- mr->NextCol(&c);
- do {
- if((i = c - ssOrg.x) >= 0 && i < ncb) c_idx[i] = 1;
- }while(mr->NextCol(&c));
- mr->GetFirst(&c, &r); mr->NextRow(&r);
- do {
- if((i = r - ssOrg.y) >= 0 && i < nrb) r_idx[i] = 1;
- }while(mr->NextRow(&r));
- delete mr;
- }
- for(i = 0; i < ncb; i++) cButtons[i]->Command(CMD_SETSTYLE, &c_idx[i], w);
- for(i = 0; i < nrb; i++) rButtons[i]->Command(CMD_SETSTYLE, &r_idx[i], w);
- if(cp) {
- c_idx[0] = r_idx[0] = 0; c_idx[1] = r_idx[1] = 1;
- r = (cp->y - ssOrg.y); c = cp->x -ssOrg.x;
- for(i = 0; i < ncb; i++) cButtons[i]->Command(CMD_SELECT, c == i ? &c_idx[1] : &c_idx[0], w);
- for(i = 0; i < nrb; i++) rButtons[i]->Command(CMD_SELECT, r == i ? &r_idx[1] : &r_idx[0], w);
- }
- free(r_idx); free(c_idx);
-}
-
-bool
-SpreadWin::PrintData(anyOutput *o)
-{
- int i, j, k, l, pgw, pfw, pcw, pch, rpp, cpp, nc, nr, ix, iy, cpages;
- int row, col, width, height, ipad, mode;
- double scale;
- RECT rc, margin, margin_first;
- POINT pp_pos, ss_pos, grid[3];
- LineDEF Line1, Line2;
- TextDEF td, tdp;
- bool bContinue;
- time_t ti = time(0L);
- anyResult res;
-
- Line1.patlength = Line2.patlength = 1.0;
- Line1.color = Line2.color = 0x00808080; //gray 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;
- }
-#ifdef _WINDOWS
- scale = 1.0/_SQRT2;
-#else
- scale = 0.9;
-#endif
- Line2.width = Line1.width * 3.0;
- d->GetSize(&nc, &nr);
- if(!(o->StartPage())) return false;
- pfw = iround(o->hres * ((double)d->ri->GetFirstWidth())/w->hres * scale);
- pcw = iround(o->hres * ((double)d->ri->GetWidth(-1))/w->hres * scale);
- pch = iround((o->vres * ((double)d->ri->GetHeight(-1))/w->vres) * scale + 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;
- 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
- tdp.iSize = iround(o->hres/6.0);
- td.fSize = defs.GetSize(SIZE_CELLTEXT);
-#else
- tdp.iSize = iround(o->hres/7.5);
- td.fSize = defs.GetSize(SIZE_CELLTEXT)*.8;
-#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));
- pp_pos.x = margin.left; pp_pos.y = margin.top;
- ss_pos.x = 0; ss_pos.y = 0; cpages = 1;
- rpp = (rc.bottom - margin.top - margin.bottom - pch)/pch;
- mode = 0;
- if((nr * pch) < ((rc.bottom - rc.top - margin.top - margin.bottom)>>1)) mode = 1;
- do {
- k = (rc.right - margin.left - margin.right - pfw);
- for(i = pgw = 0; pgw < k && (i+ss_pos.x) < nc; i++ ){
- pgw += (pcw = iround(o->hres * ((double)d->ri->GetWidth(i+ss_pos.x))/w->hres * scale));
- if(i >=(nc-1)) break;
- }
- if(pgw < k) {
- cpp = i+1;
- if(!mode && !ss_pos.x && pgw < (k>>1)) mode = 2;
- }
- else {
- cpp = i-1; pgw -= pcw;
- }
- mode = mode;
- 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);
- grid[0].x = margin.left+pfw; grid[1].x = grid[0].x + pgw;
- 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(&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); grid[0].x = grid[1].x = pp_pos.x + pfw;
- for(i = 0, ix = pp_pos.x + pfw; i <= k; i++) { //column headers
- pcw = iround(o->hres * ((double)d->ri->GetWidth(i+ss_pos.x))/w->hres * scale);
- o->oSolidLine(grid); grid[0].x = grid[1].x = ix + pcw;
- if(i < k) o->oTextOut(ix + (pcw >>1), iy, Int2ColLabel(i+ss_pos.x, true), 0);
- ix += pcw;
- }
- 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);
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "%d", i+1+ss_pos.y);
-#else
- sprintf(TmpTxt, "%d", i+1+ss_pos.y);
-#endif
- if(i < l) o->oTextOut(ix, iy, TmpTxt, 0);
- }
- ipad = iround(o->hres/30.0);
- grid[0].x = margin.left+pfw + ipad;
- for(i = 0; i < k; i++, grid[0].x += pcw) { //spreadsheet data
- pcw = iround(o->hres * ((double)d->ri->GetWidth(i+ss_pos.x))/w->hres * scale);
- for (j = 0; j < l; j++) {
- row = j+ss_pos.y; col = i+ss_pos.x;
- if(row >= 0 && row < d->cRows && col >= 0 && col < d->cCols && d->etRows[row][col]) {
- d->etRows[row][col]->GetResult(&res, false);
- TranslateResult(&res);
- td.Align = TXA_HLEFT | TXA_VCENTER;
- ix = grid[0].x;
- switch (res.type) {
- case ET_VALUE:
- ix = ix + pcw - ( ipad<<1 );
- td.Align = TXA_HRIGHT | TXA_VCENTER;
- rlp_strcpy(TmpTxt, TMP_TXT_SIZE, res.text);
- fit_num_rect(o, pcw - ipad, TmpTxt);
- Int2Nat(TmpTxt); break;
- case ET_BOOL: case ET_DATE: case ET_TIME: case ET_DATETIME:
- ix = ix + pcw - ( ipad<<1 );
- td.Align = TXA_HRIGHT | TXA_VCENTER;
- case ET_TEXT: case ET_UNKNOWN:
- if(res.text&& strlen(res.text) < 40)
- rlp_strcpy(TmpTxt, TMP_TXT_SIZE, res.text[0] != '\'' ? res.text : res.text +1);
- else if(res.text) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "#SIZE");
- else TmpTxt[0] = 0;
- do {
- o->oGetTextExtent(TmpTxt, (int)strlen(TmpTxt), &width, &height);
- if(width > (pcw + iround(o->hres/20.0))) TmpTxt[strlen(TmpTxt)-1] = 0;
- }while(width > (pcw + ipad));
- break;
- case ET_ERROR:
- rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "#ERROR"); break;
- default:
- rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "#VALUE"); break;
- }
- iy = pp_pos.y + pch + (pch>>1) + j * pch;
- o->SetTextSpec(&td); o->oTextOut(ix, iy, TmpTxt, 0);
- grid[0].y = grid[1].y = iy+(pch>>1); grid[2].y = grid[1].y - pch;
- grid[0].x -= ipad; grid[1].x = grid[2].x = grid[0].x + pcw;
- o->SetLine(&Line1); o->oPolyline(grid, 3, 0L);
- grid[0].x += ipad;
- }
- }
- }
- //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 + pgw + iround(o->hres/3.5);
- iy = (l+2)*pch;
- if(mode == 2 && (margin.left + ix + pfw + pgw) < (rc.right-margin.right)) {
- margin.left += pfw + k*pcw + iround(o->hres/3.5);
- bContinue = true;
- }
- else if(mode == 1 && (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);
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "page %d", cpages++);
-#else
- sprintf(TmpTxt, "page %d", cpages++);
-#endif
- o->oTextOut(rc.right-margin.right, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
- tdp.Align = TXA_HCENTER | TXA_VCENTER; o->SetTextSpec(&tdp);
-#ifdef USE_WIN_SECURE
- ctime_s(TmpTxt, 50, &ti); TmpTxt[24] = 0;
-#else
- sprintf(TmpTxt, "%s", ctime(&ti)); TmpTxt[24] = 0;
-#endif
- o->oTextOut((rc.right-rc.left)>>1, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
- tdp.Align = TXA_HLEFT | TXA_VCENTER; o->SetTextSpec(&tdp);
- i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "RLPlot ");
- rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, 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);
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "page %d", cpages++);
-#else
- sprintf(TmpTxt, "page %d", cpages++);
-#endif
- o->oTextOut(rc.right-margin.right, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
- tdp.Align = TXA_HCENTER | TXA_VCENTER; o->SetTextSpec(&tdp);
-#ifdef USE_WIN_SECURE
- ctime_s(TmpTxt, 50, &ti); TmpTxt[24] = 0;
-#else
- sprintf(TmpTxt, "%s", ctime(&ti)); TmpTxt[24] = 0;
-#endif
- o->oTextOut((rc.right-rc.left)>>1, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
- tdp.Align = TXA_HLEFT | TXA_VCENTER; o->SetTextSpec(&tdp);
- i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "RLPlot ");
- rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, 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, newsize;
- int i;
-
- for(i = 0; i < NumGraphs; i++) if(g[i]) {
- if((pg = (unsigned char*)GraphToMem(g[i], &cb)) && cb) {
- newsize = *cbd + cb + 100;
- *ptr = (unsigned char*)realloc(*ptr, newsize);
- *cbd += rlp_strcpy((char*)(*ptr)+*cbd, 20, "<Graph><![CDATA[\n");
- memcpy(*ptr+ *cbd, pg, cb); *cbd += cb;
- *cbd += rlp_strcpy((char*)(*ptr)+*cbd, 20, "]]>\n</Graph>\n");
- if(pg) free(pg); pg = 0L; cb = 0;
- }
- }
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// This data object is a spreadsheet
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class SpreadData:public DataObj{
-typedef struct _pos_info {
- POINT ssOrg, currpos;
- void *CurrText;};
-
-public:
- SpreadData(GraphObj *par);
- ~SpreadData();
- bool Init(int nRows, int nCols);
- bool mpos2dpos(POINT *mp, POINT *dp, bool can_scroll);
- bool Select(POINT *p);
- void MarkRange(char *range, POINT *cp = 0L);
- void HideMark(bool cclp);
- bool WriteData(char *FileName);
- bool AddCols(int nCols);
- bool AddRows(int nRows);
- bool ChangeSize(int nCols, int nRows, bool bUndo);
- bool DeleteCols();
- bool InsertCols();
- bool DeleteRows();
- bool InsertRows();
- void DoPlot(anyOutput *o);
- bool DelRange();
- bool PasteRange(int cmd, char *txt);
- bool InitCopy(int cmd, void *tmpl, anyOutput *o);
- bool SavePos();
- 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, DWORD undo_flags = 0L);
- bool ReadTSV(char *file, unsigned char *buffer, int type);
- bool MemList(unsigned char **ptr, int type);
-
-private:
- int CellHeight, CellWidth, FirstWidth, mrk_offs;
- RECT cp_src_rec; //bounding rectangle for copy range
- bool bActive, new_mark, bCopyCut, bUpdate, isRowMark, isColMark;
- POINT currpos, currpos2;
- anyOutput *w;
- SpreadWin *Disp;
- GraphObj *g_parent;
- EditText *et_racc;
- char *m_range, *c_range; //mark and copy ranges
- char *err_msg, *last_err; //error message
- char *rlw_file; //use this name for save
- _pos_info pos_info; //save position settings
-};
-
-SpreadData::SpreadData(GraphObj *par)
-{
- Disp = 0L; m_range = 0L; c_range = 0L; w = 0L; err_msg=last_err=rlw_file = 0L;
- g_parent = par; CellWidth = 76; CellHeight = 19; FirstWidth = 32;
- et_racc = 0L; currpos.x = currpos.y = mrk_offs = 0;
- r_disp = 60; c_disp = 40;
- bActive = bCopyCut = bUpdate = isRowMark = isColMark = false;
- 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, false);
- }
- pos_info.currpos.x = currpos.x; pos_info.currpos.y = currpos.y;
- pos_info.CurrText = CurrText;
-}
-
-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;
- if(rlw_file) free(rlw_file); rlw_file = 0L;
-}
-
-bool
-SpreadData::Init(int nRows, int nCols)
-{
- int i, j;
- RECT rc;
- RangeInfo *o_ri;
-
- cRows = nRows; cCols = nCols; currpos.x = currpos.y = 0;
- new_mark = bCopyCut = false; if(w && m_range) HideMark(true);
- while(ri->Type()) {
- o_ri = ri; ri = ri->Next(); delete(o_ri);
- }
- if(!Disp) {
- Disp = new SpreadWin(g_parent, this);
- w = Disp->w;
- if(w) {
- CellWidth = w->un2ix(defs.GetSize(SIZE_CELLWIDTH));
-#ifdef _WINDOWS
- CellHeight = w->un2iy(defs.GetSize(SIZE_CELLTEXT)/defs.ss_txt) + 2;
-#else
- CellHeight = w->un2iy(defs.GetSize(SIZE_CELLTEXT)/(defs.ss_txt *0.7)) + 2;
-#endif
- if(CellHeight < 12)CellHeight = 19; if(CellWidth < 40)CellWidth = 76;
- FirstWidth = 32; w->GetSize(&rc);
- r_disp = (rc.bottom-rc.top)/CellHeight;
- c_disp = (rc.right-rc.left)/CellWidth+1;
- }
- else return false;
- pos_info.ssOrg.x = Disp->ssOrg.x; pos_info.ssOrg.y = Disp->ssOrg.y;
- pos_info.CurrText = CurrText;
- }
- if(etRows)FlushData();
- etRows = (EditText ***)calloc (cRows, sizeof(EditText **));
- if(etRows) for(i = 0; i < cRows; i++) {
- etRows[i] = (EditText **)calloc(cCols, sizeof(EditText *));
- if(etRows[i]) for(j = 0; j < cCols; j++) {
-#ifdef _DEBUG
- char text[20];
-#ifdef USE_WIN_SECURE
- sprintf_s (text, 20, "%.2f", i*10.0 + j);
-#else
- sprintf (text, "%.2f", i*10.0 + j);
-#endif
- etRows[i][j] = new EditText(this, text, i, j);
-#else
- etRows[i][j] = new EditText(this, 0L, i, j);
-#endif
- }
- }
- if (LoadFile) {
- rlp_strcpy(TmpTxt, TMP_TXT_SIZE, LoadFile); //we will reenter by recursion !
- free(LoadFile);
- LoadFile = 0L;
- Disp->Command(CMD_DROPFILE, TmpTxt, w);
- }
- else DoPlot(w);
- return true;
-}
-
-bool
-SpreadData::mpos2dpos(POINT *mp, POINT *dp, bool can_scroll)
-{
- int mx;
-
- CurrGO = 0L;
- dp->y = (mp->y - w->MenuHeight - CellHeight)/CellHeight + Disp->ssOrg.y;
- dp->x = Disp->ssOrg.x;
- for(mx = mp->x - ri->GetFirstWidth() - ri->GetWidth(dp->x); mx > 0; dp->x++, mx -= ri->GetWidth(dp->x));
- if(can_scroll) {
- if(dp->x < cCols && mp->x < (ri->GetFirstWidth()+10) && mp->x > ri->GetFirstWidth() && Disp->ssOrg.x >0) {
- Disp->ssOrg.x -= 1;
- if(CurrText) CurrText->Update(2, w, mp); CurrText = 0L;
- Disp->Command(CMD_SETSCROLL, 0L, w);
- }
- if(mp->y < (w->MenuHeight + CellHeight+9) && 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);
- }
- 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);
- }
- 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); CurrText = 0L;
- }
- }
- 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);
- Disp->Command(CMD_CURRPOS, &currpos, w);
- if(CurrText->isFormula() && CurrText->hasMark()) et_racc = CurrText;
- return true;
- }
- if(!(mpos2dpos(p, &currpos, false)))return false;
- 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);
- }
- Disp->Command(CMD_CURRPOS, &currpos, w);
- return true;
- }
- }
- if(CurrText) CurrText->Update(2, w, p); CurrText = 0L;
- return false;
-}
-
-void
-SpreadData::MarkRange(char *range, POINT *cp)
-{
- AccRange *nr, *oldr;
- int r, c, cb;
-
- 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) && r < cRows && c >= Disp->ssOrg.x
- && c < (c_disp + Disp->ssOrg.x) && c < cCols && !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) && r < cRows && c < cCols)
- etRows[r][c]->Mark(w, etRows[r][c] != CurrText ? 2 : 3);
- }
- }
- if(range && (m_range = (char*)realloc(m_range, cb = ((int)strlen(range)+6)))) rlp_strcpy(m_range, cb, range);
- else if (m_range) m_range[0] = 0;
- if(oldr) delete(oldr); if(nr) delete(nr);
- new_mark = true; Disp->MarkButtons(m_range, cp);
-}
-
-void
-SpreadData::HideMark(bool cclp)
-{
- if(cclp && c_range && c_range != m_range){
- free(c_range); c_range = 0L;
- }
- if(m_range){
- free(m_range); m_range = 0L;
- DoPlot(w);
- }
- if(cclp) EmptyClip(); new_mark = false;
- Disp->MarkButtons(m_range, 0L);
-}
-
-bool
-SpreadData::WriteData(char *FileName)
-{
- FILE *File;
- int i, j;
- unsigned char *buff = 0L;
- anyResult res;
- bool bErr = false;
-
- if(!cRows || !cCols || !etRows) return false;
- if(!FileName) FileName = rlw_file;
- if(FileName && FileName[0]) BackupFile(FileName);
- else return false;
-#ifdef USE_WIN_SECURE
- if(fopen_s(&File, FileName, "w")) {
-#else
- if(!(File = fopen(FileName, "w"))) {
-#endif
- ErrorBox("An error occured during write,\n\nplease try again!");
- return false;
- }
- HideMark(true);
- i = (int)strlen(FileName);
- //test for xml extension
- if(!strcmp(".xml", FileName+i-4) || !strcmp(".XML", FileName+i-4)) {
- MemList(&buff, FF_XML);
- if(buff){
- if(fprintf(File, "%s", buff) <= 0) bErr = true;
- 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){
- if(fprintf(File, "%s", buff) <= 0) bErr = true;
- 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){
- if(rlw_file != FileName) {
- if(rlw_file) free(rlw_file);
- rlw_file = (char*)memdup(FileName, (int)strlen(FileName)+1, 0);
- }
- if(fprintf(File, "%s", buff) <= 0) bErr = true;
- free(buff); fclose(File);
- return true;
- }
- return false;
- }
- //test for slk extension
- if(!strcmp(".slk", FileName+i-4) || !strcmp(".SLK", FileName+i-4)) {
- MemList(&buff, FF_SYLK);
- if(buff){
- if(fprintf(File, "%s", buff) <= 0) bErr = true;
- 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]->GetResult(&res, false); TranslateResult(&res);
- switch(res.type) {
- case ET_TEXT:
- fprintf(File, "\"%s\"", res.text);
- break;
- case ET_VALUE: case ET_DATE: case ET_TIME:
- case ET_DATETIME: case ET_BOOL:
- fprintf(File, "%s", res.text);
- break;
- }
- }
- if(j < (cCols-1)) fprintf(File, ", ");
- }
- if(fprintf(File, "\n") <= 0) bErr = true;
- }
- fclose(File);
- if(bErr) ErrorBox("An error occured during write,\n\nplease try again!");
- return true;
-}
-
-bool
-SpreadData::ReadData(char *FileName, unsigned char *buffer, int type)
-{
- int i, j;
- char ItemText[20];
- bool success;
-
- if(FileName) { //read disk file
- if(!Disp->Command(CMD_CAN_CLOSE, 0L, 0L))return false;
- 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)){
- Disp->Command(CMD_DELGRAPH, 0L, w);
- if(ReadXML(FileName, buffer, type, 0L)){
- if(0 == strcmp(".rlw", FileName+strlen(FileName)-4) ||
- 0 == strcmp(".RLW", FileName+strlen(FileName)-4)) {
- if(rlw_file) free(rlw_file);
- rlw_file = (char*)memdup(FileName, (int)strlen(FileName)+1, 0);
- }
- return true;
- }
- return false;
- }
- if(0 == strcmp(".tsv", FileName+strlen(FileName)-4) ||
- 0 == strcmp(".TSV", FileName+strlen(FileName)-4)){
- return ReadTSV(FileName, buffer, type);
- }
- if(!(Cache = new ReadCache())) return false;
- if(! Cache->Open(FileName)) {
- delete Cache;
- i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Error open data file\n\"");
- i += rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, FileName);
- i += rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, "\"\n");
- 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, 0L);
- 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;
- 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]) goto ReadError;
- if(ItemText[0] == '"') {
- rmquot(ItemText);
- etRows[i][j]->SetText(ItemText);
- etRows[i][j]->Update(20, 0L, 0L);
- }
- else if(ItemText[0]){
- etRows[i][j]->SetText(ItemText);
- etRows[i][j]->Update(10, 0L, 0L);
- }
- else etRows[i][j]->SetText("");
- j++;
- }
- if(!success && !Cache->IsEOF()) {i++; j = 0;} //eol
- }while (ItemText[0] || !Cache->IsEOF()); //eof
- Cache->Close(); delete Cache; Cache = 0L;
- 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;
-
- if (nCols <= cCols || !etRows || !etRows[0] || !etRows[0][cCols-1]) return false;
- for(i = 0; i < cRows; i++) {
- if(NewRow = (EditText **)realloc(etRows[i], nCols * sizeof(EditText*))){
- for(j = cCols; j < nCols; j++) {
- NewRow[j] = new EditText(this, 0L, i, j);
- }
- etRows[i] = NewRow;
- }
- else return false; //memory allocation error
- }
- cCols = nCols;
- return true;
-}
-
-bool
-SpreadData::AddRows(int nRows)
-{
- int i, j;
- EditText ***NewRows;
-
- if (nRows <= cRows || !etRows || !etRows[cRows-1] || !etRows[cRows-1][0] ) 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, 0L, i, j);
- }
- else { //memory allocation error
- cRows = i-1;
- return false;
- }
- }
- 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(c_range){
- free(c_range); c_range = 0L; EmptyClip();
- }
- if(bUndo) Undo.DataObject(Disp, w, this, 0L, 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) {
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "%d00", nRows);
-#else
- sprintf(TmpTxt, "%d00", nRows);
-#endif
- w->oGetTextExtent(TmpTxt, 0, &i, &j);
- if(i > FirstWidth) FirstWidth = i;
- Disp->Command(CMD_SETSCROLL, 0L, w);
- }
- return RetVal;
-}
-
-bool
-SpreadData::DeleteCols()
-{
- int i, j, r0, c0, c1, c2, cn, dc, nc;
- RECT rc;
- lfPOINT *cs;
-
- AccRange * ar;
- if(!isColMark || !m_range || !m_range[0]){
- InfoBox("No columns selected!");
- return false;
- }
- if(c_range){
- free(c_range); c_range = 0L; EmptyClip();
- }
- Undo.DataObject(Disp, w, this, 0L, 0L);
- Undo.String(0L, &m_range, UNDO_CONTINUE);
- if(!(ar = new AccRange(m_range))) return false;
- ar->BoundRec(&rc);
- if(!(cs = (lfPOINT*)malloc((rc.right-rc.left+2)*sizeof(lfPOINT)))) {
- delete ar; return false;
- }
- if(!(ar->GetFirst(&c0, &r0))) {
- free(cs); delete ar; return false;
- }
- ar->NextCol(&c1); cn = c1; nc = 0;
- do {
- for(c0 = c1 = c2 = cn; ar->NextCol(&c2); ) {
- if(c2 > c1+1 || c2 < c0) break;
- c1 = c2;
- }
- dc = c1-c0+1; cn = c2;
- cs[nc].fx = c0; cs[nc].fy = c1; nc++;
- }while(c2!=c1);
- SortFpArray(nc, cs); nc--;
- do {
- c0 = (int)cs[nc].fx; c1 = (int)cs[nc].fy; dc = c1-c0+1;
- for(i = 0; i < cRows; i++) {
- for(j = c0+dc; j <cCols; j++) {
- if(etRows && etRows[i] && etRows[i][j] && etRows[i][j-dc]) {
- switch(etRows[i][j]->type) {
- default:
- etRows[i][j-dc]->SetText(etRows[i][j]->text);
- break;
- case ET_VALUE:
- etRows[i][j-dc]->SetText(etRows[i][j]->text);
- etRows[i][j-dc]->Value = etRows[i][j]->Value;
- etRows[i][j-dc]->type = ET_VALUE;
- break;
- case ET_FORMULA:
- MoveFormula(this, etRows[i][j]->text, TmpTxt, TMP_TXT_SIZE, -dc, 0, -1, c0);
- etRows[i][j-dc]->SetText(TmpTxt); etRows[i][j]->type = ET_FORMULA;
- break;
- }
- }
- }
- }
- for(i = 0; i < cRows; i++) {
- if(etRows[i]){
- for(j = cCols-dc; j < cCols; j++) if(etRows[i][j]) {
- delete(etRows[i][j]);
- etRows[i][j] = 0L;
- }
- }
- }
- cCols -= dc;
- MoveFormula(this, m_range, TmpTxt, TMP_TXT_SIZE, -dc, 0, -1, c0+1); free(m_range);
- m_range = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0); nc--;
- for(i = 0; i < c0; i++) for(j = 0; j < c0; j++) {
- if(etRows && etRows[i] && etRows[i][j] && etRows[i][j]->type == ET_FORMULA) {
- MoveFormula(this, etRows[i][j]->text, TmpTxt, TMP_TXT_SIZE, -dc, 0, -1, c0);
- etRows[i][j]->SetText(TmpTxt); etRows[i][j]->type = ET_FORMULA;
- }
- }
- }while(nc >= 0);
- delete ar;
- Disp->Command(CMD_SETSCROLL, 0L, w); Disp->Command(CMD_MRK_DIRTY, 0L, w);
- return true;
-}
-
-bool
-SpreadData::InsertCols()
-{
- int i, j, r0, c0, c1, c2, cn, dc, nc;
- RECT rc;
- lfPOINT *cs;
-
- AccRange * ar;
- if(!isColMark || !m_range || !m_range[0]){
- InfoBox("No columns selected!");
- return false;
- }
- if(c_range){
- free(c_range); c_range = 0L; EmptyClip();
- }
- Undo.DataObject(Disp, w, this, 0L, 0L);
- Undo.String(0L, &m_range, UNDO_CONTINUE);
- if(!(ar = new AccRange(m_range))) return false;
- ar->BoundRec(&rc);
- if(!(cs = (lfPOINT*)malloc((rc.right-rc.left+2)*sizeof(lfPOINT)))) {
- delete ar; return false;
- }
- if(!(ar->GetFirst(&c0, &r0))) {
- free(cs); delete ar; return false;
- }
- ar->NextCol(&c1); cn = c1; nc = 0;
- do {
- for(c0 = c1 = c2 = cn; ar->NextCol(&c2); ) {
- if(c2 > c1+1 || c2 < c0) break;
- c1 = c2;
- }
- dc = c1-c0+1; cn = c2;
- cs[nc].fx = c0; cs[nc].fy = c1; nc++;
- }while(c2!=c1);
- SortFpArray(nc, cs); nc--;
- do {
- c0 = (int)cs[nc].fx; c1 = (int)cs[nc].fy; dc = c1-c0+1;
- if(AddCols(cCols + dc)) for(i = 0; i < cRows; i++) {
- for(j = cCols-1; j >= c0+dc; j--) {
- if(etRows && etRows[i] && etRows[i][j] && etRows[i][j-dc]) {
- switch(etRows[i][j-dc]->type) {
- default:
- etRows[i][j]->SetText(etRows[i][j-dc]->text);
- break;
- case ET_VALUE:
- etRows[i][j]->SetText(etRows[i][j-dc]->text);
- etRows[i][j]->Value = etRows[i][j-dc]->Value;
- etRows[i][j]->type = ET_VALUE;
- break;
- case ET_FORMULA:
- MoveFormula(this, etRows[i][j-dc]->text, TmpTxt, TMP_TXT_SIZE, dc, 0, -1, c0);
- etRows[i][j]->SetText(TmpTxt); etRows[i][j]->type = ET_FORMULA;
- break;
- }
- etRows[i][j-dc]->SetText("");
- }
- }
- }
- MoveFormula(this, m_range, TmpTxt, TMP_TXT_SIZE, dc, 0, -1, c0); free(m_range);
- m_range = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0); nc--;
- for(i = 0; i < c0; i++) for(j = 0; j < c0; j++) {
- if(etRows && etRows[i] && etRows[i][j] && etRows[i][j]->type == ET_FORMULA) {
- MoveFormula(this, etRows[i][j]->text, TmpTxt, TMP_TXT_SIZE, dc, 0, -1, c0);
- etRows[i][j]->SetText(TmpTxt); etRows[i][j]->type = ET_FORMULA;
- }
- }
- }while(nc >= 0);
- delete ar;
- Disp->Command(CMD_SETSCROLL, 0L, w); Disp->Command(CMD_MRK_DIRTY, 0L, w);
- return true;
-}
-
-bool
-SpreadData::DeleteRows()
-{
- int i, j, r0, c0, r1, r2, rn, dr, nr;
- AccRange * ar;
- RECT rc;
- lfPOINT *rs;
-
- if(!isRowMark || !m_range || !m_range[0]){
- InfoBox("No rows selected!");
- return false;
- }
- if(c_range){
- free(c_range); c_range = 0L; EmptyClip();
- }
- Undo.DataObject(Disp, w, this, 0L, 0L);
- Undo.String(0L, &m_range, UNDO_CONTINUE);
- if(!(ar = new AccRange(m_range))) return false;
- ar->BoundRec(&rc);
- if(!(rs = (lfPOINT*)malloc((rc.bottom-rc.top+2)*sizeof(lfPOINT)))) {
- delete ar; return false;
- }
- if(!(ar->GetFirst(&c0, &r0))) {
- free(rs); delete ar; return false;
- }
- ar->NextRow(&r1); rn = r1; nr = 0;
- do {
- for(r0 = r1 = r2 = rn;ar->NextRow(&r2); ) {
- if(r2 > r1+1 || r2 < r0) break;
- r1 = r2;
- }
- dr = r1-r0+1; rn = r2;
- rs[nr].fx = r0; rs[nr].fy = r1; nr++;
- }while(r2!=r1);
- SortFpArray(nr, rs); nr--;
- do {
- r0 = (int)rs[nr].fx; r1 = (int)rs[nr].fy; dr = r1-r0+1;
- for(i = r0+dr; i < cRows; i++) {
- for(j = 0; j < cCols; j++) {
- if(etRows && etRows[i-dr] && etRows[i-dr][j] && etRows[i] && etRows[i][j]) {
- switch(etRows[i][j]->type) {
- default:
- etRows[i-dr][j]->SetText(etRows[i][j]->text);
- break;
- case ET_VALUE:
- etRows[i-dr][j]->SetText(etRows[i][j]->text);
- etRows[i-dr][j]->Value = etRows[i][j]->Value;
- etRows[i-dr][j]->type = ET_VALUE;
- break;
- case ET_FORMULA:
- MoveFormula(this, etRows[i][j]->text, TmpTxt, TMP_TXT_SIZE, 0, -dr, r0, -1);
- etRows[i-dr][j]->SetText(TmpTxt); etRows[i-dr][j]->type = ET_FORMULA;
- break;
- }
- }
- }
- }
- for(i = cRows-1; i >= cRows-dr; i--) {
- if(etRows[i]){
- for(j = 0; j < cCols; j++) if(etRows[i][j]) delete(etRows[i][j]);
- free(etRows[i]);
- }
- }
- cRows -= dr;
- MoveFormula(this, m_range, TmpTxt, TMP_TXT_SIZE, 0, -dr, r0+1, -1); free(m_range);
- m_range = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0); nr--;
- for(i = 0; i < r0; i++) for(j = 0; j < cCols; j++) {
- if(etRows && etRows[i] && etRows[i][j] && etRows[i][j]->type == ET_FORMULA) {
- MoveFormula(this, etRows[i][j]->text, TmpTxt, TMP_TXT_SIZE, 0, -dr, r0, -1);
- etRows[i][j]->SetText(TmpTxt); etRows[i][j]->type = ET_FORMULA;
- }
- }
- }while(nr >= 0);
- delete ar;
- if(w) {
- Disp->Command(CMD_SETSCROLL, 0L, w); Disp->Command(CMD_MRK_DIRTY, 0L, w);
- }
- return true;
-}
-
-bool
-SpreadData::InsertRows()
-{
- int i, j, r0, c0, r1, r2, rn, dr, nr;
- AccRange * ar;
- RECT rc;
- lfPOINT *rs;
-
- if(!isRowMark || !m_range || !m_range[0]){
- InfoBox("No rows selected!");
- return false;
- }
- if(c_range){
- free(c_range); c_range = 0L; EmptyClip();
- }
- Undo.DataObject(Disp, w, this, 0L, 0L);
- Undo.String(0L, &m_range, UNDO_CONTINUE);
- if(!(ar = new AccRange(m_range))) return false;
- ar->BoundRec(&rc);
- if(!(rs = (lfPOINT*)malloc((rc.bottom-rc.top+2)*sizeof(lfPOINT)))) {
- delete ar; return false;
- }
- if(!(ar->GetFirst(&c0, &r0))) {
- free(rs); delete ar; return false;
- }
- ar->NextRow(&r1); rn = r1; nr = 0;
- do {
- for(r0 = r1 = r2 = rn;ar->NextRow(&r2); ) {
- if(r2 > r1+1 || r2 < r0) break;
- r1 = r2;
- }
- dr = r1-r0+1; rn = r2;
- rs[nr].fx = r0; rs[nr].fy = r1; nr++;
- }while(r2!=r1);
- SortFpArray(nr, rs); nr--;
- do {
- r0 = (int)rs[nr].fx; r1 = (int)rs[nr].fy; dr = r1-r0+1;
- if(AddRows(cRows + dr)) for(i = cRows-1; i >= r0+dr; i--) {
- for(j = 0; j < cCols; j++) {
- if(etRows && etRows[i-dr] && etRows[i-dr][j] && etRows[i] && etRows[i][j]) {
- switch(etRows[i-dr][j]->type) {
- default:
- etRows[i][j]->SetText(etRows[i-dr][j]->text);
- break;
- case ET_VALUE:
- etRows[i][j]->SetText(etRows[i-dr][j]->text);
- etRows[i][j]->Value = etRows[i-dr][j]->Value;
- etRows[i][j]->type = ET_VALUE;
- break;
- case ET_FORMULA:
- MoveFormula(this, etRows[i-dr][j]->text, TmpTxt, TMP_TXT_SIZE, 0, dr, r0, -1);
- etRows[i][j]->SetText(TmpTxt); etRows[i][j]->type = ET_FORMULA;
- break;
- }
- etRows[i-dr][j]->SetText("");
- }
- }
- }
- MoveFormula(this, m_range, TmpTxt, TMP_TXT_SIZE, 0, dr, r0, -1); free(m_range);
- m_range = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0); nr--;
- for(i = 0; i < r0; i++) for(j = 0; j < cCols; j++) {
- if(etRows && etRows[i] && etRows[i][j] && etRows[i][j]->type == ET_FORMULA) {
- MoveFormula(this, etRows[i][j]->text, TmpTxt, TMP_TXT_SIZE, 0, dr, r0, -1);
- etRows[i][j]->SetText(TmpTxt); etRows[i][j]->type = ET_FORMULA;
- }
- }
- }while(nr >= 0);
- delete ar;
- if(w) {
-#ifdef USE_WIN_SECURE
- sprintf_s(TmpTxt, TMP_TXT_SIZE, "%d00", cRows);
-#else
- sprintf(TmpTxt, "%d00", cRows);
-#endif
- w->oGetTextExtent(TmpTxt, 0, &i, &j);
- if(i > FirstWidth) FirstWidth = i;
- Disp->Command(CMD_SETSCROLL, 0L, w); Disp->Command(CMD_MRK_DIRTY, 0L, w);
- }
- return true;
-}
-
-void
-SpreadData::DoPlot(anyOutput *o)
-{
- RECT rc;
- int i, j, r, c;
- AccRange *ar;
-
- if(!w || !Disp) return;
- w->Erase(0x00e8e8e8L); if(!(w->ActualSize(&rc)))return;
- w->SetTextSpec(&ssText); et_racc = 0L;
- r_disp = (rc.bottom-rc.top)/CellHeight;
- for(c = Disp->ssOrg.x, j=rc.left, c_disp = 1; c < cCols && j <= (rc.right-rc.left) && c_disp < cCols; c++, c_disp++) {
- j += ri->GetWidth(c);
- }
- if(j >= (rc.right-rc.left))c_disp--;
- Disp->ShowGrid(CellWidth, CellHeight, FirstWidth, &currpos);
- rc.top = w->MenuHeight; rc.bottom = rc.top + CellHeight;
- LockData(false, false);
- for(i = 0; i <= (cRows - Disp->ssOrg.y) && i <= r_disp; i++) {
- rc.left = ri->GetFirstWidth(); rc.right = rc.left + ri->GetWidth(Disp->ssOrg.x);
- rc.top += CellHeight; rc.bottom += CellHeight;
- for(j = 0; j <= (cCols - Disp->ssOrg.x) && j <= c_disp; 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]->Update(2, 0L, 0L);
- etRows[r][c]->Redraw(w, false);
- }
- rc.left += ri->GetWidth(Disp->ssOrg.x+j);
- rc.right += ri->GetWidth(Disp->ssOrg.x+j+1);
- }
- }
- if(bUpdate) {
- for(i = 0; i <= (cRows - Disp->ssOrg.y) && i <= r_disp; i++) {
- for(j = 0; j <= (cCols - Disp->ssOrg.x) && j <= c_disp; 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]->Redraw(w, false);
- }
- }
- }
- }
- if(CurrText && CurrText->row >= Disp->ssOrg.y && CurrText->row < (Disp->ssOrg.y + r_disp)
- && CurrText->col >= Disp->ssOrg.x && CurrText->col < (Disp->ssOrg.x +c_disp))
- CurrText->Update(1, w, 0L);
- bUpdate = false;
- 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
- && r < cRows && c < cCols
- && c < (c_disp + Disp->ssOrg.x) && etRows[r] && etRows[r][c])
- etRows[r][c]->Mark(w, etRows[r][c] != CurrText ? 2 : 3);
- }
- delete (ar);
- }
- LockData(false, false);
- if(c_range) InitCopy(0, 0L, w); //move animated rectangle
- if(!(w->ActualSize(&rc))) return;
- rc.bottom += CellHeight; w->UpdateRect(&rc, false);
- if(err_msg && (!last_err || strcmp(err_msg,last_err))) {
- ErrorBox(last_err = err_msg);
- }
-}
-
-bool
-SpreadData::DelRange()
-{
- AccRange *ar;
- int r, c;
- RECT rec;
-
- if(m_range && (ar = new AccRange(m_range)) && ar->GetFirst(&c, &r)) {
- ar->BoundRec(&rec);
- Undo.DataObject(Disp, w, this, &rec, 0L);
- while(ar->GetNext(&c, &r)) {
- if(r >= 0 && r < cRows && c >= 0 && c < cCols){
- if(etRows[r][c] && etRows[r][c]->text) etRows[r][c]->SetText("");
- }
- }
- delete (ar); HideTextCursor();
- }
- HideMark(false);
- if(CurrText) CurrText->Update(1, w, 0L);
- bCopyCut = false;
- return true;
-}
-
-bool
-SpreadData::PasteRange(int cmd, char *txt)
-{
- AccRange *cr;
- int i, r, c;
- RECT mrk_range;
-
- if(new_mark && m_range && (cr = new AccRange(m_range)) && cr->GetFirst(&c, &r)) {
- cr->BoundRec(&mrk_range);
- for(i = 0 ; cr->GetNext(&c, &r); i++) 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_SSV: ReadTSV(0L, (unsigned char*)txt, FF_SSV); break;
- case CMD_PASTE_XML: ReadXML(0L, (unsigned char*)txt, FF_XML, i ? UNDO_CONTINUE : 0L); 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_SSV:
- return ReadTSV(0L, (unsigned char*)txt, FF_SSV);
- case CMD_PASTE_XML:
- return ReadXML(0L, (unsigned char*)txt, FF_XML, 0L);
- case CMD_PASTE_CSV:
- return ReadData(0L, (unsigned char*)txt, FF_CSV);
- }
- return bCopyCut = false;
-}
-
-bool
-SpreadData::InitCopy(int cmd, void *tmpl, anyOutput *o)
-{
- int r, c;
- AccRange *ar;
- RECT rc_band, rcCopy;
- bool bRet = false;
-
- rcCopy.left = rcCopy.top = 0;
- rcCopy.bottom = cRows-1; rcCopy.right = cCols-1;
- if(cmd) {
- bCopyCut = (cmd == CMD_CUT);
- new_mark = false;
- if(m_range && m_range[0]) {
- if(c_range) free(c_range);
- c_range = (char*)memdup(m_range, (int)strlen(m_range)+1, 0);
- if(c_range && (ar = new AccRange(c_range))) {
- ar->BoundRec(&rcCopy);
- delete ar; bRet = true;;
- }
- }
- else if (CurrText) {
- if(CurrText->hasMark()) return CurrText->Command(CMD_COPY, o, 0L);
- else {
- if(m_range = (char*)realloc(m_range, 40*sizeof(char)))
- rlp_strcpy(m_range, 40, mkRangeRef(currpos.y, currpos.x, currpos.y, currpos.x));
- DoPlot(o);
- return InitCopy(cmd, tmpl, o);
- }
- }
- }
- if(bRet || !cmd) { //calculate animated mark
- if(c_range && (ar = new AccRange(c_range))) {
- ar->BoundRec(&rcCopy); delete ar;
- }
- 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(r >= cRows) r = cRows-1; if(c >= cCols) c = cRows -1;
- if(etRows[r][c]){
- rc_band.right = etRows[r][c]->GetX()+ri->GetWidth(c);
- rc_band.bottom = etRows[r][c]->GetY()+CellHeight;
- if(rc_band.left >= rc_band.right) rc_band.right = rc_band.left + CellWidth;
- if(rc_band.top >= rc_band.bottom) rc_band.bottom = rc_band.top + CellHeight;
- ShowCopyMark(o, &rc_band, 1);
- }
- }
- return bRet;
-}
-
-bool
-SpreadData::SavePos()
-{
- bool bRet = false;
-
- if(pos_info.currpos.x != currpos.x || pos_info.currpos.y != pos_info.currpos.y
- || CurrText != pos_info.CurrText) {
- Undo.Point(Disp, &currpos, w, UNDO_CONTINUE);
- Undo.VoidPtr(Disp, (void**)&CurrText, 0L, 0L, UNDO_CONTINUE);
- }
- if(pos_info.ssOrg.x != Disp->ssOrg.x || pos_info.ssOrg.y != Disp->ssOrg.y) {
- Swap(pos_info.ssOrg.x, Disp->ssOrg.x ); Swap(pos_info.ssOrg.y, Disp->ssOrg.y );
- Undo.Point(Disp, &Disp->ssOrg, w, UNDO_CONTINUE);
- Swap(pos_info.ssOrg.x, Disp->ssOrg.x ); Swap(pos_info.ssOrg.y, Disp->ssOrg.y );
- }
- pos_info.currpos.x = currpos.x; pos_info.currpos.y = currpos.y;
- pos_info.ssOrg.x = Disp->ssOrg.x; pos_info.ssOrg.y = Disp->ssOrg.y;
- pos_info.CurrText = CurrText;
- return bRet;
-}
-
-bool
-SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
-{
- int i;
- static int move_cr = CMD_CURRDOWN;
- MouseEvent *mev;
- POINT p, cp;
- RECT rc;
-
- 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 || p.y < (w->MenuHeight+CellHeight)) {
- if(!(mpos2dpos(&p, &cp, (mev->StateFlags & 1) == 1))) return false;
- if(cp.y >= cRows || cp.x >= cCols || cp.y < 0 || cp.x < 0) return false;
- }
- else cp.x = cp.y = 0;
- switch (mev->Action) {
- case MOUSE_LBDOWN:
- if(m_range && (mev->StateFlags & 0x18)) mrk_offs = (int)strlen(m_range);
- else mrk_offs = 0;
- bActive = true; new_mark = false;
- if(!et_racc && 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_MOVE:
- if(p.y < (w->MenuHeight+CellHeight)) {
- if(Disp->Command(CMD_COL_MOUSE, tmpl, w)) return true;
- }
- else w->MouseCursor(MC_ARROW, false);
- case MOUSE_LBDOUBLECLICK:
- 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(!et_racc && !m_range && CurrText) {
- CurrText->Update(2, w, &p); CurrText = 0L;
- }
- if(mrk_offs && m_range && m_range[0]){
- mrk_offs = rlp_strcpy(TmpTxt, mrk_offs+1, m_range);
- }
- else mrk_offs = 0;
- if(p.x < FirstWidth || p.y < (w->MenuHeight+CellHeight)) {
- if(mrk_offs && TmpTxt[mrk_offs-1] != ';')TmpTxt[mrk_offs++] = ';';
- rlp_strcpy(TmpTxt+mrk_offs, TMP_TXT_SIZE - mrk_offs, mkRangeRef(
- p.y < (w->MenuHeight+CellHeight) ? 0 : currpos.y, p.x < FirstWidth ? 0 : currpos.x,
- p.y < (w->MenuHeight+CellHeight) ? cRows : cp.y, p.x < FirstWidth ? cCols-1 : cp.x));
- }
- else {
- if(mrk_offs && TmpTxt[mrk_offs-1] != ';')TmpTxt[mrk_offs++] = ';';
- rlp_strcpy(TmpTxt+mrk_offs, TMP_TXT_SIZE - mrk_offs, mkRangeRef(currpos.y, currpos.x, cp.y, cp.x));
- }
- if(!CurrText || et_racc)MarkRange(TmpTxt, &cp);
- 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.y < (w->MenuHeight+CellHeight)) {
- if(Disp->Command(CMD_COL_MOUSE, tmpl, w)) return true;
- }
- isRowMark = p.x < FirstWidth;
- isColMark = p.y < (w->MenuHeight+CellHeight);
- if(isRowMark || isColMark) {
- if(p.x < FirstWidth) {
- currpos.x = 0; cp.x = cCols-1;
- }
- if(p.y < (w->MenuHeight+CellHeight)) {
- currpos.y = 0; cp.y = cRows-1;
- }
- if(mrk_offs && m_range && m_range[0]){
- mrk_offs = rlp_strcpy(TmpTxt, mrk_offs+1, m_range);
- }
- else mrk_offs = 0;
- if(mrk_offs && TmpTxt[mrk_offs-1] != ';')TmpTxt[mrk_offs++] = ';';
- rlp_strcpy(TmpTxt+mrk_offs, TMP_TXT_SIZE - mrk_offs, mkRangeRef(currpos.y, currpos.x, cp.y, cp.x));
- MarkRange(TmpTxt); currpos2.x = cp.x; currpos2.y = cp.y + 1;
- }
- else if((m_range) && !new_mark) HideMark(false);
- if(et_racc && !et_racc->isInRect(&p)) {
- CurrText = et_racc;
- if(m_range && m_range[0] && (currpos.x != cp.x || currpos.y != cp.y)) {
- CurrText->Command(CMD_ADDTXT, o, (DataObj*) m_range);
- }
- else {
- m_range = (char*)realloc(m_range, 40*sizeof(char));
- rlp_strcpy(m_range, 40, mkCellRef(currpos.y, currpos.x));
- CurrText->Command(CMD_ADDTXT, o, (DataObj*) m_range);
- }
- }
- else 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: case CMD_PASTE_SSV:
- if(PasteRange(cmd, (char*)tmpl))
- return Disp->Command(CMD_SETSCROLL, 0L, w);
- return false;
- case CMD_HIDEMARK:
- if(c_range){
- free(c_range); c_range = 0L; return true;
- }
- return false;
- case CMD_GETFILENAME:
- if(!tmpl) return false;
- if(rlw_file && rlw_file[0]) {
- if(rlp_strcpy((char*)tmpl, TMP_TXT_SIZE, rlw_file))return true;
- else return false;
- }
- return false;
- case CMD_ETRACC:
- if(et_racc && tmpl && ((EditText*)tmpl)->parent != this) HideMark(false);
- et_racc = (EditText*) tmpl;
- if(CurrText && CurrText->parent != this) CurrText = 0L;
- return true;
- 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:
- if(err_msg && err_msg[0] && tmpl && *((char*)tmpl)) {
- if(!(strcmp((char*)tmpl, "parse error")))return false; //parse error has lowest priority
- }
- if(!tmpl && err_msg && err_msg[0] && strcmp(err_msg, "parse error")) return false;
- err_msg = (char*)tmpl;
- break;
- case CMD_UPDATE:
- bUpdate = true;
- break;
- case CMD_SAVEPOS:
- return SavePos();
- case CMD_CLEAR_ERROR:
- err_msg = last_err = 0L;
- break;
- case CMD_TOOLMODE: //ESC pressed
- HideMark(true);
- if(CurrText){
- CurrText->Update(2, w, 0L); CurrText->Update(1, w, 0L);
- }
- et_racc = 0L; w->MouseCursor(MC_ARROW, true);
- break;
- case CMD_UPDHISTORY:
- if(w) w->FileHistory();
- break;
- case CMD_MRK_DIRTY:
- move_cr = CMD_CURRDOWN;
- err_msg = last_err = 0L;
- 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; Disp->Command(CMD_SETSCROLL, 0L, w);
- }
- 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; Disp->Command(CMD_SETSCROLL, 0L, w);
- }
- if(currpos.x < Disp->ssOrg.x) {
- Disp->ssOrg.x = currpos.x; Disp->Command(CMD_SETSCROLL, 0L, w);
- }
- else if(currpos.x > (Disp->ssOrg.x + c_disp -3) && (CurrText->GetRX()+ 10) > Disp->currRC.right ) {
- Disp->ssOrg.x = currpos.x - (c_disp-3);
- if(Disp->ssOrg.x < 0) Disp->ssOrg.x = 0; Disp->Command(CMD_SETSCROLL, 0L, w);
- }
- currpos2.x = currpos.x; currpos2.y = currpos.y;
- i = *((int*)tmpl);
- Disp->Command(CMD_CURRPOS, &currpos, w);
- if(i == 27) return Command(CMD_TOOLMODE, tmpl, o);
- if(i !=3 && i != 22 && i != 24 && i != 26) HideMark(true); //Do not hide upon ^C, ^V, ^X, ^Z
- 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);;
- }
- Disp->Command(CMD_CURRPOS, &currpos, w);
- break;
- case CMD_SHIFTUP:
- if(Disp->ssOrg.y && currpos2.y <= Disp->ssOrg.y) {
- Disp->ssOrg.y --; Disp->Command(CMD_SETSCROLL, 0L, w);
- }
- currpos2.y -= 2;
- case CMD_SHIFTDOWN:
- if(cmd == CMD_SHIFTDOWN && r_disp > 3 && (currpos2.y-Disp->ssOrg.y) >= (r_disp-3)) {
- Disp->ssOrg.y ++; Disp->Command(CMD_SETSCROLL, 0L, w);
- }
- currpos2.y ++;
- if(currpos2.y >= cRows) currpos2.y --; if(currpos2.y < 0) currpos2.y ++;
- //mark rectangular range
- rlp_strcpy(TmpTxt, 40, mkRangeRef(currpos.y, currpos.x, currpos2.y, currpos2.x));
- MarkRange(TmpTxt); HideTextCursor();
- break;
- case CMD_SHIFTRIGHT: case CMD_SHIFTLEFT:
- if(!m_range && CurrText && CurrText->Command(cmd, w, this)) break;
- if(cmd == CMD_SHIFTLEFT && c_disp > 3 && Disp->ssOrg.x && (currpos2.x-Disp->ssOrg.x) < 1) {
- Disp->ssOrg.x --; Disp->Command(CMD_SETSCROLL, 0L, w);
- }
- if(cmd == CMD_SHIFTRIGHT && c_disp > 3 && (currpos2.x-Disp->ssOrg.x) >= (c_disp-3)) {
- Disp->ssOrg.x ++; Disp->Command(CMD_SETSCROLL, 0L, w);
- }
- if(cmd == CMD_SHIFTLEFT) currpos2.x --;
- else currpos2.x ++;
- if(currpos2.x >= cCols) currpos2.x --; if(currpos2.x < 0) currpos2.x ++;
- //mark rectangular range
- rlp_strcpy(TmpTxt, 40, mkRangeRef(currpos.y, currpos.x, currpos2.y, currpos2.x));
- MarkRange(TmpTxt); HideTextCursor();
- break;
- case CMD_SHPGUP:
- if(Disp->ssOrg.y >0) {
- Disp->ssOrg.y -= (r_disp-2);
- if(Disp->ssOrg.y < 0) Disp->ssOrg.y = 0;
- Disp->Command(CMD_SETSCROLL, 0L, w);
- currpos2.y -= r_disp; if(currpos2.y < 0) currpos2.y = 0;
- rlp_strcpy(TmpTxt, 40, mkRangeRef(currpos.y, currpos.x, currpos2.y, currpos2.x));
- MarkRange(TmpTxt); HideTextCursor();
- }
- break;
- case CMD_SHPGDOWN:
- i = (Disp->ssOrg.y + 2*r_disp) < cRows ? r_disp-2 : cRows-r_disp - Disp->ssOrg.y+3;
- if(i > 0) {
- Disp->ssOrg.y += i; Disp->Command(CMD_SETSCROLL, 0L, w);
- }
- if(currpos2.y < (cRows-1)) {
- currpos2.y += r_disp; if(currpos2.y >= cRows) currpos2.y = cRows-1;
- //mark rectangular range
- rlp_strcpy(TmpTxt, 40, mkRangeRef(currpos.y, currpos.x, currpos2.y, currpos2.x));
- MarkRange(TmpTxt); HideTextCursor();
- }
- break;
- case CMD_CURRIGHT: case CMD_CURRDOWN:
- move_cr = cmd; w->ActualSize(&rc);
- 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);
- Disp->Command(CMD_CURRPOS, &currpos, w);
- 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(CurrText && cmd == CMD_CURRIGHT && c_disp > 3 && ((currpos.x-Disp->ssOrg.x) >= (c_disp-1) || CurrText->GetRX() >= (rc.right-rc.left-10))) {
- Disp->ssOrg.x ++; currpos.y ++; DoPlot(o);
- 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);
- }
- Disp->Command(CMD_CURRPOS, &currpos, w);
- HideMark(false);
- currpos2.x = currpos.x; currpos2.y = currpos.y;
- 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);
- }
- Disp->Command(CMD_CURRPOS, &currpos, w);
- return true;
- case CMD_UNDO:
- if(w) {
- w->MouseCursor(MC_WAIT, true);
- Undo.Restore(true, w);
- w->MouseCursor(MC_ARROW, true);
- if(et_racc) {
- CurrText = et_racc;
- CurrText->Update(1, w, 0L);
- }
- }
- return true;
- case CMD_DELETE:
- if(m_range) DelRange();
- else if(CurrText) return CurrText->Command(cmd, o, this);
- Disp->Command(CMD_CURRPOS, &currpos, w);
- return true;
- case CMD_QUERY_COPY: case CMD_CUT:
- et_racc = 0L;
- 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])) {
- Undo.ValInt(Disp, &FirstWidth, UNDO_CONTINUE); Undo.ValInt(Disp, &CellWidth, UNDO_CONTINUE);
- Undo.ValInt(Disp, &CellHeight, UNDO_CONTINUE); FirstWidth = ((int*)tmpl)[0];
- CellWidth = ((int*)tmpl)[1]; CellHeight = ((int*)tmpl)[2];
- }
- break;
- case CMD_TEXTSIZE:
- if(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_DOPLOT: case CMD_REDRAW:
- if(CurrText) CurrText->Update(2, 0L, 0L);
- if(etRows && etRows[currpos.y] && currpos.y < cRows && currpos.x < cCols)
- if(CurrText = etRows[currpos.y][currpos.x]) CurrText->Update(1,0L, 0L);
- DoPlot(o);
- break;
- case CMD_FILLRANGE:
- Undo.SetDisp(w);
- FillSsRange(this, &m_range, Disp);
- DoPlot(o);
- Undo.SetDisp(w);
- break;
- case CMD_GETMARK:
- if(tmpl && m_range && m_range[0]) {
- *((char**)tmpl) = m_range;
- return true;
- }
- return false;
- case CMD_INSROW:
- return InsertRows();
- case CMD_INSCOL:
- return InsertCols();
- case CMD_DELROW:
- return DeleteRows();
- case CMD_DELCOL:
- return DeleteCols();
- }
- return true;
-}
-
-bool
-SpreadData::ReadXML(char *file, unsigned char *buffer, int type, DWORD undo_flags)
-{
- int i, row, col, tag, cpgr, spgr, ufl = 0;
- bool bContinue, bRet = false, bUndo_done = false;
- ReadCache *XMLcache;
- POINT pt, mov;
- char TmpTxt[1024], *tmp_range;
- unsigned char *pgr = 0L;
- RECT rc_undo;
-
- if(file) {
- if(!(XMLcache = new ReadCache())) return false;
- if(! XMLcache->Open(file)) {
- delete XMLcache;
- i = rlp_strcpy(TmpTxt, 40, "Error open file\n\""); i = rlp_strcpy(TmpTxt+i, 200, file);
- rlp_strcpy(TmpTxt+i, 2, "\""); ErrorBox(TmpTxt);
- return false;
- }
- bUndo_done = true;
- 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)){
- if(!bUndo_done) {
- rc_undo.left = currpos.x;
- rc_undo.right = cp_src_rec.right - cp_src_rec.left + currpos.x;
- rc_undo.top = currpos.y;
- rc_undo.bottom = cp_src_rec.bottom - cp_src_rec.top + currpos.y;
- if(ufl == 3) Undo.DataObject(Disp, w, this, &rc_undo, undo_flags);
- bUndo_done = true;
- }
- tag = 1;
- }
- else if(!strcmp("<pos1", TmpTxt)) tag = 2;
- else if(!strcmp("<pos2", TmpTxt)) tag = 3;
- else if(!strcmp("<RLPl", TmpTxt)) {
- do {
- TmpTxt[i++] = XMLcache->Getc();
- }while(TmpTxt[i-1] > 31 && TmpTxt[i-1] != '>');
- TmpTxt[i] = 0;
- row = col = 0;
- if(TmpTxt[17] == '=' && TmpTxt[13] == 'r') {
-#ifdef USE_WIN_SECURE
- sscanf_s(TmpTxt+19, "%d", &row);
-#else
- sscanf(TmpTxt+19, "%d", &row);
-#endif
- }
- else break;
- for(i = 20; TmpTxt[i] && TmpTxt[i] != '='; i++);
-#ifdef USE_WIN_SECURE
- sscanf_s(TmpTxt+i+2, "%d", &col);
-#else
- sscanf(TmpTxt+i+2, "%d", &col);
-#endif
- if(row && col) {
- AddCols(col); AddRows(row);
- }
- row = col = -1;
- }
- 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);
- if(cpgr >20)OpenGraph(Disp, 0L, pgr, false);
- 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;
- ufl |= 1;
- }
- else if(tag ==3) {
- cp_src_rec.right = col; cp_src_rec.bottom = row;
- ufl |= 2;
- }
- 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; i++) {
- if(!(TmpTxt[i] =XMLcache->Getc())) break;
- if(i >1 && TmpTxt[i-2] == '<' && TmpTxt[i-1] == '/' && TmpTxt[i] == 't') break;
- }
- i -=2; 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, TMP_TXT_SIZE, currpos.x-mov.x, currpos.y-mov.y, -1, -1);
- }
- 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;
- i = rlp_strcpy(TmpTxt, 200, "Error open file\n\"");
- i += rlp_strcpy(TmpTxt+i, 200-i, file);
- i += rlp_strcpy(TmpTxt+i, 200-i, "\"\n");
- ErrorBox(TmpTxt);
- return false;
- }
- if(!Init(1, 1)) goto TSVError;
- etRows[0][0]->SetText("");
- }
- else if(buffer && (type == FF_TSV || type == FF_SSV)) {
- 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;
- case ' ':
- if(type == FF_SSV) col ++; break;
- }
- }while(TmpTxt[0] && ((unsigned char)TmpTxt[0] < 33));
- for(i = 1; ((unsigned char)(TmpTxt[i] = c = TSVcache->Getc()))>= (type == FF_SSV ? 33 : 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;
- case ' ':
- if(type == FF_SSV) col ++; break;
- }
- }
- }while(!TSVcache->IsEOF());
- bRet = true;
-TSVError:
- TSVcache->Close();
- delete TSVcache;
- return bRet;
-}
-
-static void sylk_cell_ref(char** ptr, int *cbd, int *size, char *first, char* trail, int row, int col)
-{
- if(first && first[0]) add_to_buff(ptr, cbd, size, first, 0);
- add_to_buff(ptr, cbd, size, "Y", 1); add_int_to_buff(ptr, cbd, size, row+1, false, 0);
- add_to_buff(ptr, cbd, size, ";X", 2); add_int_to_buff(ptr, cbd, size, col+1, false, 0);
- if(trail && trail[0]) add_to_buff(ptr, cbd, size, trail, 0);
-}
-
-bool
-SpreadData::MemList(unsigned char **ptr, int type)
-{
- int i, j, nc, nl;
- int cbd = 0, size;
- bool bLimit = true;
- AccRange *ar;
- anyResult res;
- RECT rcCopy;
-
- if(!(*ptr = (unsigned char *)malloc(size = 10000)))return false;
- if (c_range && c_range[0]) {
- ar = new AccRange(c_range); ar->BoundRec(&rcCopy);
- if(bCopyCut) Undo.DataObject(Disp, w, this, &rcCopy, 0L);
- }
- else {
- ar = 0L; rcCopy.left = rcCopy.top = 0;
- rcCopy.right = cCols-1; rcCopy.bottom = cRows-1;
- }
- 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 = rlp_strcpy((char*)*ptr, size, "ID;PWXL;N;E\n"
- "P;Pdd/mm/yyyy\nP;Phh:mm:ss\nP;Pdd/mm/yyyy hh:mm:ss\n");
- else if(type == FF_XML) {
- cbd = rlp_strcpy((char*)*ptr, 100, "<?xml version=\"1.0\"?><!DOCTYPE spreadsheet-snippet>"
- "<spreadsheet-snippet rows=\"");
- add_int_to_buff((char**)ptr, &cbd, &size, cRows, false, 0);
- add_to_buff((char**)ptr, &cbd, &size, "\" columns=\"", 11);
- add_int_to_buff((char**)ptr, &cbd, &size, cCols, false, 0);
- add_to_buff((char**)ptr, &cbd, &size, "\">\n", 3);
- if(rcCopy.left || rcCopy.top || rcCopy.bottom || rcCopy.right){
- add_to_buff((char**)ptr, &cbd, &size, " <pos1 row=\"", 12);
- add_int_to_buff((char**)ptr, &cbd, &size, rcCopy.top, false, 0);
- add_to_buff((char**)ptr, &cbd, &size, "\" column=\"", 10);
- add_int_to_buff((char**)ptr, &cbd, &size, rcCopy.left, false, 0);
- add_to_buff((char**)ptr, &cbd, &size, "\"></pos1>\n <pos2 row=\"", 22);
- add_int_to_buff((char**)ptr, &cbd, &size, rcCopy.bottom, false, 0);
- add_to_buff((char**)ptr, &cbd, &size, "\" column=\"", 10);
- add_int_to_buff((char**)ptr, &cbd, &size, rcCopy.right, false, 0);
- add_to_buff((char**)ptr, &cbd, &size, "\"></pos2>\n", 10);
- }
- }
- else if(type == FF_RLW) {
- cbd = rlp_strcpy((char*)*ptr, size, "<?xml version=\"1.0\"?><!DOCTYPE RLPlot-workbook>\n<RLPlot-data rows=\"");
- add_int_to_buff((char**)ptr, &cbd, &size, cRows, false, 0);
- add_to_buff((char**)ptr, &cbd, &size, "\" columns=\"", 11);
- add_int_to_buff((char**)ptr, &cbd, &size, cCols, false, 0);
- add_to_buff((char**)ptr, &cbd, &size, "\">\n", 3);
- }
- for(nl =0, i = rcCopy.top; i <= rcCopy.bottom; i++, nl++) {
- for(nc = 0, j = rcCopy.left; j <= rcCopy.right; j++, nc++) {
- switch (type) {
- case FF_TSV:
- if(nl || nc) add_to_buff((char**)ptr, &cbd, &size, nc ? (char*)"\t" : (char*)"\n", 1);
- if(etRows[i] && etRows[i][j]){
- if((ar && ar->IsInRange(j,i)) || !ar) {
- etRows[i][j]->GetResult(&res, false);
- TranslateResult(&res);
- add_to_buff((char**)ptr, &cbd, &size, res.text, 0);
- }
- }
- break;
- case FF_SYLK:
- if(etRows[i] && etRows[i][j] && etRows[i][j]->text && ((ar && ar->IsInRange(j,i)) || !ar)){
- etRows[i][j]->GetResult(&res, false);
- TranslateResult(&res);
- switch(res.type) {
- case ET_VALUE: case ET_BOOL:
- sylk_cell_ref((char**) ptr, &cbd, &size, "C;", ";K", nl, nc);
- add_to_buff((char**)ptr, &cbd, &size, res.text, 0);
- break;
- case ET_DATE:
- sylk_cell_ref((char**) ptr, &cbd, &size, "F;P0;FG0G;", "\nC;K", nl, nc);
- add_dbl_to_buff((char**)ptr, &cbd, &size, res.value+1, false);
- break;
- case ET_DATETIME:
- sylk_cell_ref((char**) ptr, &cbd, &size, "F;P2;FG0G;", "\nC;K", nl, nc);
- add_dbl_to_buff((char**)ptr, &cbd, &size, res.value+1, false);
- break;
- case ET_TIME:
- sylk_cell_ref((char**) ptr, &cbd, &size, "F;P1;FG0G;", "\nC;K", nl, nc);
- add_dbl_to_buff((char**)ptr, &cbd, &size, res.value, false);
- break;
- case ET_TEXT:
- sylk_cell_ref((char**) ptr, &cbd, &size, "C;", ";K\"", nl, nc);
- add_to_buff((char**)ptr, &cbd, &size, res.text, 0);
- add_to_buff((char**)ptr, &cbd, &size, "\"", 1);
- break;
- }
- add_to_buff((char**)ptr, &cbd, &size, "\n", 1);
- if(bCopyCut) etRows[i][j]->SetText("");
- }
- break;
- case FF_RLW: case FF_XML:
- if(etRows[i] && etRows[i][j] && etRows[i][j]->text && ((ar && ar->IsInRange(j,i)) || !ar)
- && etRows[i][j]->text[0]){
- add_to_buff((char**)ptr, &cbd, &size, " <cell row=\"", 12);
- add_int_to_buff((char**)ptr, &cbd, &size, nl+1, false, 0);
- add_to_buff((char**)ptr, &cbd, &size, "\" column=\"", 10);
- add_int_to_buff((char**)ptr, &cbd, &size, nc+1, false, 0);
- add_to_buff((char**)ptr, &cbd, &size, "\">\n <text>", 11);
- add_to_buff((char**)ptr, &cbd, &size, etRows[i][j]->text, 0);
- add_to_buff((char**)ptr, &cbd, &size, "</text>\n </cell>\n", 17);
- if(bCopyCut) etRows[i][j]->SetText("");
- }
- break;
- }
- }
- }
- if(type == FF_SYLK) {
- if(!bLimit) {
- add_to_buff((char**)ptr, &cbd, &size, "C;Y", 3);
- add_int_to_buff((char**)ptr, &cbd, &size, i+2, false, 0);
- add_to_buff((char**)ptr, &cbd, &size, ";X1;K\"long strings were"
- " truncated to 256 characters due to limitations of the SYLK format!\"\n", 92);
- }
- add_to_buff((char**)ptr, &cbd, &size, "E\n", 2);
- }
- else if(type == FF_TSV) add_to_buff((char**)ptr, &cbd, &size, "\n", 1);
- else if(type == FF_XML) add_to_buff((char**)ptr, &cbd, &size, "</spreadsheet-snippet>\n", 23);
- else if(type == FF_RLW){
- Disp->Command(CMD_WRITE_GRAPHS, ptr, (anyOutput*)&cbd);
- //note: cbd may be greater than size !
- add_to_buff((char**)ptr, &cbd, &size, "</RLPlot-data>\n", 15);
- }
- if(ar) delete ar;
- if(bCopyCut && type == FF_XML || type == FF_SYLK || type == FF_RLW){
- bCopyCut = false;
- DoPlot(w);
- }
- return true;
-}
-
-void SpreadMain(bool show)
-{
- static SpreadData *w = 0L;
-
- if(show) {
- if(w = new SpreadData(0L)) w->Init(50, 10);
- do_formula(w, 0L); //init mfcalc
- }
- else if (w) delete(w);
-}
+//spreadwin.cpp, (c)2000-2008 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 <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 const LineDEF GrayLine;
+extern GraphObj *CurrGO, *TrackGO; //Selected Graphic Objects
+extern EditText *CurrText;
+extern char *LoadFile;
+extern char TmpTxt[];
+extern Default defs;
+extern UndoObj Undo;
+
+static ReadCache *Cache = 0L;
+static TextDEF ssText;
+static char *szRlpData = "RLPlot data";
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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, ns;
+
+ if(ptr) {
+ for(i = nt = nl = nc = ns = 0; ptr[i] && nl<100; i++) {
+ switch(ptr[i]) {
+ case 0x09: //tab
+ nt++;
+ break;
+ case 0x0a: //LF
+ nl++;
+ break;
+ case ',':
+ nc++;
+ break;
+ case ' ':
+ ns++;
+ break;
+ }
+ }
+ if(dispatch && i && !nt && !nl) {
+ if(CurrText){
+ g->Command(CMD_SETFOCUS, 0L, 0L);
+ for(i = 0; ptr[i]; i++) CurrText->AddChar(ptr[i], i? 0L : Undo.cdisp, 0L);
+ g->Command(CMD_REDRAW, 0L, 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 && ns && 0 == (ns % nl)) RetVal = FF_SSV;
+ 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_SSV: g->Command(CMD_PASTE_SSV, 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(GraphObj *par, DataObj *Data);
+ ~SpreadWin();
+ void DoPlot(anyOutput *target);
+ bool Command(int cmd, void *tmpl, anyOutput *o);
+
+ bool ShowGrid(int CellWidth, int CellHeight, int FirstWidth, POINT *cpos);
+ void MarkButtons(char *rng, POINT *cp = 0L);
+ bool PrintData(anyOutput *o);
+ void WriteGraphXML(unsigned char **ptr, long *cbd);
+
+private:
+ bool is_modified, bDoColWidth;
+ char *filename;
+ ssButton **cButtons, **rButtons;
+ ssButton *aButton;
+ POINT cpos;
+ DataObj *d;
+ int NumGraphs, CurrCol;
+ Graph **g;
+ RECT rc_line;
+ POINT line[2];
+};
+
+SpreadWin::SpreadWin(GraphObj *par, DataObj *Data):GraphObj(par, Data)
+{
+ d = Data; g = 0L; ssOrg.x = ssOrg.y = 0; NumGraphs = 0;
+ filename=0L; aButton = 0L;
+ w = 0L; cButtons = rButtons = 0L;
+ if(w = NewDispClass(this)){
+ w->hasHistMenu = true;
+ ssText.RotBL = ssText.RotCHAR = 0.0;
+ ssText.fSize = 0.0f;
+ ssText.iSize = w->un2iy(defs.GetSize(SIZE_CELLTEXT));
+ ssText.Align = TXA_VCENTER | TXA_HLEFT; ssText.Mode = TXM_TRANSPARENT;
+ ssText.Style = TXS_NORMAL; ssText.ColBg = 0x00e8e8e8L;
+ ssText.ColTxt = 0x00000000L; ssText.text = 0L;
+ ssText.Font = FONT_HELVETICA; w->SetTextSpec(&ssText);
+ w->SetMenu(MENU_SPREAD); w->FileHistory();
+ w->Erase(0x00e8e8e8L); w->Caption(szRlpData, false);
+ d->ri->SetDefWidth(w->un2ix(defs.GetSize(SIZE_CELLWIDTH)));
+ d->ri->SetHeight(w->un2iy(defs.GetSize(SIZE_CELLTEXT)/defs.ss_txt) + 2);
+ d->ri->SetFirstWidth(32);
+ }
+ else if(d && d->ri) {
+ d->ri->SetHeight(19); d->ri->SetDefWidth(76); d->ri->SetFirstWidth(32);
+ }
+ Id = GO_SPREADDATA;
+ is_modified = bDoColWidth = false;
+}
+
+SpreadWin::~SpreadWin()
+{
+ int i;
+
+ if(parent) {
+ 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]) delete(g[i]);
+ free (g);
+ }
+ if(filename) free(filename); filename=0L;
+ }
+}
+
+void
+SpreadWin::DoPlot(anyOutput *o)
+{
+ if(!(o->ActualSize(&currRC)))return;
+ o->StartPage();
+ d->Command(CMD_DOPLOT, (void*)this, o);
+ o->EndPage();
+}
+
+bool
+SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ char *Name;
+ Graph *g2;
+ int i, j, k;
+ bool bRet;
+ MouseEvent *mev;
+ POINT p1, p2;
+
+ if(d) {
+ if(!o) o = w;
+ switch(cmd) {
+ case CMD_CURRPOS:
+ if(tmpl && cButtons && rButtons) {
+ int ac = 1, na = 0;
+ RECT urc;
+ if(((POINT*)tmpl)->x != cpos.x) {
+ for(cpos.x = ((POINT*)tmpl)->x, i = 0; cButtons[i]; i++) {
+ cButtons[i]->Command(CMD_SELECT, (cpos.x == (i+ssOrg.x)) ? &ac : &na, w);
+ }
+ urc.left = cButtons[0]->rDims.left; urc.bottom = cButtons[0]->rDims.bottom;
+ urc.top = cButtons[0]->rDims.top; urc.right = urc.left + d->ri->GetWidth(i+ssOrg.x) * (i-1);
+ w->UpdateRect(&urc, false);
+ }
+ if(((POINT*)tmpl)->y != cpos.y) {
+ for(cpos.y = ((POINT*)tmpl)->y, i = 0; rButtons[i]; i++) {
+ rButtons[i]->Command(CMD_SELECT, (cpos.y == (i+ssOrg.y)) ? &ac : &na, w);
+ }
+ urc.left = rButtons[0]->rDims.left; urc.right = rButtons[0]->rDims.right;
+ urc.top = rButtons[0]->rDims.top; urc.bottom = urc.top + d->ri->GetHeight(i+ssOrg.y) * (i-1);
+ w->UpdateRect(&urc, false);
+ }
+ }
+ else return false;
+ return true;
+ case CMD_CAN_CLOSE:
+ HideTextCursor();
+ if(is_modified == true) {
+ is_modified=false;
+ if(Undo.isEmpty(0L)) return true;
+ i = YesNoCancelBox("The spreadsheet or a graph has been modified!\n\nDo you want to save it now?");
+ if(i == 2) return false;
+ else if(i == 1) return Command(CMD_SAVEAS, tmpl, o);
+ }
+ return true;
+ case CMD_MRK_DIRTY:
+ if(!is_modified) {
+ o->Caption(filename && filename[0]?filename : szRlpData, true);
+ }
+ return is_modified = true;
+ case CMD_WRITE_GRAPHS:
+ if (g && NumGraphs) WriteGraphXML((unsigned char**)tmpl, (long*)o);
+ return true;
+ case CMD_DROP_GRAPH:
+ if(!tmpl) return false; if(o) o->FileHistory();
+ if(g && NumGraphs) {
+ if(g = (Graph**)realloc(g, (NumGraphs+2) * sizeof(Graph*)))
+ g[NumGraphs++] = (Graph *)tmpl;
+ else return false;
+ }
+ else {
+ if(g = (Graph **)calloc(2, sizeof(Graph*))){
+ g[0] = (Graph *)tmpl; NumGraphs = 1;
+ }
+ }
+ for(i = j = 0; i < NumGraphs; i++) {
+ if(g[i]) {
+ g[j] = g[i]; g[j]->parent = this;
+ g[j]->Command(CMD_SET_DATAOBJ, (void*)d, 0L);
+ j++;
+ }
+ }
+ NumGraphs = j; g[j-1]->DoPlot(0L);
+ return true;
+ case CMD_NEWGRAPH:
+ if((g2 = new Graph(this, d, 0L, 0)) && g2->PropertyDlg() &&
+ Command(CMD_DROP_GRAPH, g2, o))return Command(CMD_REDRAW, 0L, o);
+ else if(g2) DeleteGO(g2);
+ Undo.SetDisp(w);
+ return false;
+ case CMD_NEWPAGE:
+ if((g2 = new Page(this, d)) &&
+ Command(CMD_DROP_GRAPH, g2, o))return Command(CMD_REDRAW, 0L, o);
+ else if(g2) DeleteGO(g2);
+ Undo.SetDisp(w);
+ return false;
+ case CMD_DELGRAPH:
+ if (g && NumGraphs) {
+ for(i = 0; i < NumGraphs; i++) if(g[i]) DeleteGO(g[i]);
+ free (g);
+ }
+ g = 0L; NumGraphs = 0; Undo.Flush();
+ return true;
+ case CMD_DELOBJ:
+ i = j = 0;
+ if(g && tmpl) for(; i < NumGraphs; i++) {
+ if(g[i] == (Graph*) tmpl) {
+ DeleteGO(g[i]);
+ }
+ else (g[j++] = g[i]);
+ }
+ if(g && j < i) g[j] = 0L; NumGraphs = j;
+ return true;
+ case CMD_SAVE:
+ if(o) o->MouseCursor(MC_WAIT, false);
+ if(d->WriteData(0L)) {
+ o->Caption(filename && filename[0]?filename : szRlpData, false);
+ is_modified=false;
+ if(o) o->MouseCursor(MC_ARROW, false);
+ return true;
+ }
+ if(o) o->MouseCursor(MC_ARROW, true);
+ case CMD_SAVEAS:
+ is_modified=false;
+ if((Name = SaveDataAsName(filename)) && Name[0]){
+ if(o) o->FileHistory();
+ if(Name && d->WriteData(Name)) {
+ o->Caption(filename && filename[0]?filename : szRlpData, false);
+ if(filename) free(filename);
+ filename = (char*)memdup(Name, (int)strlen(Name)+1, 0);
+ }
+ else return false;
+ }
+ else return false;
+ return true;
+ case CMD_DROPFILE:
+ if(!Command(CMD_CAN_CLOSE, 0L, o)) return false;
+ if(IsRlpFile((char*)tmpl)) return OpenGraph(this, (char*)tmpl, 0L, false);
+ else if(d->ReadData((char*)tmpl, 0L, FF_UNKNOWN)){
+ if(filename) free(filename);
+ filename = (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1, 0);
+ o->Caption(filename && filename[0]?filename : szRlpData, is_modified = false);
+ return Command(CMD_SETSCROLL, 0L, w);
+ }
+ else ErrorBox("The selected file is not valid\nor not accessible!\n");
+ return false;
+ case CMD_OPEN:
+ if(!Command(CMD_CAN_CLOSE, 0L, o)) return false;
+ Undo.KillDisp(o); Undo.SetDisp(o);
+ if((Name = OpenDataName(filename)) && Name[0]){
+ if(o) o->FileHistory();
+ if(IsRlpFile(Name)) return OpenGraph(this, Name, 0L, false);
+ else if(d->ReadData(Name, 0L, FF_UNKNOWN)){
+ if(filename) free(filename);
+ filename = (char*)memdup(Name, (int)strlen(Name)+1, 0);
+ return Command(CMD_SETSCROLL, 0L, w);
+ }
+ }
+ return false;
+ case CMD_ADDROWCOL:
+ if(DoSpShSize(d, this)) DoPlot(o);
+ return true;
+ case CMD_COL_MOUSE:
+ if(o && cButtons && rButtons && (mev = (MouseEvent*)tmpl) && mev->y > o->MenuHeight) {
+ for(i = 0; cButtons[i]; i++){
+ if(bDoColWidth) {
+ o->MouseCursor(MC_COLWIDTH, false);
+ }
+ else if(mev->x > cButtons[i]->rDims.left && mev->x < cButtons[i]->rDims.right+2){
+ if(mev->x > cButtons[i]->rDims.right-4) {
+ switch(mev->Action) {
+ case MOUSE_LBDOWN:
+ CurrCol = i; line[0].x = line[1].x = mev->x;
+ line[0].y = o->MenuHeight; line[1].y = currRC.bottom;
+ d->Command(CMD_TOOLMODE, tmpl, o);
+ o->MouseCursor(MC_COLWIDTH, false);
+ return bDoColWidth = true;
+ }
+ o->MouseCursor(MC_COLWIDTH, false);
+ }
+ else o->MouseCursor(MC_ARROW, false);
+ return false;
+ }
+ else o->MouseCursor(MC_ARROW, false);
+ if(mev->Action == MOUSE_MOVE && bDoColWidth && (mev->StateFlags & 0x01)) {
+ rc_line.left = line[0].x - 2; rc_line.right = line[1].x + 2;
+ rc_line.top = line[0].y - 2; rc_line.bottom = line[1].y +2;
+ o->UpdateRect(&rc_line, false);
+ if(mev->x < (cButtons[CurrCol]->rDims.left +20))mev->x = cButtons[CurrCol]->rDims.left +20;
+ k = mev->x - cButtons[CurrCol]->rDims.right;
+ for(j = CurrCol; cButtons[j] && cButtons[j]->rDims.left < (currRC.right-k); j++) {
+ cButtons[j]->rDims.right += k; cButtons[j]->rDims.left += j > CurrCol ? k : 0;
+ cButtons[j]->DoPlot(o); o->UpdateRect(&cButtons[j]->rDims, false);
+ cButtons[j]->rDims.right -= k; cButtons[j]->rDims.left -= j > CurrCol ? k : 0;
+ }
+ line[0].x = line[1].x = mev->x;
+ line[0].y = o->MenuHeight; line[1].y = currRC.bottom;
+ o->ShowLine(line, 2, 0x00a0a0a0);
+ return true;
+ }
+ if(mev->Action == MOUSE_LBUP && bDoColWidth) {
+ bDoColWidth = false;
+ k = line[0].x - cButtons[CurrCol]->rDims.left;
+ if(abs(k - cButtons[CurrCol]->rDims.right + cButtons[CurrCol]->rDims.left)>3) {
+ rlp_strcpy(TmpTxt, 40, mkRangeRef(0, CurrCol + ssOrg.x, 0, CurrCol + ssOrg.x));
+ d->ri = new RangeInfo(1, TmpTxt, d->ri);
+ d->ri->SetWidth(k >=20 ? k : 20);
+ }
+ d->Command(CMD_REDRAW, 0L, o);
+ return true;
+ }
+ else bDoColWidth = false;
+ }
+ }
+ else o->MouseCursor(MC_ARROW, false);
+ return false;
+ case CMD_MOUSE_EVENT:
+ if(!(mev =(MouseEvent*)tmpl)) return false;
+ if(bDoColWidth)return Command(CMD_COL_MOUSE, tmpl, o);
+ p1.x = mev->x; p1.y = mev->y;
+ if(mev->y < o->MenuHeight) o->MouseCursor(MC_ARROW, false);
+ else if(o && cButtons && rButtons) {
+ if(mev->x < d->ri->GetFirstWidth() && mev->y < (o->MenuHeight + d->ri->GetHeight(-1)) && aButton) {
+ aButton->Command(cmd, tmpl, o);
+ }
+ else if(mev->x < d->ri->GetFirstWidth() && rButtons) {
+ if(!(d->mpos2dpos(&p1, &p2, false)))return false;
+ p2.x -= ssOrg.x; p2.y -= ssOrg.y;
+ if (p2.y < 0 || p2.y >= (d->r_disp-1)) return false;
+ if(rButtons[p2.y]) rButtons[p2.y]->Command(cmd, tmpl, o);
+ }
+ else if(mev->y < (o->MenuHeight + d->ri->GetHeight(-1)) && cButtons) {
+ if(!(d->mpos2dpos(&p1, &p2, false)))return false;
+ p2.x -= ssOrg.x; p2.y -= ssOrg.y;
+ if (p2.x < 0 || p2.x >= d->c_disp) return false;
+ if(cButtons[p2.x]) cButtons[p2.x]->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_CSV: case CMD_PASTE_SSV:
+ Undo.DataObject(this, w, d, 0L, 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_PASTE_XML: case CMD_DELROW: case CMD_INSROW:
+ case CMD_INSCOL: case CMD_DELCOL: case CMD_UNDO:
+ case CMD_SHPGUP: case CMD_SHPGDOWN: case CMD_HIDEMARK:
+ bDoColWidth = false; bRet = d->Command(cmd, tmpl, o);
+ if(cmd == CMD_UNDO && is_modified && Undo.isEmpty(0L)) {
+ w->Caption(filename && filename[0]?filename : szRlpData, is_modified = false);
+ }
+ return bRet;
+ case CMD_MENUHEIGHT:
+ if(w) w->MenuHeight = defs.iMenuHeight;
+ bDoColWidth = true;
+ case CMD_REDRAW:
+ Undo.SetDisp(w); d->Command(cmd, tmpl, o);
+ return true;
+ case CMD_MOUSECURSOR:
+ if(o)o->MouseCursor(MC_ARROW, false);
+ return true;
+ case CMD_SETSCROLL:
+ HideTextCursor(); if(!(o->ActualSize(&currRC)))return false;
+ k = (currRC.bottom-currRC.top)/d->ri->GetHeight(-1);
+ d->GetSize(&i, &j); o->MouseCursor(MC_WAIT, true);
+ o->SetScroll(true, 0, j, k, ssOrg.y); k = (currRC.right-currRC.left)/d->ri->GetWidth(-1);
+ o->SetScroll(false, 0, i, k, ssOrg.x); DoPlot(o);
+ o->MouseCursor(MC_ARROW, true);
+ return true;
+ case CMD_PAGEUP: case CMD_PAGEDOWN:
+ k = (currRC.bottom-currRC.top)/d->ri->GetHeight(-1);
+ k = k > 3 ? k-2 : 1; p1.x = d->ri->GetFirstWidth() + 2;
+ p1.y = d->ri->GetHeight(-1) + 2;
+ if(CurrText){
+ p1.x = CurrText->GetX()+2; p1.y = CurrText->GetY()+12;
+ }
+ d->GetSize(&i, &j);
+ if(cmd == CMD_PAGEUP) ssOrg.y = ssOrg.y > k ? ssOrg.y-k : 0;
+ else ssOrg.y = ssOrg.y < j-k*2 ? ssOrg.y+k : j > k ? j-k : 0;
+ Command(CMD_SETSCROLL, tmpl, o);
+ CurrText = 0L; d->Select(&p1);
+ return true;
+ 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:
+ Undo.SetDisp(w);
+ return true;
+ case CMD_KILLFOCUS:
+ return true;
+ case CMD_TEXTSIZE:
+ if(tmpl && *((int*)tmpl) != ssText.iSize) {
+ Undo.ValInt(this, &ssText.iSize, UNDO_CONTINUE);
+ ssText.iSize = o->un2iy(defs.GetSize(SIZE_CELLTEXT));
+ }
+ return true;
+ case CMD_CONFIG:
+ if(defs.PropertyDlg()) return Command(CMD_REDRAW, 0L, o);
+ return false;
+ case CMD_NONE:
+ return true;
+ case CMD_PRINT:
+ return PrintData(o);
+ }
+ }
+ return false;
+}
+
+bool
+SpreadWin::ShowGrid(int CellWidth, int CellHeight, int FirstWidth, POINT *cp)
+{
+ int i, c, nr, nc, cx, cw, ac = 1, na = 0;
+ RECT rc;
+ char text[20];
+ TextDEF ButtText;
+ bool redim = bDoColWidth;
+
+ w->HideMark();
+ cpos.x = cp->x; cpos.y = cp->y;
+ if(d->ri->GetHeight(-1) != CellHeight || d->ri->GetWidth(-1) != CellWidth || d->ri->GetFirstWidth() != FirstWidth) redim = true;
+ if(redim){
+ d->ri->SetHeight(CellHeight); d->ri->SetDefWidth(CellWidth); d->ri->SetFirstWidth(FirstWidth);
+ 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 = d->c_disp; if(c < 40 || c > 200) d->c_disp = c = 40;
+ cButtons = (ssButton **)calloc(c, sizeof(ssButton*));
+ for(i = 0, cx = FirstWidth; i < (c-1); i++) {
+ cw = d->ri->GetWidth(i+ssOrg.x);
+ cButtons[i] = new ssButton(this, cx, w->MenuHeight, cw+1, CellHeight);
+ cx += cw;
+ }
+ }
+ else {
+ for(i = 0, cx = FirstWidth; cButtons[i]; i++) {
+ cw = d->ri->GetWidth(i+ssOrg.x);
+ cButtons[i]->rDims.left = cx; cButtons[i]->rDims.right = cx + cw + 1;
+ cx += cw;
+ }
+ }
+ if(!rButtons) {
+ c = d->r_disp; if(c < 60 || c > 300) d->c_disp = c = 60;
+ 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);
+ }
+ d->GetSize(&nc, &nr);
+ if(rButtons) for(i = 0; rButtons[i]; i++) {
+#ifdef USE_WIN_SECURE
+ sprintf_s(text, 20, "%d", i+1+ssOrg.y);
+#else
+ sprintf(text, "%d", i+1+ssOrg.y);
+#endif
+ if(rButtons[i]) {
+ rButtons[i]->Command(CMD_SETTEXTDEF, &ButtText, w);
+ rButtons[i]->Command(CMD_SETTEXT, text, w);
+ rButtons[i]->Command(CMD_SELECT, (cpos.y == (i+ssOrg.y)) ? &ac : &na, w);
+ }
+ }
+ 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]->Command(CMD_SELECT, (cpos.x == (i+ssOrg.x)) ? &ac : &na, w);
+ }
+ }
+ w->SetTextSpec(&ssText);
+ if(aButton) aButton->DoPlot(w);
+ return true;
+}
+
+void
+SpreadWin::MarkButtons(char *rng, POINT *cp)
+{
+ int i, r, c, ncb, nrb, *r_idx, *c_idx;
+ AccRange *mr;
+
+ if(!rButtons || !cButtons) return;
+ for(ncb = 0; cButtons[ncb]; ncb++); ncb--;
+ for(nrb = 0; rButtons[nrb]; nrb++); nrb--;
+ if(!nrb || !ncb || !(r_idx=(int*)calloc(nrb,sizeof(int))) || !(c_idx=(int*)calloc(ncb,sizeof(int)))) return;
+ if(rng && rng[0] && (mr = new AccRange(rng)) && mr->GetFirst(&c, &r)) {
+ mr->NextCol(&c);
+ do {
+ if((i = c - ssOrg.x) >= 0 && i < ncb) c_idx[i] = 1;
+ }while(mr->NextCol(&c));
+ mr->GetFirst(&c, &r); mr->NextRow(&r);
+ do {
+ if((i = r - ssOrg.y) >= 0 && i < nrb) r_idx[i] = 1;
+ }while(mr->NextRow(&r));
+ delete mr;
+ }
+ for(i = 0; i < ncb; i++) cButtons[i]->Command(CMD_SETSTYLE, &c_idx[i], w);
+ for(i = 0; i < nrb; i++) rButtons[i]->Command(CMD_SETSTYLE, &r_idx[i], w);
+ if(cp) {
+ c_idx[0] = r_idx[0] = 0; c_idx[1] = r_idx[1] = 1;
+ r = (cp->y - ssOrg.y); c = cp->x -ssOrg.x;
+ for(i = 0; i < ncb; i++) cButtons[i]->Command(CMD_SELECT, c == i ? &c_idx[1] : &c_idx[0], w);
+ for(i = 0; i < nrb; i++) rButtons[i]->Command(CMD_SELECT, r == i ? &r_idx[1] : &r_idx[0], w);
+ }
+ free(r_idx); free(c_idx);
+}
+
+bool
+SpreadWin::PrintData(anyOutput *o)
+{
+ int i, j, k, l, pgw, pfw, pcw, pch, rpp, cpp, nc, nr, ix, iy, cpages;
+ int row, col, width, height, ipad, mode;
+ double scale;
+ RECT rc, margin, margin_first;
+ POINT pp_pos, ss_pos, grid[3];
+ LineDEF Line1, Line2;
+ TextDEF td, tdp;
+ bool bContinue;
+ time_t ti = time(0L);
+ anyResult res;
+
+ Line1.patlength = Line2.patlength = 1.0;
+ Line1.color = Line2.color = 0x00808080; //gray 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;
+ }
+#ifdef _WINDOWS
+ scale = 1.0/_SQRT2;
+#else
+ scale = 0.9;
+#endif
+ Line2.width = Line1.width * 3.0;
+ d->GetSize(&nc, &nr);
+ if(!(o->StartPage())) return false;
+ pfw = iround(o->hres * ((double)d->ri->GetFirstWidth())/w->hres * scale);
+ pcw = iround(o->hres * ((double)d->ri->GetWidth(-1))/w->hres * scale);
+ pch = iround((o->vres * ((double)d->ri->GetHeight(-1))/w->vres) * scale + 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;
+ 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
+ tdp.iSize = iround(o->hres/6.0);
+ td.fSize = defs.GetSize(SIZE_CELLTEXT);
+#else
+ tdp.iSize = iround(o->hres/7.5);
+ td.fSize = defs.GetSize(SIZE_CELLTEXT)*.8;
+#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));
+ pp_pos.x = margin.left; pp_pos.y = margin.top;
+ ss_pos.x = 0; ss_pos.y = 0; cpages = 1;
+ rpp = (rc.bottom - margin.top - margin.bottom - pch)/pch;
+ mode = 0;
+ if((nr * pch) < ((rc.bottom - rc.top - margin.top - margin.bottom)>>1)) mode = 1;
+ do {
+ k = (rc.right - margin.left - margin.right - pfw);
+ for(i = pgw = 0; pgw < k && (i+ss_pos.x) < nc; i++ ){
+ pgw += (pcw = iround(o->hres * ((double)d->ri->GetWidth(i+ss_pos.x))/w->hres * scale));
+ if(i >=(nc-1)) break;
+ }
+ if(pgw < k) {
+ cpp = i+1;
+ if(!mode && !ss_pos.x && pgw < (k>>1)) mode = 2;
+ }
+ else {
+ cpp = i-1; pgw -= pcw;
+ }
+ mode = mode;
+ 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);
+ grid[0].x = margin.left+pfw; grid[1].x = grid[0].x + pgw;
+ 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(&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); grid[0].x = grid[1].x = pp_pos.x + pfw;
+ for(i = 0, ix = pp_pos.x + pfw; i <= k; i++) { //column headers
+ pcw = iround(o->hres * ((double)d->ri->GetWidth(i+ss_pos.x))/w->hres * scale);
+ o->oSolidLine(grid); grid[0].x = grid[1].x = ix + pcw;
+ if(i < k) o->oTextOut(ix + (pcw >>1), iy, Int2ColLabel(i+ss_pos.x, true), 0);
+ ix += pcw;
+ }
+ 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);
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "%d", i+1+ss_pos.y);
+#else
+ sprintf(TmpTxt, "%d", i+1+ss_pos.y);
+#endif
+ if(i < l) o->oTextOut(ix, iy, TmpTxt, 0);
+ }
+ ipad = iround(o->hres/30.0);
+ grid[0].x = margin.left+pfw + ipad;
+ for(i = 0; i < k; i++, grid[0].x += pcw) { //spreadsheet data
+ pcw = iround(o->hres * ((double)d->ri->GetWidth(i+ss_pos.x))/w->hres * scale);
+ for (j = 0; j < l; j++) {
+ row = j+ss_pos.y; col = i+ss_pos.x;
+ if(row >= 0 && row < d->cRows && col >= 0 && col < d->cCols && d->etRows[row][col]) {
+ d->etRows[row][col]->GetResult(&res, false);
+ TranslateResult(&res);
+ td.Align = TXA_HLEFT | TXA_VCENTER;
+ ix = grid[0].x;
+ switch (res.type) {
+ case ET_VALUE:
+ ix = ix + pcw - ( ipad<<1 );
+ td.Align = TXA_HRIGHT | TXA_VCENTER;
+ rlp_strcpy(TmpTxt, TMP_TXT_SIZE, res.text);
+ fit_num_rect(o, pcw - ipad, TmpTxt);
+ Int2Nat(TmpTxt); break;
+ case ET_BOOL: case ET_DATE: case ET_TIME: case ET_DATETIME:
+ ix = ix + pcw - ( ipad<<1 );
+ td.Align = TXA_HRIGHT | TXA_VCENTER;
+ case ET_TEXT: case ET_UNKNOWN:
+ if(res.text&& strlen(res.text) < 40)
+ rlp_strcpy(TmpTxt, TMP_TXT_SIZE, res.text[0] != '\'' ? res.text : res.text +1);
+ else if(res.text) rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "#SIZE");
+ else TmpTxt[0] = 0;
+ do {
+ o->oGetTextExtent(TmpTxt, (int)strlen(TmpTxt), &width, &height);
+ if(width > (pcw + iround(o->hres/20.0))) TmpTxt[strlen(TmpTxt)-1] = 0;
+ }while(width > (pcw + ipad));
+ break;
+ case ET_ERROR:
+ rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "#ERROR"); break;
+ default:
+ rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "#VALUE"); break;
+ }
+ iy = pp_pos.y + pch + (pch>>1) + j * pch;
+ o->SetTextSpec(&td); o->oTextOut(ix, iy, TmpTxt, 0);
+ grid[0].y = grid[1].y = iy+(pch>>1); grid[2].y = grid[1].y - pch;
+ grid[0].x -= ipad; grid[1].x = grid[2].x = grid[0].x + pcw;
+ o->SetLine(&Line1); o->oPolyline(grid, 3, 0L);
+ grid[0].x += ipad;
+ }
+ }
+ }
+ //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 + pgw + iround(o->hres/3.5);
+ iy = (l+2)*pch;
+ if(mode == 2 && (margin.left + ix + pfw + pgw) < (rc.right-margin.right)) {
+ margin.left += pfw + k*pcw + iround(o->hres/3.5);
+ bContinue = true;
+ }
+ else if(mode == 1 && (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);
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "page %d", cpages++);
+#else
+ sprintf(TmpTxt, "page %d", cpages++);
+#endif
+ o->oTextOut(rc.right-margin.right, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
+ tdp.Align = TXA_HCENTER | TXA_VCENTER; o->SetTextSpec(&tdp);
+#ifdef USE_WIN_SECURE
+ ctime_s(TmpTxt, 50, &ti); TmpTxt[24] = 0;
+#else
+ sprintf(TmpTxt, "%s", ctime(&ti)); TmpTxt[24] = 0;
+#endif
+ o->oTextOut((rc.right-rc.left)>>1, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
+ tdp.Align = TXA_HLEFT | TXA_VCENTER; o->SetTextSpec(&tdp);
+ i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "RLPlot ");
+ rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, 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);
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "page %d", cpages++);
+#else
+ sprintf(TmpTxt, "page %d", cpages++);
+#endif
+ o->oTextOut(rc.right-margin.right, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
+ tdp.Align = TXA_HCENTER | TXA_VCENTER; o->SetTextSpec(&tdp);
+#ifdef USE_WIN_SECURE
+ ctime_s(TmpTxt, 50, &ti); TmpTxt[24] = 0;
+#else
+ sprintf(TmpTxt, "%s", ctime(&ti)); TmpTxt[24] = 0;
+#endif
+ o->oTextOut((rc.right-rc.left)>>1, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
+ tdp.Align = TXA_HLEFT | TXA_VCENTER; o->SetTextSpec(&tdp);
+ i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "RLPlot ");
+ rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, 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, newsize;
+ int i;
+
+ for(i = 0; i < NumGraphs; i++) if(g[i]) {
+ if((pg = (unsigned char*)GraphToMem(g[i], &cb)) && cb) {
+ newsize = *cbd + cb + 100;
+ *ptr = (unsigned char*)realloc(*ptr, newsize);
+ *cbd += rlp_strcpy((char*)(*ptr)+*cbd, 20, "<Graph><![CDATA[\n");
+ memcpy(*ptr+ *cbd, pg, cb); *cbd += cb;
+ *cbd += rlp_strcpy((char*)(*ptr)+*cbd, 20, "]]>\n</Graph>\n");
+ if(pg) free(pg); pg = 0L; cb = 0;
+ }
+ }
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// This data object is a spreadsheet
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class SpreadData:public DataObj{
+typedef struct _pos_info {
+ POINT ssOrg, currpos;
+ void *CurrText;};
+
+public:
+ SpreadData(GraphObj *par);
+ ~SpreadData();
+ bool Init(int nRows, int nCols);
+ bool mpos2dpos(POINT *mp, POINT *dp, bool can_scroll);
+ bool Select(POINT *p);
+ void MarkRange(char *range, POINT *cp = 0L);
+ void HideMark(bool cclp);
+ bool WriteData(char *FileName);
+ bool AddCols(int nCols);
+ bool AddRows(int nRows);
+ bool ChangeSize(int nCols, int nRows, bool bUndo);
+ bool DeleteCols();
+ bool InsertCols();
+ bool DeleteRows();
+ bool InsertRows();
+ void DoPlot(anyOutput *o);
+ bool DelRange();
+ bool PasteRange(int cmd, char *txt);
+ bool InitCopy(int cmd, void *tmpl, anyOutput *o);
+ bool SavePos();
+ 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, DWORD undo_flags = 0L);
+ bool ReadTSV(char *file, unsigned char *buffer, int type);
+ bool MemList(unsigned char **ptr, int type);
+
+private:
+ int CellHeight, CellWidth, FirstWidth, mrk_offs;
+ RECT cp_src_rec; //bounding rectangle for copy range
+ bool bActive, new_mark, bCopyCut, bUpdate, isRowMark, isColMark;
+ POINT currpos, currpos2;
+ anyOutput *w;
+ SpreadWin *Disp;
+ GraphObj *g_parent;
+ EditText *et_racc;
+ char *m_range, *c_range; //mark and copy ranges
+ char *err_msg, *last_err; //error message
+ char *rlw_file; //use this name for save
+ _pos_info pos_info; //save position settings
+};
+
+SpreadData::SpreadData(GraphObj *par)
+{
+ Disp = 0L; m_range = 0L; c_range = 0L; w = 0L; err_msg=last_err=rlw_file = 0L;
+ g_parent = par; CellWidth = 76; CellHeight = 19; FirstWidth = 32;
+ et_racc = 0L; currpos.x = currpos.y = mrk_offs = 0;
+ r_disp = 60; c_disp = 40;
+ bActive = bCopyCut = bUpdate = isRowMark = isColMark = false;
+ 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, false);
+ }
+ pos_info.currpos.x = currpos.x; pos_info.currpos.y = currpos.y;
+ pos_info.CurrText = CurrText;
+}
+
+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;
+ if(rlw_file) free(rlw_file); rlw_file = 0L;
+}
+
+bool
+SpreadData::Init(int nRows, int nCols)
+{
+ int i, j;
+ RECT rc;
+ RangeInfo *o_ri;
+
+ cRows = nRows; cCols = nCols; currpos.x = currpos.y = 0;
+ new_mark = bCopyCut = false; if(w && m_range) HideMark(true);
+ bUpdate = true;
+ while(ri->Type()) {
+ o_ri = ri; ri = ri->Next(); delete(o_ri);
+ }
+ if(!Disp) {
+ Disp = new SpreadWin(g_parent, this);
+ w = Disp->w;
+ if(w) {
+ CellWidth = w->un2ix(defs.GetSize(SIZE_CELLWIDTH));
+#ifdef _WINDOWS
+ CellHeight = w->un2iy(defs.GetSize(SIZE_CELLTEXT)/defs.ss_txt) + 2;
+#else
+ CellHeight = w->un2iy(defs.GetSize(SIZE_CELLTEXT)/(defs.ss_txt *0.7)) + 2;
+#endif
+ if(CellHeight < 12)CellHeight = 19; if(CellWidth < 40)CellWidth = 76;
+ FirstWidth = 32; w->GetSize(&rc);
+ r_disp = (rc.bottom-rc.top)/CellHeight;
+ c_disp = (rc.right-rc.left)/CellWidth+1;
+ }
+ else return false;
+ pos_info.ssOrg.x = Disp->ssOrg.x; pos_info.ssOrg.y = Disp->ssOrg.y;
+ pos_info.CurrText = CurrText;
+ }
+ if(etRows)FlushData();
+ etRows = (EditText ***)calloc (cRows, sizeof(EditText **));
+ if(etRows) for(i = 0; i < cRows; i++) {
+ etRows[i] = (EditText **)calloc(cCols, sizeof(EditText *));
+ if(etRows[i]) for(j = 0; j < cCols; j++) {
+#ifdef _DEBUG
+ char text[20];
+#ifdef USE_WIN_SECURE
+ sprintf_s (text, 20, "%.2f", i*10.0 + j);
+#else
+ sprintf (text, "%.2f", i*10.0 + j);
+#endif
+ etRows[i][j] = new EditText(this, text, i, j);
+#else
+ etRows[i][j] = new EditText(this, 0L, i, j);
+#endif
+ }
+ }
+ if (LoadFile) {
+ rlp_strcpy(TmpTxt, TMP_TXT_SIZE, LoadFile); //we will reenter by recursion !
+ free(LoadFile);
+ LoadFile = 0L;
+ Disp->Command(CMD_DROPFILE, TmpTxt, w);
+ }
+ else DoPlot(w);
+ return true;
+}
+
+bool
+SpreadData::mpos2dpos(POINT *mp, POINT *dp, bool can_scroll)
+{
+ int mx;
+
+ CurrGO = 0L;
+ dp->y = (mp->y - w->MenuHeight - CellHeight)/CellHeight + Disp->ssOrg.y;
+ dp->x = Disp->ssOrg.x;
+ for(mx = mp->x - ri->GetFirstWidth() - ri->GetWidth(dp->x); mx > 0; dp->x++, mx -= ri->GetWidth(dp->x));
+ if(can_scroll) {
+ if(dp->x < cCols && mp->x < (ri->GetFirstWidth()+10) && mp->x > ri->GetFirstWidth() && Disp->ssOrg.x >0) {
+ Disp->ssOrg.x -= 1;
+ if(CurrText) CurrText->Update(2, w, mp); CurrText = 0L;
+ Disp->Command(CMD_SETSCROLL, 0L, w);
+ }
+ if(mp->y < (w->MenuHeight + CellHeight+9) && 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);
+ }
+ 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);
+ }
+ 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); CurrText = 0L;
+ }
+ }
+ 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);
+ Disp->Command(CMD_CURRPOS, &currpos, w);
+ if(CurrText->isFormula() && CurrText->hasMark()) et_racc = CurrText;
+ return true;
+ }
+ if(!(mpos2dpos(p, &currpos, false)))return false;
+ 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);
+ }
+ Disp->Command(CMD_CURRPOS, &currpos, w);
+ return true;
+ }
+ }
+ if(CurrText) CurrText->Update(2, w, p); CurrText = 0L;
+ return false;
+}
+
+void
+SpreadData::MarkRange(char *range, POINT *cp)
+{
+ AccRange *nr, *oldr;
+ int r, c, cb;
+
+ 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) && r < cRows && c >= Disp->ssOrg.x
+ && c < (c_disp + Disp->ssOrg.x) && c < cCols && !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) && r < cRows && c < cCols)
+ etRows[r][c]->Mark(w, etRows[r][c] != CurrText ? 2 : 3);
+ }
+ }
+ if(range && (m_range = (char*)realloc(m_range, cb = ((int)strlen(range)+6)))) rlp_strcpy(m_range, cb, range);
+ else if (m_range) m_range[0] = 0;
+ if(oldr) delete(oldr); if(nr) delete(nr);
+ new_mark = true; Disp->MarkButtons(m_range, cp);
+}
+
+void
+SpreadData::HideMark(bool cclp)
+{
+ if(cclp && c_range && c_range != m_range){
+ free(c_range); c_range = 0L;
+ }
+ if(m_range){
+ free(m_range); m_range = 0L;
+ DoPlot(w);
+ }
+ if(cclp) EmptyClip(); new_mark = false;
+ Disp->MarkButtons(m_range, 0L);
+}
+
+bool
+SpreadData::WriteData(char *FileName)
+{
+ FILE *File;
+ int i, j;
+ unsigned char *buff = 0L;
+ anyResult res;
+ bool bErr = false;
+
+ if(!cRows || !cCols || !etRows) return false;
+ if(!FileName) FileName = rlw_file;
+ if(FileName && FileName[0]) BackupFile(FileName);
+ else return false;
+#ifdef USE_WIN_SECURE
+ if(fopen_s(&File, FileName, "w")) {
+#else
+ if(!(File = fopen(FileName, "w"))) {
+#endif
+ ErrorBox("An error occured during write,\n\nplease try again!");
+ return false;
+ }
+ HideMark(true);
+ i = (int)strlen(FileName);
+ //test for xml extension
+ if(!strcmp(".xml", FileName+i-4) || !strcmp(".XML", FileName+i-4)) {
+ MemList(&buff, FF_XML);
+ if(buff){
+ if(fprintf(File, "%s", buff) <= 0) bErr = true;
+ 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){
+ if(fprintf(File, "%s", buff) <= 0) bErr = true;
+ 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){
+ if(rlw_file != FileName) {
+ if(rlw_file) free(rlw_file);
+ rlw_file = (char*)memdup(FileName, (int)strlen(FileName)+1, 0);
+ }
+ if(fprintf(File, "%s", buff) <= 0) bErr = true;
+ free(buff); fclose(File);
+ return true;
+ }
+ return false;
+ }
+ //test for slk extension
+ if(!strcmp(".slk", FileName+i-4) || !strcmp(".SLK", FileName+i-4)) {
+ MemList(&buff, FF_SYLK);
+ if(buff){
+ if(fprintf(File, "%s", buff) <= 0) bErr = true;
+ 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]->GetResult(&res, false); TranslateResult(&res);
+ switch(res.type) {
+ case ET_TEXT:
+ fprintf(File, "\"%s\"", res.text);
+ break;
+ case ET_VALUE: case ET_DATE: case ET_TIME:
+ case ET_DATETIME: case ET_BOOL:
+ fprintf(File, "%s", res.text);
+ break;
+ }
+ }
+ if(j < (cCols-1)) fprintf(File, ", ");
+ }
+ if(fprintf(File, "\n") <= 0) bErr = true;
+ }
+ fclose(File);
+ if(bErr) ErrorBox("An error occured during write,\n\nplease try again!");
+ return true;
+}
+
+bool
+SpreadData::ReadData(char *FileName, unsigned char *buffer, int type)
+{
+ int i, j;
+ char ItemText[20];
+ bool success;
+
+ if(FileName) { //read disk file
+ if(!Disp->Command(CMD_CAN_CLOSE, 0L, 0L))return false;
+ 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)){
+ Disp->Command(CMD_DELGRAPH, 0L, w);
+ if(ReadXML(FileName, buffer, type, 0L)){
+ if(0 == strcmp(".rlw", FileName+strlen(FileName)-4) ||
+ 0 == strcmp(".RLW", FileName+strlen(FileName)-4)) {
+ if(rlw_file) free(rlw_file);
+ rlw_file = (char*)memdup(FileName, (int)strlen(FileName)+1, 0);
+ }
+ return true;
+ }
+ return false;
+ }
+ if(0 == strcmp(".tsv", FileName+strlen(FileName)-4) ||
+ 0 == strcmp(".TSV", FileName+strlen(FileName)-4)){
+ return ReadTSV(FileName, buffer, type);
+ }
+ if(!(Cache = new ReadCache())) return false;
+ if(! Cache->Open(FileName)) {
+ delete Cache;
+ i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, "Error open data file\n\"");
+ i += rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, FileName);
+ i += rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, "\"\n");
+ 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, 0L);
+ 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;
+ 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]) goto ReadError;
+ if(ItemText[0] == '"') {
+ rmquot(ItemText);
+ etRows[i][j]->SetText(ItemText);
+ etRows[i][j]->Update(20, 0L, 0L);
+ }
+ else if(ItemText[0]){
+ etRows[i][j]->SetText(ItemText);
+ etRows[i][j]->Update(10, 0L, 0L);
+ }
+ else etRows[i][j]->SetText("");
+ j++;
+ }
+ if(!success && !Cache->IsEOF()) {i++; j = 0;} //eol
+ }while (ItemText[0] || !Cache->IsEOF()); //eof
+ Cache->Close(); delete Cache; Cache = 0L;
+ Disp->ssOrg.x = Disp->ssOrg.y = 0;
+ bUpdate = true;
+ return true;
+
+ReadError:
+ Cache->Close(); delete Cache; Cache = 0L;
+ return false;
+
+}
+
+bool
+SpreadData::AddCols(int nCols)
+{
+ EditText **NewRow;
+ int i, j;
+
+ if (nCols <= cCols || !etRows || !etRows[0] || !etRows[0][cCols-1]) return false;
+ for(i = 0; i < cRows; i++) {
+ if(NewRow = (EditText **)realloc(etRows[i], nCols * sizeof(EditText*))){
+ for(j = cCols; j < nCols; j++) {
+ NewRow[j] = new EditText(this, 0L, i, j);
+ }
+ etRows[i] = NewRow;
+ }
+ else return false; //memory allocation error
+ }
+ cCols = nCols;
+ return true;
+}
+
+bool
+SpreadData::AddRows(int nRows)
+{
+ int i, j;
+ EditText ***NewRows;
+
+ if (nRows <= cRows || !etRows || !etRows[cRows-1] || !etRows[cRows-1][0] ) 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, 0L, i, j);
+ }
+ else { //memory allocation error
+ cRows = i-1;
+ return false;
+ }
+ }
+ 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(c_range){
+ free(c_range); c_range = 0L; EmptyClip();
+ }
+ if(bUndo) Undo.DataObject(Disp, w, this, 0L, 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) {
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "%d00", nRows);
+#else
+ sprintf(TmpTxt, "%d00", nRows);
+#endif
+ w->oGetTextExtent(TmpTxt, 0, &i, &j);
+ if(i > FirstWidth) FirstWidth = i;
+ Disp->Command(CMD_SETSCROLL, 0L, w);
+ }
+ return RetVal;
+}
+
+bool
+SpreadData::DeleteCols()
+{
+ int i, j, r0, c0, c1, c2, cn, dc, nc;
+ RECT rc;
+ lfPOINT *cs;
+
+ AccRange * ar;
+ if(!isColMark || !m_range || !m_range[0]){
+ InfoBox("No columns selected!");
+ return false;
+ }
+ if(c_range){
+ free(c_range); c_range = 0L; EmptyClip();
+ }
+ Undo.DataObject(Disp, w, this, 0L, 0L);
+ Undo.String(0L, &m_range, UNDO_CONTINUE);
+ if(!(ar = new AccRange(m_range))) return false;
+ ar->BoundRec(&rc);
+ if(!(cs = (lfPOINT*)malloc((rc.right-rc.left+2)*sizeof(lfPOINT)))) {
+ delete ar; return false;
+ }
+ if(!(ar->GetFirst(&c0, &r0))) {
+ free(cs); delete ar; return false;
+ }
+ ar->NextCol(&c1); cn = c1; nc = 0;
+ Disp->Command(CMD_MRK_DIRTY, 0L, 0L);
+ do {
+ for(c0 = c1 = c2 = cn; ar->NextCol(&c2); ) {
+ if(c2 > c1+1 || c2 < c0) break;
+ c1 = c2;
+ }
+ dc = c1-c0+1; cn = c2;
+ cs[nc].fx = c0; cs[nc].fy = c1; nc++;
+ }while(c2!=c1);
+ SortFpArray(nc, cs); nc--;
+ do {
+ c0 = (int)cs[nc].fx; c1 = (int)cs[nc].fy; dc = c1-c0+1;
+ for(i = 0; i < cRows; i++) {
+ for(j = c0+dc; j <cCols; j++) {
+ if(etRows && etRows[i] && etRows[i][j] && etRows[i][j-dc]) {
+ switch(etRows[i][j]->type) {
+ default:
+ etRows[i][j-dc]->SetText(etRows[i][j]->text);
+ break;
+ case ET_VALUE:
+ etRows[i][j-dc]->SetText(etRows[i][j]->text);
+ etRows[i][j-dc]->Value = etRows[i][j]->Value;
+ etRows[i][j-dc]->type = ET_VALUE;
+ break;
+ case ET_FORMULA:
+ MoveFormula(this, etRows[i][j]->text, TmpTxt, TMP_TXT_SIZE, -dc, 0, -1, c0);
+ etRows[i][j-dc]->SetText(TmpTxt); etRows[i][j]->type = ET_FORMULA;
+ break;
+ }
+ }
+ }
+ }
+ for(i = 0; i < cRows; i++) {
+ if(etRows[i]){
+ for(j = cCols-dc; j < cCols; j++) if(etRows[i][j]) {
+ delete(etRows[i][j]);
+ etRows[i][j] = 0L;
+ }
+ }
+ }
+ cCols -= dc;
+ MoveFormula(this, m_range, TmpTxt, TMP_TXT_SIZE, -dc, 0, -1, c0+1); free(m_range);
+ m_range = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0); nc--;
+ for(i = 0; i < c0; i++) for(j = 0; j < c0; j++) {
+ if(etRows && etRows[i] && etRows[i][j] && etRows[i][j]->type == ET_FORMULA) {
+ MoveFormula(this, etRows[i][j]->text, TmpTxt, TMP_TXT_SIZE, -dc, 0, -1, c0);
+ etRows[i][j]->SetText(TmpTxt); etRows[i][j]->type = ET_FORMULA;
+ }
+ }
+ }while(nc >= 0);
+ delete ar;
+ Disp->Command(CMD_SETSCROLL, 0L, w); Disp->Command(CMD_MRK_DIRTY, 0L, w);
+ return true;
+}
+
+bool
+SpreadData::InsertCols()
+{
+ int i, j, r0, c0, c1, c2, cn, dc, nc;
+ RECT rc;
+ lfPOINT *cs;
+
+ AccRange * ar;
+ if(!isColMark || !m_range || !m_range[0]){
+ InfoBox("No columns selected!");
+ return false;
+ }
+ if(c_range){
+ free(c_range); c_range = 0L; EmptyClip();
+ }
+ Undo.DataObject(Disp, w, this, 0L, 0L);
+ Undo.String(0L, &m_range, UNDO_CONTINUE);
+ if(!(ar = new AccRange(m_range))) return false;
+ ar->BoundRec(&rc);
+ if(!(cs = (lfPOINT*)malloc((rc.right-rc.left+2)*sizeof(lfPOINT)))) {
+ delete ar; return false;
+ }
+ if(!(ar->GetFirst(&c0, &r0))) {
+ free(cs); delete ar; return false;
+ }
+ ar->NextCol(&c1); cn = c1; nc = 0;
+ do {
+ for(c0 = c1 = c2 = cn; ar->NextCol(&c2); ) {
+ if(c2 > c1+1 || c2 < c0) break;
+ c1 = c2;
+ }
+ dc = c1-c0+1; cn = c2;
+ cs[nc].fx = c0; cs[nc].fy = c1; nc++;
+ }while(c2!=c1);
+ SortFpArray(nc, cs); nc--; Disp->Command(CMD_MRK_DIRTY, 0L, w);
+ do {
+ c0 = (int)cs[nc].fx; c1 = (int)cs[nc].fy; dc = c1-c0+1;
+ if(AddCols(cCols + dc)) for(i = 0; i < cRows; i++) {
+ for(j = cCols-1; j >= c0+dc; j--) {
+ if(etRows && etRows[i] && etRows[i][j] && etRows[i][j-dc]) {
+ switch(etRows[i][j-dc]->type) {
+ default:
+ etRows[i][j]->SetText(etRows[i][j-dc]->text);
+ break;
+ case ET_VALUE:
+ etRows[i][j]->SetText(etRows[i][j-dc]->text);
+ etRows[i][j]->Value = etRows[i][j-dc]->Value;
+ etRows[i][j]->type = ET_VALUE;
+ break;
+ case ET_FORMULA:
+ MoveFormula(this, etRows[i][j-dc]->text, TmpTxt, TMP_TXT_SIZE, dc, 0, -1, c0);
+ etRows[i][j]->SetText(TmpTxt); etRows[i][j]->type = ET_FORMULA;
+ break;
+ }
+ etRows[i][j-dc]->SetText("");
+ }
+ }
+ }
+ MoveFormula(this, m_range, TmpTxt, TMP_TXT_SIZE, dc, 0, -1, c0); free(m_range);
+ m_range = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0); nc--;
+ for(i = 0; i < c0; i++) for(j = 0; j < c0; j++) {
+ if(etRows && etRows[i] && etRows[i][j] && etRows[i][j]->type == ET_FORMULA) {
+ MoveFormula(this, etRows[i][j]->text, TmpTxt, TMP_TXT_SIZE, dc, 0, -1, c0);
+ etRows[i][j]->SetText(TmpTxt); etRows[i][j]->type = ET_FORMULA;
+ }
+ }
+ }while(nc >= 0);
+ delete ar;
+ Disp->Command(CMD_SETSCROLL, 0L, w); Disp->Command(CMD_MRK_DIRTY, 0L, w);
+ return true;
+}
+
+bool
+SpreadData::DeleteRows()
+{
+ int i, j, r0, c0, r1, r2, rn, dr, nr;
+ AccRange * ar;
+ RECT rc;
+ lfPOINT *rs;
+
+ if(!isRowMark || !m_range || !m_range[0]){
+ InfoBox("No rows selected!");
+ return false;
+ }
+ if(c_range){
+ free(c_range); c_range = 0L; EmptyClip();
+ }
+ Undo.DataObject(Disp, w, this, 0L, 0L);
+ Undo.String(0L, &m_range, UNDO_CONTINUE);
+ if(!(ar = new AccRange(m_range))) return false;
+ ar->BoundRec(&rc);
+ if(!(rs = (lfPOINT*)malloc((rc.bottom-rc.top+2)*sizeof(lfPOINT)))) {
+ delete ar; return false;
+ }
+ if(!(ar->GetFirst(&c0, &r0))) {
+ free(rs); delete ar; return false;
+ }
+ ar->NextRow(&r1); rn = r1; nr = 0;
+ Disp->Command(CMD_MRK_DIRTY, 0L, w);
+ do {
+ for(r0 = r1 = r2 = rn;ar->NextRow(&r2); ) {
+ if(r2 > r1+1 || r2 < r0) break;
+ r1 = r2;
+ }
+ dr = r1-r0+1; rn = r2;
+ rs[nr].fx = r0; rs[nr].fy = r1; nr++;
+ }while(r2!=r1);
+ SortFpArray(nr, rs); nr--;
+ do {
+ r0 = (int)rs[nr].fx; r1 = (int)rs[nr].fy; dr = r1-r0+1;
+ for(i = r0+dr; i < cRows; i++) {
+ for(j = 0; j < cCols; j++) {
+ if(etRows && etRows[i-dr] && etRows[i-dr][j] && etRows[i] && etRows[i][j]) {
+ switch(etRows[i][j]->type) {
+ default:
+ etRows[i-dr][j]->SetText(etRows[i][j]->text);
+ break;
+ case ET_VALUE:
+ etRows[i-dr][j]->SetText(etRows[i][j]->text);
+ etRows[i-dr][j]->Value = etRows[i][j]->Value;
+ etRows[i-dr][j]->type = ET_VALUE;
+ break;
+ case ET_FORMULA:
+ MoveFormula(this, etRows[i][j]->text, TmpTxt, TMP_TXT_SIZE, 0, -dr, r0, -1);
+ etRows[i-dr][j]->SetText(TmpTxt); etRows[i-dr][j]->type = ET_FORMULA;
+ break;
+ }
+ }
+ }
+ }
+ for(i = cRows-1; i >= cRows-dr; i--) {
+ if(etRows[i]){
+ for(j = 0; j < cCols; j++) if(etRows[i][j]) delete(etRows[i][j]);
+ free(etRows[i]);
+ }
+ }
+ cRows -= dr;
+ MoveFormula(this, m_range, TmpTxt, TMP_TXT_SIZE, 0, -dr, r0+1, -1); free(m_range);
+ m_range = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0); nr--;
+ for(i = 0; i < r0; i++) for(j = 0; j < cCols; j++) {
+ if(etRows && etRows[i] && etRows[i][j] && etRows[i][j]->type == ET_FORMULA) {
+ MoveFormula(this, etRows[i][j]->text, TmpTxt, TMP_TXT_SIZE, 0, -dr, r0, -1);
+ etRows[i][j]->SetText(TmpTxt); etRows[i][j]->type = ET_FORMULA;
+ }
+ }
+ }while(nr >= 0);
+ delete ar;
+ if(w) {
+ Disp->Command(CMD_SETSCROLL, 0L, w); Disp->Command(CMD_MRK_DIRTY, 0L, w);
+ }
+ return true;
+}
+
+bool
+SpreadData::InsertRows()
+{
+ int i, j, r0, c0, r1, r2, rn, dr, nr;
+ AccRange * ar;
+ RECT rc;
+ lfPOINT *rs;
+
+ if(!isRowMark || !m_range || !m_range[0]){
+ InfoBox("No rows selected!");
+ return false;
+ }
+ if(c_range){
+ free(c_range); c_range = 0L; EmptyClip();
+ }
+ Undo.DataObject(Disp, w, this, 0L, 0L);
+ Undo.String(0L, &m_range, UNDO_CONTINUE);
+ if(!(ar = new AccRange(m_range))) return false;
+ ar->BoundRec(&rc);
+ if(!(rs = (lfPOINT*)malloc((rc.bottom-rc.top+2)*sizeof(lfPOINT)))) {
+ delete ar; return false;
+ }
+ if(!(ar->GetFirst(&c0, &r0))) {
+ free(rs); delete ar; return false;
+ }
+ ar->NextRow(&r1); rn = r1; nr = 0;
+ Disp->Command(CMD_MRK_DIRTY, 0L, w);
+ do {
+ for(r0 = r1 = r2 = rn;ar->NextRow(&r2); ) {
+ if(r2 > r1+1 || r2 < r0) break;
+ r1 = r2;
+ }
+ dr = r1-r0+1; rn = r2;
+ rs[nr].fx = r0; rs[nr].fy = r1; nr++;
+ }while(r2!=r1);
+ SortFpArray(nr, rs); nr--;
+ do {
+ r0 = (int)rs[nr].fx; r1 = (int)rs[nr].fy; dr = r1-r0+1;
+ if(AddRows(cRows + dr)) for(i = cRows-1; i >= r0+dr; i--) {
+ for(j = 0; j < cCols; j++) {
+ if(etRows && etRows[i-dr] && etRows[i-dr][j] && etRows[i] && etRows[i][j]) {
+ switch(etRows[i-dr][j]->type) {
+ default:
+ etRows[i][j]->SetText(etRows[i-dr][j]->text);
+ break;
+ case ET_VALUE:
+ etRows[i][j]->SetText(etRows[i-dr][j]->text);
+ etRows[i][j]->Value = etRows[i-dr][j]->Value;
+ etRows[i][j]->type = ET_VALUE;
+ break;
+ case ET_FORMULA:
+ MoveFormula(this, etRows[i-dr][j]->text, TmpTxt, TMP_TXT_SIZE, 0, dr, r0, -1);
+ etRows[i][j]->SetText(TmpTxt); etRows[i][j]->type = ET_FORMULA;
+ break;
+ }
+ etRows[i-dr][j]->SetText("");
+ }
+ }
+ }
+ MoveFormula(this, m_range, TmpTxt, TMP_TXT_SIZE, 0, dr, r0, -1); free(m_range);
+ m_range = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0); nr--;
+ for(i = 0; i < r0; i++) for(j = 0; j < cCols; j++) {
+ if(etRows && etRows[i] && etRows[i][j] && etRows[i][j]->type == ET_FORMULA) {
+ MoveFormula(this, etRows[i][j]->text, TmpTxt, TMP_TXT_SIZE, 0, dr, r0, -1);
+ etRows[i][j]->SetText(TmpTxt); etRows[i][j]->type = ET_FORMULA;
+ }
+ }
+ }while(nr >= 0);
+ delete ar;
+ if(w) {
+#ifdef USE_WIN_SECURE
+ sprintf_s(TmpTxt, TMP_TXT_SIZE, "%d00", cRows);
+#else
+ sprintf(TmpTxt, "%d00", cRows);
+#endif
+ w->oGetTextExtent(TmpTxt, 0, &i, &j);
+ if(i > FirstWidth) FirstWidth = i;
+ Disp->Command(CMD_SETSCROLL, 0L, w); Disp->Command(CMD_MRK_DIRTY, 0L, w);
+ }
+ return true;
+}
+
+void
+SpreadData::DoPlot(anyOutput *o)
+{
+ RECT rc;
+ int i, j, r, c;
+ AccRange *ar;
+ double v;
+
+ if(!w || !Disp) return;
+ w->Erase(0x00e8e8e8L); if(!(w->ActualSize(&rc)))return;
+ w->SetTextSpec(&ssText); et_racc = 0L;
+ r_disp = (rc.bottom-rc.top)/CellHeight;
+ for(c = Disp->ssOrg.x, j=rc.left, c_disp = 1; c < cCols && j <= (rc.right-rc.left) && c_disp < cCols; c++, c_disp++) {
+ j += ri->GetWidth(c);
+ }
+ if(j >= (rc.right-rc.left))c_disp--;
+ Disp->ShowGrid(CellWidth, CellHeight, FirstWidth, &currpos);
+ rc.top = w->MenuHeight; rc.bottom = rc.top + CellHeight;
+ LockData(false, false);
+ if(bUpdate) {
+ for(i = cRows-1; i >= 0; i--) {
+ for(j = cCols-1; j >= 0; j--) etRows[i][j]->GetValue(&v);
+ }
+ bUpdate = false;
+ }
+ for(i = 0; i <= (cRows - Disp->ssOrg.y) && i <= r_disp; i++) {
+ rc.left = ri->GetFirstWidth(); rc.right = rc.left + ri->GetWidth(Disp->ssOrg.x);
+ rc.top += CellHeight; rc.bottom += CellHeight;
+ for(j = 0; j <= (cCols - Disp->ssOrg.x) && j <= c_disp; 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]->Update(2, 0L, 0L);
+ etRows[r][c]->Redraw(w, false);
+ }
+ rc.left += ri->GetWidth(Disp->ssOrg.x+j);
+ rc.right += ri->GetWidth(Disp->ssOrg.x+j+1);
+ }
+ }
+ if(CurrText && CurrText->row >= Disp->ssOrg.y && CurrText->row < (Disp->ssOrg.y + r_disp)
+ && CurrText->col >= Disp->ssOrg.x && CurrText->col < (Disp->ssOrg.x +c_disp))
+ CurrText->Update(1, w, 0L);
+ 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
+ && r < cRows && c < cCols
+ && c < (c_disp + Disp->ssOrg.x) && etRows[r] && etRows[r][c])
+ etRows[r][c]->Mark(w, etRows[r][c] != CurrText ? 2 : 3);
+ }
+ delete (ar);
+ }
+ LockData(false, false);
+ if(c_range) InitCopy(0, 0L, w); //move animated rectangle
+ if(!(w->ActualSize(&rc))) return;
+ rc.bottom += CellHeight; w->UpdateRect(&rc, false);
+ if(err_msg && (!last_err || strcmp(err_msg,last_err))) {
+ ErrorBox(last_err = err_msg);
+ }
+}
+
+bool
+SpreadData::DelRange()
+{
+ AccRange *ar;
+ int r, c;
+ RECT rec;
+
+ if(m_range && (ar = new AccRange(m_range)) && ar->GetFirst(&c, &r)) {
+ Disp->Command(CMD_MRK_DIRTY, 0L, w);
+ ar->BoundRec(&rec);
+ Undo.DataObject(Disp, w, this, &rec, 0L);
+ while(ar->GetNext(&c, &r)) {
+ if(r >= 0 && r < cRows && c >= 0 && c < cCols){
+ if(etRows[r][c] && etRows[r][c]->text) etRows[r][c]->SetText("");
+ }
+ }
+ delete (ar); HideTextCursor();
+ }
+ HideMark(false);
+ if(CurrText) CurrText->Update(1, w, 0L);
+ bCopyCut = false;
+ return true;
+}
+
+bool
+SpreadData::PasteRange(int cmd, char *txt)
+{
+ AccRange *cr;
+ int i, r, c;
+ RECT mrk_range;
+
+ if(new_mark && m_range && (cr = new AccRange(m_range)) && cr->GetFirst(&c, &r)) {
+ cr->BoundRec(&mrk_range); Disp->Command(CMD_MRK_DIRTY, 0L, w);
+ for(i = 0 ; cr->GetNext(&c, &r); i++) 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_SSV: ReadTSV(0L, (unsigned char*)txt, FF_SSV); break;
+ case CMD_PASTE_XML: ReadXML(0L, (unsigned char*)txt, FF_XML, i ? UNDO_CONTINUE : 0L); 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_SSV:
+ return ReadTSV(0L, (unsigned char*)txt, FF_SSV);
+ case CMD_PASTE_XML:
+ return ReadXML(0L, (unsigned char*)txt, FF_XML, 0L);
+ case CMD_PASTE_CSV:
+ return ReadData(0L, (unsigned char*)txt, FF_CSV);
+ }
+ return bCopyCut = false;
+}
+
+bool
+SpreadData::InitCopy(int cmd, void *tmpl, anyOutput *o)
+{
+ int r, c;
+ AccRange *ar;
+ RECT rc_band, rcCopy;
+ bool bRet = false;
+
+ rcCopy.left = rcCopy.top = 0;
+ rcCopy.bottom = cRows-1; rcCopy.right = cCols-1;
+ if(cmd) {
+ bCopyCut = (cmd == CMD_CUT);
+ new_mark = false;
+ if(m_range && m_range[0]) {
+ if(c_range) free(c_range);
+ c_range = (char*)memdup(m_range, (int)strlen(m_range)+1, 0);
+ if(c_range && (ar = new AccRange(c_range))) {
+ ar->BoundRec(&rcCopy);
+ delete ar; bRet = true;;
+ }
+ }
+ else if (CurrText) {
+ if(CurrText->hasMark()) return CurrText->Command(CMD_COPY, o, 0L);
+ else {
+ if(m_range = (char*)realloc(m_range, 40*sizeof(char)))
+ rlp_strcpy(m_range, 40, mkRangeRef(currpos.y, currpos.x, currpos.y, currpos.x));
+ DoPlot(o);
+ return InitCopy(cmd, tmpl, o);
+ }
+ }
+ }
+ if(bRet || !cmd) { //calculate animated mark
+ if(c_range && (ar = new AccRange(c_range))) {
+ ar->BoundRec(&rcCopy); delete ar;
+ }
+ 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(r >= cRows) r = cRows-1; if(c >= cCols) c = cRows -1;
+ if(etRows[r][c]){
+ rc_band.right = etRows[r][c]->GetX()+ri->GetWidth(c);
+ rc_band.bottom = etRows[r][c]->GetY()+CellHeight;
+ if(rc_band.left >= rc_band.right) rc_band.right = rc_band.left + CellWidth;
+ if(rc_band.top >= rc_band.bottom) rc_band.bottom = rc_band.top + CellHeight;
+ ShowCopyMark(o, &rc_band, 1);
+ }
+ }
+ return bRet;
+}
+
+bool
+SpreadData::SavePos()
+{
+ bool bRet = false;
+
+ if(pos_info.currpos.x != currpos.x || pos_info.currpos.y != pos_info.currpos.y
+ || CurrText != pos_info.CurrText) {
+ Undo.Point(Disp, &currpos, w, UNDO_CONTINUE);
+ Undo.VoidPtr(Disp, (void**)&CurrText, 0L, 0L, UNDO_CONTINUE);
+ }
+ if(pos_info.ssOrg.x != Disp->ssOrg.x || pos_info.ssOrg.y != Disp->ssOrg.y) {
+ Swap(pos_info.ssOrg.x, Disp->ssOrg.x ); Swap(pos_info.ssOrg.y, Disp->ssOrg.y );
+ Undo.Point(Disp, &Disp->ssOrg, w, UNDO_CONTINUE);
+ Swap(pos_info.ssOrg.x, Disp->ssOrg.x ); Swap(pos_info.ssOrg.y, Disp->ssOrg.y );
+ }
+ pos_info.currpos.x = currpos.x; pos_info.currpos.y = currpos.y;
+ pos_info.ssOrg.x = Disp->ssOrg.x; pos_info.ssOrg.y = Disp->ssOrg.y;
+ pos_info.CurrText = CurrText;
+ return bRet;
+}
+
+bool
+SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
+{
+ int i;
+ static int move_cr = CMD_CURRDOWN;
+ MouseEvent *mev;
+ POINT p, cp;
+ RECT rc;
+
+ 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 || p.y < (w->MenuHeight+CellHeight)) {
+ if(!(mpos2dpos(&p, &cp, (mev->StateFlags & 1) == 1))) return false;
+ if(cp.y >= cRows || cp.x >= cCols || cp.y < 0 || cp.x < 0) return false;
+ }
+ else cp.x = cp.y = 0;
+ switch (mev->Action) {
+ case MOUSE_LBDOWN:
+ if(m_range && (mev->StateFlags & 0x18)) mrk_offs = (int)strlen(m_range);
+ else mrk_offs = 0;
+ bActive = true; new_mark = false;
+ if(!et_racc && 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_MOVE:
+ if(p.y < (w->MenuHeight+CellHeight)) {
+ if(Disp->Command(CMD_COL_MOUSE, tmpl, w)) return true;
+ }
+ else w->MouseCursor(MC_ARROW, false);
+ case MOUSE_LBDOUBLECLICK:
+ 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(!et_racc && !m_range && CurrText) {
+ CurrText->Update(2, w, &p); CurrText = 0L;
+ }
+ if(mrk_offs && m_range && m_range[0]){
+ mrk_offs = rlp_strcpy(TmpTxt, mrk_offs+1, m_range);
+ }
+ else mrk_offs = 0;
+ if(p.x < FirstWidth || p.y < (w->MenuHeight+CellHeight)) {
+ if(mrk_offs && TmpTxt[mrk_offs-1] != ';')TmpTxt[mrk_offs++] = ';';
+ rlp_strcpy(TmpTxt+mrk_offs, TMP_TXT_SIZE - mrk_offs, mkRangeRef(
+ p.y < (w->MenuHeight+CellHeight) ? 0 : currpos.y, p.x < FirstWidth ? 0 : currpos.x,
+ p.y < (w->MenuHeight+CellHeight) ? cRows : cp.y, p.x < FirstWidth ? cCols-1 : cp.x));
+ }
+ else {
+ if(mrk_offs && TmpTxt[mrk_offs-1] != ';')TmpTxt[mrk_offs++] = ';';
+ rlp_strcpy(TmpTxt+mrk_offs, TMP_TXT_SIZE - mrk_offs, mkRangeRef(currpos.y, currpos.x, cp.y, cp.x));
+ }
+ if(!CurrText || et_racc)MarkRange(TmpTxt, &cp);
+ 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.y < (w->MenuHeight+CellHeight)) {
+ if(Disp->Command(CMD_COL_MOUSE, tmpl, w)) return true;
+ }
+ isRowMark = p.x < FirstWidth;
+ isColMark = p.y < (w->MenuHeight+CellHeight);
+ if(isRowMark || isColMark) {
+ if(p.x < FirstWidth) {
+ currpos.x = 0; cp.x = cCols-1;
+ }
+ if(p.y < (w->MenuHeight+CellHeight)) {
+ currpos.y = 0; cp.y = cRows-1;
+ }
+ if(mrk_offs && m_range && m_range[0]){
+ mrk_offs = rlp_strcpy(TmpTxt, mrk_offs+1, m_range);
+ }
+ else mrk_offs = 0;
+ if(mrk_offs && TmpTxt[mrk_offs-1] != ';')TmpTxt[mrk_offs++] = ';';
+ rlp_strcpy(TmpTxt+mrk_offs, TMP_TXT_SIZE - mrk_offs, mkRangeRef(currpos.y, currpos.x, cp.y, cp.x));
+ MarkRange(TmpTxt); currpos2.x = cp.x; currpos2.y = cp.y + 1;
+ }
+ else if((m_range) && !new_mark) HideMark(false);
+ if(et_racc && !et_racc->isInRect(&p)) {
+ CurrText = et_racc;
+ if(m_range && m_range[0] && (currpos.x != cp.x || currpos.y != cp.y)) {
+ CurrText->Command(CMD_ADDTXT, o, (DataObj*) m_range);
+ }
+ else {
+ m_range = (char*)realloc(m_range, 40*sizeof(char));
+ rlp_strcpy(m_range, 40, mkCellRef(currpos.y, currpos.x));
+ CurrText->Command(CMD_ADDTXT, o, (DataObj*) m_range);
+ }
+ }
+ else 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: case CMD_PASTE_SSV:
+ bUpdate = true; Disp->Command(CMD_MRK_DIRTY, 0L, 0L);
+ if(PasteRange(cmd, (char*)tmpl))
+ return Disp->Command(CMD_SETSCROLL, 0L, w);
+ return false;
+ case CMD_HIDEMARK:
+ if(c_range){
+ free(c_range); c_range = 0L; return true;
+ }
+ return false;
+ case CMD_GETFILENAME:
+ if(!tmpl) return false;
+ if(rlw_file && rlw_file[0]) {
+ if(rlp_strcpy((char*)tmpl, TMP_TXT_SIZE, rlw_file))return true;
+ else return false;
+ }
+ return false;
+ case CMD_ETRACC:
+ if(et_racc && tmpl && ((EditText*)tmpl)->parent != this) HideMark(false);
+ et_racc = (EditText*) tmpl;
+ if(CurrText && CurrText->parent != this) CurrText = 0L;
+ return true;
+ 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:
+ if(err_msg && err_msg[0] && tmpl && *((char*)tmpl)) {
+ if(!(strcmp((char*)tmpl, "parse error")))return false; //parse error has lowest priority
+ }
+ if(!tmpl && err_msg && err_msg[0] && strcmp(err_msg, "parse error")) return false;
+ err_msg = (char*)tmpl;
+ break;
+ case CMD_UPDATE:
+ bUpdate = true;
+ break;
+ case CMD_SAVEPOS:
+ return SavePos();
+ case CMD_CLEAR_ERROR:
+ err_msg = last_err = 0L;
+ break;
+ case CMD_TOOLMODE: //ESC pressed
+ HideMark(true);
+ if(CurrText){
+ CurrText->Update(2, w, 0L); CurrText->Update(1, w, 0L);
+ }
+ et_racc = 0L; w->MouseCursor(MC_ARROW, true);
+ break;
+ case CMD_UPDHISTORY:
+ if(w) w->FileHistory();
+ break;
+ case CMD_MRK_DIRTY:
+ move_cr = CMD_CURRDOWN;
+ err_msg = last_err = 0L;
+ 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; Disp->Command(CMD_SETSCROLL, 0L, w);
+ }
+ 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; Disp->Command(CMD_SETSCROLL, 0L, w);
+ }
+ if(currpos.x < Disp->ssOrg.x) {
+ Disp->ssOrg.x = currpos.x; Disp->Command(CMD_SETSCROLL, 0L, w);
+ }
+ else if(currpos.x > (Disp->ssOrg.x + c_disp -3) && (CurrText->GetRX()+ 10) > Disp->currRC.right ) {
+ Disp->ssOrg.x = currpos.x - (c_disp-3);
+ if(Disp->ssOrg.x < 0) Disp->ssOrg.x = 0; Disp->Command(CMD_SETSCROLL, 0L, w);
+ }
+ currpos2.x = currpos.x; currpos2.y = currpos.y;
+ i = *((int*)tmpl);
+ Disp->Command(CMD_CURRPOS, &currpos, w);
+ if(i == 27) return Command(CMD_TOOLMODE, tmpl, o);
+ if(i !=3 && i != 22 && i != 24 && i != 26) HideMark(true); //Do not hide upon ^C, ^V, ^X, ^Z
+ 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);;
+ }
+ Disp->Command(CMD_CURRPOS, &currpos, w);
+ break;
+ case CMD_SHIFTUP:
+ if(Disp->ssOrg.y && currpos2.y <= Disp->ssOrg.y) {
+ Disp->ssOrg.y --; Disp->Command(CMD_SETSCROLL, 0L, w);
+ }
+ currpos2.y -= 2;
+ case CMD_SHIFTDOWN:
+ if(cmd == CMD_SHIFTDOWN && r_disp > 3 && (currpos2.y-Disp->ssOrg.y) >= (r_disp-3)) {
+ Disp->ssOrg.y ++; Disp->Command(CMD_SETSCROLL, 0L, w);
+ }
+ currpos2.y ++;
+ if(currpos2.y >= cRows) currpos2.y --; if(currpos2.y < 0) currpos2.y ++;
+ //mark rectangular range
+ rlp_strcpy(TmpTxt, 40, mkRangeRef(currpos.y, currpos.x, currpos2.y, currpos2.x));
+ MarkRange(TmpTxt); HideTextCursor();
+ break;
+ case CMD_SHIFTRIGHT: case CMD_SHIFTLEFT:
+ if(!m_range && CurrText && CurrText->Command(cmd, w, this)) break;
+ if(cmd == CMD_SHIFTLEFT && c_disp > 3 && Disp->ssOrg.x && (currpos2.x-Disp->ssOrg.x) < 1) {
+ Disp->ssOrg.x --; Disp->Command(CMD_SETSCROLL, 0L, w);
+ }
+ if(cmd == CMD_SHIFTRIGHT && c_disp > 3 && (currpos2.x-Disp->ssOrg.x) >= (c_disp-3)) {
+ Disp->ssOrg.x ++; Disp->Command(CMD_SETSCROLL, 0L, w);
+ }
+ if(cmd == CMD_SHIFTLEFT) currpos2.x --;
+ else currpos2.x ++;
+ if(currpos2.x >= cCols) currpos2.x --; if(currpos2.x < 0) currpos2.x ++;
+ //mark rectangular range
+ rlp_strcpy(TmpTxt, 40, mkRangeRef(currpos.y, currpos.x, currpos2.y, currpos2.x));
+ MarkRange(TmpTxt); HideTextCursor();
+ break;
+ case CMD_SHPGUP:
+ if(Disp->ssOrg.y >0) {
+ Disp->ssOrg.y -= (r_disp-2);
+ if(Disp->ssOrg.y < 0) Disp->ssOrg.y = 0;
+ Disp->Command(CMD_SETSCROLL, 0L, w);
+ currpos2.y -= r_disp; if(currpos2.y < 0) currpos2.y = 0;
+ rlp_strcpy(TmpTxt, 40, mkRangeRef(currpos.y, currpos.x, currpos2.y, currpos2.x));
+ MarkRange(TmpTxt); HideTextCursor();
+ }
+ break;
+ case CMD_SHPGDOWN:
+ i = (Disp->ssOrg.y + 2*r_disp) < cRows ? r_disp-2 : cRows-r_disp - Disp->ssOrg.y+3;
+ if(i > 0) {
+ Disp->ssOrg.y += i; Disp->Command(CMD_SETSCROLL, 0L, w);
+ }
+ if(currpos2.y < (cRows-1)) {
+ currpos2.y += r_disp; if(currpos2.y >= cRows) currpos2.y = cRows-1;
+ //mark rectangular range
+ rlp_strcpy(TmpTxt, 40, mkRangeRef(currpos.y, currpos.x, currpos2.y, currpos2.x));
+ MarkRange(TmpTxt); HideTextCursor();
+ }
+ break;
+ case CMD_CURRIGHT: case CMD_CURRDOWN:
+ move_cr = cmd; w->ActualSize(&rc);
+ 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);
+ Disp->Command(CMD_CURRPOS, &currpos, w);
+ 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(CurrText && cmd == CMD_CURRIGHT && c_disp > 3 && ((currpos.x-Disp->ssOrg.x) >= (c_disp-1) || CurrText->GetRX() >= (rc.right-rc.left-10))) {
+ Disp->ssOrg.x ++; currpos.y ++; DoPlot(o);
+ 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);
+ }
+ Disp->Command(CMD_CURRPOS, &currpos, w);
+ HideMark(false);
+ currpos2.x = currpos.x; currpos2.y = currpos.y;
+ 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);
+ }
+ Disp->Command(CMD_CURRPOS, &currpos, w);
+ return true;
+ case CMD_UNDO:
+ if(w) {
+ w->MouseCursor(MC_WAIT, true);
+ Undo.Restore(true, w);
+ w->MouseCursor(MC_ARROW, true);
+ if(et_racc) {
+ CurrText = et_racc;
+ CurrText->Update(1, w, 0L);
+ }
+ }
+
+ return true;
+ case CMD_DELETE:
+ if(m_range) DelRange();
+ else if(CurrText) return CurrText->Command(cmd, o, this);
+ Disp->Command(CMD_CURRPOS, &currpos, w);
+ return true;
+ case CMD_QUERY_COPY: case CMD_CUT:
+ et_racc = 0L;
+ 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])) {
+ Undo.ValInt(Disp, &FirstWidth, UNDO_CONTINUE); Undo.ValInt(Disp, &CellWidth, UNDO_CONTINUE);
+ Undo.ValInt(Disp, &CellHeight, UNDO_CONTINUE); FirstWidth = ((int*)tmpl)[0];
+ CellWidth = ((int*)tmpl)[1]; CellHeight = ((int*)tmpl)[2];
+ }
+ break;
+ case CMD_TEXTSIZE:
+ if(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_MENUHEIGHT:
+ case CMD_DOPLOT: case CMD_REDRAW:
+ if(CurrText) CurrText->Update(2, 0L, 0L);
+ if(etRows && etRows[currpos.y] && currpos.y < cRows && currpos.x < cCols)
+ if(CurrText = etRows[currpos.y][currpos.x]) CurrText->Update(1,0L, 0L);
+ DoPlot(o);
+ break;
+ case CMD_FILLRANGE:
+ Undo.SetDisp(w);
+ if(FillSsRange(this, &m_range, Disp)) Disp->Command(CMD_MRK_DIRTY, 0L, o);
+ DoPlot(o);
+ Undo.SetDisp(w);
+ break;
+ case CMD_GETMARK:
+ if(tmpl && m_range && m_range[0]) {
+ *((char**)tmpl) = m_range;
+ return true;
+ }
+ return false;
+ case CMD_INSROW:
+ return InsertRows();
+ case CMD_INSCOL:
+ return InsertCols();
+ case CMD_DELROW:
+ return DeleteRows();
+ case CMD_DELCOL:
+ return DeleteCols();
+ }
+ return true;
+}
+
+bool
+SpreadData::ReadXML(char *file, unsigned char *buffer, int type, DWORD undo_flags)
+{
+ int i, row, col, tag, cpgr, spgr, ufl = 0;
+ bool bContinue, bRet = false, bUndo_done = false;
+ ReadCache *XMLcache;
+ POINT pt, mov;
+ char TmpTxt[1024], *tmp_range;
+ unsigned char *pgr = 0L;
+ RECT rc_undo;
+
+ if(file) {
+ if(!(XMLcache = new ReadCache())) return false;
+ if(! XMLcache->Open(file)) {
+ delete XMLcache;
+ i = rlp_strcpy(TmpTxt, 40, "Error open file\n\""); i = rlp_strcpy(TmpTxt+i, 200, file);
+ rlp_strcpy(TmpTxt+i, 2, "\""); ErrorBox(TmpTxt);
+ return false;
+ }
+ bUndo_done = true;
+ 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)){
+ if(!bUndo_done) {
+ rc_undo.left = currpos.x;
+ rc_undo.right = cp_src_rec.right - cp_src_rec.left + currpos.x;
+ rc_undo.top = currpos.y;
+ rc_undo.bottom = cp_src_rec.bottom - cp_src_rec.top + currpos.y;
+ if(ufl == 3) Undo.DataObject(Disp, w, this, &rc_undo, undo_flags);
+ bUndo_done = true;
+ }
+ tag = 1;
+ }
+ else if(!strcmp("<pos1", TmpTxt)) tag = 2;
+ else if(!strcmp("<pos2", TmpTxt)) tag = 3;
+ else if(!strcmp("<RLPl", TmpTxt)) {
+ do {
+ TmpTxt[i++] = XMLcache->Getc();
+ }while(TmpTxt[i-1] > 31 && TmpTxt[i-1] != '>');
+ TmpTxt[i] = 0;
+ row = col = 0;
+ if(TmpTxt[17] == '=' && TmpTxt[13] == 'r') {
+#ifdef USE_WIN_SECURE
+ sscanf_s(TmpTxt+19, "%d", &row);
+#else
+ sscanf(TmpTxt+19, "%d", &row);
+#endif
+ }
+ else break;
+ for(i = 20; TmpTxt[i] && TmpTxt[i] != '='; i++);
+#ifdef USE_WIN_SECURE
+ sscanf_s(TmpTxt+i+2, "%d", &col);
+#else
+ sscanf(TmpTxt+i+2, "%d", &col);
+#endif
+ if(row && col) {
+ AddCols(col); AddRows(row);
+ }
+ row = col = -1;
+ }
+ 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);
+ if(cpgr >20)OpenGraph(Disp, 0L, pgr, false);
+ 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;
+ ufl |= 1;
+ }
+ else if(tag ==3) {
+ cp_src_rec.right = col; cp_src_rec.bottom = row;
+ ufl |= 2;
+ }
+ 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; i++) {
+ if(!(TmpTxt[i] =XMLcache->Getc())) break;
+ if(i >1 && TmpTxt[i-2] == '<' && TmpTxt[i-1] == '/' && TmpTxt[i] == 't') break;
+ }
+ i -=2; 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] == '=' && (currpos.x || currpos.y || mov.x || mov.y)) {
+ MoveFormula(this, TmpTxt, TmpTxt, TMP_TXT_SIZE, currpos.x-mov.x, currpos.y-mov.y, -1, -1);
+ }
+ 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;
+ i = rlp_strcpy(TmpTxt, 200, "Error open file\n\"");
+ i += rlp_strcpy(TmpTxt+i, 200-i, file);
+ i += rlp_strcpy(TmpTxt+i, 200-i, "\"\n");
+ ErrorBox(TmpTxt);
+ return false;
+ }
+ if(!Init(1, 1)) goto TSVError;
+ etRows[0][0]->SetText("");
+ }
+ else if(buffer && (type == FF_TSV || type == FF_SSV)) {
+ 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;
+ case ' ':
+ if(type == FF_SSV) col ++; break;
+ }
+ }while(TmpTxt[0] && ((unsigned char)TmpTxt[0] < 33));
+ for(i = 1; ((unsigned char)(TmpTxt[i] = c = TSVcache->Getc()))>= (type == FF_SSV ? 33 : 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;
+ case ' ':
+ if(type == FF_SSV) col ++; break;
+ }
+ }
+ }while(!TSVcache->IsEOF());
+ bRet = true;
+TSVError:
+ TSVcache->Close();
+ delete TSVcache;
+ return bRet;
+}
+
+static void sylk_cell_ref(char** ptr, int *cbd, int *size, char *first, char* trail, int row, int col)
+{
+ if(first && first[0]) add_to_buff(ptr, cbd, size, first, 0);
+ add_to_buff(ptr, cbd, size, "Y", 1); add_int_to_buff(ptr, cbd, size, row+1, false, 0);
+ add_to_buff(ptr, cbd, size, ";X", 2); add_int_to_buff(ptr, cbd, size, col+1, false, 0);
+ if(trail && trail[0]) add_to_buff(ptr, cbd, size, trail, 0);
+}
+
+bool
+SpreadData::MemList(unsigned char **ptr, int type)
+{
+ int i, j, nc, nl;
+ int cbd = 0, size;
+ bool bLimit = true;
+ AccRange *ar;
+ anyResult res;
+ RECT rcCopy;
+
+ if(!(*ptr = (unsigned char *)malloc(size = 10000)))return false;
+ if (c_range && c_range[0]) {
+ ar = new AccRange(c_range); ar->BoundRec(&rcCopy);
+ if(bCopyCut) Undo.DataObject(Disp, w, this, &rcCopy, 0L);
+ }
+ else {
+ ar = 0L; rcCopy.left = rcCopy.top = 0;
+ rcCopy.right = cCols-1; rcCopy.bottom = cRows-1;
+ }
+ 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 = rlp_strcpy((char*)*ptr, size, "ID;PWXL;N;E\n"
+ "P;Pdd/mm/yyyy\nP;Phh:mm:ss\nP;Pdd/mm/yyyy hh:mm:ss\n");
+ else if(type == FF_XML) {
+ cbd = rlp_strcpy((char*)*ptr, 100, "<?xml version=\"1.0\"?><!DOCTYPE spreadsheet-snippet>"
+ "<spreadsheet-snippet rows=\"");
+ add_int_to_buff((char**)ptr, &cbd, &size, cRows, false, 0);
+ add_to_buff((char**)ptr, &cbd, &size, "\" columns=\"", 11);
+ add_int_to_buff((char**)ptr, &cbd, &size, cCols, false, 0);
+ add_to_buff((char**)ptr, &cbd, &size, "\">\n", 3);
+ if(rcCopy.left || rcCopy.top || rcCopy.bottom || rcCopy.right){
+ add_to_buff((char**)ptr, &cbd, &size, " <pos1 row=\"", 12);
+ add_int_to_buff((char**)ptr, &cbd, &size, rcCopy.top, false, 0);
+ add_to_buff((char**)ptr, &cbd, &size, "\" column=\"", 10);
+ add_int_to_buff((char**)ptr, &cbd, &size, rcCopy.left, false, 0);
+ add_to_buff((char**)ptr, &cbd, &size, "\"></pos1>\n <pos2 row=\"", 22);
+ add_int_to_buff((char**)ptr, &cbd, &size, rcCopy.bottom, false, 0);
+ add_to_buff((char**)ptr, &cbd, &size, "\" column=\"", 10);
+ add_int_to_buff((char**)ptr, &cbd, &size, rcCopy.right, false, 0);
+ add_to_buff((char**)ptr, &cbd, &size, "\"></pos2>\n", 10);
+ }
+ }
+ else if(type == FF_RLW) {
+ cbd = rlp_strcpy((char*)*ptr, size, "<?xml version=\"1.0\"?><!DOCTYPE RLPlot-workbook>\n<RLPlot-data rows=\"");
+ add_int_to_buff((char**)ptr, &cbd, &size, cRows, false, 0);
+ add_to_buff((char**)ptr, &cbd, &size, "\" columns=\"", 11);
+ add_int_to_buff((char**)ptr, &cbd, &size, cCols, false, 0);
+ add_to_buff((char**)ptr, &cbd, &size, "\">\n", 3);
+ }
+ for(nl =0, i = rcCopy.top; i <= rcCopy.bottom; i++, nl++) {
+ for(nc = 0, j = rcCopy.left; j <= rcCopy.right; j++, nc++) {
+ switch (type) {
+ case FF_TSV:
+ if(nl || nc) add_to_buff((char**)ptr, &cbd, &size, nc ? (char*)"\t" : (char*)"\n", 1);
+ if(etRows[i] && etRows[i][j]){
+ if((ar && ar->IsInRange(j,i)) || !ar) {
+ etRows[i][j]->GetResult(&res, false);
+ TranslateResult(&res);
+ add_to_buff((char**)ptr, &cbd, &size, res.text, 0);
+ }
+ }
+ break;
+ case FF_SYLK:
+ if(etRows[i] && etRows[i][j] && etRows[i][j]->text && ((ar && ar->IsInRange(j,i)) || !ar)){
+ etRows[i][j]->GetResult(&res, false);
+ TranslateResult(&res);
+ switch(res.type) {
+ case ET_VALUE: case ET_BOOL:
+ sylk_cell_ref((char**) ptr, &cbd, &size, "C;", ";K", nl, nc);
+ add_to_buff((char**)ptr, &cbd, &size, res.text, 0);
+ break;
+ case ET_DATE:
+ sylk_cell_ref((char**) ptr, &cbd, &size, "F;P0;FG0G;", "\nC;K", nl, nc);
+ add_dbl_to_buff((char**)ptr, &cbd, &size, res.value+1, false);
+ break;
+ case ET_DATETIME:
+ sylk_cell_ref((char**) ptr, &cbd, &size, "F;P2;FG0G;", "\nC;K", nl, nc);
+ add_dbl_to_buff((char**)ptr, &cbd, &size, res.value+1, false);
+ break;
+ case ET_TIME:
+ sylk_cell_ref((char**) ptr, &cbd, &size, "F;P1;FG0G;", "\nC;K", nl, nc);
+ add_dbl_to_buff((char**)ptr, &cbd, &size, res.value, false);
+ break;
+ case ET_TEXT:
+ sylk_cell_ref((char**) ptr, &cbd, &size, "C;", ";K\"", nl, nc);
+ add_to_buff((char**)ptr, &cbd, &size, res.text, 0);
+ add_to_buff((char**)ptr, &cbd, &size, "\"", 1);
+ break;
+ }
+ add_to_buff((char**)ptr, &cbd, &size, "\n", 1);
+ if(bCopyCut) etRows[i][j]->SetText("");
+ }
+ break;
+ case FF_RLW: case FF_XML:
+ if(etRows[i] && etRows[i][j] && etRows[i][j]->text && ((ar && ar->IsInRange(j,i)) || !ar)
+ && etRows[i][j]->text[0]){
+ add_to_buff((char**)ptr, &cbd, &size, " <cell row=\"", 12);
+ add_int_to_buff((char**)ptr, &cbd, &size, nl+1, false, 0);
+ add_to_buff((char**)ptr, &cbd, &size, "\" column=\"", 10);
+ add_int_to_buff((char**)ptr, &cbd, &size, nc+1, false, 0);
+ add_to_buff((char**)ptr, &cbd, &size, "\">\n <text>", 11);
+ add_to_buff((char**)ptr, &cbd, &size, etRows[i][j]->text, 0);
+ add_to_buff((char**)ptr, &cbd, &size, "</text>\n </cell>\n", 17);
+ if(bCopyCut) etRows[i][j]->SetText("");
+ }
+ break;
+ }
+ }
+ }
+ if(type == FF_SYLK) {
+ if(!bLimit) {
+ add_to_buff((char**)ptr, &cbd, &size, "C;Y", 3);
+ add_int_to_buff((char**)ptr, &cbd, &size, i+2, false, 0);
+ add_to_buff((char**)ptr, &cbd, &size, ";X1;K\"long strings were"
+ " truncated to 256 characters due to limitations of the SYLK format!\"\n", 92);
+ }
+ add_to_buff((char**)ptr, &cbd, &size, "E\n", 2);
+ }
+ else if(type == FF_TSV) add_to_buff((char**)ptr, &cbd, &size, "\n", 1);
+ else if(type == FF_XML) add_to_buff((char**)ptr, &cbd, &size, "</spreadsheet-snippet>\n", 23);
+ else if(type == FF_RLW){
+ Disp->Command(CMD_WRITE_GRAPHS, ptr, (anyOutput*)&cbd);
+ //note: cbd may be greater than size !
+ add_to_buff((char**)ptr, &cbd, &size, "</RLPlot-data>\n", 15);
+ }
+ if(ar) delete ar;
+ if(bCopyCut && type == FF_XML || type == FF_SYLK || type == FF_RLW){
+ bCopyCut = false;
+ DoPlot(w);
+ }
+ return true;
+}
+
+void SpreadMain(bool show)
+{
+ static SpreadData *w = 0L;
+
+ if(show) {
+ if(w = new SpreadData(0L)) w->Init(50, 10);
+ do_formula(w, 0L); //init mfcalc
+ }
+ else if (w) delete(w);
+}
diff --git a/use_gui.cpp b/use_gui.cpp
index 2c45985..18a0f36 100755
--- a/use_gui.cpp
+++ b/use_gui.cpp
@@ -1,1930 +1,1940 @@
-//use_gui.cpp, Copyright 2000-2007 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 builds using a graphical user interface.
-// Builds running without GUI use no_gui.cpp instead.
-//
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//
-#include "rlplot.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-extern char TmpTxt[];
-extern Default defs;
-extern GraphObj *CurrGO, *TrackGO; //Selected Graphic Objects
-extern Graph *CurrGraph;
-extern dragHandle *CurrHandle;
-extern UndoObj Undo;
-extern fmtText DrawFmtText;
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Spread sheet buttons used for rows and columns
-ssButton::ssButton(GraphObj *par, int x, int y, int w, int h):GraphObj(par, 0L)
-{
- bLBdown = bSelected = bMarked = 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 = 0x00e8e8e8L;
- 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;
- if(bSelected) {
- Fill.color = bMarked ? 0x00ffffe0L : 0x00ffffffL;
- }
- else {
- Fill.color = bMarked ? 0x00ffe0e0L : 0x00e8e8e8L;
- }
- 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) {
- rlp_strcpy((char*)tmpl, 10, TextDef.text);
- return true;
- }
- return false;
- case CMD_SELECT:
- if(tmpl && *((int*)tmpl)) bSelected = true;
- else bSelected = false;
- if(o) {
- DoPlot(o);
- o->UpdateRect(&rDims, false);
- }
- return true;
- case CMD_SETSTYLE:
- if(tmpl && *((int*)tmpl)) bMarked = true;
- else bMarked = false;
- if(o) {
- DoPlot(o); o->UpdateRect(&rDims, false);
- }
- return true;
- case CMD_SETTEXT:
- if(tmpl) {
- if(! TextDef.text) TextDef.text = (char*)malloc(10*sizeof(char));
- rlp_strcpy(TextDef.text, 10, (char*)tmpl);
- }
- 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, idx;
- 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) {
- idx = (type - DH_DATA);
- o->SetLine(&LineDef); o->SetFill(&FillDef);
- if(parent->Id == GO_BEZIER && (idx %3)) {
- IncrementMinMaxRect(&rDims, -1);
- o->oRectangle(rDims.left, rDims.top, rDims.right, rDims.bottom);
- }
- else if(parent->Id == GO_POLYLINE || parent->Id == GO_BEZIER) {
- o->oCircle(rDims.left, rDims.top, rDims.right, rDims.bottom);
- }
- else {
- 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], bez[256];
- double dx, dy;
- int i, first=0, last = 0, idx;
- long nbez;
- 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);
- last = 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[3].x = pts[2].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx +1)+dx);
- pts[3].y = 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);
- if(parent ->Id == GO_BEZIER) {
- switch(idx % 3) {
- case 0:
- o->ShowLine(pts, 3, 0x00c0c0c0L);
- pts[0].x = pts[1].x; pts[0].y = pts[1].y;
- for(nbez = 0, i = 1; i < 4; i++) {
- pts[i].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx +i)+dx);
- pts[i].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx +i)+dy);
- }
- DrawBezier(&nbez, bez, pts[0], pts[1], pts[2], pts[3], 0);
- o->ShowLine(bez, nbez, color);
- if(idx < 3) return;
- pts[3].x = pts[0].x; pts[3].y = pts[0].y;
- for(i = nbez = 0, idx -= 3; i < 3; i++) {
- pts[i].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx +i)+dx);
- pts[i].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx +i)+dy);
- }
- DrawBezier(&nbez, bez, pts[0], pts[1], pts[2], pts[3], 0);
- o->ShowLine(bez, nbez, color);
- return;
- case 1:
- pts[3].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx +2)+dx);
- pts[3].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx +2)+dy);
- last = 2; break;
- case 2:
- pts[2].x = pts[1].x; pts[2].y = pts[1].y;
- pts[1].x = pts[0].x; pts[1].y = pts[0].y;
- pts[0].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx -2)+dx);
- pts[0].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx -2)+dy);
- first = 2; last = 4; break;
- }
- if(idx %3) {
- nbez = 0;
- DrawBezier(&nbez, bez, pts[0], pts[1], pts[2], pts[3], 0);
- o->ShowLine(bez, nbez, color);
- }
- color = 0x00c0c0c0L;
- }
- else last = 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;
- last = 5;
- if(parent->parent->Id == GO_ELLIPSE) o->ShowEllipse(p1, p2, color);
- }
- o->ShowLine(pts+first, last-first, 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){
- if(mo) DelBitmapClass(mo); mo = 0L;
- 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(!CurrGraph && 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);
- }
-
-}
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-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
-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];
- DWORD flags;
-
- if(!o || (ci != 13 && ci < 32)) return false;
- if(CheckMark()) {
- Undo.String(this, &TextDef.text, 0L);
- Undo.ValInt(this, &m1, UNDO_CONTINUE);
- Undo.ValInt(this, &m2, UNDO_CONTINUE);
- rlp_strcpy(TextDef.text+m1, (int)strlen(TextDef.text+m1)+1, TextDef.text+m2);
- CursorPos = m1; flags = UNDO_CONTINUE;
- }
- else flags = 0L;
- m1 = m2 = -1;
- 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(TextDef.text && TextDef.text[0]) i = (int)strlen(TextDef.text);
- else i = 0; if(CursorPos > i)CursorPos = i;
- if(ci > 254) {
- Undo.String(this, &TextDef.text, flags);
- Undo.ValInt(this, &CursorPos, flags = UNDO_CONTINUE);
- txt1 = (char*)malloc((i+12)*sizeof(char));
- if(txt1) {
- if(j=CursorPos) k = rlp_strcpy(txt1, CursorPos+1, TextDef.text);
- else k = 0;
-#ifdef USE_WIN_SECURE
- k += sprintf_s(txt1+k, i+12-k, "&#%d;",ci);
-#else
- k += sprintf(txt1+k, "&#%d;",ci);
-#endif
- CursorPos = k;
- k += rlp_strcpy(txt1+k, i+12-k, TextDef.text+j);
- if(TextDef.text) free(TextDef.text);
- TextDef.text = txt1; RedrawEdit(o);
- }
- return true;
- }
- else if( ci > 31) c = (char)ci;
- else return false;
- if(!TextDef.text || CursorPos < 10 || c == ' ') {
- Undo.String(this, &TextDef.text, flags);
- Undo.ValInt(this, &CursorPos, flags = UNDO_CONTINUE);
- }
- txt1 = (char*)malloc((i+4)* sizeof(char));
- if(txt1) {
- if(j=CursorPos) k = rlp_strcpy(txt1, CursorPos+1, TextDef.text);
- else k = 0; txt1[k++] = c;
- k += rlp_strcpy(txt1+k, i+12-k, TextDef.text+j);
- if(TextDef.text) free(TextDef.text);
- TextDef.text = txt1; txt1[k] = 0;
- 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++) {
- DrawFmtText.SetText(0L, TextDef.text, 0L, 0L);
- DrawFmtText.oGetTextExtent(o, &x2, &h, i);
- 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 = (int)strlen(TextDef.text);
-}
-
-void
-TextFrame::ShowCursor(anyOutput *o)
-{
- int cx, cy, w, h;
-
- if(!o) return;
- TextDef.iSize = o->un2iy(TextDef.fSize);
-#ifdef _WINDOWS
- linc = o->un2iy(TextDef.fSize*lspc);
-#else
- linc = o->un2iy(TextDef.fSize*lspc*1.2);
-#endif
- o->SetTextSpec(&TextDef);
- cy = rDims.top + linc * cur_pos.y; cx = rDims.left;
- cx += ipad.left; cy += ipad.top;
- if(cur_pos.y < nlines) {
- if(lines[cur_pos.y] && lines[cur_pos.y][0] && cur_pos.x) {
- fmt_txt.SetText(0L, (char*)lines[cur_pos.y], &cx, &cy);
- if(!fmt_txt.oGetTextExtent(o, &w, &h, cur_pos.x))return;
- }
- else {
- if(!o->oGetTextExtent("A", 1, &w, &h))return; w = 0;
- }
- Cursor.left = cx+w; Cursor.right = cx+w;
- Cursor.top = cy; Cursor.bottom = cy+linc;
- ShowTextCursor(o, &Cursor, TextDef.ColTxt);
- }
-}
-
-void
-TextFrame::CalcCursorPos(int x, int y, anyOutput *o)
-{
- int i, iy, ix, x1, x2, h;
-
- if(!o) return;
- TextDef.iSize = o->un2iy(TextDef.fSize);
- o->SetTextSpec(&TextDef);
- iy = (y-rDims.top-ipad.top)/linc; x1 = x2 = 0;
- if(iy >= nlines) iy = nlines-1; cur_pos.y = iy;
- x2 = rDims.right - rDims.left -ipad.left - ipad.right;
- x = x - rDims.left -ipad.left;
- fmt_txt.SetText(0L, (char*)lines[iy], &x1, &x2);
- for(i = 0, ix = x1 = 0; lines[iy][i]; i++) {
- if(i) fmt_txt.oGetTextExtent(o, &x1, &h, i);
- x1 -= (TextDef.iSize >> 2);
- if(i && x1 <= x2 && x1 >= x) {
- if(i >1) fmt_txt.oGetTextExtent(o, &x1, &h, i-1);
- else x1 = 0;
- fmt_txt.oGetTextExtent(o, &x2, &h, i);
- ix = (abs(x1-x)<abs(x2-x)) ? i = (i-1) : i;
- break;
- }
- }
- if(ix) cur_pos.x = ix;
- else cur_pos.x = i;
-}
-
-void
-Axis::DoMark(anyOutput *o, bool mark)
-{
- LineDEF mrkLine;
- double minw = DefSize(SIZE_DATA_LINE);
- POINT *arc;
- long narc = 0;
-
- if(axis->flags & AXIS_ANGULAR) {
- if(mark) {
- if(mo) DelBitmapClass(mo); mo = 0L;
- o->GetSize(&mrc); mo = GetRectBitmap(&mrc, o);
- memcpy(&mrkLine, &axline, sizeof(LineDEF));
- mrkLine.width = axline.width < minw ? minw * 3.0 : axline.width *3.0;
- o->SetLine(&mrkLine);
- if(arc = MakeArc(pts[0].x, pts[0].y, pts[1].x, 0x0f, &narc)) {
- o->oPolyline(arc, (int)narc, 0L);
- mrkLine.color ^= 0x00ffffffL; mrkLine.width = axline.width;
- o->SetLine(&mrkLine); o->oPolyline(arc, (int)narc, 0L);
- free(arc);
- }
- o->UpdateRect(&mrc, false);
- }
- else RestoreRectBitmap(&mo, &mrc, o);
- return;
- }
- if(mark){
- if(mo) DelBitmapClass(mo); mo = 0L;
- 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);
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Graphs are graphic objects containing plots, axes, and drawn objects
-bool
-Graph::ExecTool(MouseEvent *mev)
-{
- static POINT pl = {0, 0}, pc = {0, 0};
- static DWORD color = 0L;
- scaleINFO scale;
- 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(mev->Action == MOUSE_LBUP) SuspendAnimation(CurrDisp, false);
- if(ToolMode & TM_MOVE) switch (mev->Action) {
- case MOUSE_LBDOWN:
- pl.x = pc.x = mev->x; pl.y = pc.y = mev->y;
- if(TrackGO && TrackGO->Command(CMD_MOUSECURSOR, 0L, CurrDisp)) return true;
- CurrDisp->HideMark(); 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
- rc_mrk.left = rc_mrk.right = rc_mrk.top = rc_mrk.bottom = 0;
- ToolMode = TM_STANDARD; CurrDisp->MouseCursor(MC_ARROW, false);
- 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(ToolMode == TM_PASTE) {
- switch (mev->Action) {
- case MOUSE_LBDOWN:
- CurrGO = 0L;
- CurrDisp->MrkMode = MRK_NONE;
- 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;
- 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, 0x00c0c0c0L);
- memcpy(&rcUpd, &rcDim, sizeof(RECT));
- UpdateMinMaxRect(&rcUpd, mev->x, mev->y);
- IncrementMinMaxRect(&rcUpd, 2);
- return true;
- }
- break;
- case MOUSE_LBUP:
- if(!PasteObj) return false;
- pc.x = mev->x; pc.y = mev->y;
- if((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(lfp[0].fx > lfp[1].fx) {
- x = lfp[0].fx; lfp[0].fx = lfp[1].fx; lfp[1].fx = x;
- }
- if(lfp[0].fy > lfp[1].fy) {
- y = lfp[0].fy; lfp[0].fy = lfp[1].fy; lfp[1].fy = y;
- }
- }
- else {
- DeleteGO(PasteObj); PasteObj = 0L;
- ToolMode = TM_STANDARD; CurrDisp->MouseCursor(MC_ARROW, false);
- return true;
- }
- scale.sx.fx = lfp[0].fx; scale.sy.fx = lfp[0].fy; scale.sz.fx = 0.0;
- scale.sx.fy = scale.sy.fy = scale.sz.fy = 1.0;
- if(PasteObj->Id == GO_GRAPH) {
- if(abs(pc.x -pl.x) > 20 && abs(pc.y -pl.y) >20) {
- x = ((Graph*)PasteObj)->GRect.Xmax - ((Graph*)PasteObj)->GRect.Xmin;
- y = ((Graph*)PasteObj)->GRect.Ymax - ((Graph*)PasteObj)->GRect.Ymin;
- scale.sx.fy = (lfp[1].fx - lfp[0].fx)/x; scale.sy.fy = (lfp[1].fy - lfp[0].fy)/y;
- scale.sx.fy = (scale.sx.fy + scale.sy.fy) /2.0; //preserve aspect ratio
- scale.sy.fy = scale.sx.fy;
- }
- ((Graph*)PasteObj)->GRect.Xmax -= ((Graph*)PasteObj)->GRect.Xmin;
- ((Graph*)PasteObj)->GRect.Ymax -= ((Graph*)PasteObj)->GRect.Ymin;
- ((Graph*)PasteObj)->GRect.Ymin = ((Graph*)PasteObj)->GRect.Xmin = 0.0;
- PasteObj->Command(CMD_SCALE, &scale, 0L);
- Command(CMD_DROP_GRAPH, (void*)PasteObj, 0L);
- }
- else {
- anyOutput *ScaleOut;
-
- if(ScaleOut = NewBitmapClass(10, 10, CurrDisp->hres, CurrDisp->vres)) {
- PasteObj->parent = this; PasteObj->DoPlot(ScaleOut);
- switch(PasteObj->Id){
- case GO_POLYLINE: case GO_POLYGON:
- IncrementMinMaxRect(&PasteObj->rDims, -(3*CurrDisp->un2ix(((polyline*)PasteObj)->pgLine.width)+3));
- break;
- case GO_BEZIER:
- IncrementMinMaxRect(&PasteObj->rDims, 3);
- break;
- }
- scale.sx.fx = CurrDisp->fix2un(-PasteObj->rDims.left);
- scale.sy.fx = CurrDisp->fiy2un(-PasteObj->rDims.top);
- PasteObj->Command(CMD_SCALE, &scale, 0L);
- scale.sx.fx = lfp[0].fx; scale.sy.fx = lfp[0].fy; scale.sz.fx = 0.0;
- if(abs(pc.x -pl.x) > 8 && abs(pc.y -pl.y) > 8) {
- x = CurrDisp->fix2un(PasteObj->rDims.right - PasteObj->rDims.left);
- y = CurrDisp->fiy2un(PasteObj->rDims.bottom - PasteObj->rDims.top);
- scale.sx.fy = (lfp[1].fx - lfp[0].fx)/x;
- scale.sy.fy = (lfp[1].fy - lfp[0].fy)/y;
- }
- PasteObj->Command(CMD_SCALE, &scale, 0L);
- delete ScaleOut;
- }
- Command(CMD_DROP_GRAPH, (void*)PasteObj, 0L);
- }
- PasteObj = 0L;
- ToolMode = TM_STANDARD; CurrDisp->MouseCursor(MC_ARROW, false);
- break;
- }
- 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);
- Undo.SetGO(this, &Plots[i], new Bezier(this, data, lfp, (int)tl_nPts, 0,
- (CurrDisp->hres/CurrDisp->VPscale+CurrDisp->vres/CurrDisp->VPscale)/2.0), 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;
- AddToPolygon(&tl_nPts, tl_pts, &pc);
-#ifdef _WINDOWS
- CurrDisp->ShowLine(line, 2, color);
-#else
- CurrDisp->ShowLine(tl_pts, tl_nPts, color);
-#endif
- 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) :
- (GraphObj*) 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; CurrDisp->HideMark();
- 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_LBDOWN:
- CurrGO = 0L;
- CurrDisp->MrkMode = MRK_NONE;
- Command(CMD_REDRAW, 0L, CurrDisp);
- color = 0x00cbcbcb;
- 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) {
- CurrDisp->MouseCursor(MC_TXTFRM, false);
- 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);
- }
- 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(((abs(pc.x-pl.x) >20 && abs(pc.y-pl.y) >20)) &&
- (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;
- new_go = new TextFrame(this, data, &lfp[0], &lfp[1], 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);
- CurrDisp->CheckMenu(ToolMode & 0x0f, false);
- CurrDisp->CheckMenu(ToolMode = TM_STANDARD, true);
- CurrDisp->MouseCursor(MC_ARROW, false);
- }
- else {
- CurrDisp->MouseCursor(MC_TEXT, false);
- 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 = DefSize(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;
- HideCopyMark();
- 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;
- if(!(CurrDisp->ActualSize(&cw)))return false;
- 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;
- }
- if(!(CurrDisp->ActualSize(&cw)))return false;
- 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;
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 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+_SBINC)) {
- if(list[i]) {
- curr_obj = list[i]; n = 0;
- if(i) while(curr_obj && curr_obj != list[0]) {
- if(curr_obj != list[0]) n += rlp_strcpy(TmpTxt+n, TMP_TXT_SIZE -n, " -");
- if(curr_obj) curr_obj = curr_obj->parent;
- }
- if(n) TmpTxt[n++] = ' ';
- n += rlp_strcpy(TmpTxt+n, TMP_TXT_SIZE -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)+_SBINC) * (count+1);
- 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;
-}
-
+//use_gui.cpp, Copyright 2000-2008 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 builds using a graphical user interface.
+// Builds running without GUI use no_gui.cpp instead.
+//
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+#include "rlplot.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+extern char TmpTxt[];
+extern Default defs;
+extern GraphObj *CurrGO, *TrackGO; //Selected Graphic Objects
+extern Graph *CurrGraph;
+extern dragHandle *CurrHandle;
+extern UndoObj Undo;
+extern fmtText DrawFmtText;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Spread sheet buttons used for rows and columns
+ssButton::ssButton(GraphObj *par, int x, int y, int w, int h):GraphObj(par, 0L)
+{
+ bLBdown = bSelected = bMarked = 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 = 0x00e8e8e8L;
+ 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;
+ if(bSelected) {
+ Fill.color = bMarked ? 0x00ffffe0L : 0x00ffffffL;
+ }
+ else {
+ Fill.color = bMarked ? 0x00ffe0e0L : 0x00e8e8e8L;
+ }
+ o->SetLine(&Line); o->SetFill(&Fill);
+ if(bLBdown){
+ o->oRectangle(rDims.left, rDims.top, rDims.right-1, rDims.bottom-1);
+ }
+ else {
+ o->oRectangle(rDims.left, rDims.top, rDims.right-2, rDims.bottom-2);
+ 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) {
+ rlp_strcpy((char*)tmpl, 10, TextDef.text);
+ return true;
+ }
+ return false;
+ case CMD_SELECT:
+ if(tmpl && *((int*)tmpl)) bSelected = true;
+ else bSelected = false;
+ if(o) {
+ DoPlot(o);
+ o->UpdateRect(&rDims, false);
+ }
+ return true;
+ case CMD_SETSTYLE:
+ if(tmpl && *((int*)tmpl)) bMarked = true;
+ else bMarked = false;
+ if(o) {
+ DoPlot(o); o->UpdateRect(&rDims, false);
+ }
+ return true;
+ case CMD_SETTEXT:
+ if(tmpl) {
+ if(! TextDef.text) TextDef.text = (char*)malloc(10*sizeof(char));
+ rlp_strcpy(TextDef.text, 10, (char*)tmpl);
+ }
+ 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, idx;
+ 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) {
+ idx = (type - DH_DATA);
+ o->SetLine(&LineDef); o->SetFill(&FillDef);
+ if(parent->Id == GO_BEZIER && (idx %3)) {
+ IncrementMinMaxRect(&rDims, -1);
+ o->oRectangle(rDims.left, rDims.top, rDims.right, rDims.bottom);
+ }
+ else if(parent->Id == GO_POLYLINE || parent->Id == GO_BEZIER) {
+ o->oCircle(rDims.left, rDims.top, rDims.right, rDims.bottom);
+ }
+ else {
+ o->oRectangle(rDims.left, rDims.top, rDims.right, rDims.bottom);
+ }
+ o->UpdateRect(&rDims, false);
+ }
+ else {
+ IncrementMinMaxRect(&rDims, -1);
+#ifdef _WINDOWS
+ o->UpdateRect(&rDims, true);
+#else
+ o->ShowInvert(&rDims);
+#endif
+ }
+ 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], bez[256];
+ double dx, dy;
+ int i, first=0, last = 0, idx;
+ long nbez;
+ 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);
+ last = 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[3].x = pts[2].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx +1)+dx);
+ pts[3].y = 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);
+ if(parent ->Id == GO_BEZIER) {
+ switch(idx % 3) {
+ case 0:
+ o->ShowLine(pts, 3, 0x00c0c0c0L);
+ pts[0].x = pts[1].x; pts[0].y = pts[1].y;
+ for(nbez = 0, i = 1; i < 4; i++) {
+ pts[i].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx +i)+dx);
+ pts[i].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx +i)+dy);
+ }
+ DrawBezier(&nbez, bez, pts[0], pts[1], pts[2], pts[3], 0);
+ o->ShowLine(bez, nbez, color);
+ if(idx < 3) return;
+ pts[3].x = pts[0].x; pts[3].y = pts[0].y;
+ for(i = nbez = 0, idx -= 3; i < 3; i++) {
+ pts[i].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx +i)+dx);
+ pts[i].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx +i)+dy);
+ }
+ DrawBezier(&nbez, bez, pts[0], pts[1], pts[2], pts[3], 0);
+ o->ShowLine(bez, nbez, color);
+ return;
+ case 1:
+ pts[3].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx +2)+dx);
+ pts[3].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx +2)+dy);
+ last = 2; break;
+ case 2:
+ pts[2].x = pts[1].x; pts[2].y = pts[1].y;
+ pts[1].x = pts[0].x; pts[1].y = pts[0].y;
+ pts[0].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx -2)+dx);
+ pts[0].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx -2)+dy);
+ first = 2; last = 4; break;
+ }
+ if(idx %3) {
+ nbez = 0;
+ DrawBezier(&nbez, bez, pts[0], pts[1], pts[2], pts[3], 0);
+ o->ShowLine(bez, nbez, color);
+ }
+ color = 0x00c0c0c0L;
+ }
+ else last = 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;
+ last = 5;
+ if(parent->parent->Id == GO_ELLIPSE) o->ShowEllipse(p1, p2, color);
+ }
+ o->ShowLine(pts+first, last-first, 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){
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ 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(!CurrGraph && 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);
+ }
+
+}
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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
+Label::ShowCursor(anyOutput *o)
+{
+ if(o) {
+ CalcRect(o);
+ if((o->OC_type & 0xff) == OC_BITMAP) ShowTextCursor(o, &Cursor, TextDef.ColTxt);
+ }
+}
+
+bool
+Label::AddChar(int ci, anyOutput *o)
+{
+ char c, *txt1 = 0L;
+ int i, j, k;
+ GraphObj *golist[2];
+ DWORD flags;
+
+ if(!o || (ci != 13 && ci < 32)) return false;
+ if(CheckMark()) {
+ Undo.String(this, &TextDef.text, 0L);
+ Undo.ValInt(this, &m1, UNDO_CONTINUE);
+ Undo.ValInt(this, &m2, UNDO_CONTINUE);
+ rlp_strcpy(TextDef.text+m1, (int)strlen(TextDef.text+m1)+1, TextDef.text+m2);
+ CursorPos = m1; flags = UNDO_CONTINUE;
+ }
+ else flags = 0L;
+ m1 = m2 = -1;
+ 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(TextDef.text && TextDef.text[0]) i = (int)strlen(TextDef.text);
+ else i = 0; if(CursorPos > i)CursorPos = i;
+ if(ci > 254) {
+ Undo.String(this, &TextDef.text, flags);
+ Undo.ValInt(this, &CursorPos, flags = UNDO_CONTINUE);
+ txt1 = (char*)malloc((i+12)*sizeof(char));
+ if(txt1) {
+ if(j=CursorPos) k = rlp_strcpy(txt1, CursorPos+1, TextDef.text);
+ else k = 0;
+#ifdef USE_WIN_SECURE
+ k += sprintf_s(txt1+k, i+12-k, "&#%d;",ci);
+#else
+ k += sprintf(txt1+k, "&#%d;",ci);
+#endif
+ CursorPos = k;
+ k += rlp_strcpy(txt1+k, i+12-k, TextDef.text+j);
+ if(TextDef.text) free(TextDef.text);
+ TextDef.text = txt1; RedrawEdit(o);
+ }
+ return true;
+ }
+ else if( ci > 31) c = (char)ci;
+ else return false;
+ if(!TextDef.text || CursorPos < 10 || c == ' ') {
+ Undo.String(this, &TextDef.text, flags);
+ Undo.ValInt(this, &CursorPos, flags = UNDO_CONTINUE);
+ }
+ txt1 = (char*)malloc((i+4)* sizeof(char));
+ if(txt1) {
+ if(j=CursorPos) k = rlp_strcpy(txt1, CursorPos+1, TextDef.text);
+ else k = 0; txt1[k++] = c;
+ k += rlp_strcpy(txt1+k, i+12-k, TextDef.text+j);
+ if(TextDef.text) free(TextDef.text);
+ TextDef.text = txt1; txt1[k] = 0;
+ 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++) {
+ DrawFmtText.SetText(0L, TextDef.text, 0L, 0L);
+ DrawFmtText.oGetTextExtent(o, &x2, &h, i);
+ 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 = (int)strlen(TextDef.text);
+}
+
+void
+TextFrame::ShowCursor(anyOutput *o)
+{
+ int cx, cy, w, h;
+
+ if(!o || (o->OC_type & 0xff) != OC_BITMAP) return;
+ TextDef.iSize = o->un2iy(TextDef.fSize);
+#ifdef _WINDOWS
+ linc = o->un2iy(TextDef.fSize*lspc);
+#else
+ linc = o->un2iy(TextDef.fSize*lspc*1.2);
+#endif
+ o->SetTextSpec(&TextDef);
+ cy = rDims.top + linc * cur_pos.y; cx = rDims.left;
+ cx += ipad.left; cy += ipad.top;
+ if(cur_pos.y < nlines) {
+ if(lines[cur_pos.y] && lines[cur_pos.y][0] && cur_pos.x) {
+ fmt_txt.SetText(0L, (char*)lines[cur_pos.y], &cx, &cy);
+ if(!fmt_txt.oGetTextExtent(o, &w, &h, cur_pos.x))return;
+ }
+ else {
+ if(!o->oGetTextExtent("A", 1, &w, &h))return; w = 0;
+ }
+ Cursor.left = cx+w; Cursor.right = cx+w;
+ Cursor.top = cy; Cursor.bottom = cy+linc;
+ ShowTextCursor(o, &Cursor, TextDef.ColTxt);
+ }
+}
+
+void
+TextFrame::CalcCursorPos(int x, int y, anyOutput *o)
+{
+ int i, iy, ix, x1, x2, h;
+
+ if(!o) return;
+ TextDef.iSize = o->un2iy(TextDef.fSize);
+ o->SetTextSpec(&TextDef);
+ iy = (y-rDims.top-ipad.top)/linc; x1 = x2 = 0;
+ if(iy >= nlines) iy = nlines-1; cur_pos.y = iy;
+ x2 = rDims.right - rDims.left -ipad.left - ipad.right;
+ x = x - rDims.left -ipad.left;
+ fmt_txt.SetText(0L, (char*)lines[iy], &x1, &x2);
+ for(i = 0, ix = x1 = 0; lines[iy][i]; i++) {
+ if(i) fmt_txt.oGetTextExtent(o, &x1, &h, i);
+ x1 -= (TextDef.iSize >> 2);
+ if(i && x1 <= x2 && x1 >= x) {
+ if(i >1) fmt_txt.oGetTextExtent(o, &x1, &h, i-1);
+ else x1 = 0;
+ fmt_txt.oGetTextExtent(o, &x2, &h, i);
+ ix = (abs(x1-x)<abs(x2-x)) ? i = (i-1) : i;
+ break;
+ }
+ }
+ if(ix) cur_pos.x = ix;
+ else cur_pos.x = i;
+}
+
+void
+Axis::DoMark(anyOutput *o, bool mark)
+{
+ LineDEF mrkLine;
+ double minw = DefSize(SIZE_DATA_LINE);
+ POINT *arc;
+ long narc = 0;
+
+ if(axis->flags & AXIS_ANGULAR) {
+ if(mark) {
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ o->GetSize(&mrc); mo = GetRectBitmap(&mrc, o);
+ memcpy(&mrkLine, &axline, sizeof(LineDEF));
+ mrkLine.width = axline.width < minw ? minw * 3.0 : axline.width *3.0;
+ o->SetLine(&mrkLine);
+ if(arc = MakeArc(pts[0].x, pts[0].y, pts[1].x, 0x0f, &narc)) {
+ o->oPolyline(arc, (int)narc, 0L);
+ mrkLine.color ^= 0x00ffffffL; mrkLine.width = axline.width;
+ o->SetLine(&mrkLine); o->oPolyline(arc, (int)narc, 0L);
+ free(arc);
+ }
+ o->UpdateRect(&mrc, false);
+ }
+ else RestoreRectBitmap(&mo, &mrc, o);
+ return;
+ }
+ if(mark){
+ if(mo) DelBitmapClass(mo); mo = 0L;
+ memcpy(&mrc, &rDims, sizeof(RECT));
+ IncrementMinMaxRect(&mrc, 6 + o->un2ix(axline.width));
+ mo = GetRectBitmap(&mrc, o);
+ if(type & 0x04) InvertLine(gradient_box, 5, &axline, &rDims, o, mark);
+ else InvertLine(pts, 2, &axline, &rDims, o, mark);
+ o->UpdateRect(&mrc, false);
+ }
+ else RestoreRectBitmap(&mo, &mrc, o);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Graphs are graphic objects containing plots, axes, and drawn objects
+bool
+Graph::ExecTool(MouseEvent *mev)
+{
+ static POINT pl = {0, 0}, pc = {0, 0};
+ static DWORD color = 0L;
+ scaleINFO scale;
+ 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(mev->Action == MOUSE_LBUP) SuspendAnimation(CurrDisp, false);
+ if(ToolMode & TM_MOVE) switch (mev->Action) {
+ case MOUSE_LBDOWN:
+ pl.x = pc.x = mev->x; pl.y = pc.y = mev->y;
+ if(TrackGO && TrackGO->Command(CMD_MOUSECURSOR, 0L, CurrDisp)) return true;
+ CurrDisp->HideMark(); CurrDisp->MouseCursor(MC_MOVE, false);
+ return true;
+ case MOUSE_MOVE:
+ defs.Idle(CMD_UPDATE);
+ 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
+ rc_mrk.left = rc_mrk.right = rc_mrk.top = rc_mrk.bottom = 0;
+ ToolMode = TM_STANDARD; CurrDisp->MouseCursor(MC_ARROW, false);
+ 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(ToolMode == TM_PASTE) {
+ switch (mev->Action) {
+ case MOUSE_LBDOWN:
+ CurrGO = 0L;
+ CurrDisp->MrkMode = MRK_NONE;
+ 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;
+ 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, 0x00c0c0c0L);
+ memcpy(&rcUpd, &rcDim, sizeof(RECT));
+ UpdateMinMaxRect(&rcUpd, mev->x, mev->y);
+ IncrementMinMaxRect(&rcUpd, 2);
+ return true;
+ }
+ break;
+ case MOUSE_LBUP:
+ if(!PasteObj) return false;
+ pc.x = mev->x; pc.y = mev->y;
+ if((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(lfp[0].fx > lfp[1].fx) {
+ x = lfp[0].fx; lfp[0].fx = lfp[1].fx; lfp[1].fx = x;
+ }
+ if(lfp[0].fy > lfp[1].fy) {
+ y = lfp[0].fy; lfp[0].fy = lfp[1].fy; lfp[1].fy = y;
+ }
+ }
+ else {
+ DeleteGO(PasteObj); PasteObj = 0L;
+ ToolMode = TM_STANDARD; CurrDisp->MouseCursor(MC_ARROW, false);
+ return true;
+ }
+ scale.sx.fx = lfp[0].fx; scale.sy.fx = lfp[0].fy; scale.sz.fx = 0.0;
+ scale.sx.fy = scale.sy.fy = scale.sz.fy = 1.0;
+ if(PasteObj->Id == GO_GRAPH) {
+ if(abs(pc.x -pl.x) > 20 && abs(pc.y -pl.y) >20) {
+ x = ((Graph*)PasteObj)->GRect.Xmax - ((Graph*)PasteObj)->GRect.Xmin;
+ y = ((Graph*)PasteObj)->GRect.Ymax - ((Graph*)PasteObj)->GRect.Ymin;
+ scale.sx.fy = (lfp[1].fx - lfp[0].fx)/x; scale.sy.fy = (lfp[1].fy - lfp[0].fy)/y;
+ scale.sx.fy = (scale.sx.fy + scale.sy.fy) /2.0; //preserve aspect ratio
+ scale.sy.fy = scale.sx.fy;
+ }
+ ((Graph*)PasteObj)->GRect.Xmax -= ((Graph*)PasteObj)->GRect.Xmin;
+ ((Graph*)PasteObj)->GRect.Ymax -= ((Graph*)PasteObj)->GRect.Ymin;
+ ((Graph*)PasteObj)->GRect.Ymin = ((Graph*)PasteObj)->GRect.Xmin = 0.0;
+ PasteObj->Command(CMD_SCALE, &scale, 0L);
+ PasteObj->moveable = 1;
+ Command(CMD_DROP_GRAPH, (void*)PasteObj, 0L);
+ }
+ else {
+ anyOutput *ScaleOut;
+
+ if(ScaleOut = NewBitmapClass(10, 10, CurrDisp->hres, CurrDisp->vres)) {
+ PasteObj->parent = this; PasteObj->DoPlot(ScaleOut);
+ switch(PasteObj->Id){
+ case GO_POLYLINE: case GO_POLYGON:
+ IncrementMinMaxRect(&PasteObj->rDims, -(3*CurrDisp->un2ix(((polyline*)PasteObj)->pgLine.width)+3));
+ break;
+ case GO_BEZIER:
+ IncrementMinMaxRect(&PasteObj->rDims, 3);
+ break;
+ }
+ scale.sx.fx = CurrDisp->fix2un(-PasteObj->rDims.left);
+ scale.sy.fx = CurrDisp->fiy2un(-PasteObj->rDims.top);
+ PasteObj->Command(CMD_SCALE, &scale, 0L);
+ scale.sx.fx = lfp[0].fx; scale.sy.fx = lfp[0].fy; scale.sz.fx = 0.0;
+ if(abs(pc.x -pl.x) > 8 && abs(pc.y -pl.y) > 8) {
+ x = CurrDisp->fix2un(PasteObj->rDims.right - PasteObj->rDims.left);
+ y = CurrDisp->fiy2un(PasteObj->rDims.bottom - PasteObj->rDims.top);
+ scale.sx.fy = (lfp[1].fx - lfp[0].fx)/x;
+ scale.sy.fy = (lfp[1].fy - lfp[0].fy)/y;
+ }
+ PasteObj->Command(CMD_SCALE, &scale, 0L);
+ delete ScaleOut;
+ }
+ Command(CMD_DROP_GRAPH, (void*)PasteObj, 0L);
+ }
+ PasteObj = 0L;
+ ToolMode = TM_STANDARD; CurrDisp->MouseCursor(MC_ARROW, false);
+ break;
+ }
+ 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);
+ Undo.SetGO(this, &Plots[i], new Bezier(this, data, lfp, (int)tl_nPts, 0,
+ (CurrDisp->hres/CurrDisp->VPscale+CurrDisp->vres/CurrDisp->VPscale)/2.0), 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;
+ AddToPolygon(&tl_nPts, tl_pts, &pc);
+#ifdef _WINDOWS
+ CurrDisp->ShowLine(line, 2, color);
+#else
+ CurrDisp->ShowLine(tl_pts, tl_nPts, color);
+#endif
+ 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) :
+ (GraphObj*) 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; CurrDisp->HideMark();
+ 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_LBDOWN:
+ CurrGO = 0L;
+ CurrDisp->MrkMode = MRK_NONE;
+ Command(CMD_REDRAW, 0L, CurrDisp);
+ color = 0x00cbcbcb;
+ 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) {
+ CurrDisp->MouseCursor(MC_TXTFRM, false);
+ 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);
+ }
+ 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(((abs(pc.x-pl.x) >20 && abs(pc.y-pl.y) >20)) &&
+ (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;
+ new_go = new TextFrame(this, data, &lfp[0], &lfp[1], 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);
+ CurrDisp->CheckMenu(ToolMode & 0x0f, false);
+ CurrDisp->CheckMenu(ToolMode = TM_STANDARD, true);
+ CurrDisp->MouseCursor(MC_ARROW, false);
+ }
+ else {
+ CurrDisp->MouseCursor(MC_TEXT, false);
+ 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 = DefSize(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;
+ HideCopyMark();
+ 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;
+ if(!(CurrDisp->ActualSize(&cw)))return false;
+ 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;
+ }
+ if(!(CurrDisp->ActualSize(&cw)))return false;
+ 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;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 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+_SBINC)) {
+ if(list[i]) {
+ curr_obj = list[i]; n = 0;
+ if(i) while(curr_obj && curr_obj != list[0]) {
+ if(curr_obj != list[0]) n += rlp_strcpy(TmpTxt+n, TMP_TXT_SIZE -n, " -");
+ if(curr_obj) curr_obj = curr_obj->parent;
+ }
+ if(n) TmpTxt[n++] = ' ';
+ n += rlp_strcpy(TmpTxt+n, TMP_TXT_SIZE -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)+_SBINC) * (count+1);
+ 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;
+}
+
--
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