rlplot/reports.cpp0000775000076400007640000040574210752122043013065 0ustar c71960c71960//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 #include #include #include #include #include #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, ""); cb += rlp_strcpy(desc+cb, 40-cb, name); cb += rlp_strcpy(desc+cb, 40-cb, ":"); 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, ""); cb += rlp_strcpy(desc+cb, 40-cb, name); cb += rlp_strcpy(desc+cb, 40-cb, ":"); 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[] = {"df", "SS", "MS", "F", "P"}; 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[] = {"Groups", "Mean", "Std. Dev.", "N", "Contrasts1)"}; 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, "Summary:"); 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, "1) 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, "Homogeneity of Variances:"); 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, "Chi2 = %.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, "Single-Classification ANOVA", data); if((graph = new Graph(parent, data, 0L, 0)) && (txt_obj = mk_scatt(0, 0L, csums, css, ncols, nc, "Mean", "Groups", "Means + 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, "Anova:"); 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, "Breakdown and Single-Classification ANOVA", data); if((graph = new Graph(parent, data, 0L, 0)) && (txt_obj = mk_scatt(0, 0L, csums, css, ncols, nc, "Mean", "Groups", "Means + 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, "Anova:"); 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, "Two-Way ANOVA", 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 + 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 + 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, "Anova:"); 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, "Friedman's non-parametric two-way ANOVA", 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, "Between columns:"); 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, Chi2 = %.2lf, P ", nc-hc, rchi2); if(prob > 0.001) sprintf_s(TmpTxt+i, 20, "= %.3lf", prob); #else i = sprintf(TmpTxt, "N = %d, Chi2 = %.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, "Between rows:"); 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, Chi2 = %.2lf, P ", nr-hr, cchi2); if(prob > 0.001) sprintf_s(TmpTxt+i, 20, "= %.3lf", prob); #else i = sprintf(TmpTxt, "N = %d, Chi2 = %.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, "Two-Way ANOVA with Replication", data); cx = txtdef1.fSize*5.0; cy = txtdef1.fSize*10.0; rep_DrawText(page, cx, cy, false, TXA_HLEFT, &txtdef1, "Anova:"); 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[] = {"Groups", "N", "Median", "25% - 75%", "Range","Rank Sums"}; 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, "Kruskal-Wallis Test for Differences of Location", 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, "Test Statistics:"); 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, "Summary:"); 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, "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, "\""); 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, "Descriptive Statistics:"); 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, "Test for Normal Distribution:"); 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 2 = %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, "Regression:"); 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, "Linear Regression Analysis", 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, "Anova:"); 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, "Kendall's Robust Line-Fit", 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, "Pearsons product moment correlations", data); break; case 2: mk_header(page, "Spearmans rank correlations", data); break; case 3: mk_header(page, "Kendalls non parametric correlations", data); break; default: mk_header(page, "### Correlation Error ###", 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, "rS = %.4lf, n = %g, ", r, dn); break; case 3: cb = dbl_to_str2(TmpTxt, 80, "rK = %.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, "Compare Means of Two Groups", 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, "t-Test:"); 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, "u-Test:"); 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); } rlplot/QT_Spec.cpp0000775000076400007640000037701211006661526012672 0ustar c71960c71960//QT_Spec.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 // #include #include #include #include #if QT_VERSION < 0x040000 #include "QT3_Spec.h" #else #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; extern char *WWWbrowser; extern char *LoadFile; //command line argument extern char TmpTxt[]; extern Default defs; extern UndoObj Undo; 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 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ int ExportQPixmap(GraphObj *g, char *filename, int type) { double res, width, height; int w, h; anyOutput *bmo; char *formats[] = {0L, "Export Portable Network Grafics (*.png)", "Export Joint Photographic Experts Group (*.jpg)", "Export X11 Pixmap (*.xpm)"}; if(!g || !filename) return 0; 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, formats[type])){ w = iround(width * res * Units[defs.cUnits].convert/25.4); h = iround(height * res * Units[defs.cUnits].convert/25.4); if(bmo = NewBitmapClass(w, h, res, res)){ bmo->VPorg.fy = -bmo->co2fiy(g->GetSize(SIZE_GRECT_TOP)); bmo->VPorg.fx = -bmo->co2fix(g->GetSize(SIZE_GRECT_LEFT)); bmo->Erase(0x00ffffffL); g->DoPlot(bmo); if(!((OutputQT*)bmo)->mempic->save(filename, 0, -1)) ErrorBox("An Error occured during export\n"); delete(bmo); } g->Command(CMD_REDRAW, 0L, 0L); } return 0; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Exute a file open dialog for the different situations //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ static char UserFileName[600]; // Get a new file name to store data in char *SaveDataAsName(char *oldname) { #if QT_VERSION < 0x040000 QFileDialog qf(0,0,true); QString filters("RLPlot workbook (*.rlw);;data files (*.csv);;" "tab separated (*.tsv);;XML (*.xml)"); int i, cb; char *ext; qf.setFilters(filters); qf.setDir(defs.currPath); qf.setSelection(oldname); qf.setMode(QFileDialog::AnyFile); if(qf.exec() == QDialog::Accepted) { if(!qf.selectedFile().isEmpty()) { cb = rlp_strcpy(UserFileName, 600, (char*)qf.selectedFile().ascii()); if(cb < 4 || UserFileName[cb-4] != '.'){ ext = (char*)qf.selectedFilter().ascii(); for(i = 0; ext[i] && ext[i] != '*'; i++); rlp_strcpy(UserFileName+cb, 5, ext+i+1); } defs.FileHistory(UserFileName); return UserFileName; } } return 0L; #else QFileDialog qf((QWidget*)0L, (Qt::WindowFlags)0); QStringList filters; filters << "RLPlot workbook (*.rlw)" << "data files (*.csv)" << "tab separated (*.tsv)" << "XML (*.xml)"; int i, cb; char *ext; qf.setDirectory(defs.currPath); qf.setViewMode(QFileDialog::Detail); qf.selectFile(oldname); qf.setFileMode(QFileDialog::AnyFile); qf.setFilters(filters); if(qf.exec() == QDialog::Accepted) { if(!qf.selectedFiles().isEmpty()) { cb = rlp_strcpy(UserFileName, 600, (char*)qf.selectedFiles().first().toAscii().data()); if(cb < 4 || UserFileName[cb-4] != '.'){ ext = (char*)qf.selectedFilter().toAscii().data(); for(i = 0; ext[i] && ext[i] != '*'; i++); rlp_strcpy(UserFileName+cb, 5, ext+i+1); } defs.FileHistory(UserFileName); return UserFileName; } } return 0L; #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Get a new file name to store graph char *SaveGraphAsName(char *oldname) { #if QT_VERSION < 0x040000 QFileDialog qf(0,0,true); QString filters("RLPlot files (*.rlp)"); int i, cb; char *ext; qf.setFilters(filters); qf.setDir(defs.currPath); qf.setSelection(oldname); qf.setMode(QFileDialog::AnyFile); if(qf.exec() == QDialog::Accepted) { if(!qf.selectedFile().isEmpty()) { cb = rlp_strcpy(UserFileName, 600, (char*)qf.selectedFile().ascii()); if(cb < 4 || UserFileName[cb-4] != '.'){ ext = (char*)qf.selectedFilter().ascii(); for(i = 0; ext[i] && ext[i] != '*'; i++); rlp_strcpy(UserFileName+cb, 5, ext+i+1); } defs.FileHistory(UserFileName); return UserFileName; } } return 0L; #else QFileDialog qf((QWidget*)0L, (Qt::WindowFlags)0); QStringList filters; filters << "RLPlot files (*.rlp)"; int i, cb; char *ext; qf.setDirectory(defs.currPath); qf.setViewMode(QFileDialog::Detail); qf.selectFile(oldname); qf.setFileMode(QFileDialog::AnyFile); qf.setFilters(filters); if(qf.exec() == QDialog::Accepted) { if(!qf.selectedFiles().isEmpty()) { cb = rlp_strcpy(UserFileName, 600, (char*)qf.selectedFiles().first().toAscii().data()); if(cb < 4 || UserFileName[cb-4] != '.'){ ext = (char*)qf.selectedFilter().toAscii().data(); for(i = 0; ext[i] && ext[i] != '*'; i++); rlp_strcpy(UserFileName+cb, 5, ext+i+1); } defs.FileHistory(UserFileName); return UserFileName; } } return 0L; #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Get file name to read graph char *OpenGraphName(char *oldname) { #if QT_VERSION < 0x040000 QString fileName = QFileDialog::getOpenFileName(oldname?oldname:defs.currPath, "RLPlot files (*.rlp)", 0L); if(!fileName.isEmpty()){ strcpy(UserFileName, fileName); defs.FileHistory(UserFileName); return UserFileName; } return 0L; #else QString fileName = QFileDialog::getOpenFileName(0L, "Open Graph", oldname?oldname:defs.currPath, "RLPlot files (*.rlp)"); if(!fileName.isEmpty()){ rlp_strcpy(UserFileName, 600, fileName.toAscii().data()); defs.FileHistory(UserFileName); return UserFileName; } return 0L; #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Get a file name to load data char *OpenDataName(char *oldname) { #if QT_VERSION < 0x040000 QString fileName = QFileDialog::getOpenFileName(oldname?oldname:defs.currPath, "RLPlot workbook (*.rlw)\ndata files (*.csv)\ntab separated file (*.tsv)\n" "RLPlot files (*.rlp)\nall files (*.*)", 0L); if(!fileName.isEmpty()){ strcpy(UserFileName, fileName); defs.FileHistory(UserFileName); return UserFileName; } return 0L; #else QString fileName = QFileDialog::getOpenFileName(0L, "Open File", oldname?oldname:defs.currPath, "RLPlot workbook (*.rlw)\ndata files (*.csv)\ntab separated file (*.tsv)\n" "RLPlot files (*.rlp)\nall files (*.*)"); if(!fileName.isEmpty()){ rlp_strcpy(UserFileName, 600, fileName.toAscii().data()); defs.FileHistory(UserFileName); return UserFileName; } return 0L; #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Get a file name to export graph void OpenExportName(GraphObj *g, char *oldname) { #if QT_VERSION < 0x040000 int i; PrintQT *out=0L; if (!g) return; QString fileName = QFileDialog::getSaveFileName(oldname?oldname:defs.currPath, "Scalable Vector Graphics (*.svg)\nEncapsulated Post Script (*.eps)\n" "Tag Image File Format(*.tif *.tiff)", 0L); if(!fileName.isEmpty()){ strcpy(UserFileName, fileName); i = strlen(UserFileName); g->Command(CMD_BUSY, 0L, 0L); if(0==strcasecmp(".svg", UserFileName+i-4)) { DoExportSvg(g, UserFileName, 0L); } else if(0==strcasecmp(".wmf", UserFileName+i-4)) { DoExportWmf(g, UserFileName, 600.0f, 0L); } else if(0==strcasecmp(".eps", UserFileName+i-4)) { DoExportEps(g, UserFileName, 0L); } else if(0==strcasecmp(".tif", UserFileName+i-4)) { DoExportTif(g, UserFileName, 0L); } else if(0==strcasecmp(".tiff", UserFileName+i-5)) { DoExportTif(g, UserFileName, 0L); } else ErrorBox("Unknown file extension or format"); g->Command(CMD_MOUSECURSOR, 0L, 0L); } #else QFileDialog qf((QWidget*)0L, (Qt::WindowFlags)0); QStringList filters; filters << "Scalable Vector Graphics (*.svg)" << "Encapsulated Post Script (*.eps)" << "Tag Image File Format (*.tif *.tiff)" << "Portable Network Graphics (*.png)" << "Joint Photographic Experts Group (*.jpg *.jpeg)" << "X11 Pixmap (*.xpm)"; int i, cb; char *ext; qf.setDirectory(defs.currPath); qf.setViewMode(QFileDialog::Detail); qf.selectFile(oldname); qf.setFileMode(QFileDialog::AnyFile); qf.setFilters(filters); if(qf.exec() == QDialog::Accepted) { if(!qf.selectedFiles().isEmpty()) { cb = rlp_strcpy(UserFileName, 600, (char*)qf.selectedFiles().first().toAscii().data()); if(cb < 5 || (UserFileName[cb-4] != '.' && UserFileName[cb-5] != '.')){ ext = (char*)qf.selectedFilter().toAscii().data(); for(i = 0; ext[i] && ext[i] != '*'; i++); rlp_strcpy(UserFileName+cb, 5, ext+i+1); } i = strlen(UserFileName); g->Command(CMD_BUSY, 0L, 0L); if(0==strcasecmp(".svg", UserFileName+i-4)) { DoExportSvg(g, UserFileName, 0L); } else if(0==strcasecmp(".wmf", UserFileName+i-4)) { DoExportWmf(g, UserFileName, 600.0f, 0L); } else if(0==strcasecmp(".eps", UserFileName+i-4)) { DoExportEps(g, UserFileName, 0L); } else if(0==strcasecmp(".tif", UserFileName+i-4)) { DoExportTif(g, UserFileName, 0L); } else if(0==strcasecmp(".tiff", UserFileName+i-5)) { DoExportTif(g, UserFileName, 0L); } else if(0==strcasecmp(".png", UserFileName+i-4)) { ExportQPixmap(g, UserFileName, 1); } else if(0==strcasecmp(".jpg", UserFileName+i-4)) { ExportQPixmap(g, UserFileName, 2); } else if(0==strcasecmp(".jpeg", UserFileName+i-5)) { ExportQPixmap(g, UserFileName, 2); } else if(0==strcasecmp(".xpm", UserFileName+i-4)) { ExportQPixmap(g, UserFileName, 3); } else ErrorBox("Unknown file extension or format"); } g->Command(CMD_MOUSECURSOR, 0L, 0L); } #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Common alert boxes //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ static char the_message[500]; void InfoBox(char *Msg) { QMessageBox::information(QAppl->focusWidget(), "Info", Msg); } void ErrorBox(char *Msg) { QMessageBox::critical(QAppl->focusWidget(), "ERROR", Msg); } bool YesNoBox(char *Msg) { int cb; cb = rlp_strcpy(the_message, 450, Msg); rlp_strcpy(the_message+cb, 500-cb, "\n"); if(QMessageBox::information(QAppl->focusWidget(), "RLPlot", the_message, "&Yes", "&No", 0L, 0, -1)) return false; return true; } int YesNoCancelBox(char *Msg) { int res, cb; cb = rlp_strcpy(the_message, 450, Msg); rlp_strcpy(the_message+cb, 500-cb, "\n"); res = QMessageBox::information(QAppl->focusWidget(), "RLPlot", the_message, "&Yes", "&No", "&Cancel", 0, -1); switch(res) { case 0: return 1; case 1: return 0; default: return 2; } return 0; } void Qt_Box() { QMessageBox::aboutQt(QAppl->focusWidget(), "RLPlot uses Qt"); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Temporary visible objects: show action //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class eph_obj { public: eph_obj(eph_obj *nxt); virtual ~eph_obj(); virtual void DoPlot(QPainter *qp) {if(next) next->DoPlot(qp);}; virtual void Animate(anyOutput *o) {if(next) next->Animate(o);}; int cp, rx, ry, rw, rh, anim_base; eph_obj *next; POINT *points, p1, p2; DWORD lcolor; RECT bounds; QPixmap *source; bool invert; }; class eph_line:public eph_obj { public: eph_line(eph_obj *nxt, POINT * pts, int n, DWORD color); ~eph_line(); void DoPlot(QPainter *qp); }; class eph_ellipse:public eph_obj { public: eph_ellipse(eph_obj *nxt, POINT pt1, POINT pt2, DWORD color); ~eph_ellipse(); void DoPlot(QPainter *qp); }; class eph_invert:public eph_obj { public: eph_invert(eph_obj *nxt, QPixmap *src, int x, int y, int w, int h); ~eph_invert(); void DoPlot(QPainter *qp); }; class eph_animated:public eph_obj { public: eph_animated(eph_obj *nxt, int x, int y, int w, int h); ~eph_animated(); void DoPlot(QPainter *qp); void Animate(anyOutput *o); }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ eph_obj::eph_obj(eph_obj *nxt) { next = nxt; points = 0L; lcolor = 0x0; } eph_obj::~eph_obj() { if(next) delete(next); next = 0L; if(points) free(points); points = 0L; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ eph_line::eph_line(eph_obj *nxt, POINT * pts, int n, DWORD color):eph_obj(nxt) { if(points = (POINT*)malloc(n * sizeof(POINT))) { memcpy(points, pts, n * sizeof(POINT)); cp = n; lcolor = color; } } eph_line::~eph_line() { if(next) delete(next); next = 0L; if(points) free(points); points = 0L; } void eph_line::DoPlot(QPainter *qp) { int i; QPen qpen; if(next)next->DoPlot(qp); if(!points || cp < 2) return; 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); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ eph_ellipse::eph_ellipse(eph_obj *nxt, POINT pt1, POINT pt2, DWORD color):eph_obj(nxt) { p1.x = pt1.x; p1.y = pt1.y; p2.x = pt2.x; p2.y = pt2.y; lcolor = color; } eph_ellipse::~eph_ellipse() { if(next) delete(next); next = 0L; } void eph_ellipse::DoPlot(QPainter *qp) { QPen qpen; if(next)next->DoPlot(qp); 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); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ eph_invert::eph_invert(eph_obj *nxt, QPixmap *src, int x, int y, int w, int h):eph_obj(nxt) { eph_obj *eo = nxt; source = src; invert = true; rx = x; ry = y; rw = w; rh = h; while(eo) { eo->invert = false; eo = eo->next; } } eph_invert::~eph_invert() { if(next) delete(next); next = 0L; } void eph_invert::DoPlot(QPainter *qp) { if(next)next->DoPlot(qp); #if QT_VERSION >= 0x040000 QImage qi = (source->copy(rx, ry, rw, rh)).toImage(); if(invert) qi.invertPixels(); qp->drawImage(rx, ry, qi); #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ eph_animated::eph_animated(eph_obj *nxt, int x, int y, int w, int h):eph_obj(nxt) { rx = x; ry = y; rw = w; rh = h; anim_base = 0; SetMinMaxRect(&bounds, x, y, x+w, y+h); IncrementMinMaxRect(&bounds, 2); } eph_animated::~eph_animated() { if(next) delete(next); next = 0L; } void eph_animated::DoPlot(QPainter *qp) { int i, j, sx, sy, rlp; QPen qpen; POINT pts[3]; if(next)next->DoPlot(qp); if(!rw || !rh) return; rlp = anim_base; qpen.setWidth(1); qpen.setStyle(Qt::SolidLine); qpen.setCapStyle(Qt::RoundCap); qpen.setJoinStyle(Qt::RoundJoin); for(i = 0; i < 4; i++) { qpen.setColor((DWORD)0x00ffffffL); qp->setPen(qpen); switch(i) { case 0: pts[0].x = rx; pts[0].y = ry; pts[2].x = rx+rw; pts[2].y = ry; sx = rw > 0 ? 1 : -1; sy = 0; break; case 1: pts[0].x = rx+rw; pts[0].y = ry; pts[2].x = rx+rw; pts[2].y = ry+rh; sx = 0; sy = rh > 0 ? 1 : -1; break; case 2: pts[0].x = rx+rw; pts[0].y = ry+rh; pts[2].x = rx; pts[2].y = ry+rh; sx = rw > 0 ? -1 : 1; sy = 0; break; case 3: pts[0].x = rx; pts[0].y = ry+rh; pts[2].x = rx; pts[2].y = ry; sx = 0; sy = rh > 0 ? -1: 1; break; } qp->drawLine(pts[0].x, pts[0].y, pts[2].x, pts[2].y); qpen.setColor((DWORD)0x0L); qp->setPen(qpen); pts[1].x = pts[0].x; pts[1].y = pts[0].y; for( ; pts[1].x != pts[2].x || pts[1].y != pts[2].y; ) { pts[1].x += sx; pts[1].y += sy; rlp = (rlp+1) & 0x07; if(rlp == 0) { pts[0].x = pts[1].x; pts[0].y = pts[1].y; } else if(rlp == 3) { qp->drawLine(pts[0].x, pts[0].y, pts[1].x, pts[1].y); } } if(rlp < 3 && (pts[0].x != pts[1].x || pts[0].y != pts[1].y)) qp->drawLine(pts[0].x, pts[0].y, pts[1].x, pts[1].y); } } #if QT_VERSION < 0x040000 void eph_animated::Animate(anyOutput *o) { if(next) next->Animate(o); anim_base = (anim_base-1) & 0x07; if(((OutputQT*)o)->widget) { QPainter qp(((OutputQT*)o)->widget); DoPlot(&qp); } else if(((OutputQT*)o)->dlgwidget) { QPainter qp(((OutputQT*)o)->dlgwidget); DoPlot(&qp); } } #else void eph_animated::Animate(anyOutput *o) { if(next) next->Animate(o); anim_base = (anim_base-1) & 0x07; o->UpdateRect(&bounds, false); } #endif //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Display blinking text cursor //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ static anyOutput *oTxtCur = 0L, *txtcur0 = 0L, *txtcur1 = 0L; static anyOutput *oCopyMark = 0L; RECT rTxtCur, rCopyMark; static bool bTxtCur = false, bSuspend = false; static DWORD coTxtCur = 0x0L; static TxtCurBlink *cTxtCur = 0L; static POINT ptTxtCurLine[2]; void HideTextCursor() { if(txtcur0 && txtcur1) { DelBitmapClass(txtcur1); RestoreRectBitmap(&txtcur0, &rTxtCur, oTxtCur); } else if(oTxtCur) { bTxtCur = false; oTxtCur->UpdateRect(&rTxtCur, false); } txtcur0 = txtcur1 = oTxtCur = 0L; } void HideTextCursorObj(anyOutput *out) { if(oTxtCur && oTxtCur == out) HideTextCursor(); } 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; ptTxtCurLine[1].x = rTxtCur.right - rTxtCur.left; ptTxtCurLine[1].y = rTxtCur.bottom-rTxtCur.top; rTxtCur.bottom++; rTxtCur.right++; bTxtCur = true; txtcur0 = GetRectBitmap(&rTxtCur, out); txtcur1 = GetRectBitmap(&rTxtCur, out); liTxtCur.color = color; txtcur1->SetLine(&liTxtCur); txtcur1->oPolyline(ptTxtCurLine, 2); if(cTxtCur) cTxtCur->Show(); } void InitTextCursor(bool init) { if(init && !cTxtCur) cTxtCur = new TxtCurBlink(); else if(!init && cTxtCur) { delete cTxtCur; cTxtCur = 0L; } } void HideCopyMark() { if(oCopyMark) { if(((OutputQT*)oCopyMark)->ShowObj) delete (eph_obj*)(((OutputQT*)oCopyMark)->ShowObj); if(((OutputQT*)oCopyMark)->ShowAnimated) delete (eph_obj*)(((OutputQT*)oCopyMark)->ShowAnimated); (((OutputQT*)oCopyMark)->ShowObj) = (((OutputQT*)oCopyMark)->ShowAnimated) = 0L; oCopyMark->UpdateRect(&rCopyMark, false); } oCopyMark = 0L; } 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); ((OutputQT*)out)->ShowAnimated = (new eph_animated((eph_obj*) 0L, mrk[0].left, mrk[0].top, mrk[0].right - mrk[0].left, mrk[0].bottom - mrk[0].top)); oCopyMark = out; rCopyMark.left = mrk[0].left; rCopyMark.right = mrk[0].right; rCopyMark.top = mrk[0].top; rCopyMark.bottom = mrk[0].bottom; for(i = 1; i < nRec; i++) { UpdateMinMaxRect(&rCopyMark, mrk[i].left, mrk[i].top); UpdateMinMaxRect(&rCopyMark, mrk[i].right, mrk[i].bottom); } IncrementMinMaxRect(&rCopyMark, 2); out->UpdateRect(&rCopyMark, false); } 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) { oTxtCur = 0L; bTxtCur = false; } } void SuspendAnimation(anyOutput *o, bool bSusp) { if(!o || (o->OC_type&0xff) != OC_BITMAP) return; if(!o || !cTxtCur) return; if(!bSusp) bSuspend = false; else { if(o == oCopyMark) bSuspend = bSusp; if(o == oTxtCur) bSuspend = 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); } TxtCurBlink::TxtCurBlink():QObject(CurrWidget) { isVis = false; count = 0; startTimer(60); } void TxtCurBlink::Show() { count = -4; isVis = true; if(bTxtCur && oTxtCur && txtcur0 && txtcur1){ oTxtCur->CopyBitmap(rTxtCur.left, rTxtCur.top, txtcur1, 0, 0, rTxtCur.right - rTxtCur.left, rTxtCur.bottom - rTxtCur.top, false); oTxtCur->UpdateRect(&rTxtCur, false); } } void TxtCurBlink::timerEvent(QTimerEvent *ev) { if(bSuspend) return; showCopyMark(); if(!oTxtCur || (ptTxtCurLine[0].x == ptTxtCurLine[1].x && ptTxtCurLine[0].y == ptTxtCurLine[1].y)) return; count++; if(count < 10) return; count = 0; if(bTxtCur && oTxtCur) { if(isVis) { oTxtCur->CopyBitmap(rTxtCur.left, rTxtCur.top, txtcur0, 0, 0, rTxtCur.right - rTxtCur.left, rTxtCur.bottom - rTxtCur.top, false); oTxtCur->UpdateRect(&rTxtCur, false); isVis = false; } else { oTxtCur->CopyBitmap(rTxtCur.left, rTxtCur.top, txtcur1, 0, 0, rTxtCur.right - rTxtCur.left, rTxtCur.bottom - rTxtCur.top, false); oTxtCur->UpdateRect(&rTxtCur, false); isVis = true; } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Clipboard support: the clipboard server uses sockets // code based on Qt example code //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ static RLPserver *rlpsrv = 0L; #ifdef RLP_PORT static char *cb_owner = 0L; //user name #if __GCC__ >= 3 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // close remote clipboard server //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ bool CloseCB(char *msg) { int i, cb, sock; char buff[1024]; sockaddr_in cb_host; hostent *hp; if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) return false; if(!(hp = gethostbyname("127.0.0.1")))return false; memset(&cb_host, 0, sizeof(cb_host)); 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 && 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; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // connect and read remote clipboard server //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ bool ReadCB(char *server, GraphObj *g) { int i, j, sock, cb; char buff[1024], line[25], format[20], *cb_data; sockaddr_in cb_host; hostent *hp; bool bRet = false; if(!g || ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)) return false; if(!(hp = gethostbyname("127.0.0.1")))return false; memset(&cb_host, 0, sizeof(cb_host)); 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 && 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; } 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; } line[j] = 0; if(g->Id == GO_SPREADDATA && (strcmp(line, "text/xml") == 0 || strcmp(line, "text/rlp-graph") == 0 || strcmp(line, "text/rlp-page") == 0)) { rlp_strcpy(format, 20, line); i = cb; } else if((g->Id == GO_PAGE || g->Id == GO_GRAPH) && (strcmp(line, "text/rlp-graph") == 0 || strcmp(line, "text/rlp-page") == 0)) { rlp_strcpy(format, 20, line); i = cb; } } if(format[0] && (cb_data = (char*)malloc(j = 1024))) { cb = rlp_strcpy(line, 25, "get "); cb += rlp_strcpy(line+cb, 25-cb, format); line[cb++] = '\n'; line[cb++] = 0; if(write(sock, line, cb) >= 0) { cb = 0; while((i = read(sock, cb_data+cb, 1024)) == 1024) { cb_data = (char*)realloc(cb_data, (j += 1024)); cb += i; } cb += i; cb_data[cb] = 0; if(cb > 5 && g->Id == GO_SPREADDATA) { bRet = true; if(strcmp(format, "text/xml") == 0) g->Command(CMD_PASTE_XML, (void*)cb_data, 0L); else if(strcmp(format, "text/rlp-graph") == 0) OpenGraph(g, 0L, (unsigned char*)cb_data, true); else if(strcmp(format, "text/rlp-page") == 0) OpenGraph(g, 0L, (unsigned char*)cb_data, true); else bRet = false; } else if(cb > 5 && (g->Id == GO_PAGE || g->Id == GO_GRAPH)) { bRet = true; if(strcmp(format, "text/rlp-graph") == 0) OpenGraph(g, 0L, (unsigned char*)cb_data, true); else if(strcmp(format, "text/rlp-page") == 0) OpenGraph(g, 0L, (unsigned char*)cb_data, true); else bRet = false; } } } } } close(sock); return bRet; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // this thread is a single-threaded server //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ static void *ServerCB(void* attr) { int cb, msgsock; char buff[1024], *data; static char *fmts_1 = "text/xml\ntext/plain\n"; static char *fmts_2 = "text/rlp-graph\n"; static char *fmts_3 = "text/rlp-page\n"; RLPserver *parent = (RLPserver*)attr; sockaddr_in client; socklen_t clientlen = sizeof(client); 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; 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); } else if(parent->SourceGO->Id == GO_GRAPH) { write(msgsock, fmts_2, strlen(fmts_2)+1); } else if(parent->SourceGO->Id == GO_PAGE) { write(msgsock, fmts_3, strlen(fmts_3)+1); } else close(msgsock); } else if(strcmp(buff, "get text/xml\n") == 0) { if(data = parent->GetXML()) write(msgsock, data, strlen(data)+1); close(msgsock); } else if(strcmp(buff, "get text/plain\n") == 0) { if(data = parent->GetTXT()) write(msgsock, data, strlen(data)+1); close(msgsock); } else if(strcmp(buff, "get text/rlp-graph\n") == 0 || strcmp(buff, "get text/rlp-page\n") == 0) { if(data = parent->GetRLP()) write(msgsock, data, strlen(data)+1); close(msgsock); } else if(strcmp(buff, "exit\n") == 0 || strcmp(buff, "close\n") == 0 || strcmp(buff, "exit") == 0 || strcmp(buff, "close") == 0) { 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; } else if(strcmp(buff, "user\n") == 0 || strcmp(buff, "user:") == 0) { write(msgsock, cb_owner, strlen(cb_owner)+1); } } close(msgsock); } else if(msgsock < 0) return 0L; } return 0L; } // 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); CreateThread(); } RLPserver::~RLPserver() { rlpsrv = 0L; HideCopyMark(); if(text_xml) free(text_xml); text_xml = 0L; 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 //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 RLPserver::SetGO(GraphObj *g) { QClipboard *cb; SourceGO = g; if(text_xml) free(text_xml); text_xml = 0L; if(text_rlp) free(text_rlp); text_rlp = 0L; if(text_plain) free(text_plain); text_plain = 0L; if(SourceGO && SourceGO->Id == GO_SPREADDATA) { SourceGO->Command(CMD_COPY_TSV, &text_plain, 0L); if(text_plain && text_plain[0]){ cb = QAppl->clipboard(); cb->clear(); #if QT_VERSION < 0x030000 //n.a. in Qt version 2 cb->setText(text_plain, QClipboard::Clipboard); cb->setText(text_plain, QClipboard::Selection); #else cb->setText(text_plain); #endif } } if(!bValid) CreateThread(); } char * RLPserver::GetXML() { if(SourceGO && SourceGO->Id == GO_SPREADDATA) { if(!text_xml) SourceGO->Command(CMD_COPY_XML, &text_xml, 0L); return text_xml; } return 0L; } char * RLPserver::GetRLP() { long cb; if(SourceGO) { text_rlp = GraphToMem(SourceGO, &cb); return text_rlp; } return 0L; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Process paste command: check for clipboard contents void TestClipboard(GraphObj *g) { QClipboard *cb; if(!g) return; if(rlpsrv && rlpsrv->SourceGO) { if(rlpsrv->SourceGO->Id == GO_GRAPH || rlpsrv->SourceGO->Id == GO_PAGE || rlpsrv->SourceGO->Id == GO_POLYLINE || rlpsrv->SourceGO->Id == GO_POLYGON || rlpsrv->SourceGO->Id == GO_RECTANGLE || rlpsrv->SourceGO->Id == GO_ROUNDREC || 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){ 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; if((cb = QAppl->clipboard()) && (mime = (QDragObject *)cb->data())) { if(g->Id == GO_SPREADDATA) { if(mime->provides("text/plain")) { ProcMemData(g, (unsigned char*)cb->text().latin1(), true); return; } } } #else const QMimeData *mime; const char *cdata; if((cb = QAppl->clipboard()) && (mime = cb->mimeData())) { if(g->Id == GO_SPREADDATA) { if(mime->hasFormat("text/plain")) { QByteArray b = mime->data("text/plain"); if(cdata = b) ProcMemData(g, (unsigned char*)cdata, true); return; } } } #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Copy spreadsheet or graph to clipboard void CopyData(GraphObj *g) { QAppl->clipboard()->clear(); if(rlpsrv) rlpsrv->SetGO(g); else rlpsrv = new RLPserver(0, g); } void CopyGraph(GraphObj *g) { if(g->Id == GO_PAGE && CurrGraph) CopyData(CurrGraph); else CopyData(g); } void EmptyClip() { #if __GCC__ >= 3 #ifdef RLP_PORT CloseCB("close\n"); #endif //RLP_PORT #endif //GCC if(rlpsrv && !rlpsrv->bValid) { delete(rlpsrv); rlpsrv = 0L; } HideCopyMark(); QAppl->clipboard()->clear(); } void CopyText(char *txt, int len) { QClipboard *cb; EmptyClip(); if(!(cb = QAppl->clipboard()) || !txt || !txt[0]) return; cb->clear(); cb->setText(txt); } unsigned char* PasteText() { QClipboard *cb = QAppl->clipboard(); #if QT_VERSION < 0x040000 return (unsigned char*)cb->text().ascii(); #else return (unsigned char*)cb->text().toAscii().data(); #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Get display (desktop) size //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void GetDesktopSize(int *width, int *height) { #if QT_VERSION < 0x040000 QWidget *d = QApplication::desktop(); #else QDesktopWidget *d = QApplication::desktop(); #endif if(d) { *width = d->width(); *height = d->height(); } if(!d || *width < 800 || *height < 600){ *width = 1280; *height = 1024; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Common code for all QT output classes //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ bool com_QStringExt(QString txt, int *width, int *height, int cb, TextDEF *TxtSet, QPainter *qP) { QRect rc; if(cb >0)txt.truncate(cb); rc = qP->boundingRect(0, 0, 10000, 1000, Qt::AlignLeft | Qt::AlignTop, txt); #if QT_VERSION < 0x040000 *width = rc.rRight() - rc.rLeft(); *height = TxtSet->iSize +2; #else *width = rc.width(); *height = TxtSet->iSize +2; #endif return true; } bool com_GetTextExtent(char *txt, int *width, int *height, int cb, TextDEF *TxtSet, QPainter *qP) { if(!txt || !txt[0]) return com_QStringExt(QString("a"), width, height, 1, TxtSet, qP); else return com_QStringExt(QString(txt), width, height, cb > 0 ? cb : (int)strlen(txt), TxtSet, qP); } bool com_GetTextExtentW(w_char *txt, int *width, int *height, int cb, TextDEF *TxtSet, QPainter *qP) { int i; QString wtxt(0); if(!txt || !txt[0]) return com_QStringExt(QString("a"), width, height, 1, TxtSet, qP); for(i = 0; txt[i] && i < cb; i++) wtxt.append(QChar(txt[i])); com_QStringExt(wtxt, width, height, cb, TxtSet, qP); } bool com_QStringOut(int x, int y, QString txt, TextDEF *TxtSet, QPainter *qP, anyOutput *o) { int i, w, h, ix, iy; QBrush oldBrush; QPen oldPen, currPen; #if QT_VERSION >= 0x040000 QMatrix xf, dxf; #else QWMatrix xf, dxf; #endif if(!TxtSet->iSize && TxtSet->fSize > 0.0) TxtSet->iSize = o->un2ix(TxtSet->fSize); if(!TxtSet->iSize) return false; if(TxtSet->Align & TXA_VCENTER) y += iround(TxtSet->iSize * 0.4); else if(TxtSet->Align & TXA_VBOTTOM) y -= iround(TxtSet->iSize * 0.1); else y += iround(TxtSet->iSize); oldBrush = qP->brush(); dxf = qP->worldMatrix(); oldPen = currPen = qP->pen(); iy = y; com_QStringExt(txt, &w, &h, -1, TxtSet, qP); if(TxtSet->Align & TXA_HCENTER) ix = x - (w >> 1); else if(TxtSet->Align & TXA_HRIGHT) ix = x - w; else ix = x; 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(MK_QCOLOR(TxtSet->ColBg)); qP->setPen(currPen); qP->setBrush(MK_QCOLOR(TxtSet->ColBg)); qP->drawRect(0, - iround(h*.8), w, h); currPen.setColor(MK_QCOLOR(TxtSet->ColTxt)); qP->setPen(currPen); } if(TxtSet->Style & TXS_SUB) iy += ((TxtSet->iSize <<2)/10); else if(TxtSet->Style & TXS_SUPER) iy -= ((TxtSet->iSize <<2)/10); qP->drawText(ix-x, iy-y, txt); } else { if(TxtSet->Mode == TXM_OPAQUE){ currPen.setColor(MK_QCOLOR(TxtSet->ColBg)); qP->setPen(currPen); qP->setBrush(MK_QCOLOR(TxtSet->ColBg)); qP->drawRect(ix, iy - iround(h*.8), w, h); currPen.setColor(MK_QCOLOR(TxtSet->ColTxt)); qP->setPen(currPen); } if(TxtSet->Style & TXS_SUB) iy += o->un2iy(TxtSet->fSize*0.4); else if(TxtSet->Style & TXS_SUPER) iy -= o->un2iy(TxtSet->fSize*0.4); qP->drawText(ix, iy, txt); } oldPen.setCapStyle(Qt::RoundCap); oldPen.setJoinStyle(Qt::RoundJoin); qP->setPen(oldPen); qP->setBrush(oldBrush); qP->setWorldMatrix(dxf, FALSE); return true; } bool com_TextOut(int x, int y, char *ctxt, TextDEF *TxtSet, QPainter *qP, anyOutput *o) { int i, w, h, ix, iy; QString txt(ctxt); if(!ctxt || !ctxt[0] || !TxtSet || !qP || !o) return false; if(TxtSet->Font==FONT_GREEK) { txt.truncate(0); for(i = 0; ctxt[i]; i++) { if((ctxt[i] >= 'A' && ctxt[i] <= 'Z')) txt.append(QChar(ctxt[i] - 'A' + 0x391)); else if((ctxt[i] >= 'a' && ctxt[i] <= 'z')) txt.append(QChar(ctxt[i] - 'a' + 0x3B1)); else txt.append(QChar(ctxt[i])); } } return com_QStringOut(x, y, txt, TxtSet, qP, o); } bool com_TextOutW(int x, int y, w_char *wtxt, TextDEF *TxtSet, QPainter *qP, anyOutput *o) { int i; QString txt(0); if(!wtxt || !wtxt[0] || !TxtSet || !qP || !o) return false; for(i = 0; wtxt[i]; i++) txt.append(QChar(wtxt[i])); return com_QStringOut(x, y, txt, TxtSet, qP, o); } bool com_SetTextSpec(TextDEF *set, TextDEF *TxtSet, anyOutput *o, QFont qF, QPainter *qP) { bool RetVal; if(!set->iSize && set->fSize > 0.0) set->iSize = o->un2iy(set->fSize); if(!set->iSize) return false; RetVal = o->anyOutput::SetTextSpec(set); if(true) { qF.setBold((TxtSet->Style & TXS_BOLD) ? true : false); qF.setItalic((TxtSet->Style & TXS_ITALIC) ? true : false); qF.setUnderline((TxtSet->Style &TXS_UNDERLINE) ? true : false); if((TxtSet->Style & TXS_SUPER) || (TxtSet->Style & TXS_SUB)) qF.setPointSize((TxtSet->iSize > 1) ? (int)(TxtSet->iSize*0.71) : 1); else qF.setPointSize((TxtSet->iSize > 2) ? TxtSet->iSize : 2); switch(TxtSet->Font){ case FONT_HELVETICA: default: qF.setFamily("Helvetica"); break; case FONT_GREEK: case FONT_TIMES: qF.setFamily("Times"); break; case FONT_COURIER: qF.setFamily("Courier"); break; } qP->setFont(qF); if(TxtSet->fSize >0.0) TxtSet->iSize = o->un2iy(TxtSet->fSize); //correct for printer } return RetVal; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Icon definitions //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //this icon has been taken from trolltech's Qt: qmessagebox.cpp const static char *information_xpm[]={ "32 32 5 1", ". c None", "c c #000000", "* c #999999", "a c #ffffff", "b c #0000ff", "...........********.............", "........***aaaaaaaa***..........", "......**aaaaaaaaaaaaaa**........", ".....*aaaaaaaaaaaaaaaaaa*.......", "....*aaaaaaaabbbbaaaaaaaac......", "...*aaaaaaaabbbbbbaaaaaaaac.....", "..*aaaaaaaaabbbbbbaaaaaaaaac....", ".*aaaaaaaaaaabbbbaaaaaaaaaaac...", ".*aaaaaaaaaaaaaaaaaaaaaaaaaac*..", "*aaaaaaaaaaaaaaaaaaaaaaaaaaaac*.", "*aaaaaaaaaabbbbbbbaaaaaaaaaaac*.", "*aaaaaaaaaaaabbbbbaaaaaaaaaaac**", "*aaaaaaaaaaaabbbbbaaaaaaaaaaac**", "*aaaaaaaaaaaabbbbbaaaaaaaaaaac**", "*aaaaaaaaaaaabbbbbaaaaaaaaaaac**", "*aaaaaaaaaaaabbbbbaaaaaaaaaaac**", ".*aaaaaaaaaaabbbbbaaaaaaaaaac***", ".*aaaaaaaaaaabbbbbaaaaaaaaaac***", "..*aaaaaaaaaabbbbbaaaaaaaaac***.", "...caaaaaaabbbbbbbbbaaaaaac****.", "....caaaaaaaaaaaaaaaaaaaac****..", ".....caaaaaaaaaaaaaaaaaac****...", "......ccaaaaaaaaaaaaaacc****....", ".......*cccaaaaaaaaccc*****.....", "........***cccaaaac*******......", "..........****caaac*****........", ".............*caaac**...........", "...............caac**...........", "................cac**...........", ".................cc**...........", "..................***...........", "...................**..........."}; //this icon has been taken from trolltech's Qt: qmessagebox.cpp const static char *critical_xpm[]={ "32 32 4 1", ". c None", "a c #999999", "* c #ff0000", "b c #ffffff", "...........********.............", ".........************...........", ".......****************.........", "......******************........", ".....********************a......", "....**********************a.....", "...************************a....", "..*******b**********b*******a...", "..******bbb********bbb******a...", ".******bbbbb******bbbbb******a..", ".*******bbbbb****bbbbb*******a..", "*********bbbbb**bbbbb*********a.", "**********bbbbbbbbbb**********a.", "***********bbbbbbbb***********aa", "************bbbbbb************aa", "************bbbbbb************aa", "***********bbbbbbbb***********aa", "**********bbbbbbbbbb**********aa", "*********bbbbb**bbbbb*********aa", ".*******bbbbb****bbbbb*******aa.", ".******bbbbb******bbbbb******aa.", "..******bbb********bbb******aaa.", "..*******b**********b*******aa..", "...************************aaa..", "....**********************aaa...", "....a********************aaa....", ".....a******************aaa.....", "......a****************aaa......", ".......aa************aaaa.......", ".........aa********aaaaa........", "...........aaaaaaaaaaa..........", ".............aaaaaaa............"}; //thanks to Markus Bongard for the following icon const static char *RLPlot_xpm[]={ /* width height ncolors chars_per_pixel */ "32 32 169 2", /* colors */ "AA c #FFFFFFFFFFFF", "BA c #FFFFF7F79494", "CA c #FFFFF7F78484", "DA c #FFFFF7F77373", "EA c #FFFFF7F75252", "FA c #FFFFF7F74242", "GA c #FFFFF7F73939", "HA c #FFFFEFEF8C8C", "IA c #FFFFEFEF4A4A", "JA c #FFFFEFEF2929", "KA c #F7F7E7E77B7B", "LA c #F7F7C6C6ADAD", "MA c #F7F7B5B59C9C", "NA c #F7F7ADAD9494", "OA c #EFEFF7F7F7F7", "PA c #EFEFF7F7EFEF", "AB c #EFEFEFEFEFEF", "BB c #EFEFEFEFDEDE", "CB c #EFEFE7E7A5A5", "DB c #EFEFDEDE7373", "EB c #EFEFDEDE3939", "FB c #EFEFDEDE2929", "GB c #EFEFD6D64242", "HB c #EFEFA5A58C8C", "IB c #EFEF94947B7B", "JB c #EFEF84847373", "KB c #EFEF84846363", "LB c #EFEF7B7B7373", "MB c #E7E7E7E7CECE", "NB c #E7E7E7E79494", "OB c #E7E7DEDE6B6B", "PB c #E7E7DEDE5252", "AC c #E7E7CECE5252", "BC c #E7E77B7B6363", "CC c #E7E773735A5A", "DC c #E7E76B6B5252", "EC c #E7E75A5A4A4A", "FC c #DEDEE7E7F7F7", "GC c #DEDEE7E7EFEF", "HC c #DEDEDEDEDEDE", "IC c #DEDEDEDEBDBD", "JC c #DEDECECE4A4A", "KC c #DEDE4A4A3939", "LC c #D6D6EFEFCECE", "MC c #D6D6DEDEEFEF", "NC c #D6D6DEDECECE", "OC c #CECEDEDEDEDE", "PC c #CECED6D6CECE", "AD c #CECECECEB5B5", "BD c #CECECECE5A5A", "CD c #C6C6E7E7C6C6", "DD c #C6C6DEDEEFEF", "ED c #C6C6D6D67373", "FD c #C6C6CECE4A4A", "GD c #BDBDDEDEB5B5", "HD c #BDBDCECEE7E7", "ID c #BDBDCECECECE", "JD c #BDBDC6C6D6D6", "KD c #BDBD39394242", "LD c #B5B5DEDEADAD", "MD c #B5B5BDBDCECE", "ND c #B5B5BDBD4242", "OD c #B5B5B5B59C9C", "PD c #ADADD6D6ADAD", "AE c #ADADCECEDEDE", "BE c #ADADBDBDB5B5", "CE c #ADADB5B54242", "DE c #ADAD4A4A5252", "EE c #A5A5BDBDDEDE", "FE c #A5A5BDBDCECE", "GE c #A5A5ADADB5B5", "HE c #A5A5ADAD4242", "IE c #A5A563637B7B", "JE c #9C9CD6D6A5A5", "KE c #9C9CBDBDD6D6", "LE c #9C9CBDBDBDBD", "ME c #9C9CADADCECE", "NE c #9C9CADADA5A5", "OE c #9C9C52525252", "PE c #9C9C4A4A5252", "AF c #9494CECE9C9C", "BF c #9494B5B5CECE", "CF c #9494ADAD5A5A", "DF c #9494ADAD3939", "EF c #8C8CCECE9494", "FF c #8C8CCECE8C8C", "GF c #8C8CB5B5B5B5", "HF c #8C8CADADD6D6", "IF c #8C8CADADCECE", "JF c #8C8CADADB5B5", "KF c #8C8CADADA5A5", "LF c #8C8C9C9CB5B5", "MF c #8C8C9C9CADAD", "NF c #8C8C8C8CA5A5", "OF c #8C8C52526363", "PF c #8C8C42425252", "AG c #8484B5B5CECE", "BG c #7B7BCECE9494", "CG c #7B7BC6C68484", "DG c #7B7BC6C67B7B", "EG c #7B7BADADC6C6", "FG c #7B7BADADADAD", "GG c #7B7B9C9CC6C6", "HG c #7B7B9C9CB5B5", "IG c #7B7B9C9CADAD", "JG c #7B7B84849C9C", "KG c #7B7B42425252", "LG c #737384848C8C", "MG c #737373738484", "NG c #737339395252", "OG c #6B6BC6C68484", "PG c #6B6BBDBD7B7B", "AH c #6B6BA5A5CECE", "BH c #6B6B9C9CBDBD", "CH c #6B6B9C9CA5A5", "DH c #6B6B94949C9C", "EH c #6B6B8C8CA5A5", "FH c #6B6B8C8C9C9C", "GH c #6B6B6B6B7B7B", "HH c #6B6B42425252", "IH c #6363BDBD6B6B", "JH c #6363B5B58C8C", "KH c #6363A5A58C8C", "LH c #63639C9CC6C6", "MH c #5A5AB5B56363", "NH c #5A5A9C9CBDBD", "OH c #5A5A8C8C9C9C", "PH c #5A5A7B7B8C8C", "AI c #5A5A6B6B8484", "BI c #5A5A63637B7B", "CI c #5252BDBD7373", "DI c #5252ADAD8484", "EI c #5252A5A57B7B", "FI c #4A4AB5B55A5A", "GI c #4A4A8C8CBDBD", "HI c #4A4A8C8CADAD", "II c #4A4A7B7B9C9C", "JI c #4A4A7B7B8484", "KI c #4A4A6B6B7B7B", "LI c #42429C9C7373", "MI c #42428C8C7B7B", "NI c #42425A5A7373", "OI c #42424A4A6B6B", "PI c #3939ADAD6B6B", "AJ c #3939ADAD5A5A", "BJ c #39399C9C6B6B", "CJ c #39398484BDBD", "DJ c #39397B7BADAD", "EJ c #39397B7B8C8C", "FJ c #393973737B7B", "GJ c #313163637B7B", "HJ c #31315A5A7B7B", "IJ c #292984846B6B", "JJ c #29296B6B7B7B", "KJ c #21217B7BB5B5", "LJ c #21217373A5A5", "MJ c #212173739C9C", "NJ c #21216B6B8C8C", "OJ c #212152527373", "PJ c #181884846363", "AK c #18186B6B7B7B", "BK c #18185A5A7373", "CK c #10106B6B9C9C", "DK c #10105A5A8484", "EK c #08087B7B6363", "FK c #08085A5A7B7B", "GK c #00006B6B9C9C", "HK c #000063637B7B", "IK c #00005A5A8C8C", /* pixels */ "CJAHAHAHAHHILHLHBHLHLJNHNHNHGINHGINHGINHGINHGINHGINHGINHGINHGIKJ", "AHAAAAAAAGHDABBBGCBFBFHCPCOCEEHDJDEEJDEEHDJDEEHDJDEEJDEEHDEEJDNH", "AHAAAGAAABABABKEOCHCHCPCFEFEABAEHDFCDDJDDDMCJDHDFCHDHDGCDDJDDDLH", "EGAEDDABOAABOCEGHCHCPCHCBHJDJDEEJDEEJDEEJDAEJDEEAEJDEEJDEEJDEELH", "AHAAAAAAMCJDGCABHCHCBFOCPCJDEEJDEEJDEEAEEEEEAEJDEEFEFEFEEEEEJDGI", "AHAAAAPAAGGCABBBMCEGJDNCPCPCEEEEEEEEEEEEEEJDEEEEFEDIPIGFFEFEEENH", "EGOAKEAAABPAABKEHCHCHCHCMEBFABJDAEMCOCEEMCMCFEOCDDLEKHIDIDEEDDLH", "LHAEMCAAABABAEIFHCHCHCPCBHOCKEKEEEFEEEFEEEFEEEKEBFGEDIKFMEFEEEGI", "AHAAAAABGCJDABGCBBOCHGHCPCMDEEFEKEEEFEKEFEKEEEMEBFJFDIGEIFBFFEGI", "AHAAAAPAAHGCABBBMCJFMDOCPCJDMEKEKEMEKEKEKEKEMEIFGEFGEIIGJFGEMEGI", "AHAAAEAAABABGCNBDBOCNCNCMDEEMCEEEEMCJDKEDDDDLFCIDIEIPICIDIDIJDNH", "AHKEDDAAPAABOCKFPBICNCPCHGFEMEMEMEMEHFMEMEIFJFJELCCDCGBBCDLIIGHI", "EGAAAAABABJDMBNCPBADGENCMDMDMEHFIFHFMEHFIFMECHJEPCLDBGGDGDLIIGDJ", "AHAAAAAAAHEDKAOBEBBDCEODICMDIFIFMEIFIFIFIFIFCHEFLDPDOGGDPDMIFHHI", "AHAAOCABMBEABABAFABABAGBNELEHDKEHFDDEEIFJDEEFGCGLDPDPGPDPDAJMFHI", "AHDDEGABBBEABACAFABACBGBFHGEIFGGIFGGIFIFGGIFDHCGJEMHFIAFAFBJDHII", "AHAAAAABMBEAHAEAEADACABDODBEHGIFGGIFHGGGIFHGCHJHAFAFEFAFFFFJDHMJ", "AHAAAAAABEIADADAKACADAGBODNEGGHGIEIENFGGHGGGOHDGFFFFFFFFFFAJOHHI", "AHAAABABPCGAKADADAKADAFDODMFHIHIAIPFIIIIHIHIEJCIFFDGFFDGDGJJFJCK", "AHAAAHHCMBGAEAEAEAFAFAJCLGFKPEPEPEKDPEPEOIIKHKLIDGDGPGDGIHEKIKGK", "EGFCDDAANCJAIAIAIAIAIANDBKOJJBLALALBLAMANGFKHKFIMHPGMHFILIEKFKGK", "LHAAAABBNCFBJAJAJAEBGBDFBKOJBCNADCDCIBHBNGBKAKFIMHMHMHMHMHEKHKGK", "AHAAAAABADEBJCEBGBACACHEBKNIBCJBJBHBJBJBHHOJJJPIIHPGIHIHIHPJDKGK", "AHAAOCJDNCEBOBACOBOBOBHEEJNIKCLBKBBCKBCCKGHJJJMHDGIHPGDGIHEKEJCK", "AHAAKEABMBEBDBDBOBOBOBHENIAIKCDCDCDCDCECKGKIGJCIDGFFLGDGDGPJNJMJ", "CJAAOAABBBIADBHADBHAKAHEAIBIDCDCBCCCDCCCPFKIJIPGBGCFDGFFDGIJIIMJ", "AHAAAAABMBIABADBBAHAHAHEAIGHKCJBBCKBKBBCKGPHJIPGFFGFFFFFFFIJJILJ", "AHAAAAABMDFDFDBDFDNDBDHEFHJGDEDEDEDEOEDEOFPHMGBJBJAJBJBJBJMIOHDJ", "EGAAAAJDHGNFFHMGFHJGMGEHJGNFNFMGMGMGMGMGLGJGCHEHFHPHMGOHPHFHIGDJ", "LHAAOCIFIFIFLFLFMFMFJFLFIFJFHGIGMFIGNFMFMFLFIFLFHGIGFGIGIGHGJFCJ", "EGDDKEKEMEBFBFBFBFMEBFBFFEKEMEMEMEGEBFMEBFBFBFKEMEBFMEBFBFKEKEGI", "KJLHGINHGINHNHNHNHGINHNHGINHGINHNHGIGINHGINHNHGINHNHGIGINHNHGICJ"}; //this icon has been taken from trolltech's Qt: qmessagebox.cpp const static char *qtlogo_xpm[] = { /* width height ncolors chars_per_pixel */ "50 50 17 1", /* colors */ " c #000000", ". c #495808", "X c #2A3304", "o c #242B04", "O c #030401", "+ c #9EC011", "@ c #93B310", "# c #748E0C", "$ c #A2C511", "% c #8BA90E", "& c #99BA10", "* c #060701", "= c #181D02", "- c #212804", "; c #61770A", ": c #0B0D01", "/ c None", /* pixels */ "/$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$/", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$+++$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$@;.o=::=o.;@$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$+#X* **X#+$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$#oO* O **o#+$$$$$$$$$$$$$$", "$$$$$$$$$$$$$&.* OO O*.&$$$$$$$$$$$$$", "$$$$$$$$$$$$@XOO * OO X&$$$$$$$$$$$$", "$$$$$$$$$$$@XO OO O **:::OOO OOO X@$$$$$$$$$$$", "$$$$$$$$$$&XO O-;#@++@%.oOO X&$$$$$$$$$$", "$$$$$$$$$$.O : *-#+$$$$$$$$+#- : O O*.$$$$$$$$$$", "$$$$$$$$$#*OO O*.&$$$$$$$$$$$$+.OOOO **#$$$$$$$$$", "$$$$$$$$+-OO O *;$$$$$$$$$$$&$$$$;* o+$$$$$$$$", "$$$$$$$$#O* O .+$$$$$$$$$$@X;$$$+.O *#$$$$$$$$", "$$$$$$$$X* -&$$$$$$$$$$@- :;$$$&- OX$$$$$$$$", "$$$$$$$@*O *O#$$$$$$$$$$@oOO**;$$$# O*%$$$$$$$", "$$$$$$$; -+$$$$$$$$$@o O OO ;+$$-O *;$$$$$$$", "$$$$$$$. ;$$$$$$$$$@-OO OO X&$$;O .$$$$$$$", "$$$$$$$o *#$$$$$$$$@o O O O-@$$$#O *o$$$$$$$", "$$$$$$+= *@$$$$$$$@o* OO -@$$$$&: =$$$$$$$", "$$$$$$+: :+$$$$$$@- *-@$$$$$$: :+$$$$$$", "$$$$$$+: :+$$$$$@o* O *-@$$$$$$: :+$$$$$$", "$$$$$$$= :@$$$$@o*OOO -@$$$$@: =+$$$$$$", "$$$$$$$- O%$$$@o* O O O O-@$$$#* OX$$$$$$$", "$$$$$$$. O *O;$$&o O*O* *O -@$$; O.$$$$$$$", "$$$$$$$;* Oo+$$;O*O:OO-- Oo@+= *;$$$$$$$", "$$$$$$$@* O O#$$$;*OOOo@@-O Oo;O* **@$$$$$$$", "$$$$$$$$X* OOO-+$$$;O o@$$@- O O OX$$$$$$$$", "$$$$$$$$#* * O.$$$$;X@$$$$@-O O O#$$$$$$$$", "$$$$$$$$+oO O OO.+$$+&$$$$$$@-O o+$$$$$$$$", "$$$$$$$$$#* **.&$$$$$$$$$$@o OO:#$$$$$$$$$", "$$$$$$$$$+. O* O-#+$$$$$$$$+;O OOO:@$$$$$$$$$", "$$$$$$$$$$&X *O -;#@++@#;=O O -@$$$$$$$$", "$$$$$$$$$$$&X O O*O::::O OO Oo@$$$$$$$", "$$$$$$$$$$$$@XOO OO O*X+$$$$$$", "$$$$$$$$$$$$$&.* ** O :: *:#$$$$$$$", "$$$$$$$$$$$$$$$#o*OO O Oo#@-OOO=#$$$$$$$$", "$$$$$$$$$$$$$$$$+#X:* * O**X#+$$@-*:#$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$%;.o=::=o.#@$$$$$$@X#$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$+++$$$$$$$$$$$+$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "/$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$/"}; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Bitmap class for display export etc. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #if QT_VERSION >= 0x040000 BitMapQT::BitMapQT(GraphObj *g, QMainWindow *wi, int vr, int hr):anyOutput() { int w, h; hres = (double)hr; vres = (double)vr; image = 0L; hgo = 0L; dlgwidget = 0L; widget = wi; ShowObj = ShowAnimated = 0L; minLW = 1; OC_type = OC_BITMAP; if(wi) { w = wi->width(); h = wi->height(); } else { GetDesktopSize(&w, &h); } Box1.Xmin = Box1.Ymin = 0.0; Box1.Xmax = w; Box1.Ymax = h; DeskRect.left = DeskRect.top = 0; GetDesktopSize(&w, &h); DeskRect.right = w; DeskRect.bottom = h; mempic = new QPixmap(w, h); mempic->fill(0x00ffffffL); qPainter.begin(mempic); qPen.setCapStyle(Qt::RoundCap); qPen.setJoinStyle(Qt::RoundJoin); qPainter.setPen(qPen); qFont = qPainter.font(); } #endif BitMapQT::BitMapQT(GraphObj *g, QWidget *wi, int vr, int hr):anyOutput() { int w, h; hres = (double)hr; vres = (double)vr; image = 0L; hgo = 0L; dlgwidget = wi; widget = 0L; ShowObj = ShowAnimated = 0L; minLW = 1; OC_type = OC_BITMAP; if(wi) { w = wi->width(); h = wi->height(); } else { GetDesktopSize(&w, &h); } Box1.Xmin = Box1.Ymin = 0.0; Box1.Xmax = w; Box1.Ymax = h; DeskRect.left = DeskRect.top = 0; GetDesktopSize(&w, &h); DeskRect.right = w; DeskRect.bottom = h; mempic = new QPixmap(w, h); mempic->fill(0x00ffffffL); qPainter.begin(mempic); qPen.setCapStyle(Qt::RoundCap); qPen.setJoinStyle(Qt::RoundJoin); qPainter.setPen(qPen); qFont = qPainter.font(); } BitMapQT::BitMapQT(int w, int h, double hr, double vr):anyOutput() { hres = hr; vres = vr; image = 0L; hgo = 0L; widget = 0L; w = abs(w); h = abs(h); ShowObj = ShowAnimated = 0L; 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; OC_type = OC_BITMAP; mempic = new QPixmap(w, h); mempic->fill(0x00ffffffL); qPainter.begin(mempic); qPen.setCapStyle(Qt::RoundCap); qPen.setJoinStyle(Qt::RoundJoin); qPainter.setPen(qPen); qFont = qPainter.font(); } BitMapQT::~BitMapQT() { Undo.KillDisp(this); if(ShowObj) delete((eph_obj*)ShowObj); ShowObj = 0L; if(qPainter.isActive()) qPainter.end(); HideTextCursorObj(this); if(mempic) delete mempic; if(hgo) delete hgo; if(image) delete image; mempic = 0L; hgo = 0L; image = 0L; } bool BitMapQT::SetLine(LineDEF *lDef) { int iw; if(ShowObj) { delete((eph_obj*)ShowObj); ShowObj = 0L; } if(lDef->width != LineWidth || lDef->width != LineWidth || lDef->pattern != dPattern || lDef->color != dLineCol) { LineWidth = lDef->width; iw = iround(un2ix(lDef->width)); dPattern = lDef->pattern; RLP.finc = 256.0/un2fix(lDef->patlength*8.0); RLP.fp = 0.0; if(iLine == iw && dLineCol == lDef->color) return true; iLine = iw > 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; } bool BitMapQT::SetFill(FillDEF *fill) { if(ShowObj) { delete((eph_obj*)ShowObj); ShowObj = 0L; } if(!fill) return false; if((fill->type & 0xff) != FILL_NONE) { if(!hgo) hgo = new HatchOut(this); if(hgo) hgo->SetFill(fill); } else { if(hgo) delete hgo; hgo = 0L; } qPainter.setBrush(MK_QCOLOR(fill->color)); dFillCol = fill->color; dFillCol2 = fill->color2; return true; } bool BitMapQT::SetTextSpec(TextDEF *set) { if(ShowObj) { delete((eph_obj*)ShowObj); ShowObj = 0L; } return com_SetTextSpec(set, &TxtSet, this, qFont, &qPainter); } bool BitMapQT::Erase(DWORD color) { if(!mempic) return false; mempic->fill(color); if(image) delete image; image = 0L; return true; } bool BitMapQT::CopyBitmap(int x, int y, anyOutput* sr, int sx, int sy, int sw, int sh, bool invert) { BitMapQT *src = (BitMapQT*)sr; if(!mempic) return false; #if QT_VERSION < 0x040000 bitBlt(mempic, x, y, src->mempic, sx, sy, sw, sh, invert ? Qt::NotCopyROP : Qt::CopyROP); #else if(invert) { QImage qi = src->mempic->copy(sx, sy, sw, sh).toImage(); qi.invertPixels(); qPainter.drawImage(x, y, qi); } else qPainter.drawPixmap(x, y, *src->mempic, sx, sy, sw, sh); #endif return true; } bool BitMapQT::oGetTextExtent(char *text, int cb, int *width, int *height) { return com_GetTextExtent(text, width, height, cb, &TxtSet, &qPainter); } bool BitMapQT::oGetTextExtentW(w_char *text, int cb, int *width, int *height) { return com_GetTextExtentW(text, width, height, cb, &TxtSet, &qPainter); } bool BitMapQT::oGetPix(int x, int y, DWORD *col) { DWORD pix; #if QT_VERSION < 0x040000 if(!image && !(image = new QImage(mempic->convertToImage())))return false; #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 = image->pixel(x,y); *col = pix & 0x0000ff00L; *col |= (pix>>16)&0x000000ffL; *col |= (pix<<16)&0x00ff0000L; return true; } return false; } bool BitMapQT::oDrawIcon(int type, int x, int y) { const char** xpm_data; switch (type) { case ICO_INFO: xpm_data = information_xpm; break; case ICO_ERROR: xpm_data = critical_xpm; break; case ICO_RLPLOT: xpm_data = RLPlot_xpm; break; case ICO_QT: xpm_data = qtlogo_xpm; break; default: return false; } if (xpm_data) { #if QT_VERSION < 0x040000 QPixmap pm; QImage image(xpm_data); pm.convertFromImage(image); bitBlt(mempic, x, y, &pm, 0, 0, -1, -1, Qt::CopyROP); #else QPixmap pm(xpm_data); qPainter.drawPixmap(x, y, pm); #endif return true; } return false; } bool BitMapQT::oCircle(int x1, int y1, int x2, int y2, char* nam) { qPainter.drawEllipse(x1, y1, x2-x1, y2-y1); if(hgo) return hgo->oCircle(x1, y1, x2, y2); return true; } bool BitMapQT::oPolyline(POINT * pts, int cp, char *nam) { int i; if(cp < 1) return false; if (dPattern) { for (i = 1; i < cp; i++) PatLine(pts[i-1], pts[i]); } else { for (i = 1; i < cp; i++)qPainter.drawLine(pts[i-1].x, pts[i-1].y, pts[i].x, pts[i].y); } return true; } bool 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, y2-y1); #endif if(hgo) hgo->oRectangle(x1, y1, x2, y2, 0L); return true; } bool BitMapQT::oSolidLine(POINT *p) { qPainter.drawLine(p[0].x, p[0].y, p[1].x, p[1].y); return true; } bool BitMapQT::oTextOut(int x, int y, char *txt, int cb) { if(!txt || !txt[0]) return false; return com_TextOut(x, y, txt, &TxtSet, &qPainter, this); } bool BitMapQT::oTextOutW(int x, int y, w_char *txt, int cb) { if(!txt || !txt[0]) return false; return com_TextOutW(x, y, txt, &TxtSet, &qPainter, this); } bool BitMapQT::oPolygon(POINT *pts, int cp, char *nam) { int i; #if QT_VERSION < 0x040000 QPointArray *a; if(!pts || cp <2) return false; a = new QPointArray(cp); if (a) { for(i = 0; i < cp; i++) a->setPoint(i, pts[i].x, pts[i].y); qPainter.drawPolygon(*a); delete a; } #else QPoint *a; if(a = (QPoint*)malloc(cp * sizeof(QPoint))) { for(i = 0; i < cp; i++) { a[i].setX(pts[i].x); a[i].setY(pts[i].y); } qPainter.drawPolygon(a, cp); free(a); } #endif if(hgo) hgo->oPolygon(pts, cp); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Process a menu event //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ static void ToolMenu(GraphObj *b, anyOutput *o, int tm) { if(b && o) b->Command(CMD_TOOLMODE, (void*)(& tm), o); } bool ProcMenuEvent(int id, QWidget *parent, anyOutput *OutputClass, GraphObj *BaseObj) { PrintQT *out; if(OutputClass) Undo.SetDisp(OutputClass); if(parent && (parent->y() || parent->x())) { CurrWidgetPos.x = parent->x(); CurrWidgetPos.y = parent->y(); CurrWidget = parent; } if(BaseObj) switch(id) { case CM_OPEN: BaseObj->Command(CMD_OPEN, 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: BaseObj->Command(CMD_INSCOL, 0L, OutputClass); return true; case CM_DELROW: BaseObj->Command(CMD_DELROW, 0L, OutputClass); return true; case CM_DELCOL: BaseObj->Command(CMD_DELCOL, 0L, OutputClass); return true; case CM_EXPORT: if(OutputClass) { OutputClass->HideMark(); OpenExportName(BaseObj, 0L); } BaseObj->DoPlot(0L); return true; case CM_REDRAW: if(OutputClass && OutputClass->Erase(defs.Color(COL_BG))) { CurrGO=0L; OutputClass->HideMark(); BaseObj->Command(CMD_SETSCROLL, 0L, OutputClass); } BaseObj->DoPlot(0L); return true; case CM_UPDATE: BaseObj->Command(CMD_UPDATE, 0L, OutputClass); return true; case CM_LAYERS: BaseObj->Command(CMD_LAYERS, 0L, OutputClass); return true; case CM_ADDPLOT: BaseObj->Command(CMD_ADDPLOT, 0L, OutputClass); return true; case CM_ADDAXIS: BaseObj->Command(CMD_ADDAXIS, 0L, OutputClass); return true; case CM_LEGEND: BaseObj->Command(CMD_LEGEND, 0L, OutputClass); return true; case CM_DELOBJ: if(OutputClass && CurrGO && CurrGO->parent && CurrGO->parent->Command(CMD_DELOBJ, (void*)CurrGO, OutputClass)) { CurrGO = 0L; OutputClass->Erase(defs.Color(COL_BG)); BaseObj->DoPlot(OutputClass); } else if(!CurrGO) InfoBox("No object selected!"); return true; case CM_PRINT: if(!BaseObj) return false; out = new PrintQT(0L, 0L); #if QT_VERSION >= 0x030000 //Qt version 3, n.a. in version 2 // int m = iround(out->hres/60.0); // out->printer->setMargins(m, m, m, m); #endif if(BaseObj->Id == GO_SPREADDATA) { BaseObj->Command(CMD_PRINT, 0L, out); } else if(out->StartPage()){ BaseObj->DoPlot(out); out->EndPage(); } BaseObj->DoPlot(OutputClass); delete out; return true; case CM_ADDROWCOL: BaseObj->Command(CMD_ADDROWCOL, 0L, OutputClass); return true; case CM_FILLRANGE: BaseObj->Command(CMD_FILLRANGE, 0L, OutputClass); return true; case CM_NEWGRAPH: BaseObj->Command(CMD_NEWGRAPH, 0L, OutputClass); return true; case CM_NEWPAGE: BaseObj->Command(CMD_NEWPAGE, 0L, OutputClass); return true; case CM_DELGRAPH: BaseObj->Command(CMD_DELGRAPH, 0L, OutputClass); return true; case CM_DEFAULTS: 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: rep_twoway_anova(BaseObj, BaseObj->data); return true; case CM_REPTWANOV: rep_twanova(BaseObj, BaseObj->data); return true; case CM_REPFRIEDM: rep_fmanova(BaseObj, BaseObj->data); return true; case CM_CORRELM: rep_correl(BaseObj, BaseObj->data, 0); return true; case CM_CORRELT: rep_correl(BaseObj, BaseObj->data, 1); return true; case CM_SMPLSTAT: rep_samplestats(BaseObj, BaseObj->data); return true; case CM_REPCMEANS: rep_compmeans(BaseObj, BaseObj->data); return true; case CM_REPTWOWAY: rep_twowaytable(BaseObj, BaseObj->data); return true; case CM_REPREGR: rep_regression(BaseObj, BaseObj->data); return true; case CM_ROBUSTLINE: rep_robustline(BaseObj, BaseObj->data); return true; case CM_ABOUT: RLPlotInfo(); return true; case CM_FILE1: ((RLPwidget*)parent)->openHistoryFile(0); return true; case CM_FILE2: ((RLPwidget*)parent)->openHistoryFile(1); return true; case CM_FILE3: ((RLPwidget*)parent)->openHistoryFile(2); return true; case CM_FILE4: ((RLPwidget*)parent)->openHistoryFile(3); return true; case CM_FILE5: ((RLPwidget*)parent)->openHistoryFile(4); return true; case CM_FILE6: ((RLPwidget*)parent)->openHistoryFile(5); return true; case CM_EXIT: if(BaseObj->Command(CMD_CAN_CLOSE, 0L, 0L)){ if(BaseObj->parent) BaseObj->parent->Command(CMD_DELOBJ, BaseObj, 0L); 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: 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) { if(OutputClass) ShowCopyMark(OutputClass, &CurrGO->rDims, 1); CopyData(CurrGO); return true; } else if(CurrGO->Id == GO_TEXTFRAME) { if(CurrGO->Command(CMD_COPY, 0L, OutputClass)) return true; } } if(BaseObj->Id == GO_SPREADDATA && BaseObj->Command(id == CM_CUT ? CMD_CUT : CMD_QUERY_COPY, 0L, OutputClass)) { CopyData(BaseObj); } else if(id == CM_CUT) return true; else if(BaseObj->Id == GO_PAGE) { if(CurrGraph) { if(OutputClass) ShowCopyMark(OutputClass, &CurrGraph->rDims, 1); CopyGraph(CurrGraph); } } else if(CurrGraph && CurrGraph->Id == GO_GRAPH){ if(OutputClass) ShowCopyMark(OutputClass, &CurrGraph->rDims, 1); CopyGraph(CurrGraph); } else if(BaseObj->Id == GO_GRAPH) { if(OutputClass) ShowCopyMark(OutputClass, &BaseObj->rDims, 1); CopyGraph(BaseObj); } return true; case CM_ZOOMIN: BaseObj->Command(CMD_ZOOM, (void*)(&"+"), OutputClass); return true; case CM_ZOOMOUT: BaseObj->Command(CMD_ZOOM, (void*)(&"-"), OutputClass); return true; case CM_ZOOMFIT: BaseObj->Command(CMD_ZOOM, (void*)(&"fit"), OutputClass); return true; case CM_ZOOM25: BaseObj->Command(CMD_ZOOM, (void*)(&"25"), OutputClass); return true; case CM_ZOOM50: BaseObj->Command(CMD_ZOOM, (void*)(&"50"), OutputClass); return true; case CM_ZOOM100: BaseObj->Command(CMD_ZOOM, (void*)(&"100"), OutputClass); return true; case CM_ZOOM200: BaseObj->Command(CMD_ZOOM, (void*)(&"200"), OutputClass); return true; case CM_ZOOM400: BaseObj->Command(CMD_ZOOM, (void*)(&"400"), OutputClass); return true; case CM_T_STANDARD: HideCopyMark(); ToolMenu(BaseObj, OutputClass, TM_STANDARD); return true; case CM_T_DRAW: ToolMenu(BaseObj, OutputClass, TM_DRAW); return true; case CM_T_POLYLINE: ToolMenu(BaseObj, OutputClass, TM_POLYLINE); return true; case CM_T_POLYGON: ToolMenu(BaseObj, OutputClass, TM_POLYGON); return true; case CM_T_RECTANGLE: ToolMenu(BaseObj, OutputClass, TM_RECTANGLE); return true; case CM_T_ROUNDREC: ToolMenu(BaseObj, OutputClass, TM_ROUNDREC); return true; case CM_T_ELLIPSE: ToolMenu(BaseObj, OutputClass, TM_ELLIPSE); return true; case CM_T_ARROW: ToolMenu(BaseObj, OutputClass, TM_ARROW); return true; case CM_T_TEXT: ToolMenu(BaseObj, OutputClass, TM_TEXT); return true; } return false; } #if QT_VERSION < 0x040000 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // The menu class //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RLPmenu::RLPmenu(QWidget *par, anyOutput *o, GraphObj *g) :QMenuBar(par) { parent = par; OutputClass = o; BaseObj = g; connect(this, SIGNAL(activated(int)), this, SLOT(doMenuItem(int))); } void RLPmenu::doMenuItem(int id) { ProcMenuEvent(id, parent, OutputClass, BaseObj); } #else //Qt version >= 4.0 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Menu item //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RLPaction::RLPaction(QWidget *par, anyOutput *o, GraphObj *g, char *name, int id):QAction(name, par) { Id = id; OutputClass = o; BaseObj = g; parent = par; connect(this, SIGNAL(triggered()), this, SLOT(doMenuItem())); switch(id) { case CM_FILE1: ((OutputQT*)o)->itFil1 = this; setVisible(false); break; case CM_FILE2: ((OutputQT*)o)->itFil2 = this; setVisible(false); break; case CM_FILE3: ((OutputQT*)o)->itFil3 = this; setVisible(false); break; case CM_FILE4: ((OutputQT*)o)->itFil4 = this; setVisible(false); break; case CM_FILE5: ((OutputQT*)o)->itFil5 = this; setVisible(false); break; case CM_FILE6: ((OutputQT*)o)->itFil6 = this; setVisible(false); break; case CM_T_STANDARD: ((OutputQT*)o)->ittStd = this; setCheckable(true); break; case CM_T_DRAW: ((OutputQT*)o)->ittDraw = this; setCheckable(true); break; case CM_T_POLYLINE: ((OutputQT*)o)->ittPl = this; setCheckable(true); break; case CM_T_POLYGON: ((OutputQT*)o)->ittPg = this; setCheckable(true); break; case CM_T_RECTANGLE: ((OutputQT*)o)->ittRec = this; setCheckable(true); break; case CM_T_ROUNDREC: ((OutputQT*)o)->ittRrec = this; setCheckable(true); break; case CM_T_ELLIPSE: ((OutputQT*)o)->ittElly = this; setCheckable(true); break; case CM_T_ARROW: ((OutputQT*)o)->ittArr = this; setCheckable(true); break; case CM_T_TEXT: ((OutputQT*)o)->ittTxt = this; setCheckable(true); break; } } void RLPaction::doMenuItem() { if(ProcMenuEvent(Id, parent, OutputClass, BaseObj)) return; } #endif //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // The display output class //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #if QT_VERSION < 0x040000 OutputQT::OutputQT(GraphObj *g):BitMapQT(g, (QWidget*)0L) #else OutputQT::OutputQT(GraphObj *g):BitMapQT(g, (QMainWindow*)0L) #endif { int w, h; HScroll = VScroll = 0L; GetDesktopSize(&w, &h); CreateNewWindow(BaseObj = g); if(widget) { if(CurrWidgetPos.x >= ((w>>1)-100))CurrWidgetPos.x = CurrWidgetPos.y = 50; widget->show(); widget->move(CurrWidgetPos.x+=50, CurrWidgetPos.y+=50); if(widget->x() || widget->y()) { CurrWidgetPos.x = widget->x(); CurrWidgetPos.y = widget->y(); } } #if QT_VERSION >= 0x040000 itFil1 = itFil2 = itFil3 = itFil4 = itFil5 = itFil6 = 0L; ittStd = ittDraw = ittPl = ittPg = ittRec = ittRrec = ittElly = ittArr = ittTxt = 0L; #endif } OutputQT::OutputQT(DlgWidget *wi):BitMapQT(0L, wi) { //assume fixed size (dialog) widget if(dlgwidget = wi) { wi->move(CurrWidgetPos.x+50, CurrWidgetPos.y+50); } HScroll = VScroll = 0L; BaseObj = 0L; wi->OutputClass = this; wi->mempic = mempic; xAxis.flags = 0L; yAxis.flags = AXIS_INVERT; //drawing origin upper left corner } OutputQT::~OutputQT() { if(qPainter.isActive()) qPainter.end(); if(widget) delete widget; widget = 0L; HideTextCursorObj(this); if(mempic) delete mempic; mempic = 0L; if(hgo) delete hgo; hgo = 0L; if(image) delete image; image = 0L; } bool OutputQT::ActualSize(RECT *rc) { if(rc) { rc->left = rc->top = 0; if(widget) { rc->bottom = widget->height() - MenuHeight-6; rc->right = widget->width(); } else if(dlgwidget) { rc->bottom = dlgwidget->height() - MenuHeight-6; rc->right = dlgwidget->width(); } if(rc->bottom < 10 && rc->right < 10) { rc->right = 600; rc->bottom = 400; } return (rc->right > 40 && rc->bottom > 40); } return false; } void 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); #else if(widget) widget->setWindowTitle(cap); else if(dlgwidget) dlgwidget->setWindowTitle(cap); #endif } #if QT_VERSION < 0x040000 const static unsigned char hand_bits[] = { //hand cursor bitmap 0x80, 0x01, 0x58, 0x0e, 0x64, 0x12, 0x64, 0x52, 0x48, 0xb2, 0x48, 0x92, 0x16, 0x90, 0x19, 0x80, 0x11, 0x40, 0x02, 0x40, 0x02, 0x40, 0x04, 0x20, 0x08, 0x20, 0x10, 0x10, 0x20, 0x10, 0x20, 0x10}; const static unsigned char hand_mask[] = { //hand cursor mask 0x80, 0x01, 0xd8, 0x0f, 0xfc, 0x1f, 0xfc, 0x5f, 0xf8, 0xbf, 0xf8, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfc, 0x3f, 0xf8, 0x3f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0, 0x1f}; const static unsigned char zoom_bits[] = { //zoom cursor bitmap 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x60, 0x0a, 0x10, 0x10, 0x08, 0x21, 0x08, 0x21, 0x04, 0x40, 0x64, 0x4c, 0x04, 0x40, 0x08, 0x21, 0x08, 0x21, 0x10, 0x10, 0x60, 0x0a, 0x80, 0x03, 0x00, 0x00}; const static unsigned char zoom_mask[] = { //zoom cursor mask 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0xe0, 0x0f, 0xf0, 0x1f, 0xf8, 0x3f, 0xf8, 0x3f, 0xf4, 0x7e, 0x7c, 0x7c, 0xfc, 0x7e, 0xf8, 0x3f, 0xf8, 0x3f, 0xf0, 0x1f, 0xe0, 0x0f, 0x80, 0x03, 0x00, 0x00}; const static unsigned char paste_bits[] = { //paste cursor bitmap 0x04, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00, 0xc4, 0x7f, 0x20, 0xa0, 0xa0, 0xa0, 0xa0, 0x9f, 0x20, 0x80, 0x20, 0x80, 0x20, 0x80, 0x20, 0x80, 0x20, 0x80, 0x20, 0x80, 0xc0, 0x7f, 0x00, 0x00}; const static unsigned char paste_mask[] = { //paste cursor mask 0x04, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00, 0xc4, 0x7f, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xc0, 0x7f, 0x00, 0x00}; const static unsigned char drawpen_bits[] = { //draw cursor bitmap 0x03, 0x00, 0x0f, 0x00, 0x3e, 0x00, 0xce, 0x00, 0x04, 0x01, 0x44, 0x02, 0x88, 0x04, 0x08, 0x09, 0x10, 0x12, 0x20, 0x24, 0x40, 0x48, 0x80, 0xd0, 0x00, 0xe1, 0x00, 0x72, 0x00, 0x3c, 0x00, 0x18}; const static unsigned char drawpen_mask[] = { //draw cursor mask 0x03, 0x00, 0x0f, 0x00, 0x3e, 0x00, 0xfe, 0x00, 0xfc, 0x01, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x0f, 0xf0, 0x1f, 0xe0, 0x3f, 0xc0, 0x7f, 0x80, 0xff, 0x00, 0xff, 0x00, 0x7e, 0x00, 0x3c, 0x00, 0x18}; const static unsigned char drect_bits[] = { //draw rectangle bitmap 0x04, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x08, 0x80, 0x08, 0x80, 0x08, 0x80, 0x08, 0x80, 0x08, 0x80, 0x08, 0x80, 0x08, 0x80, 0xf8, 0xff, 0x00, 0x00}; const static unsigned char drect_mask[] = { //draw rectangle mask 0x04, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0x00, 0x00}; const static unsigned char drrect_bits[] = { //draw rounded rectangle bitmap 0x04, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x3f, 0x10, 0x40, 0x08, 0x80, 0x08, 0x80, 0x08, 0x80, 0x08, 0x80, 0x08, 0x80, 0x10, 0x40, 0xe0, 0x3f, 0x00, 0x00}; const static unsigned char drrect_mask[] = { //draw rounded rectangle mask 0x04, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x3f, 0xf0, 0x7f, 0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf0, 0x7f, 0xe0, 0x3f, 0x00, 0x00}; const static unsigned char delly_bits[] = { //draw ellipse bitmap 0x04, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x60, 0x30, 0x10, 0x40, 0x08, 0x80, 0x08, 0x80, 0x08, 0x80, 0x10, 0x40, 0x60, 0x30, 0x80, 0x0f, 0x00, 0x00}; const static unsigned char delly_mask[] = { //draw ellipse mask 0x04, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x0f, 0xe0, 0x3f, 0xf0, 0x7f, 0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf0, 0x7f, 0xe0, 0x3f, 0x80, 0x0f, 0x00, 0x00}; #else const static char* hand_xpm[] = { "16 16 3 1", ". c None", "1 c #000000", "0 c #ffffff", ".......11.......", "...110100111....", "..10011001001...", "..1001100100101.", "...1001001001101", "...1001001001001", ".110100000001001", "1001100000000001", "100010000000001.", ".10000000000001.", ".10000000000001.", "..100000000001..", "...10000000001..", "....100000001...", ".....10000001...", ".....10000001..."}; const static char* zoom_xpm[] = { "16 16 3 1", ". c None", "1 c #000000", "0 c #ffffff", "................", "................", ".......111......", ".....11...11....", "....1.......1...", "...1....1....1..", "...1....1....1..", "..1.....0.....1.", "..1..1100011..1.", "..1.....0.....1.", "...1....1....1..", "...1....1....1..", "....1.......1...", ".....11...11....", ".......111......", "................"}; const static char* drawpen_xpm[] = { "16 16 3 1", ". c None", "1 c #000000", "0 c #ffffff", "11..............", "1111............", ".11111..........", ".1110011........", "..1000001.......", "..10001001......", "...10001001.....", "...100001001....", "....100001001...", ".....100001001..", "......100001001.", ".......100001011", "........10000111", ".........100111.", "..........1111..", "...........11..."}; const static char* paste_xpm[] = { "16 16 3 1", ". c None", "1 c #000000", "0 c #ffffff", "..1.............", "..1.............", "11111...........", "..1.............", "..1...111111111.", ".....10000000101", ".....10100000101", ".....10111111001", ".....10000000001", ".....10000000001", ".....10000000001", ".....10000000001", ".....10000000001", ".....10000000001", "......111111111.", "................"}; const static char* drect_xpm[] = { "16 16 3 1", ". c None", "1 c #000000", "0 c #ffffff", "..1.............", "..1.............", "11111...........", "..1.............", "..1.............", "................", "...1111111111111", "...1000000000001", "...1000000000001", "...1000000000001", "...1000000000001", "...1000000000001", "...1000000000001", "...1000000000001", "...1111111111111", "................"}; const static char* drrect_xpm[] = { "16 16 3 1", ". c None", "1 c #000000", "0 c #ffffff", "..1.............", "..1.............", "11111...........", "..1.............", "..1.............", "................", ".....111111111..", "....10000000001.", "...1000000000001", "...1000000000001", "...1000000000001", "...1000000000001", "...1000000000001", "....10000000001.", ".....111111111..", "................"}; const static char* delly_xpm[] = { "16 16 3 1", ". c None", "1 c #000000", "0 c #ffffff", "..1.............", "..1.............", "11111...........", "..1.............", "..1.............", "................", ".......11111....", ".....110000011..", "....10000000001.", "...1000000000001", "...1000000000001", "...1000000000001", "....10000000001.", ".....110000011..", ".......11111....", "................"}; #endif //display 16x16 cursor data: developers utility /* void disp_bm(unsigned char *tb) { char txt[512]; unsigned char currbyte; int i, j, pos; for(i = pos = 0; i < 32; i++) { currbyte = tb[i]; for (j = 0; j < 8; j++) { if(currbyte & 0x01) pos += sprintf(txt+pos, "1"); else pos += sprintf(txt+pos, "0"); currbyte >>= 1; } if(i & 1)pos += sprintf(txt+pos, "\n"); } // InfoBox(txt); printf("\n%s\n", txt); } */ void OutputQT::MouseCursor(int cid, bool force) { if(cid == cCursor && !force) return; if(cid == MC_LAST) cid = cCursor; #if QT_VERSION < 0x040000 QBitmap *bits, *mask; bits = mask = 0L; #endif if(widget)CurrWidget = widget; else if(dlgwidget) CurrWidget = dlgwidget; if(widget) switch(cid) { #if QT_VERSION >= 0x030000 //Qt version 3 case MC_ARROW: widget->setCursor(QCursor(Qt::ArrowCursor)); break; case MC_TXTFRM: case MC_CROSS: widget->setCursor(QCursor(Qt::CrossCursor)); break; case MC_WAIT: widget->setCursor(QCursor(Qt::WaitCursor)); break; // case MC_TEXT: widget->setCursor(QCursor(Qt::IbeamCursor)); break; case MC_NORTH: widget->setCursor(QCursor(Qt::SizeVerCursor)); break; case MC_NE: widget->setCursor(QCursor(Qt::SizeBDiagCursor));break; case MC_COLWIDTH: case MC_EAST: widget->setCursor(QCursor(Qt::SizeHorCursor)); break; case MC_SE: widget->setCursor(QCursor(Qt::SizeFDiagCursor));break; case MC_SALL: widget->setCursor(QCursor(Qt::SizeAllCursor)); break; #else //Qt version 2 case MC_ARROW: widget->setCursor(QCursor(ArrowCursor)); break; case MC_TXTFRM: case MC_CROSS: widget->setCursor(QCursor(CrossCursor)); break; case MC_WAIT: widget->setCursor(QCursor(WaitCursor)); break; case MC_TEXT: widget->setCursor(QCursor(IbeamCursor)); break; case MC_NORTH: widget->setCursor(QCursor(SizeVerCursor)); break; case MC_NE: widget->setCursor(QCursor(SizeBDiagCursor));break; case MC_COLWIDTH: case MC_EAST: widget->setCursor(QCursor(SizeHorCursor)); break; case MC_SE: widget->setCursor(QCursor(SizeFDiagCursor));break; case MC_SALL: widget->setCursor(QCursor(SizeAllCursor)); break; #endif case MC_MOVE: #if QT_VERSION < 0x040000 bits = new QBitmap(16, 16, hand_bits, TRUE); mask = new QBitmap(16, 16, hand_mask, TRUE); widget->setCursor(QCursor(*bits, *mask, 7, 7)); #else widget->setCursor(QCursor(QPixmap(hand_xpm), 7, 7)); #endif break; case MC_ZOOM: #if QT_VERSION < 0x040000 bits = new QBitmap(16, 16, zoom_bits, TRUE); mask = new QBitmap(16, 16, zoom_mask, TRUE); widget->setCursor(QCursor(*bits, *mask, 7, 7)); #else widget->setCursor(QCursor(QPixmap(zoom_xpm), 7, 7)); #endif break; case MC_PASTE: #if QT_VERSION < 0x040000 bits = new QBitmap(16, 16, paste_bits, TRUE); mask = new QBitmap(16, 16, paste_mask, TRUE); widget->setCursor(QCursor(*bits, *mask, 2, 2)); #else widget->setCursor(QCursor(QPixmap(paste_xpm), 2, 2)); #endif break; case MC_DRAWPEN: #if QT_VERSION < 0x040000 bits = new QBitmap(16, 16, drawpen_bits, TRUE); mask = new QBitmap(16, 16, drawpen_mask, TRUE); widget->setCursor(QCursor(*bits, *mask, 0, 0)); #else widget->setCursor(QCursor(QPixmap(drawpen_xpm), 0, 0)); #endif break; case MC_DRAWREC: #if QT_VERSION < 0x040000 bits = new QBitmap(16, 16, drect_bits, TRUE); mask = new QBitmap(16, 16, drect_mask, TRUE); widget->setCursor(QCursor(*bits, *mask, 2, 2)); #else widget->setCursor(QCursor(QPixmap(drect_xpm), 0, 0)); #endif break; case MC_DRAWRREC: #if QT_VERSION < 0x040000 bits = new QBitmap(16, 16, drrect_bits, TRUE); mask = new QBitmap(16, 16, drrect_mask, TRUE); widget->setCursor(QCursor(*bits, *mask, 2, 2)); #else widget->setCursor(QCursor(QPixmap(drrect_xpm), 0, 0)); #endif break; case MC_DRAWELLY: #if QT_VERSION < 0x040000 bits = new QBitmap(16, 16, delly_bits, TRUE); mask = new QBitmap(16, 16, delly_mask, TRUE); widget->setCursor(QCursor(*bits, *mask, 2, 2)); #else widget->setCursor(QCursor(QPixmap(delly_xpm), 0, 0)); #endif break; default: return; } #if QT_VERSION < 0x040000 if(bits) delete bits; if(mask) delete mask; #endif cCursor = cid; } bool OutputQT::SetScroll(bool isVert, int iMin, int iMax, int iPSize, int iPos) { QScrollBar *sb; if((CurrWidget = widget) && (widget->x() || widget->y())) { CurrWidgetPos.x = widget->x(); CurrWidgetPos.y = widget->y(); } if(isVert) { if(!(sb = VScroll))return false; } else if(!(sb = HScroll)) return false; // if(iPos < sb->minValue()) return false; sb->setRange(iMin, iMax); // sb->setPageStep(iPSize); // if(BaseObj && BaseObj->Id == GO_GRAPH) sb->setLineStep(8); // else sb->setLineStep(1); sb->setValue(iPos); return true; } bool OutputQT::EndPage() { if(ShowObj) { delete((eph_obj*)ShowObj); ShowObj = 0L; } if(widget)widget->repaint(); else if(dlgwidget)dlgwidget->repaint(); 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) { int x1, x2, y1, y2; if((!widget && !dlgwidget) || !mempic) return false; if(rc->right > rc->left) { x1 = rc->left; x2 = rc->right; } else { x1 = rc->right; x2 = rc->left; } if(rc->bottom > rc->top) { y1 = rc->top; y2 = rc->bottom; } else { y1 = rc->bottom; y2 = rc->top; } if(x2 > DeskRect.right) x2 = DeskRect.right; if(y2 > DeskRect.bottom) y2 = DeskRect.right; #if QT_VERSION < 0x040000 if(widget) bitBlt(widget, x1, y1, mempic, x1, y1, x2 - x1, y2 - y1, invert ? Qt::NotCopyROP : Qt::CopyROP); if(dlgwidget) bitBlt(dlgwidget, x1, y1, mempic, x1, y1, x2 - x1, y2 - y1, invert ? Qt::NotCopyROP : Qt::CopyROP); #else if(widget)widget->update(rc->left, rc->top, rc->right-rc->left, rc->bottom-rc->top); else if(dlgwidget)dlgwidget->update(rc->left, rc->top, rc->right-rc->left, rc->bottom-rc->top); if(invert) { ShowObj = new eph_invert((eph_obj*)ShowObj, mempic, rc->left, rc->top, rc->right-rc->left, rc->bottom-rc->top); } #endif return true; } void OutputQT::ShowLine(POINT * pts, int cp, DWORD color) { int i; RECT rec; if(cp < 2) return; rec.left = rec.right = pts[0].x; rec.top = rec.bottom = pts[0].y; for(i = 1; i < cp; i++) { if(pts[i].x < rec.left) rec.left = pts[i].x; if(pts[i].x > rec.right) rec.right = pts[i].x; if(pts[i].y < rec.top) rec.top = pts[i].y; if(pts[i].y > rec.bottom) rec.bottom = pts[i].y; } rec.left -= 2; rec.top -= 2; rec.bottom += 2; rec.right += 2; if(rec.bottom < 2 && rec.top < 2) return; if(!(ShowObj = new eph_line((eph_line*)ShowObj, pts, cp, color)))return; #if QT_VERSION >= 0x040000 UpdateRect(&rec, false); #else QPainter qp(widget ? widget : dlgwidget); ((eph_obj*)ShowObj)->DoPlot(&qp); #endif } void OutputQT::ShowEllipse(POINT p1, POINT p2, DWORD color) { RECT rec; 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; if(!(ShowObj = new eph_ellipse((eph_obj*)ShowObj, p1, p2, color)))return; #if QT_VERSION >= 0x040000 UpdateRect(&rec, false); #else QPainter qp(widget ? widget : dlgwidget); ((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) #define RLP_MSEPARATOR(menu) menu->insertSeparator(); #else #define RLP_MITEM(menu,par,o,go,txt,id) menu->addAction(new RLPaction(par,o,go,txt,id)); #define RLP_MSEPARATOR(menu) menu->addSeparator(); #endif #if QT_VERSION < 0x040000 static QPopupMenu *MkToolMenu(QPopupMenu *tools, QWidget *widget, OutputQT *o, GraphObj *go) { tools->setCheckable(true); tools->insertTearOffHandle(); #else static QMenu *MkToolMenu(QMenu *tools, QWidget *widget, OutputQT *o, GraphObj *go) { tools->setTearOffEnabled(TRUE); #endif RLP_MITEM(tools, widget, o, go, "&Standard", CM_T_STANDARD); RLP_MSEPARATOR(tools); RLP_MITEM(tools, widget, o, go, "&Draw", CM_T_DRAW); RLP_MITEM(tools, widget, o, go, "Poly&line", CM_T_POLYLINE); RLP_MITEM(tools, widget, o, go, "Poly&gon", CM_T_POLYGON); RLP_MITEM(tools, widget, o, go, "&Rectangle", CM_T_RECTANGLE); RLP_MITEM(tools, widget, o, go, "r&ound Rect.", CM_T_ROUNDREC); RLP_MITEM(tools, widget, o, go, "&Ellipse", CM_T_ELLIPSE); RLP_MITEM(tools, widget, o, go, "&Arrow", CM_T_ARROW); RLP_MITEM(tools, widget, o, go, "&Text", CM_T_TEXT); return tools; } #if QT_VERSION < 0x040000 static QPopupMenu *MkZoomMenu(QPopupMenu *zoom, QWidget *widget, OutputQT *o, GraphObj *go) { zoom->insertTearOffHandle(); zoom->insertItem("zoom &in", widget, SLOT(cmZoomIn()), Qt::CTRL + Qt::Key_Plus); zoom->insertItem("zoom &out", widget, SLOT(cmZoomOut()), Qt::CTRL + Qt::Key_Minus); zoom->insertItem("&fit to widget", widget, SLOT(cmZoomFit()), Qt::CTRL + Qt::Key_F); #else static QMenu *MkZoomMenu(QMenu *zoom, QWidget *widget, OutputQT *o, GraphObj *go) { zoom->setTearOffEnabled(TRUE); zoom->addAction("zoom &in", widget, SLOT(cmZoomIn()), Qt::CTRL + Qt::Key_Plus); zoom->addAction("zoom &out", widget, SLOT(cmZoomOut()), Qt::CTRL + Qt::Key_Minus); zoom->addAction("&fit to widget", widget, SLOT(cmZoomFit()), Qt::CTRL + Qt::Key_F); #endif RLP_MSEPARATOR(zoom); RLP_MITEM(zoom, widget, o, go, "25%", CM_ZOOM25); RLP_MITEM(zoom, widget, o, go, "50%", CM_ZOOM50); RLP_MITEM(zoom, widget, o, go, "100%", CM_ZOOM100); RLP_MITEM(zoom, widget, o, go, "200%", CM_ZOOM200); RLP_MITEM(zoom, widget, o, go, "400%", CM_ZOOM400); return zoom; } bool OutputQT::SetMenu(int type) { if(!widget) return false; if(type == MENU_SPREAD){ #if QT_VERSION < 0x040000 QPopupMenu *file = new QPopupMenu(widget); QPopupMenu *edit = new QPopupMenu(widget); QPopupMenu *stats = new QPopupMenu(widget); QPopupMenu *graph = new QPopupMenu(widget); QPopupMenu *about = new QPopupMenu(widget); #else QMenu *file = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&File")); QMenu *edit = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&Edit")); QMenu *stats = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&Statistics")); QMenu *graph = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&Graph")); QMenu *about = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&?")); #endif #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); #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); RLP_MITEM(file, widget, this, BaseObj, "n.a.", CM_FILE1); RLP_MITEM(file, widget, this, BaseObj, "n.a.", CM_FILE2); RLP_MITEM(file, widget, this, BaseObj, "n.a.", CM_FILE3); RLP_MITEM(file, widget, this, BaseObj, "n.a.", CM_FILE4); RLP_MITEM(file, widget, this, BaseObj, "n.a.", CM_FILE5); RLP_MITEM(file, widget, this, BaseObj, "n.a.", CM_FILE6); #if QT_VERSION < 0x040000 edit->insertItem("&Undo", widget, SLOT(cmUndo()), Qt::CTRL + Qt::Key_Z); #else edit->addAction("&Undo", widget, SLOT(cmUndo()), Qt::CTRL +Qt::Key_Z); #endif RLP_MSEPARATOR(edit); RLP_MITEM(edit, widget, this, BaseObj, "&Rows/Cols", CM_ADDROWCOL); #if QT_VERSION < 0x040000 QPopupMenu *insert = new QPopupMenu(widget); RLP_MITEM(insert, widget, this, BaseObj, "&Rows", CM_INSROW); RLP_MITEM(insert, widget, this, BaseObj, "&Columns", CM_INSCOL); edit->insertItem("&Insert", insert); QPopupMenu *Delete = new QPopupMenu(widget); RLP_MITEM(Delete, widget, this, BaseObj, "&Rows", CM_DELROW); RLP_MITEM(Delete, widget, this, BaseObj, "&Columns", CM_DELCOL); edit->insertItem("&Delete", Delete); #else QMenu *insert = edit->addMenu("&Insert"); RLP_MITEM(insert, widget, this, BaseObj, "&Rows", CM_INSROW); RLP_MITEM(insert, widget, this, BaseObj, "&Columns", CM_INSCOL); QMenu *Delete = edit->addMenu("&Delete"); RLP_MITEM(Delete, widget, this, BaseObj, "&Rows", CM_DELROW); RLP_MITEM(Delete, widget, this, BaseObj, "&Columns", CM_DELCOL); #endif RLP_MSEPARATOR(edit); #if QT_VERSION < 0x040000 edit->insertItem("&Copy", widget, SLOT(cmCopy()), Qt::CTRL + Qt::Key_C, CM_COPY); edit->insertItem("C&ut", widget, SLOT(cmCut()), Qt::CTRL + Qt::Key_X, CM_CUT); edit->insertItem("&Paste", widget, SLOT(cmPaste()), Qt::CTRL + Qt::Key_V); #else edit->addAction("&Copy", widget, SLOT(cmCopy()), Qt::CTRL +Qt::Key_C); edit->addAction("C&ut", widget, SLOT(cmCut()), Qt::CTRL +Qt::Key_X); edit->addAction("&Paste", widget, SLOT(cmPaste()), Qt::CTRL +Qt::Key_V); #endif RLP_MSEPARATOR(edit); RLP_MITEM(edit, widget, this, BaseObj, "&Fill Range", CM_FILLRANGE); RLP_MITEM(stats, widget, this, BaseObj, "&Sample Stats", CM_SMPLSTAT); RLP_MITEM(stats, widget, this, BaseObj, "&Comp. Means", CM_REPCMEANS); #if QT_VERSION < 0x040000 QPopupMenu *anov = new QPopupMenu(widget); RLP_MITEM(anov, widget, this, BaseObj, "&One Way Anova", CM_REPANOV); RLP_MITEM(anov, widget, this, BaseObj, "&Kruskal Wallis", CM_REPKRUSKAL); RLP_MITEM(anov, widget, this, BaseObj, "&Two Way Anova", CM_REPTWANOV); RLP_MITEM(anov, widget, this, BaseObj, "&Friedman Anova", CM_REPFRIEDM); RLP_MITEM(anov, widget, this, BaseObj, "&Two Way /w Replica", CM_REPTWANR); stats->insertItem("&Anova", anov); QPopupMenu *regr = new QPopupMenu(widget); RLP_MITEM(regr, widget, this, BaseObj, "&Linear Regression", CM_REPREGR); RLP_MITEM(regr, widget, this, BaseObj, "&Robust Line-Fit", CM_ROBUSTLINE); stats->insertItem("&Regression", regr); QPopupMenu *corr = new QPopupMenu(widget); 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); RLP_MITEM(anov, widget, this, BaseObj, "&Kruskal Wallis", CM_REPKRUSKAL); RLP_MITEM(anov, widget, this, BaseObj, "&Two Way Anova", CM_REPTWANOV); RLP_MITEM(anov, widget, this, BaseObj, "&Friedman Anova", CM_REPFRIEDM); RLP_MITEM(anov, widget, this, BaseObj, "&Two Way /w Replica", CM_REPTWANR); QMenu *regr = stats->addMenu("&Regression"); RLP_MITEM(regr, widget, this, BaseObj, "&Linear Regression", CM_REPREGR); RLP_MITEM(regr, widget, this, BaseObj, "&Robust Line-Fit", CM_ROBUSTLINE); 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); RLP_MITEM(graph, widget, this, BaseObj, "Create &Graph", CM_NEWGRAPH); RLP_MITEM(graph, widget, this, BaseObj, "Create &Page", CM_NEWPAGE); RLP_MITEM(graph, widget, this, BaseObj, "&Flush Graph(s)", CM_DELGRAPH); RLP_MSEPARATOR(graph); RLP_MITEM(graph, widget, this, BaseObj, "&Settings", CM_DEFAULTS); RLP_MITEM(about, widget, this, BaseObj, "&About ...", CM_ABOUT); #if QT_VERSION < 0x040000 menu = new RLPmenu(widget, this, BaseObj); menu->insertItem("&File", file); menu->insertItem("&Edit", edit); menu->insertItem("&Statistics", stats); menu->insertItem("&Graph", graph); menu->insertItem("&?", about); #if QT_VERSION >= 0x030000 //Qt version 3, n.a. in version 2 menu->setItemVisible(CM_FILE1, false); menu->setItemVisible(CM_FILE2, false); menu->setItemVisible(CM_FILE3, false); menu->setItemVisible(CM_FILE4, false); menu->setItemVisible(CM_FILE5, false); menu->setItemVisible(CM_FILE6, false); #endif #endif } else if(type == MENU_GRAPH) { #if QT_VERSION < 0x040000 QPopupMenu *file = new QPopupMenu(widget); QPopupMenu *edit = new QPopupMenu(widget); 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")); QMenu *displ = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&Display")); 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, "Save &as", CM_SAVEAS); RLP_MSEPARATOR(file); #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); #if QT_VERSION < 0x040000 edit->insertItem("&Undo", widget, SLOT(cmUndo()), Qt::CTRL + Qt::Key_Z); edit->insertSeparator(); edit->insertItem("&Copy", widget, SLOT(cmCopy()), Qt::CTRL + Qt::Key_C, CM_COPY); edit->insertItem("&Paste", widget, SLOT(cmPaste()), Qt::CTRL + Qt::Key_V); #else edit->addAction("&Undo", widget, SLOT(cmUndo()), Qt::CTRL +Qt::Key_Z); edit->addSeparator(); edit->addAction("&Copy", widget, SLOT(cmCopy()), Qt::CTRL +Qt::Key_C); edit->addAction("&Paste", widget, SLOT(cmPaste()), Qt::CTRL +Qt::Key_V); #endif RLP_MSEPARATOR(edit); RLP_MITEM(edit, widget, this, BaseObj, "&Update Values", CM_UPDATE); RLP_MSEPARATOR(edit); RLP_MITEM(edit, widget, this, BaseObj, "&Delete Object", CM_DELOBJ); RLP_MITEM(displ, widget, this, BaseObj, "&Redraw", CM_REDRAW); #if QT_VERSION < 0x040000 displ->insertItem("&Zoom", MkZoomMenu(new QPopupMenu(widget), widget, this, BaseObj)); #else MkZoomMenu(displ->addMenu("&Zoom"), widget, this, BaseObj); #endif RLP_MITEM(displ, widget, this, BaseObj, "&Layers", CM_LAYERS); RLP_MITEM(plots, widget, this, BaseObj, "Add &Plot", CM_ADDPLOT); RLP_MITEM(plots, widget, this, BaseObj, "Add &Axis", CM_ADDAXIS); RLP_MITEM(plots, widget, this, BaseObj, "Add &Legend", CM_LEGEND); RLP_MSEPARATOR(edit); RLP_MITEM(plots, widget, this, BaseObj, "&Configure", CM_DEFAULTS); RLP_MITEM(about, widget, this, BaseObj, "&About ...", CM_ABOUT); #if QT_VERSION < 0x040000 menu = new RLPmenu(widget, this, BaseObj); menu->insertItem("&File", file); menu->insertItem("&Edit", edit); menu->insertItem("&Display", displ); menu->insertItem("&Tools", MkToolMenu(new QPopupMenu(widget), widget, this, BaseObj)); menu->insertItem("&Plots", plots); menu->insertItem("&?", about); #endif } else if(type == MENU_PAGE) { #if QT_VERSION < 0x040000 QPopupMenu *file = new QPopupMenu(widget); QPopupMenu *edit = new QPopupMenu(widget); 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")); QMenu *displ = ((RLPwidget*)widget)->menu_bar->addMenu(widget->tr("&Display")); 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, "Save &as", CM_SAVEAS); RLP_MSEPARATOR(file); #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); #if QT_VERSION < 0x040000 edit->insertItem("&Undo", widget, SLOT(cmUndo()), Qt::CTRL + Qt::Key_Z); edit->insertSeparator(); edit->insertItem("&Copy", widget, SLOT(cmCopy()), Qt::CTRL + Qt::Key_C, CM_COPY); edit->insertItem("&Paste", widget, SLOT(cmPaste()), Qt::CTRL + Qt::Key_V); #else edit->addAction("&Undo", widget, SLOT(cmUndo()), Qt::CTRL +Qt::Key_Z); edit->addSeparator(); edit->addAction("&Copy", widget, SLOT(cmCopy()), Qt::CTRL +Qt::Key_C); edit->addAction("&Paste", widget, SLOT(cmPaste()), Qt::CTRL +Qt::Key_V); #endif RLP_MSEPARATOR(edit); RLP_MITEM(edit, widget, this, BaseObj, "&Update Values", CM_UPDATE); RLP_MSEPARATOR(edit); RLP_MITEM(edit, widget, this, BaseObj, "&Delete Object", CM_DELOBJ); RLP_MITEM(displ, widget, this, BaseObj, "&Redraw", CM_REDRAW); #if QT_VERSION < 0x040000 displ->insertItem("&Zoom", MkZoomMenu(new QPopupMenu(widget), widget, this, BaseObj)); #else MkZoomMenu(displ->addMenu("&Zoom"), widget, this, BaseObj); #endif RLP_MITEM(displ, widget, this, BaseObj, "&Layers", CM_LAYERS); RLP_MITEM(plots, widget, this, BaseObj, "Add &Graph", CM_NEWGRAPH); RLP_MITEM(plots, widget, this, BaseObj, "Add &Plot", CM_ADDPLOT); RLP_MITEM(plots, widget, this, BaseObj, "Add &Axis", CM_ADDAXIS); RLP_MITEM(plots, widget, this, BaseObj, "Add &Legend", CM_LEGEND); RLP_MSEPARATOR(plots); RLP_MITEM(plots, widget, this, BaseObj, "Page &Settings", CM_DEFAULTS); RLP_MITEM(about, widget, this, BaseObj, "&About ...", CM_ABOUT); #if QT_VERSION < 0x040000 menu = new RLPmenu(widget, this, BaseObj); menu->insertItem("&File", file); menu->insertItem("&Edit", edit); menu->insertItem("&Display", displ); menu->insertItem("&Tools", MkToolMenu(new QPopupMenu(widget), widget, this, BaseObj)); menu->insertItem("&Plots", plots); menu->insertItem("&?", about); #endif } else return false; #if QT_VERSION < 0x040000 menu->show(); MenuHeight = menu->height(); widget->resize(widget->width()+8, widget->height()+8); #else ((RLPwidget*)widget)->menu_bar->show(); MenuHeight = ((RLPwidget*)widget)->menu_bar->height(); widget->resize(widget->width()+8, widget->height()+8); #endif if(MenuHeight< 20) MenuHeight = 25; if(MenuHeight< defs.iMenuHeight) MenuHeight = defs.iMenuHeight; else defs.iMenuHeight = MenuHeight; return true; } #undef RLP_MITEM #undef RLP_MSEPARATOR void OutputQT::CheckMenu(int mid, bool check) { #if QT_VERSION < 0x040000 if(mid < CM_T_STANDARD) switch(mid){ //tool mode identifier case TM_STANDARD: mid = CM_T_STANDARD; break; case TM_DRAW: mid = CM_T_DRAW; break; case TM_POLYLINE: mid = CM_T_POLYLINE; break; case TM_POLYGON: mid = CM_T_POLYGON; break; case TM_RECTANGLE: mid = CM_T_RECTANGLE; break; case TM_ROUNDREC: mid = CM_T_ROUNDREC; break; case TM_ELLIPSE: mid = CM_T_ELLIPSE; break; case TM_ARROW: mid = CM_T_ARROW; break; case TM_TEXT: mid = CM_T_TEXT; break; default: return; } if(menu) menu->setItemChecked(mid, check); #else switch(mid) { case TM_STANDARD: case CM_T_STANDARD: if(ittStd) ittStd->setChecked(check); break; case TM_DRAW: case CM_T_DRAW: if(ittDraw) ittDraw->setChecked(check); break; case TM_POLYLINE: case CM_T_POLYLINE: if(ittPl) ittPl->setChecked(check); break; case TM_POLYGON: case CM_T_POLYGON: if(ittPg) ittPg->setChecked(check); break; case TM_RECTANGLE: case CM_T_RECTANGLE: if(ittRec) ittRec->setChecked(check); break; case TM_ROUNDREC: case CM_T_ROUNDREC: if(ittRrec) ittRrec->setChecked(check); break; case TM_ELLIPSE: case CM_T_ELLIPSE: if(ittElly) ittElly->setChecked(check); break; case TM_ARROW: case CM_T_ARROW: if(ittArr) ittArr->setChecked(check); break; case TM_TEXT: case CM_T_TEXT: if(ittTxt) ittTxt->setChecked(check); break; } #endif } void OutputQT::FileHistory() { char **history[] = {&defs.File1, &defs.File2, &defs.File3, &defs.File4, &defs.File5, &defs.File6}; int i, j, k; #if QT_VERSION >= 0x040000 if(defs.File1 && defs.File1[0]) { itFil1->setText(defs.File1); itFil1->setVisible(true); } QAction *file_history[] = {itFil1, itFil2, itFil3, itFil4, itFil5, itFil6}; for(i = 0; i < 6 && *history[i] && file_history[i]; i++) { k = strlen(*history[i]); for (j = 0; j < k && defs.currPath[j] == (*history[i])[j]; j++); if((*history[i])[j] == '\\' || (*history[i])[j] == '/') j++; file_history[i]->setText(*history[i]+j); file_history[i]->setVisible(true); } HistMenuSize = i; #else //Qt 3.0, Qt 2.0 if(!hasHistMenu || !defs.File1 || !menu) return; for(i = 0; i < 6 && *history[i]; i++) { k = strlen(*history[i]); for (j = 0; j < k && defs.currPath[j] == (*history[i])[j]; j++); if((*history[i])[j] == '\\' || (*history[i])[j] == '/') j++; menu->changeItem(CM_FILE1+i, *history[i]+j); #if QT_VERSION >= 0x030000 //Qt version 3, n.a. in version 2 menu->setItemVisible(CM_FILE1+i, true); #endif } HistMenuSize = i; #endif } void OutputQT::CreateNewWindow(GraphObj *g) { int w=0, h=0; GetDesktopSize(&w, &h); if(w < 10 && h < 10) { w = 858; h = 572; } if(widget = new RLPwidget(0, 0, this, g)) { #if QT_VERSION < 0x040000 widget->setCaption("OutputQT::CreateNewWindow"); #else widget->setWindowTitle("OutputQT::CreateNewWindow"); #endif widget->setGeometry(0, 0, (int)(w*0.7), (int)(h*0.7)); ((RLPwidget*)widget)->mempic = mempic; HScroll = ((RLPwidget*)widget)->HScroll; VScroll = ((RLPwidget*)widget)->VScroll; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Common widget support //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #if QT_VERSION < 0x040000 RLPwidget::RLPwidget(QWidget *par, const char *name, anyOutput *o, GraphObj *g) : QWidget(par) #else RLPwidget::RLPwidget(QWidget *par, const char *name, anyOutput *o, GraphObj *g) : QMainWindow(par) #endif { int w, h; GetDesktopSize(&w, &h); mempic = new QPixmap(w, h); parent = par; OutputClass = o; BaseObj = g; setMinimumSize(100, 80); // setBackgroundMode(NoBackground); HScroll = new QScrollBar(Qt::Horizontal, this); HScroll->setRange(0, 1000); #if QT_VERSION < 0x040000 HScroll->setSteps(1, 16); #else HScroll->setSingleStep(1); HScroll->setPageStep(16); #endif connect(HScroll, SIGNAL(valueChanged(int)), SLOT(hScrollEvent(int))); VScroll = new QScrollBar(Qt::Vertical, this); VScroll->setRange(0, 1000); #if QT_VERSION < 0x040000 VScroll->setSteps(1, 16); #else VScroll->setSingleStep(1); VScroll->setPageStep(16); #endif connect(VScroll, SIGNAL(valueChanged(int)), SLOT(vScrollEvent(int))); #if QT_VERSION < 0x040000 menu_bar = new RLPmenu(this, o, BaseObj); if(!MainWidget) { QAppl->setMainWidget(MainWidget = this); } setFocusPolicy(StrongFocus); setKeyCompression(true); #else menu_bar = menuBar(); if(!MainWidget) { MainWidget = this; } setFocusPolicy(Qt::StrongFocus); setAttribute(Qt::WA_KeyCompression, true); #endif setMouseTracking(true); } RLPwidget::~RLPwidget() { if(OutputClass)((OutputQT*)OutputClass)->widget = 0L; OutputClass = 0L; BaseObj = 0L; } //public slots: menu items, events void RLPwidget::hScrollEvent(int pos) { if(BaseObj){ BaseObj->Command(CMD_SETHPOS, (void*)(&pos), OutputClass); repaint(); } } void RLPwidget::vScrollEvent(int pos) { if(BaseObj){ BaseObj->Command(CMD_SETVPOS, (void*)(&pos), OutputClass); repaint(); } } void RLPwidget::cmPaste() { if(BaseObj) { OutputClass->MouseCursor(MC_WAIT, true); if(BaseObj->Id == GO_SPREADDATA) TestClipboard(BaseObj); else if(BaseObj->Id == GO_PAGE || BaseObj->Id == GO_GRAPH){ if(CurrGO && CurrGO->Id == GO_TEXTFRAME && CurrGO->Command(CMD_PASTE, 0L, OutputClass)); else TestClipboard(BaseObj); } BaseObj->Command(CMD_MOUSECURSOR, 0L, OutputClass); } } //protected: widget events void RLPwidget::paintEvent(QPaintEvent *range) { QRect rc; QPainter qpainter(this); if(!mempic) return; 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); #endif } void RLPwidget::resizeEvent(QResizeEvent *) { CurrWidget = this; HScroll->resize(width() -16, 16); HScroll->move(0, height()-16); VScroll->resize(16, height()-OutputClass->MenuHeight-16); VScroll->move(width()-16, OutputClass->MenuHeight); if(BaseObj) BaseObj->Command(CMD_SETSCROLL, 0L, OutputClass); } void RLPwidget::closeEvent(QCloseEvent *e) { if(BaseObj){ if(BaseObj->Command(CMD_CAN_CLOSE, 0L, 0L)) { if(OutputClass)((OutputQT*)OutputClass)->widget = 0L; OutputClass = 0L; BaseObj = 0L; e->accept(); } } else e->accept(); if(this == MainWidget) QAppl->exit(0); } void RLPwidget::mouseDoubleClickEvent(QMouseEvent *e) { MouseEvent mev = {1, e->button() == Qt::LeftButton?MOUSE_LBDOUBLECLICK:-1,e->x(),e->y()}; if (BaseObj)BaseObj->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass); } void RLPwidget::mousePressEvent(QMouseEvent *e) { int i; MouseEvent mev = {1, e->button() == Qt::LeftButton ? MOUSE_LBDOWN : -1, e->x(), e->y()}; HideTextCursor(); CurrWidget = this; #if QT_VERSION < 0x040000 i = e->state(); if(i & Qt::ShiftButton) mev.StateFlags |= 0x08; if(i & Qt::ControlButton) mev.StateFlags |= 0x10; #else i = e->modifiers(); if(i & Qt::ShiftModifier) mev.StateFlags |= 0x08; if(i & Qt::ControlModifier) mev.StateFlags |= 0x10; #endif if(mev.StateFlags |= MOUSE_LBDOWN) mouse_buttons_down |= 0x01; if (BaseObj)BaseObj->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass); } void RLPwidget::mouseReleaseEvent(QMouseEvent *e) { int i; MouseEvent mev = {0, e->button() == Qt::LeftButton? MOUSE_LBUP : e->button() == Qt::RightButton ? MOUSE_RBUP : -1, e->x(), e->y()}; #if QT_VERSION < 0x040000 i = e->state(); if(i & Qt::ShiftButton) mev.StateFlags |= 0x08; if(i & Qt::ControlButton) mev.StateFlags |= 0x10; #else i = e->modifiers(); if(i & Qt::ShiftModifier) mev.StateFlags |= 0x08; if(i & Qt::ControlModifier) mev.StateFlags |= 0x10; #endif mouse_buttons_down = 0; if (BaseObj) BaseObj->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass); } void 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; if(i & Qt::ControlButton) mev.StateFlags |= 0x10; #else i = e->modifiers(); if(i & Qt::ShiftModifier) mev.StateFlags |= 0x08; if(i & Qt::ControlModifier) mev.StateFlags |= 0x10; #endif if(OutputClass && ((OutputQT*)OutputClass)->ShowObj) { delete((eph_obj*)((OutputQT*)OutputClass)->ShowObj); ((OutputQT*)OutputClass)->ShowObj = 0L; } if (BaseObj) BaseObj->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass); } void RLPwidget::keyPressEvent(QKeyEvent *e) { int i, c; QChar qc; w_char uc; bool is_shifted; #if QT_VERSION < 0x040000 i = e->state(); is_shifted = ((i & Qt::ShiftButton) != 0); #else i = e->modifiers(); is_shifted = ((i & Qt::ShiftModifier) != 0); #endif CurrWidget = this; if(x() || y()) { CurrWidgetPos.x = x(); CurrWidgetPos.y = y(); } if(BaseObj) switch(c = e->key()) { #if QT_VERSION < 0x040000 case Qt::Key_Prior: #else case Qt::Key_PageUp: #endif if(is_shifted) BaseObj->Command(CMD_SHPGUP, 0L, OutputClass); else BaseObj->Command(CMD_PAGEUP, 0L, OutputClass); break; #if QT_VERSION < 0x040000 case Qt::Key_Next: #else case Qt::Key_PageDown: #endif if(is_shifted) BaseObj->Command(CMD_SHPGDOWN, 0L, OutputClass); else BaseObj->Command(CMD_PAGEDOWN, 0L, OutputClass); break; case Qt::Key_Left: if(is_shifted) BaseObj->Command(CMD_SHIFTLEFT, 0L, OutputClass); else BaseObj->Command(CMD_CURRLEFT, 0L, OutputClass); break; case Qt::Key_Right: if(is_shifted) BaseObj->Command(CMD_SHIFTRIGHT, 0L, OutputClass); else BaseObj->Command(CMD_CURRIGHT, 0L, OutputClass); break; case Qt::Key_Up: if(is_shifted) BaseObj->Command(CMD_SHIFTUP, 0L, OutputClass); else BaseObj->Command(CMD_CURRUP, 0L, OutputClass); break; case Qt::Key_Down: if(is_shifted) BaseObj->Command(CMD_SHIFTDOWN, 0L, OutputClass); else BaseObj->Command(CMD_CURRDOWN, 0L, OutputClass); break; case Qt::Key_Delete: BaseObj->Command(CMD_DELETE, 0L, OutputClass); break; case Qt::Key_Tab: BaseObj->Command(CMD_TAB, 0L, OutputClass); break; case Qt::Key_Backtab: BaseObj->Command(CMD_SHTAB, 0L, OutputClass); break; case Qt::Key_Home: BaseObj->Command(CMD_POS_FIRST, 0L, OutputClass); break; case Qt::Key_End: BaseObj->Command(CMD_POS_LAST, 0L, OutputClass); break; default: QString kres = e->text(); for(i = 0; i < kres.length(); i++) { qc = kres.at(i); uc = qc.unicode(); if(uc == 3) break; else if(uc == 27 && OutputClass) { OutputClass->HideMark(); EmptyClip(); ProcMenuEvent(CM_T_STANDARD, this, OutputClass, BaseObj); } else if(uc == 22) cmPaste(); else if(uc == 26) cmUndo(); else if(uc > 255) BaseObj->Command(CMD_ADDCHARW, (void *)(&uc), OutputClass); else BaseObj->Command(CMD_ADDCHAR, (void *)(&uc), OutputClass); } break; } e->accept(); } void RLPwidget::focusInEvent(QFocusEvent *e) { if(x() || y()) { CurrWidgetPos.x = x(); CurrWidgetPos.y = y(); } CurrWidget = this; if(BaseObj) { if(BaseObj->Id == GO_GRAPH) CurrGraph = (Graph*)BaseObj; } } //private functions void RLPwidget::openHistoryFile(int idx) { char *name = 0L; switch (idx) { case 0: name = defs.File1; break; case 1: name = defs.File2; break; case 2: name = defs.File3; break; case 3: name = defs.File4; break; case 4: name = defs.File5; break; case 5: name = defs.File6; break; } if(name && FileExist(name)) { BaseObj->Command(CMD_DROPFILE, name, OutputClass); defs.FileHistory(name); OutputClass->FileHistory(); } else { ErrorBox("The selected file \ndoes not exist!\n"); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Print and output EPS to file //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class FileEPS:public QPrinter { public: FileEPS(GraphObj *g, anyOutput *o); protected: int metric(int) const; private: GraphObj *go; anyOutput *out; }; FileEPS::FileEPS(GraphObj *g, anyOutput *o) { go = g; out = o; } int FileEPS::metric(int m) const { #if QT_VERSION < 0x040000 if(go && out)switch (m) { case QPaintDeviceMetrics::PdmWidth: return out->un2ix(go->GetSize(SIZE_GRECT_RIGHT) - go->GetSize(SIZE_GRECT_LEFT))/10; case QPaintDeviceMetrics::PdmHeight: return out->un2ix(go->GetSize(SIZE_GRECT_BOTTOM) - go->GetSize(SIZE_GRECT_TOP))/10; case QPaintDeviceMetrics::PdmWidthMM: return iround((go->GetSize(SIZE_GRECT_RIGHT) - go->GetSize(SIZE_GRECT_LEFT)) * Units[defs.cUnits].convert); case QPaintDeviceMetrics::PdmHeightMM: return iround((go->GetSize(SIZE_GRECT_BOTTOM) - go->GetSize(SIZE_GRECT_TOP)) * Units[defs.cUnits].convert); } return QPrinter::metric(m); #else if(go && out)switch (m) { case PdmWidth: return out->un2ix(go->GetSize(SIZE_GRECT_RIGHT) - go->GetSize(SIZE_GRECT_LEFT))/10; case PdmHeight: return out->un2ix(go->GetSize(SIZE_GRECT_BOTTOM) - go->GetSize(SIZE_GRECT_TOP))/10; case PdmWidthMM: return iround((go->GetSize(SIZE_GRECT_RIGHT) - go->GetSize(SIZE_GRECT_LEFT)) * Units[defs.cUnits].convert); case PdmHeightMM: return iround((go->GetSize(SIZE_GRECT_BOTTOM) - go->GetSize(SIZE_GRECT_TOP)) * Units[defs.cUnits].convert); } return QPrinter::metric((QPaintDevice::PaintDeviceMetric)m); #endif } 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; minLW = 1; if(file) fileName = strdup(file); else fileName = 0L; go = g; #if QT_VERSION >= 0x030000 //Qt version 3, n.a. in version 2 if(fileName && go) printer = new FileEPS(g, this); else printer = new QPrinter(QPrinter::HighResolution); hres = vres = (9.5*((double)printer->resolution())); #else if(fileName && go) printer = new FileEPS(g, this); else printer = new QPrinter(); hres = vres = (9.5*600.0); #endif Box1.Xmin = Box1.Ymin = 0.0; Box1.Xmax = Box1.Ymax = 6000; DeskRect.left = DeskRect.top = 0; DeskRect.right = (long)(hres*6.0); DeskRect.bottom = (long)(vres*8.0); bPrinting = false; } PrintQT::~PrintQT() { if(printer) delete(printer); if(hgo) delete(hgo); if(fileName) free(fileName); } bool PrintQT::ActualSize(RECT *rc) { if(printer && rc) { #if QT_VERSION < 0x040000 QPaintDeviceMetrics dm(printer); rc->top = rc->left = 0; rc->bottom = dm.height() *10; rc->right = dm.width() *10; #else QRect qrc = printer->pageRect(); rc->top = rc->left = 0; rc->bottom = qrc.height(); rc->right = qrc.width(); #endif return true; } return false; } bool PrintQT::SetLine(LineDEF *lDef) { int iw; if(lDef->width != LineWidth || lDef->width != LineWidth || lDef->pattern != dPattern || lDef->color != dLineCol) { LineWidth = lDef->width; iw = iround(un2fix(lDef->width)); dPattern = lDef->pattern; RLP.finc = 256.0/un2fix(lDef->patlength*8.0); RLP.fp = 0.0; if(iLine == iw && dLineCol == lDef->color) return true; iLine = iw > 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; } bool PrintQT::SetFill(FillDEF *fill) { if(!fill) return false; if((fill->type & 0xff) != FILL_NONE) { if(!hgo) hgo = new HatchOut(this); if(hgo) hgo->SetFill(fill); } else { if(hgo) delete hgo; hgo = 0L; } qPainter.setBrush(MK_QCOLOR(fill->color)); dFillCol = fill->color; dFillCol2 = fill->color2; return true; } bool PrintQT::SetTextSpec(TextDEF *set) { set->iSize = un2ix(set->fSize/7.5); return com_SetTextSpec(set, &TxtSet, this, qFont, &qPainter); } bool PrintQT::StartPage() { if(!printer || bPrinting) return false; if(fileName) { VPorg.fy = -co2fiy(go->GetSize(SIZE_GRECT_TOP)); VPorg.fx = -co2fix(go->GetSize(SIZE_GRECT_LEFT)); printer->setOutputFileName(fileName); printer->setFullPage(true); qPainter.begin(printer); qPainter.setWorldMatrix(dxf, FALSE); return bPrinting = true; } #if QT_VERSION < 0x040000 if(printer->setup(0)){ #else QPrintDialog dialog(printer, 0L); if (dialog.exec()){ #endif qPainter.begin(printer); qPainter.setWorldMatrix(dxf, FALSE); return bPrinting = true; } else return false; } bool PrintQT::EndPage() { #if QT_VERSION < 0x040000 qPainter.flush(); #endif qPainter.end(); bPrinting = false; return true; } bool PrintQT::Eject() { if(!bPrinting) return false; #if QT_VERSION < 0x040000 qPainter.flush(); #endif qPainter.end(); qPainter.begin(printer); qPainter.setWorldMatrix(dxf, FALSE); return true; } bool PrintQT::oGetTextExtent(char *text, int cb, int *width, int *height) { return com_GetTextExtent(text, width, height, cb, &TxtSet, &qPainter); } bool PrintQT::oGetTextExtentW(w_char *text, int cb, int *width, int *height) { return com_GetTextExtentW(text, width, height, cb, &TxtSet, &qPainter); } bool PrintQT::oCircle(int x1, int y1, int x2, int y2, char* nam) { qPainter.drawEllipse(x1, y1, x2-x1, y2-y1); if(hgo) return hgo->oCircle(x1, y1, x2, y2); return true; } bool PrintQT::oPolyline(POINT * pts, int cp, char *nam) { int i; if(cp < 1) return false; if (dPattern) { for (i = 1; i < cp; i++) PatLine(pts[i-1], pts[i]); } else { for (i = 1; i < cp; i++)qPainter.drawLine(pts[i-1].x, pts[i-1].y, pts[i].x, pts[i].y); } return true; } bool 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, y2-y1); #endif if(hgo) hgo->oRectangle(x1, y1, x2, y2, 0L); return true; } bool PrintQT::oSolidLine(POINT *p) { qPainter.drawLine(p[0].x, p[0].y, p[1].x, p[1].y); return true; } bool PrintQT::oTextOut(int x, int y, char *txt, int cb) { if(!txt || !txt[0]) return false; return com_TextOut(x, y, txt, &TxtSet, &qPainter, this); } bool PrintQT::oTextOutW(int x, int y, w_char *txt, int cb) { if(!txt || !txt[0]) return false; return com_TextOutW(x, y, txt, &TxtSet, &qPainter, this); } bool PrintQT::oPolygon(POINT *pts, int cp, char *nam) { int i; #if QT_VERSION < 0x040000 QPointArray *a; if(!pts || cp <2) return false; a = new QPointArray(cp); if (a) { for(i = 0; i < cp; i++) a->setPoint(i, pts[i].x, pts[i].y); qPainter.drawPolygon(*a); delete a; } #else QPoint *a; if(a = (QPoint*)malloc(cp * sizeof(QPoint))) { for(i = 0; i < cp; i++) { a[i].setX(pts[i].x); a[i].setY(pts[i].y); } qPainter.drawPolygon(a, cp); free(a); } #endif if(hgo) hgo->oPolygon(pts, cp); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Find a suitable www browser and more initialization void FindBrowser() { //find a suitable browser 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"); //use home as startup directory sprintf(TmpTxt, "%s", getenv("HOME")); defs.currPath = strdup(TmpTxt); strcat(TmpTxt, "/.RLPlot"); defs.IniFile = strdup(TmpTxt); //some more initialization: create application icon #if QT_VERSION >= 0x040000 QPixmap pm(RLPlot_xpm); rlp_icon = new QIcon(pm); QAppl->setWindowIcon(*rlp_icon); #endif #ifdef RLP_PORT //clipboard info sprintf(TmpTxt, "%s", getenv("USER")); if(TmpTxt[0])cb_owner = strdup(TmpTxt); #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // The MAIN antry point //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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); a.exec(); if(defs.IniFile) { if(drw = new DefsRW()){ drw->FileIO(FILE_WRITE); delete drw; } } return 0; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Dialog box support //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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, flags & 0x00000004 ? Qt::Dialog : Qt::Window) #endif { parent = par; dlg = d; #if QT_VERSION < 0x040000 setFocusPolicy(StrongFocus); #else setFocusPolicy(Qt::StrongFocus); #endif } DlgWidget::~DlgWidget() { if(OutputClass){ ((OutputQT*)OutputClass)->widget=0L; delete ((OutputQT*)OutputClass); } } void DlgWidget::paintEvent(QPaintEvent *range) { QRect rc; QPainter qpainter(this); 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(OutputClass && ((OutputQT*)OutputClass)->ShowObj) ((eph_obj*)(((OutputQT*)OutputClass)->ShowObj))->DoPlot(&qpainter); if(OutputClass && ((OutputQT*)OutputClass)->ShowAnimated) ((eph_obj*)(((OutputQT*)OutputClass)->ShowAnimated))->DoPlot(&qpainter); #endif } void DlgWidget::mouseDoubleClickEvent(QMouseEvent *e) { MouseEvent mev = {1, e->button() == Qt::LeftButton?MOUSE_LBDOUBLECLICK:-1,e->x(),e->y()}; if (dlg) dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass); } void DlgWidget::mousePressEvent(QMouseEvent *e) { int i; MouseEvent mev = {1, e->button() == Qt::LeftButton ? MOUSE_LBDOWN : -1, e->x(), e->y()}; HideTextCursor(); CurrWidget = this; #if QT_VERSION < 0x040000 i = e->state(); if(i & Qt::ShiftButton) mev.StateFlags |= 0x08; if(i & Qt::ControlButton) mev.StateFlags |= 0x10; #else i = e->modifiers(); if(i & Qt::ShiftModifier) mev.StateFlags |= 0x08; if(i & Qt::ControlModifier) mev.StateFlags |= 0x10; #endif if(mev.StateFlags |= MOUSE_LBDOWN) mouse_buttons_down |= 0x01; if (dlg)dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass); } void DlgWidget::mouseReleaseEvent(QMouseEvent *e) { int i; MouseEvent mev = {0, e->button() == Qt::LeftButton? MOUSE_LBUP : e->button() == Qt::RightButton ? MOUSE_RBUP : -1, e->x(), e->y()}; #if QT_VERSION < 0x040000 i = e->state(); if(i & Qt::ShiftButton) mev.StateFlags |= 0x08; if(i & Qt::ControlButton) mev.StateFlags |= 0x10; #else i = e->modifiers(); if(i & Qt::ShiftModifier) mev.StateFlags |= 0x08; if(i & Qt::ControlModifier) mev.StateFlags |= 0x10; #endif mouse_buttons_down = 0; if (dlg) dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass); } void DlgWidget::mouseMoveEvent(QMouseEvent *e) { int i; MouseEvent mev = {mouse_buttons_down, MOUSE_MOVE, e->x(), e->y()}; #if QT_VERSION < 0x040000 i = e->state(); if(i & Qt::ShiftButton) mev.StateFlags |= 0x08; if(i & Qt::ControlButton) mev.StateFlags |= 0x10; #else i = e->modifiers(); if(i & Qt::ShiftModifier) mev.StateFlags |= 0x08; if(i & Qt::ControlModifier) mev.StateFlags |= 0x10; #endif if (dlg) dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass); } void DlgWidget::keyPressEvent(QKeyEvent *e) { int i, c; QChar qc; w_char uc; bool is_shifted; #if QT_VERSION < 0x040000 i = e->state(); is_shifted = ((i & Qt::ShiftButton) != 0); #else i = e->modifiers(); is_shifted = ((i & Qt::ShiftModifier) != 0); #endif CurrWidget = this; if(x() || y()) { CurrWidgetPos.x = x(); CurrWidgetPos.y = y(); } if(dlg) switch(c = e->key()) { case Qt::Key_Left: if(is_shifted) dlg->Command(CMD_SHIFTLEFT, 0L, OutputClass); else dlg->Command(CMD_CURRLEFT, 0L, OutputClass); break; case Qt::Key_Right: if(is_shifted) dlg->Command(CMD_SHIFTRIGHT, 0L, OutputClass); else dlg->Command(CMD_CURRIGHT, 0L, OutputClass); break; case Qt::Key_Up: if(is_shifted) dlg->Command(CMD_SHIFTUP, 0L, OutputClass); else dlg->Command(CMD_CURRUP, 0L, OutputClass); break; case Qt::Key_Down: if(is_shifted) dlg->Command(CMD_SHIFTDOWN, 0L, OutputClass); else dlg->Command(CMD_CURRDOWN, 0L, OutputClass); break; case Qt::Key_Delete: dlg->Command(CMD_DELETE, 0L, OutputClass); break; case Qt::Key_Tab: dlg->Command(CMD_TAB, 0L, OutputClass); break; case Qt::Key_Backtab: dlg->Command(CMD_SHTAB, 0L, OutputClass); break; case Qt::Key_Home: dlg->Command(CMD_POS_FIRST, 0L, OutputClass); break; case Qt::Key_End: dlg->Command(CMD_POS_LAST, 0L, OutputClass); break; default: QString kres = e->text(); for(i = 0; i < kres.length(); i++) { qc = kres.at(i); uc = qc.unicode(); if(uc == 3) dlg->Command(CMD_COPY, 0L, OutputClass); else if(uc == 22) dlg->Command(CMD_PASTE, 0L, OutputClass); else if(uc == 26) dlg->Command(CMD_UNDO, 0L, OutputClass); else if(uc > 255) dlg->Command(CMD_ADDCHARW, (void *)(&uc), OutputClass); else dlg->Command(CMD_ADDCHAR, (void *)(&uc), OutputClass); } break; } e->accept(); } void DlgWidget::focusInEvent(QFocusEvent *e) { if(Undo.cdisp)Undo.cdisp->MouseCursor(MC_ARROW, false); raise(); CurrWidget = this; if(x() || y()) { CurrWidgetPos.x = x(); CurrWidgetPos.y = y(); } } void DlgWidget::focusOutEvent(QFocusEvent *e) { HideTextCursorObj(OutputClass); if(dlg) dlg->Command(CMD_ENDDIALOG, 0L, OutputClass); } void DlgWidget::closeEvent(QCloseEvent *e) { HideTextCursorObj(OutputClass); e->ignore(); if(dlg){ dlg->Command(CMD_UNLOCK, 0L, OutputClass); dlg->Command(CMD_ENDDIALOG, 0L, OutputClass); } } void DlgWidget::timerEvent(QTimerEvent *) { if(dlg) dlg->Command(CMD_ENDDIALOG, dlg, OutputClass); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void *CreateDlgWnd(char *title, int x, int y, int width, int height, tag_DlgObj *d, DWORD flags) { DlgWidget *w; QWidget *pw; OutputQT *o; int dw, dh; 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 & 0x08) w->startTimer(100); if(flags & 0x1) { GetDesktopSize(&dw, &dh); w->move((dw>>1) - ((w->width())>>1), (dh>>1) - ((w->height())>>1)); } else if(pw) { if(pw->x() || pw->y()) { x += pw->x(); y += pw->y(); } else { x += CurrWidgetPos.x; y += CurrWidgetPos.y; } w->move(x, y); } d->DoPlot(o); w->show(); ((DlgRoot*)d)->hDialog = w; #if QT_VERSION < 0x040000 w->setActiveWindow(); #else w->activateWindow(); QAppl->processEvents(); w->raise(); #endif return w; } void LoopDlgWnd() //keep message processing running { #if QT_VERSION < 0x040000 QAppl->processOneEvent(); #else QAppl->processEvents(); #endif } void CloseDlgWnd(void *hDlg) { HideCopyMark(); if(hDlg) { delete((DlgWidget*) hDlg); if(CurrWidgetPos.x > 50 && CurrWidgetPos.y > 50) { CurrWidgetPos.x -= 50; CurrWidgetPos.y -= 50; } } } void ShowDlgWnd(void *hDlg) { if(hDlg){ ((DlgWidget*)hDlg)->show(); #if QT_VERSION >=0x040000 ((DlgWidget*)hDlg)->activateWindow (); #else ((DlgWidget*)hDlg)->setActiveWindow(); #endif ((DlgWidget*)hDlg)->raise(); ((DlgWidget*)hDlg)->setFocus(); } } void ResizeDlgWnd(void *hDlg, int w, int h) { ((DlgWidget*)hDlg)->setFixedSize(w-6, h-16); ((DlgWidget*)hDlg)->show(); ((DlgWidget*)hDlg)->raise(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // OS independent interface to Qt specific classes //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ anyOutput *NewDispClass(GraphObj *g) { return new OutputQT(g); } bool DelDispClass(anyOutput *w) { if(w) delete (OutputQT*) w; return true; } anyOutput *NewBitmapClass(int w, int h, double hr, double vr) { return new BitMapQT(w, h, hr, vr); } bool DelBitmapClass(anyOutput *w) { if (w) delete (BitMapQT*) w; return true; } rlplot/UtilObj.cpp0000755000076400007640000033340710745414507012746 0ustar c71960c71960//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 #include #include #include #include #include //file open flags #include //I/O flags #ifdef _WINDOWS #include //for read/write #else #define O_BINARY 0x0 #include #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*)""; tag2 = (char*)""; break; case FONT_TIMES: tag1 = (char*)""; tag2 = (char*)""; break; case FONT_COURIER: tag1 = (char*)""; tag2 = (char*)""; break; case FONT_GREEK: tag1 = (char*)""; tag2 = (char*)""; 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*)""; tag2 = (char*)""; break; case ~TXS_BOLD: tag1 = (char*)""; tag2 = (char*)""; break; case TXS_ITALIC: tag1 = (char*)""; tag2 = (char*)""; break; case ~TXS_ITALIC: tag1 = (char*)""; tag2 = (char*)""; break; case TXS_UNDERLINE: tag1 = (char*)""; tag2 = (char*)""; break; case ~TXS_UNDERLINE: tag1 = (char*)""; tag2 = (char*)""; break; case TXS_SUPER: tag1 = (char*)""; tag2 = (char*)""; break; case ~TXS_SUPER: tag1 = (char*)""; tag2 = (char*)""; break; case TXS_SUB: tag1 = (char*)""; tag2 = (char*)""; break; case ~TXS_SUB: tag1 = (char*)""; tag2 = (char*)""; 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 x >crb.x || mev->y 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[] = { {"", ~TXS_NORMAL, TXS_ITALIC, -1, 0}, {"", ~TXS_ITALIC, TXS_NORMAL, -1, 0}, {"", ~TXS_NORMAL, TXS_BOLD, -1, 0}, {"", ~TXS_BOLD, TXS_NORMAL, -1, 0}, {"", ~TXS_NORMAL, TXS_UNDERLINE, -1, 0}, {"", ~TXS_UNDERLINE, TXS_NORMAL, -1, 0}, {"", ~TXS_NORMAL, TXS_SUPER, -1, 0}, {"", ~TXS_SUPER, TXS_NORMAL, -1, 0}, {"", ~TXS_NORMAL, TXS_SUB, -1, 0}, {"", ~TXS_SUB, TXS_NORMAL, -1, 0}, {"", 0, 0, FONT_HELVETICA, 0}, {"", 0, 0, FONT_TIMES, 0}, {"", 0, 0, FONT_COURIER, 0}, {"", 0, 0, FONT_GREEK, 0}, {"", 0, 0, -2, 0}, {"", 0, 0, -1, 1}, {"", 0, 0, -1, 2}, {"", 0, 0, -1, 3}, {"", 0, 0, -1, 4}, {"", 0, 0, -1, 5}, {"", 0, 0, -1, 6}, {"", 0, 0, -1, 7}, {"", 0, 0, -1, 8}, {"", 0, 0, -1, 9}, {"", 0, 0, -1, 10}, {"", 0, 0, -1, 100}, {"", 0, 0, -1, 101}, {"", 0, 0, -1, 102}, {"", 0, 0, -1, 103}, {"", 0, 0, -1, 104}, {"", 0, 0, -1, 105}, {"", 0, 0, -1, 106}, {"", 0, 0, -1, 107}, {"", 0, 0, -1, 200}, {"", 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=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)= 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 rlplot/rlplot.h0000755000076400007640000025707410771206307012360 0ustar c71960c71960//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 #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 #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 #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->xy>loc.y && p->y= 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 rlplot/WinSpec.h0000755000076400007640000001130210760264330012370 0ustar c71960c71960//WinSpec.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 // class BitMapWin:public anyOutput{ public: HBITMAP scr; GraphObj *go; HDC memDC; HPEN hPen, oldPen; 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); BitMapWin(GraphObj *g); ~BitMapWin(); bool SetLine(LineDEF *lDef); bool SetFill(FillDEF *fill); bool SetTextSpec(TextDEF *set); virtual bool Erase(DWORD Color); virtual bool StartPage() {return true;}; bool CopyBitmap(int x, int y, anyOutput* src, int sx, int sy, int sw, int sh, bool invert); bool oGetTextExtent(char *text, int cb, int *width, int *height); bool oGetTextExtentW(w_char *text, int cb, int *width, int *height); bool oGetPix(int x, int y, DWORD *col); bool oDrawIcon(int type, int x, int y); bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L); bool oPolyline(POINT * pts, int cp, char *nam = 0L); bool oRectangle(int x1, int y1, int x2, int y2, char* nam = 0L); bool oSolidLine(POINT *p); bool oTextOut(int x, int y, char *txt, int cb); bool 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{ public: HWND hWnd; HDC hdc; OutputWin(GraphObj *g, HWND hw); ~OutputWin(); bool ActualSize(RECT *rc); void Focus(){if(hWnd) SetFocus(hWnd);}; 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); bool StartPage(); bool EndPage(); bool UpdateRect(RECT *rc, bool invert); bool UpdateRect(HDC hdc, RECT rc); void ShowBitmap(int x, int y, anyOutput* src); void ShowLine(POINT * pts, int cp, DWORD color); void ShowEllipse(POINT p1, POINT p2, DWORD color); bool SetMenu(int type); void CheckMenu(int mid, bool check); void FileHistory(); private: void CreateNewWindow(void *g); }; class WinCopyWMF:public anyOutput { public: WinCopyWMF(GraphObj *g, char* file_wmf, char *file_emf); ~WinCopyWMF(); bool SetLine(LineDEF *lDef); bool SetFill(FillDEF *fill); bool SetTextSpec(TextDEF *set); bool oGetTextExtent(char *text, int cb, int *width, int *height); bool oGetTextExtentW(w_char *text, int cb, int *width, int *height); 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 bott_y; GraphObj *go; HDC hdc; HPEN hPen; HBRUSH hBrush; HFONT hFont; HatchOut *hgo; char *wmf_file, *emf_file; }; class PrintWin:public anyOutput{ public: PrintWin(); ~PrintWin(); bool SetLine(LineDEF *lDef); bool SetFill(FillDEF *fill); bool SetTextSpec(TextDEF *set); bool oGetTextExtent(char *text, int cb, int *width, int *height); 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); 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: HPEN hPen; HBRUSH hBrush; HFONT hFont; HatchOut *hgo; char *PrintDevice, *PrintDriver, *PrintPort; HDC hDC; }; rlplot/spreadwi.cpp0000755000076400007640000025161010771147661013212 0ustar c71960c71960//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 #include #include #include #include #include //file open flags #include //I/O flags #ifdef _WINDOWS #include //for read/write #else #define O_BINARY 0x0 #include #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, "\n\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 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("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("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("", 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, "" "\n", 3); if(rcCopy.left || rcCopy.top || rcCopy.bottom || rcCopy.right){ add_to_buff((char**)ptr, &cbd, &size, " \n \n", 10); } } else if(type == FF_RLW) { cbd = rlp_strcpy((char*)*ptr, size, "\n\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, " \n ", 11); add_to_buff((char**)ptr, &cbd, &size, etRows[i][j]->text, 0); add_to_buff((char**)ptr, &cbd, &size, "\n \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, "\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, "\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); } rlplot/TheDialog.cpp0000755000076400007640000043030710770733256013236 0ustar c71960c71960//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 #include #include #include #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<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<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@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@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; } } rlplot/README0000755000076400007640000000312610741722217011536 0ustar c71960c71960README for RLPlot, Copyright (c) 2002-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 ------------------------------------------------------------------------------ The current version of RLPlot (Version 1.4) can be compiled using Qt3, Qt4 or Windows. For compilation with Qt see the supplied Makefile declarations section. Further information also concerning the build for Windows can be obtained form the online documentation: http://rlplot.sourceforge.net/Docs/index.html RLPlot for Windows is a native Windows application which is also compatible with Wine. Success! reinhard.lackner@uibk.ac.at Reinhard Lackner Reinhard Lackner Ing. Etzelstr. 19 Inst. f. Zoologie A-6020 Innsbruck Technikerstr. 25 AUSTRIA A-6020 Innsbruck AUSTRIA rlplot/Fileio.cpp0000755000076400007640000034310410756047750012604 0ustar c71960c71960//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 #include #include #include #include #include #include //file open flags #include //I/O flags #ifdef _WINDOWS #include //for read/write #else #define O_BINARY 0x0 #include #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) 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) 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) 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 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 =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; } rlplot/RLPlot.bmp0000755000076400007640000000606610741722217012540 0ustar c71960c71960BM6 6(  ¸†9¿’R¿’R¿’R¿’R¿’R¿’R¾’R¾’R¾’R¾’R¿’R¿’R¿’R¿’R¿’R¾’R¾’R¾’R¾’R¿’R¿’R¿’R¿’R¿’R¾’R¾’Q¾’Q¾’R¿’R¿’R¶‚3̧oìßÔÖ¸ŸÖ¸ŸÕ¸ŸÓ·žÐ¶ÎµÍµÍµÎµÏµÒ¶žÒ¶žÏ´žÌ²žÊ±È¯È¯Ê±Í³ÐµžÒ¶žÑµœÏ´šÍ´™Í´˜Í´˜Î´™Ðµ›Ó·¼ŒJ̧oþþþèØÊϬŒÊªŒÀ§Œµ¤‹°¢‰®¡ˆ®¡ˆ°¢‰µ£Š½¥Œ¾¤Œ¶žŒ«—Š¥’ˆ£ˆ£‘ˆ¦“‰­˜‰¹ ‰¿¤‰º¢„³ ®ž|¬z­{°ž|·¢€Â§†µ†@̧oþþþúûûàÑÀ½ž|©˜z™v‘ŒrŠpŠq’Œr˜Žv£’z§‘{š‡z‹zvƒtsrr‚sr„utŽ|užŠw¨’v n–Še‡`…^†^‘ˆa›f­—q­8̧oþþþúûûðõöÇôIÏÍMÌËKÊÈKÈÇKÉÇKÉÉ]¨‘‚kŒzuRM¶SOµQN³PM²QM³PM³eZ†‹yf†_lŸ:lŸ=kž¸VQWPjLGŠ_€gfµM{¾u{¾u{¾uy½rr»gby^–ḑoþþþúúúíôôÇÑÇ>òÿióÿióÿióÿióÿióÿIÏÙ•°µ¤™}©‚I¤JqXbQŠqJ™xJ¥I©H’‚>t»a„€„€„€„€Àxh‡$y˜Î–˜Î˜m’=›l¤~9̧oþþþèÛÇñôôÝêìXõÿ˜÷ÿ˜÷ÿKôÿ˜÷ÿ˜÷ÿSÙ⤯µ—áÐÀÔ´—Ó²”åÒÀÛÁ¨Îª‰àË·ØÈ´¤Ÿnʃª×¯¡Ó£€Âjª×¯¡Ó£m“?§©‹¬ŽO̧oþþþûûûö÷÷À£lsÒÆtæíjßç1æñ^ËÉX¯”ŒÓ×½ËÊȾ±Ï¬ŽÐ­ŽÐ­ŽÐ­ŽÐ­ŽÐ­ŽÏ­ŽÈªŠ¥¢q—ÎŒ¶Ý½¬Ø°†År¶Ý½¬Ø°o•@•q¦=̧oþþþûûú÷ø÷ðñðÙÒÁÕäåÂÚÜWáê±Íϳ»¬ÅÑÐËÐÎÎÁ´Ñ¯’ѯ’ѯ’ѯ’ѯ’ѯ’ѯ’Ê­Ž©¤uŸÒ”ÁâȶݺŒÈxÁâȶݺq˜C¢™w¨‚?̧oÜÜîäÔ÷ø÷ôôôíïïØÖʧ²TæïºÕÖÈÕÔÏÔÒ»jν¬Ò±–Ò±–Ò±–Ò±–Ò±–Ò±–Ò±–ί“¯©{§ÖœÌèÒÀâÓÌ~ÌèÒÀâÃvH¬ €®…B̧oýüûâϲ÷ø÷ôôóïðïèëê¡æé’ãæ¿ÜÝÒØÖÓÖÓÎɽ×Å­ìÞÓÚ¿¨Ù¼¥ìÞÓâ̺Դšè×ÊæÙ˾¯‡³T‚µ]{²Ug­8~²Y}²Y¥bÌdz¾š]̧oþþþûûúöõòȤlìéâëìëåçæÞãáê€ÏǵÖ×ÕÑÒÏÒŹննննննննѵšÉ±•¿­©¨€¤Q«£…·©‹Ã¯“ͳ˜º‹Ḩoþþþûûú÷ø÷êãÖàѺììëèèçãäâÝÛÖÆ¬ƒ××ÕÑÒÏÒÆºÖ¹¡Ö¹¡Ö¹¡Ö¹¡Ö¹¡Ö¹¡Ö¹¡Ö¹¡Ö¹ Ô¸ŸÍµš¶®Š…©W¸«Å±–жո ½ĶoÜÄžñéÞ÷ø÷ôôóððïÜ͵̰„ãäâÞßÝÚÛÙÖÖÓ¾¢tÓǺؼ¤Ø¼¤Ø¼¤Ø¼¤Ø¼¤Ø¼¤Ø¼¤Ø¼¤Ø¼¤Ö»£Ñ¹Ÿ¸±Ž†ªX¹­’Ç´šÓº¡Ø¼¤¾ŽM̧oú÷󨾕÷ø÷ôôóððïììëÖÃ¥ßÜÓÞßÝÚÛÙ××ÕÉ»£ÕÁ¤îâÙÞǵÜűîâÙåÓÄØ¾¨ëÝÒìßÕØ¾¨âÏ¿äÝн»›‰°aÈͺÒɶԼ¥êÛÏÇ ȩoþþþûûú÷÷öή}íëçììëèèæãäâÅ©zÔ̾××ÕÑÒÏÔÉ¿ÚÀ«ÚÀ«ÚÀ«ÚÀ«ÚÀ«ÚÀ«ÚÀ«ÚÀ«ÚÀ«Ø¿©Ó½¦ƒ¯Vk«;µ³Íº¢Ö¾§ÚÀ«¿P̧oþþþûûú÷ø÷ëåÚàÒ»ììëèèæãäâÜÛÕ̹›××ÕÑÒÏÔÊÀÚ®Ú®Ú®Ú®Ú®Ú®Ú®Ú®Ú®Ú­ØÁ«Ó¿©Î¼¥Ð½¦ÕÀªÚÁ­Ú®¿‘Ŗoá̬êÝÉ÷ø÷ôôóððïáÖÄË®€ããáÞßÝÚÛÙÖÕÓ¼kÓȼÛıÛıÛıÛıÛıÛıÛıÛıÛıÛıÛİÛïٮٯÛïÛİÛı¿’Şoüûúؽ”÷ø÷ôôóððïììëׯªÛÓÄÞßÝÚÛÙ××ÕËÀ¬×ŪðæÝâνà̺ðæÝèØÊÜÆ²íâ×ïãÙÜÆ²æÖÈðæÝâνà̺ðæÝèÙÌÜÆ²íàÕÈ¢ḩoþþþûûú÷ø÷Ñ´‡ã×ÃììëèèæãäâÌ·”Ë·˜××ÕÑÒÏÕÌÂÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´À”U¶‚0̧oʦmÉ¥lÆ f¶„6Å hßfÁd¿›b®w »—^¹–]»“W¾P¾P¾P¾P¾P¾P¾P¾P¾P¾P¾P¾P¾P¾P¾P¾P¾P²z&rlplot/Makefile0000755000076400007640000001047211006633721012314 0ustar c71960c71960# Makefile, Copyright 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 # # 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" # # 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 OBJECTS = moc_QT_Spec.o QT_Spec.o Output.o Utils.o UtilObj.o\ TheDialog.o rlplot.o Fileio.o PropertyDlg.o spreadwi.o\ Export.o PlotObs.o Axes.o ODbuttons.o mfcalc.o rlp_math.o use_gui.o\ reports.o ####### all: make Qt4 make exprlp Qt4: make rlplot QTDIR=$(QT4DIR) MOC=$(QT4MOC) CFLAGS=$(QT4CFLAGS) QTH=$(QT4H) $(MOC4FLAGS) LIBS=$(QT4LIBS) Qt3: make rlplot QTDIR=$(QT3DIR) MOC=$(QT3MOC) CFLAGS=$(QT3CFLAGS) QTH=$(QT3H) $(MOC3FLAGS) LIBS=$(QT3LIBS) rlplot: $(OBJECTS) $(CC) $(LIBS) -o rlplot $(OBJECTS) $(QTLIBS) $(X11LIBS) exprlp: $(GENOBJ) $(CC) -o exprlp $(GENOBJ) clean: rm -f *.o *~ rm -f moc_QT_Spec.cpp rm -f rlplot rm -f exprlp ####### Compile moc_QT_Spec.o: moc_QT_Spec.cpp $(SRCDIR)QT_Spec.h $(CC) $(CFLAGS) -o $@ -c $< moc_QT_Spec.cpp: $(SRCDIR)QT_Spec.h $(MOC) $(SRCDIR)$(QTH) -o moc_QT_Spec.cpp $(MOCFLAGS) mfcalc.o: $(SRCDIR)mfcalc.cpp $(CC) $(CFLAGS) -o $@ -c $< rlp_math.o: $(SRCDIR)rlp_math.cpp $(CC) $(CFLAGS) -o $@ -c $< #$(SRCDIR)mfcalc.cpp: $(SRCDIR)mfcalc.y # bison -l -o $@ $< exprlp.o: $(SRCDIR)exprlp.cpp $(CC) $(CFLAGS) -o $@ -c $< QT_Spec.o: $(SRCDIR)QT_Spec.cpp $(SRCDIR)QT_Spec.h $(SRCDIR)rlplot.h $(SRCDIR)menu.h $(CC) $(CFLAGS) -o $@ -c $< Output.o: $(SRCDIR)Output.cpp $(SRCDIR)rlplot.h $(CC) $(CFLAGS) -o $@ -c $< Utils.o: $(SRCDIR)Utils.cpp $(SRCDIR)rlplot.h $(CC) $(CFLAGS) -o $@ -c $< UtilObj.o: $(SRCDIR)UtilObj.cpp $(SRCDIR)rlplot.h $(CC) $(CFLAGS) -o $@ -c $< TheDialog.o: $(SRCDIR)TheDialog.cpp $(SRCDIR)TheDialog.h $(SRCDIR)rlplot.h $(CC) $(CFLAGS) -o $@ -c $< rlplot.o: $(SRCDIR)rlplot.cpp $(SRCDIR)rlplot.h $(CC) $(CFLAGS) -o $@ -c $< Fileio.o: $(SRCDIR)Fileio.cpp $(SRCDIR)rlplot.h $(CC) $(CFLAGS) -o $@ -c $< PropertyDlg.o: $(SRCDIR)PropertyDlg.cpp $(SRCDIR)rlplot.h $(SRCDIR)TheDialog.h $(CC) $(CFLAGS) -o $@ -c $< spreadwi.o: $(SRCDIR)spreadwi.cpp $(SRCDIR)rlplot.h $(CC) $(CFLAGS) -o $@ -c $< Export.o: $(SRCDIR)Export.cpp $(SRCDIR)rlplot.h $(CC) $(CFLAGS) -o $@ -c $< PlotObs.o: $(SRCDIR)PlotObs.cpp $(SRCDIR)rlplot.h $(CC) $(CFLAGS) -o $@ -c $< ODbuttons.o: $(SRCDIR)ODbuttons.cpp $(SRCDIR)rlplot.h $(CC) $(CFLAGS) -o $@ -c $< Axes.o: $(SRCDIR)Axes.cpp $(SRCDIR)rlplot.h $(CC) $(CFLAGS) -o $@ -c $< no_gui.o: $(SRCDIR)no_gui.cpp $(SRCDIR)rlplot.h $(CC) $(CFLAGS) -o $@ -c $< use_gui.o: $(SRCDIR)use_gui.cpp $(SRCDIR)rlplot.h $(CC) $(CFLAGS) -o $@ -c $< reports.o: $(SRCDIR)reports.cpp $(SRCDIR)TheDialog.h $(SRCDIR)rlplot.h $(CC) $(CFLAGS) -o $@ -c $< rlplot/gpl.txt0000755000076400007640000004313110741722222012175 0ustar c71960c71960 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. rlplot/.kdbgrc.rlplot0000664000076400007640000000036110736143051013420 0ustar c71960c71960[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 rlplot/use_gui.cpp0000755000076400007640000016602310771206355013033 0ustar c71960c71960//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 #include #include 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)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 = 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; } rlplot/Export.cpp0000755000076400007640000010676310757341513012661 0ustar c71960c71960//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 #include #include #include #include #include //file open flags #include //I/O flags #ifdef USE_WIN_SECURE #include //I/O flags #endif #ifdef _WINDOWS #include //for read/write #else #define O_BINARY 0x0 #include #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, "\n" "\n\n", 0); if(defs.svgScript) { add_to_buff(&out_buff, &out_pos, &out_size, "\n\n\n\n", 0); } add_to_buff(&out_buff, &out_pos, &out_size, "\n", 0); return true; } bool ExportSVG::EndPage() { FILE *oFile; add_to_buff(&out_buff, &out_pos, &out_size, "\n\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, " \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*)">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, " \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, "\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, "\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, "\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, "\n", 0); bUseGroupLine = false; } else { if(cp == 2) return oSolidLine(pts); bOutputPending = false; cb_out = rlp_strcpy(output, 20,"", 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, " \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, "\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, " \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, "\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, "\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, "\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, ".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, "\n", 0); } else add_to_buff(&out_buff, &out_pos, &out_size, "\n\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, " \n", 0); Indent(true); } bOutputPending = false; #ifdef USE_WIN_SECURE cb_out = sprintf_s(output, 120, "", 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, " \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, "\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, "\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); } rlplot/menu.h0000755000076400007640000000600311005357106011763 0ustar c71960c71960//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 rlplot/rlplot.spec0000755000076400007640000000331511006662352013044 0ustar c71960c71960Name: rlplot Version: 1.5 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 %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 * Fri May 2 2008 Reinhard Lackner - release 1.5 * Fri Sep 14 2007 Reinhard Lackner - release 1.4 * 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 rlplot/rlplot.cpp0000755000076400007640000113533010770737526012715 0ustar c71960c71960//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 #include #include #include 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; iCommand(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); } rlplot/Axes.cpp0000755000076400007640000021172710756056207012277 0ustar c71960c71960//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 #include #include #include 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); } rlplot/ODbuttons.cpp0000755000076400007640000015405510744617373013324 0ustar c71960c71960//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 #include #include #include #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; } } rlplot/Output.cpp0000755000076400007640000015633210750125435012671 0ustar c71960c71960//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 #include #include #include #include //file open flags #include //I/O flags #ifdef _WINDOWS #include //for read/write #else #define O_BINARY 0x0 #include #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(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(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); } } rlplot/QT_Spec.h0000755000076400007640000002167210771207670012337 0ustar c71960c71960//QT_Spec.h, 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 // #include "rlplot.h" #include "menu.h" #include "TheDialog.h" #include #include #include #if QT_VERSION < 0x040000 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #else #include #endif #define RLP_PORT 4321 //enable clipboard server #ifdef RLP_PORT #include #include #include #include #include #include #include #endif bool ProcMenuEvent(int id, QWidget *parent, anyOutput *OutputClass, GraphObj *BaseObj); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class TxtCurBlink:public QObject { Q_OBJECT public: TxtCurBlink(); void Show(); // void showCopyMark(); protected: void timerEvent(QTimerEvent *); private: bool isVis; int count; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // use sockets for to exchange clipboard data // undefine RLP_PORT to limit clipboard to a single instance 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(); char *GetTXT() {return text_plain; }; bool ok() {return true;}; #ifdef RLP_PORT int Socket() {return sock;}; #endif private: char *text_xml, *text_rlp, *text_plain; #ifdef RLP_PORT pthread_t thread; pthread_attr_t thread_attr; int sock; #endif }; #if QT_VERSION < 0x040000 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class RLPmenu:public QMenuBar { Q_OBJECT public: RLPmenu(QWidget *par, anyOutput *o, GraphObj *g); public slots: void doMenuItem(int id); private: anyOutput *OutputClass; QWidget *parent; GraphObj *BaseObj; }; #else //Qt version >= 4.0 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class RLPaction:public QAction { Q_OBJECT public: RLPaction(QWidget *par, anyOutput *o, GraphObj *g, char *name, int id); ~RLPaction(){;}; public slots: void doMenuItem(); private: int Id; anyOutput *OutputClass; QWidget *parent; GraphObj *BaseObj; }; #endif //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // The Qt widget class implementet for RLPlot class RLPwidget:public QMainWindow { Q_OBJECT public: QScrollBar *HScroll, *VScroll; QPixmap *mempic; QMenuBar *menu_bar; RLPwidget(QWidget *par=0, const char *name=0, anyOutput *o = 0, GraphObj *g = 0); ~RLPwidget(); void openHistoryFile(int idx); public slots: void hScrollEvent(int pos); void vScrollEvent(int pos); void cmNOP(){;}; void cmCopy(){ProcMenuEvent(CM_COPY, this, OutputClass, BaseObj);}; void cmCut(){ProcMenuEvent(CM_CUT, this, OutputClass, BaseObj);}; void cmZoomIn(){ProcMenuEvent(CM_ZOOMIN, this, OutputClass, BaseObj);}; void cmZoomOut(){ProcMenuEvent(CM_ZOOMOUT, this, OutputClass, BaseObj);}; 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 *); void resizeEvent(QResizeEvent *); void closeEvent(QCloseEvent *); void mouseDoubleClickEvent(QMouseEvent *e); void mousePressEvent(QMouseEvent *e); void mouseReleaseEvent(QMouseEvent *e); void mouseMoveEvent(QMouseEvent *e); void keyPressEvent(QKeyEvent *e); void focusInEvent(QFocusEvent *e); private: QWidget *parent; anyOutput *OutputClass; GraphObj *BaseObj; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #if QT_VERSION < 0x040000 class DlgWidget:public QWidget { #else class DlgWidget:public QWidget { #endif Q_OBJECT public: QPixmap *mempic; anyOutput *OutputClass; DlgWidget(QWidget *par=0L, const char *name = 0L, tag_DlgObj *d = 0L, DWORD flags = 0L); ~DlgWidget(); protected: void paintEvent(QPaintEvent *); void mouseDoubleClickEvent(QMouseEvent *e); void mousePressEvent(QMouseEvent *e); void mouseReleaseEvent(QMouseEvent *e); void mouseMoveEvent(QMouseEvent *e); void keyPressEvent(QKeyEvent *e); void focusInEvent(QFocusEvent *e); void focusOutEvent(QFocusEvent *e); void closeEvent(QCloseEvent *e); void timerEvent(QTimerEvent *); private: QWidget *parent; tag_DlgObj *dlg; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class BitMapQT:public anyOutput { public: QMainWindow *widget; QWidget *dlgwidget; HatchOut *hgo; QPixmap *mempic; QImage *image; QPen qPen; QPainter qPainter; QFont qFont; void *ShowObj; //eph_obj void *ShowAnimated; //copy mark BitMapQT(GraphObj *g, QMainWindow *wi, int vr = 98, int hr = 98); BitMapQT(GraphObj *g, QWidget *wi, int vr = 98, int hr = 98); BitMapQT(int w, int h, double hr, double vr); ~BitMapQT(); bool SetLine(LineDEF *lDef); bool SetFill(FillDEF *fill); bool SetTextSpec(TextDEF *set); virtual bool Erase(DWORD Color); virtual bool StartPage() {return true;}; bool CopyBitmap(int x, int y, anyOutput* src, int sx, int sy, int sw, int sh, bool invert); 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); bool oDrawIcon(int type, int x, int y); bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L); bool oPolyline(POINT * pts, int cp, char *nam = 0L); bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L); bool oSolidLine(POINT *p); bool oTextOut(int x, int y, char *txt, int cb); bool oTextOutW(int x, int y, w_char *txt, int cb); bool oPolygon(POINT *pts, int cp, char *nam = 0L); }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class OutputQT:public BitMapQT { public: QScrollBar *HScroll, *VScroll; #if QT_VERSION < 0x040000 RLPmenu *menu; #else QAction *itFil1, *itFil2, *itFil3, *itFil4, *itFil5, *itFil6; QAction *ittStd, *ittDraw, *ittPl, *ittPg, *ittRec, *ittRrec, *ittElly, *ittArr, *ittTxt; #endif OutputQT(GraphObj *g); OutputQT(DlgWidget *wi); ~OutputQT(); bool ActualSize(RECT *rc); void Focus(){if(widget){widget->show(); widget->activateWindow();widget->raise();}}; 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(); void CreateNewWindow(GraphObj *g); private: GraphObj *BaseObj; }; class PrintQT:public anyOutput{ public: HatchOut *hgo; QPrinter *printer; PrintQT(GraphObj *g, char *file); ~PrintQT(); bool ActualSize(RECT *rc); bool SetLine(LineDEF *lDef); bool SetFill(FillDEF *fill); bool SetTextSpec(TextDEF *set); bool StartPage(); bool EndPage(); bool Eject(); bool oGetTextExtent(char *text, int cb, int *width, int *height); bool oGetTextExtentW(w_char *text, int cb, int *width, int *height); bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L); bool oPolyline(POINT * pts, int cp, char *nam = 0L); bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L); bool oSolidLine(POINT *p); bool oTextOut(int x, int y, char *txt, int cb); bool oTextOutW(int x, int y, w_char *txt, int cb); bool oPolygon(POINT *pts, int cp, char *nam = 0L); private: QPen qPen; QFont qFont; QPainter qPainter; #if QT_VERSION >= 0x040000 QMatrix dxf; #else QWMatrix dxf; #endif char *fileName; GraphObj *go; bool bPrinting; }; rlplot/RLPlot-Icons.zip0000755000076400007640000011304510205053312013615 0ustar c71960c71960PK àQH2 RLPlot-Icons/UX ö€BƒBõPKêQH2RLPlot-Icons/.DS_StoreUX ó‚B(ƒBõí—MKÃ@†ßA¢^rõ¶ÀBUÄc(õ «'%DH›" 9æŸx¤ÔIöUbšŠ^¬óÀä)ÉÎÌ–„l€éÜ_µ@go Œ)Š¢(ßq Væ; EQ~ ÅûÁÒ;^÷h¿’Ò–ŽèÜÙpœGût@‡´¥#:wæKËpóaØÙp‡bBÚÒÑ—þ²¢üœÂbýߟ½ÿWåcün¿ÛÁÛ†`Šb­µ—¯ xÿ!Às>ÇKñzå¼¥#:wÖE™/PK‡HPK SI2 __MACOSX/UX ¯Ö B¯Ö BõPK SI2__MACOSX/RLPlot-Icons/UX ¯Ö B¯Ö BõPKêQH2!__MACOSX/RLPlot-Icons/._.DS_StoreUX ó‚B(ƒBõc`cg`bÀ 1N 6b(?YM PK Ž#wRPK´j<2$RLPlot-Icons/rlplot-icon_128x128.pngUX (ƒBS.úAõWeXJÝ]–n®¥»¤sAº;én¤›%¤»»%%D¤•nîî–†Çû13îÜ9ß™3gîTU–AG!Fèr²’êo+ìÿz›?ýËy[e?º8ÿ UþÔÿQ¼nRºnNŽn€ 'ë{ˆÛ'G+s+ÄÒÅÂbéäqwµ€xÚ¸YCÔUíܪÑx‚Þ2ýŸAÃÉÒÍÓÄÅ ãbâlmc&áäèaáâfáÂc { ÈËIŠkzåw ê’è,Ö±Ò?ZzþhܵLVª?X¸Þ<.]ŠËÿ¼ù+ŽŒOñ¬Ã3ÔG )!” D©*(A—µ¯’d/5ëîè?x1F ’xÿ˜kz=:êüÓ·ŸiµÞb5&ÀE«ÊPÛþº |á»{¼€_Á#›†]Æ1"]¥ô#3p)¥5ªtǤ7Ħ6Äâ7õ6²Ú’'ú#iG³´þ7è+h4Ó‡ªªÎåÍ•UœÀ—ÛùÌüqL,ªld¨j}—š øø…(AÇ_»ØÏ\¹ýryªqyêoNRÚñæî·MK9µbÉ5†¿|æø­?käÔouÅ0È £ƒ˜­Â^ŸÁ¯ýwágoSÛY×ë¿¶3€NgÇåhª[ ëýÔŽÂúÚïh‚«¬p ôi˜»'­VލëîÌÁ4½J®àçËí \úÝxŠüÜ|(/—¿½¥­¥‹­©­‹½©Ÿ›©Ÿ¹½›³9 d©S» ªº0»´ÆÇ11=7·²dwprpÜè¦Û:b[:†¡ÞRéßÜì}Ý3RßyƒÊïý/ÇW®~SÃÚaî|Ĺœç¶C|†º J’\[utLAúIJÌâÑYíj?¨ÈÕš<ÛN/úÛ Nc] ßéÈÂ&6˜Îr@WèãJšþêwC¬q£¨tòõ½ä×#<ã:ŧA£ P)GGýÙH‹«Õxn+ÅyH¿1VûÛ·Rb"rRòV<àÃÿ[Þÿep‹w˜]`ònô¶\í9鬃õXáúŠeÂããžòU‚Üó7´Ö$lö‚FÒÕHw»KgIò¾ã†ííŽÀ›\j­ÝBwTÈ@ YÚ)[>SJïŸbBïŒïv¶rº®kÇ—u‘øl˜m7'ÁÕ,ÈUYz¤¼üMa°L.Š)´uZèç«ð/‚†×U• 7ó—õý_'(ÖÖ'w0=¤ÆÓdm÷ËW·X™tÀKåŽÉ—Bïuz¸yWðFµ½ÎÇûÀS—u©´‰è"\ÑpÒ–cßè *ÏæŸòÛ_E–³–ð8„yá”1f)0´µ2œÄ>û?®õi.Is•!–±˜xwŒô½åMͦK %j+Mÿ‰1ªÒ,ŒVà‹ê$œ>÷{Ý®ø ûÿœ…n§z~•/Þ¶RÀËÆ hµÔº˜¦[›?¬Æbÿlƒ˜æ„ÎǦ¿{ÞGÇp!$g-˜QnÁ¥-·®æOh-ŒZÌÒZZÐDbxÂáyÇ3Ôœ¥0PK¢7vYŒçRŠW Yo; ôÊÕ4eþf´Æ`íl¿;©Êc}[5B}DŸÉ*ò*¶×Ìðï¾Q›T XáèÝlµÃ'ÔœÃ`A`7Ô³ß\¿b³ù»³3|6L•Ò[ÈÔ7«æØIi¢î†f]1µ™ká{»cF„êè| CHÔŒ¾*Ó£6vÛ-qR¾êp©ÛôIºÈÜj¢í~ÏqÌ^ÑŸ㔲qdé¨N_`F¸ªþ´š>dš€¸ËCQUm G)+奉<­¿LŒvØéÜ‘ Ä¿¿Ž“³ rfã®gd$j—ç1ÿ~‰'§Yš¸Q*yW£hú†˜³FewA—/èª/+ú{i½ß+÷÷¥¤^ß&ÀÓL1Âüú©ÈRCÞ‰4AëvG+èPÿߎŒƒö££ú£X¹Ÿ¨¦w À,;žÏ¼—®Í¡[ÕÞ:·ÕB«ÃØ AH&­:v”½^«Ò=1ƒ\ò€‰Pq™%ãØ„û—°-áG(zç%¿û4«G/m,ÓyÕkCLˆ¼5ЇŸX ¡VmC=É̵Ö× ó|ö=¸¯:­ÒšŸIeåõ»/5Võ‚‘äD3¶=ýÀœ«º»ÖSwrà7ÓaÄëúÄ Ü7YÆÆÄv(0ªkÌX·Ü¨©~Þêîe»·+,Gƒ”âÍß>–¤Šd-ìúk7³±*f»¨â¾TöŠÊöí–¡¢T}yÈBO.ùÆ3lK;H W[À$¥“]ê$Ëîˆ×ên…H(Ãï"×¢fïé;²SkÇ/G1¾W©)Ʊù€< oh³wâÑ›ŠN6ÐùÊ«¦3mÿAZ¼µ5 œª‹J`çÙùæ±¾àðVvˆ¥h CFŽT¾'!ð‡©c@ü‡SæJ÷Á°Þ?×Ecp\-?¦—|#1Tˆõ.G½`iÌÂ7 Qtñ‰}œõ´÷/†Ôº•¯bÛé¯1 P.œsþœ˜¹渆2‹™îc§|//4eéŠußP¯K—Ÿà½ÙÈ-x@U̧“Û·oh,Ÿ?Ñp– ¥kÕÄÚJEÅNfnó ¼Øy|ùb”Ì"a”Vhd  &R}>QW– ¯kùY' ¥ÓÏÊñPe t •f|eÚ)NæIõsPŠª¡TZK2´ÇIu vGH@Ù–|O-;ãöÒõ™€\4tQEÉy-·^ÑüïÇ;Í.}MS9öSYf[Fû]»£æ{é.;NªTä¸nv‡T‰¶¶ ¬Ök_?ôwiL’rÛ@RÍî*Ä&øAiŸPÔ£í Ý€¥{Âyø[ -Ðâ¹ #©^Üü 2W¹ÆÈòõºš±•.¯‘M ëˆ" ³h!ë[èb8*§®OÄôü°`š›S«Gƒ@d¦*x¤ª1•£æ$ØBËBæ‚™CŽ—ÒøJÞY ¤Áý Ò…ðôçù5@l2qêÖ"í_”¼¯$í Ñï‚ÕñÇéÞi^gT[þ,&("’—ÌiO †°a€CNô±–oe©£êOG)~X/hF-ÁÏn¬Ã+­4{4ïSëyù>ð>\’¼ïß‹§Õèú¹˜ºù¡*)¨Þµ—ÀáðŒ–¡üuQ€X윙ëg}à× J¸ñyŸ„Ö2‚ ².j%'eVû½£‚Cú½¹ºY-­–Ú`xä„.s=±vÅþ”#Üw¿åBPâ< äíáw»'áÔƒB!¬²ýH^³Ð«¿g¨þ¯´ËÅþõ |Ž˜eñ¹Œ®Œž¾”î½øŒ/b8ïtt‚C–¾êŠ-!q(üu-˜xöàÑs uŽŒ ®2 ©®\¡à Kì+ß×w?G—AªÏzªÏ4ZÞÁõ3úy`p;«k™Âöæ%,ìCi¿ÚÇ?êZu<¶ƒó±3à^ʰJ”ØaOÆÌ17È §y­/qÎX9¢mw'eÊy‚ÈàOKÏñdÙð³ù9YyÄù¤dÙü‚nnû-Ö/ ý­¬yÏù»tBvviîºéÆRr—x ±–¥zjy pUãpcT õˆ Ïñ£cA‡*Šã1*JñÊŠÁS˜1q7d'$‹¨„ÄdÀ_ݪN¯ÆNkÆNgb*NÐúGOv‚‚òC<üï©ë‚ê39¸}ñV?D#»M›¥$T½ù¬0šTNq5lvæÈa8ߎ´¤bJ FdS"^.ÄÜD vJÄ5— þCÆuyCŒu!A 6W½HRyLhâV—¨ó+…'U‹Å]„¾+Rbh®1ù«Ãø1Øïêijəó”¥þ1_þäåªßʨÁÕ/v¯¬Œ‡{C.²è]náÕŒÊÁ=ÃÃ~X=}S¡(SQÎ?zÞè:6SNÏ~´ žæ‰c3ñ×úI=Ü×}÷Vœ(ÿ†èvž¯îþ)†‡™ØX°YíöÎ6é|7J¡ðVs¼ FÛàè…^bóÂïÛì)°Î އ÷J ®üÈ×±pî1½ªÉ¼ƒf>í[W } ˉúÛÎô£×zƒ K5ïã„x]¬bkÃÕlÉ½Ú ;À½úi=>©¹“Ókûw¨'ò`Wƒ±¿L]ZZa.„ .$÷9¤€äôdÿô¤i™Ðú®°Ò:à½â×JÛ®ƒg·ÿ8Ž¥²á'rÛšo­®Ä,¯ÈO…¨Ow}*kúÒVÞðªÃ}¹Oµ§}öüýŸ4å±BŠÅ©gHâÆÐ•ò³…\G~kÈЛøŒ‰E€‚úÛ_‰‡¯™@5îÕG×§_ËO™--ƒ¨ô!µy]¥1q)˜h ÿn›nn²F;žÉDüsë`§§†Ñ_ç‚‘d™Êe”§óPæžÎ·T†™™'nYL,A ±Å ½•5Èb/ŸTŸÏšM‰r娬-lˆ“5118xßë.È«êãˆhweq:íP!¦3nìû–µÂB*’·ÞêÂÌð~Õ<Ó Nçcžç¹Çõß\%7 ›½&™îû+YL?$~o——_‘fWWÉp2áåLâ‡邿©>w(ß‘»­àù¶Ûú„˜–‘µ¢‚“‘¾ÓZpH^gÍé*›‚ Ö:3‹Œ·D×lYCïÓ¡åGoϨÓ88âgÇαÞiÔ‘œ'Þ´RF5­~MÍ“$ñßi·“óƒ—T,½_Ý+œ|³Õ‘Ï(*ØÒ_#9‰ÔÕÓÂÒª¬Ðå©y«ˆw½qì¸Ñ=ñ·wCL:g¡…} „ˆHüOº:kÅ=- ñh)m´¹„—ãI&oo‰}°m}}|}I|}³}}õ}EüàT¬ªZÌp«±³Ú¯Ê߆¾¢ƒX"y5Ñú@Tk%u>:†´÷{Þ^ªÍ‡œ·í6´wd6ÝiÓÚ7 h»¥¡e%ý%¿×K at¬qé:¦4© ˜ØCõš‚°gégëjµ x€”+àÿp©Q—/, …òð¿¿só:E¨ñúiâ7Ã-8Õ:q‰f÷èËìÛÆìÓÆìë[éÓ+"â."‚."¢$Òá°ÒA§€YPnÍØØÎnªÓÓûßS‚lš¾¶/©O®¬¬L¯¬­L/¯LÛØœòº»gÇ*UW´¶ÆÕ|9„+Ù)Ð… ÉȰî˳íoog/×=òq¦º®G±uœû„Æði!b•{º‡—Gu»Åräè#†hä71 öú¹ñžÈÔ{V%=âd¦mí¿”}„Ë…¬¾lšõÇ«ŒÇŽ‘“dåfž -"TB…u£‘Ou<ô£X `8„!¿ÕM¾k~dáI;EPðüñµíçðÔ_›³† ÁÖ‘]e$ðŠû$âÓÝS¬‚kƒÁû‚2%ߤVµÙ„¹‰‹íã^W3ñ ù0Ô¥RíàŒN;ßÄþ,ÎZ…㎌ȀoÛëæâ%€œúA¤$?yåÏ ån¹ 6Ãöˆè9O„F™ŠÄ,ô³©m@šf e«§K‘_ƒƒ[‰y¹G] 6Ç|¶ÕËññ„»¬¢óGqsÕ†ªíUU•UÃóG‡ŽÇ ÜžzzBm‹#¹'¥0dü‰<»:ö4EVOØ›²8"~7Hsôbè¿%1K_~dêt üÓN¿ìH›ª"7I—k—ç{bÈAöÆv‰dIÔ$‘7ÿ÷¬ÂT5´V¹r’fV ñm8u ããÌEÝŠ.šv©£¢eT È4 uQÑÏÔ=æÃƒb úâúÅßÕVäf“‰òNó‰,¬òz4\ì;³~z®'WÀ¦*§âüɸ¤wRm\i뤥C¤å$éª6†Ì†lúcÁ˜W'kDÚU¦£×­K©4ÎRCF¡­åëèL–Á"p•‰Hóço;˜ü|e<’1Söæ¶»¦ -gûØ+¿€LsNE³ü#ÕÙˆ ɹ˜Sx ÷9©™²=¦¼4FV<Áºï‹OJ€˜m5 æh†ì@Q×ßeóÞ™‡Bñh^{ŽŽ]+ªx(ÆüŒ‰‰G#B|Þ8ã_í=-N¼îå9ô G+c¼Y§WSqözdÏ•Àf…×3Çn†Ÿ°ò´½|Aë€ãã}ï?ºèèÆ"ï)PÇON…yWDDl²íÈÉjHˆ*É÷¹®=Ü=Gm]Û@Ø“iSó ª˜X®®/ÇÁ2 [|ü8œ66£J•»»Oµ Lôõåô}½õ}Ýõ}•ô}ýí|%ì|‹KšÑµ“Z©m = þNf"™ p¤V£IQh+ ~˜¡°’ é­x4ÿ3™”a'à\ºv´ûÓžf³÷¡°­ŸÓ'9$éËFÅÇÉDÊŸ°<¢A¯/¾ª¯vo¶ÕkŒöBÅK6ÍìÓvÙZþýqÛt~€¯mSY£‘Àý }£¿«ßÒÎ}<Û¨C Óýæ1d÷ï…Û±Q?À•‰RŸ¯–;–E´ñþé;+%äæiÎÍc£¯wÍê–ÖXù—×ÌNß@A¿£)F}W«T2•ˆ)§δ0âèÃl"ÀDY5s¯úó¥´ž!«@);›¤U90ÊÐæ÷dQjO?u:ÕÛuðLe*z–qudæto7œ¿“ÓÔ#§ã‚j´ ž[à¥qalº+¬”ÑѸon=Vþ×nÎÄÄš±±ð££R¬Õa»‡Ò´Í\íJ;IJ ìÃ,•uŒÊðÜ8(G.†<о°U•ÉÛÉ ìðëvóê¾їÙK6álÓ!ÐL¸fèpø§£1Ö‘>Ü›JŠ!Ñ@ðˆ#W£ÍˆůWì9§¿îfî’·ú÷ { ¼^-–m!7ï:mG¶ ¥?X ykk”W'ÖfJœlÙl+¬9-ñyßã±*J1k'¬ÝtÑüeÚA /'Ÿ/ñõ EhçdGx¹PÍ`dH™¾:wJÎ/iÁˆûò ‹7dRc4Y$¬«Ìä9qȼ6ÚuÕœ+1vê¦Ë÷Fk‡­û­:o´Îè˜pg•<93-‰X<Ìyx~£ j NÓW…7K¥S}_ù-—‰Ë Ï—µÖŸ>;€²6–ÊV!;¢€ÆùKõ~͸+ 0 Î¥ôÒ‰d_É¥ŽðVÿ‰y?YÌdëílÎJŽm¬R Øòƒ3ÅÄJT·ÆÙuÕ.*»†Ð/•h×=¨ 6jÐîXN€¬û¸ÁÛåÿ|hÖÉ«*©™´ÉvdRÚH¥ï– @¯eÁ"ª²pwÏzxèÕÔàY’¬(ÞåU+aMi÷ÏC.õŸ|º¡pŠ: «›u¢ÜáÅ©ÔÀËþHÌ:†úNÿ=%°×Q[gÇPû¬ëñçOŒájÛ:Tй&½K‰È #D€+”=VQãñB?AOஉCiü£9üéþßåÎðn÷ îÇti䤠n÷°N— ûŽK÷¬B¾.a˜£Ñ6)Êð– ð‹[§`¡êpÚöÅúæ!“Cuk§azC±9É €{ÊòÏåÎÞtG\'æ6KJÍ/‡ìÝU²úr- ?mtmu"f¦HüÐ26¤õ†Ïï…¸ÒÖµÉÜ ¨Üx2vzLx%ady‡²q®_éï?áb%–þ3ÜñqzbÁk½ôÀ9ðH0ùÝÝ'Šý Zd/dÛµtçƒx*ÍlÉŽ8/Œçêîcôˆj™Sß}MK¬¬r±³Órw×ëlOa© ²šMp%–PÚ^ÖNjˆ¥qx…¯£iJÍY%®øÁ ¥´yUóÖ…fL+ŽÁ›kpÉSM£ôjlGÀJðñ÷ë)ç‘ f|úÆðeÜ!¿[&p:p5žŠŒó¸?ÀÛkSn°bÝ TÆO ~?vz£uعÒ\o¿`:a`Õ ¿<%C´´>ÆÈc׎Záõè2W¾/ûSþ­Šu}XA6I^]±-(.럪|…GV€kaëc,ª,q@¦Œap~­ì€MØ€ã/¹˜7¶ Ðã,Xhšä¦¾„±ûˆ)p¬A²ö×;hC=:n¹sëúòoTzTBNC\±iW*0ÍÔ¯œòÅbÉššÌÌJµ•œÚ̶v(^õ¦EÍÁ 5t–³¸õÙH ÆM”Û°ç¦ÔŒ•#Ž ¬zâÈ$„¢æ8†Šp¬¹,#!_Ð!€o¨g—ÆH~\9Õ@f^SÉÎÞÍM%B£N©wÈ(ýÖ–—JÂvHåqÀ¤=jXÀ)`ÍmТß}£òàäÏF W"‚L¹ðÁ¡çæÙ&Àë?^Ž$sÄO•o8Ƶ”·¦ä®ôACkµ‰v}(5zLªO·N¡Ã¾Q½ó´fäDùHŠU0÷ø‡É;V-™…õO4ÚÝS{ }E¿qíìwlöŠþ¡(Ûs¢Ù»kùö:; "ÖÀš®ÄÒo¡¹%)ýÉ’Umh–ÊÝÃmJk|[ûÛ\»˜k¨xê›ñPÕquMð3hÌÑB?DÅLÕ ðz* [ §EYß +)oOâ9Âw~‡=±¤ÑâÌyªþíg7Á“ÂD”p˜tjÁ\¯ ŒrX—1¼}ø™á“4-Û4Ss„`N9Û'Ÿœ‚wéz1*Œ½7wï8àÒƧÑtMx‹‰³?F~ë‹ê~—ë6ÿûËRó7ºÈL”à8C‘©)£ûIó1ÄÓ⎄ä&ƒÂ‘{—ƒ›Tt½­K[ ¢«{m @%Ÿö½QOù™ˆVRÉ™¨°Å-ék§h›$hê ØVÎç|Pô!¢+%«Å‚…ìÉBËñ“M~•êh“ñ/×=‡qûÕW‘Ÿs®»‚12C”غ/Ýt(é~‚“-»Kt‚i¾ýÑUSúVÎËû?W,Ùˆ•%V‘m‹1D`JéàÍVÈ:#mÐÉw !ã Dᜨ åÍ{C9ª®íãΩ>b`£œ|Š+ÎP$Õk÷ð7‡] „_µ›4ƒµg1á1+dkã0sÿB¡Dü~ E14ßà¢hk³‡x†)z;¤´Q<˜Q"Œ¦´QnÖrÿ½½w~F½¡¦Ì,S¦ó»D§v²ÒÅO%Eòä‚ ÌУêH4AwÜ¡À€ç70¶Ás^V¦aôôµnVú”ŠÒ]TØ'k߇Ãßbv¯ 4„ø²{ôéø(C ï«ÐÔ;$Ñ2Š¡FMØ|µ.²~ìÀ}Ç#4Õˆ2ó~˜ß~ÒmdâU£»ÀD”ª]û§4.9-5Á­ci^˜)°*Ì­´k=ÑþÛˆ"W‡•!ú ol¥‹!Ç+ÓrÏçƒb+‚ŒMÁÇhJ$† ƒÌ¹Û£ÈO@ Hø £“µ` !©‚v¿)Êÿ™óJÂ`Mƒ}Pr‰dûÙÎÿ£’eN·FÇÎTݳBг‚–3x*cf*#Å”» it¶hÁÖÍÔPÑOM"é€ <ã°F®$KW*™ &tÑCã Ë#ÂÍÇK†ÄšT dY×°e½KU'MÕ#NÕÃIÕ{×3÷Åu¶ô#–¸X ¶Â·b½ëÁ0Ý(ô;qð;qÐÌûRåQ66YFfÅqH#˵1û×÷C™¨¿ÄêU1"ÚîЯÑy·ÑÑ<ÉzÉ–±‘T;' ŒdV~²ã€FŽã[ŽÄŽ ¿{’Q‰%BVã‚ê­ŠH“Uã¢]]U•儇‚<0Qß±50Ñ5†£{|MðÕ W{ VEü N­æ¡›G´Cî"÷¡å³“\7ŸNWq•/½6þùÝ,jÜ_—— x @FŒ‘@ø¤OLཪ2²ª{Ž.ªF88Î5Ä`Ù q¦Í^¶àÚ“"¦Ã7p¤0·Q v™Ëúz¥µ/bôvð ;X­[ó#ó¾Só¤[sGBýMQ¸l¡ ±Ð/á ;Ê$Ã-p ‹o€˜¨LcøíøÕ7Q‘)¤ýý•`"ø;H`Õ1€“°üÓS‚!ÂÊ;TíåñjÈú÷*û73—Hˆèå)éÈmý”Ocá»gdG v‰Ú-\Y=ĄݭoÁ¯®•VvT§ët´IÝŒ¥EÅž€¥ékš÷«A€ÚœKk¼Ý8±U!Á! ’å@¿ñ-â’K¨“Á-ò[ÜO„l']úá‘ñLGŠÒ»!rDdç øæZZcãÃkè„àv߯U"÷=öqa7i}Vdþ‘;5…rXÎo7¾¾¯øxÐ8,TúÊ»”ú'ëHìyõ¯¯=’çRÒY}qéþD\@õƒ8Ø~ z¬{H ÷Ãß—Ä{Œ¹êÌ`ߗȇ±#nþþkBÄý¡rìõÎ1®ô;òøG¢xåe¯ufhéÅ1Z¿S]¬Ô†ê?š:Gç‚{'! ßËlY™º™Î¦.Íu2æ\ŒZÇíäæï—1ÏxÖ Gß!DI¸rÑ Ê5‰KتK’Ó»= $䚘V¼'æÞ¿Û£•.&·ýËŸ«'fÕϽØÎë­á¡Ì`—X™–ªäO³`áXFIÇ(Æ¥þ¿‡¡âWÏ_f…aHÉíwmTgõRNu}uôŽÎµ1äe[8¾K׃&úy΄’Žü"¸¬b(YÄSåõY<£@©›X¬XæØOݸMÃîõËØd“ð»kĪu rŸò-®j¸£‘¥¬T™î ôð>¾yébR c¤Û`ùI1¥Ñêi›5&øÅçfYùÍ@¬$aˆøÙ!…]ß#Û—ðýÓÉþ9úª’M9ŠëcJ€>aÙ2éFâFNž«Õ›ζeS̸¬ @ÉÂHŸâÉ6øà.§7Eh<÷¯Œô„Tý» ;¢›(5 —6§!³¹} J?¯Ù†…Pz.„®Ytô Ç»-g0`òqYðü/î,Á€—¿a…˜"·ßæta–DÉ¡túž‹ JÚáÞëë_‹x̯-âØ©tÅŒÀ;žú¡©¦d­u:p+õŽ$½3˜lM,­’ûºÛ.gº.°]#õõjv¤7nô=š½bÿÖ«Rf”y´fßO„¯żz.\·ï%oŒ}ÈyPC<.ÆhîZÏ«ë7]ÄDæoü&lƒ\6\6åÌ·£èø”´þ±qÑÞÇ4þ×÷9žâéVb#ž"2`†í6â²DÜ"ÙÅmß›.Ð‰ìæ ÝÞ§J÷+‰uk 2/«Œÿ ù¦:ȯ×|ÞÔ=Ü1¬b¬…›RÄþRL‚‹> ÛǪBÑ«óÏ©7¾,/›×©‹¼,ÙM°ñOŠá}-{gæ¡èá?…ýXB}Ê(ó4¡{¬-Ûý«‡}̼ÿcŸ} *Õúˆ¨ÊÙMà¡Øyrx_~ClÀ”è¿Ï2Ëk9çñü0xR¶K7–?ÃrõöW\eïCî(H‹^ÖcZÆsýò­–Ïü“Žú;–ØžAte>/›}RŽŸ2Ÿ—¬·òŽFníŸï×ÖMvØ?å8´[ÜnÖÑ>y¡´â7-¿rf't-…Am(žÌŽ¹âæ­È>caè’R¿î•IÑØñã‡}ª[º>&Ï·º½‡ºBî2û6T–¤¡ñ½Ø·žôO[ÊwˆŒ 0j)Ã1Ú€¿ç-cÈÛ÷õ£ùö}g®­ãð®]ˆ÷ã†1КçÕ|Ϧ.äÇ`ÜSxú§è8]‹±ßÚ˜(†gLmÕ›ÿ8´wïÿ2Nä³J÷$°´oEfšïÞ+r8EôŠÅÒÝ9ß_ÍÝMÜ9!"|û9~ÙŠàs¾ÙµÍ<ÔWýe.ûsÅQ<°ýk5Sm¢É5^©‘¬.‰BE<½øVAØŽäó1‚€ÌÌÐ%Îè6Š‹ü¼7­Áê¸iîRÂ3rGV ï`R{ýg(øî©Hi>Úƒ“ßv¼gp>ÞŠEãì”ù˜Àã÷qtù”é»=þ“_ ºå?}™ òdô¤‹ ¾ ¤ð*@Eê¿ÿÀó†4|»1Á¿z³mfeÎÚcC×ß]§Q}ð¯a\qÁHó?ž%M#xIÅÀííãg©ÏÀZR”€Ù;f ÎZ~C—?ûò^=±ç|LnŒ½_g(rú}äÌW€Û#Rª—MÒ+ÏeêÕ™çŒxø: dù{ Õ$~×Óå!Ћ贉-4/ L‡á·@yÌS60g`ºêöÛÑí·ƒuûŽô]jÞ?NÍæïìPQrcôé<£á¬[¾®‡ŸkGˆpkü¤—a¿HÞà™ºÓ¶oJû-äÞ1°tW³8Æl0ì ¸êZ¦Æ’Ý$¾Š@<å4ZÄ}¡‡P—=9³¢ÖÅŒA±kƸÿ-kv{öçgœ¸Ô'½ÙßNü/pç.áK©ëŒ~Í~`‹ÉëN\àRîy#É™Ž)‹ñvGàèÆòÞàê‘åÐ ³d7‰Ñc‡7Ç9kvBÓ1ÕªKŒ÷4üc)ɺç¦ù¯~›ÀDØ·tG¥xÞ& Ï(¿e¼gOÌ'€k+Nê¦0IÒÃ\BŒ>Žê,×3äÚ€­…!?ç`ÁŒ÷|Û¯©*:ž "Éí}=À¹‰#yÁ\ö%½‰€a.#ǨÏÚyîîYÆVý#‘¼Ž`¯PLøNšk²ÇÏœ §6Ó×e¿áæÉäk0Y+źÿ0A‘Ži vÊåj"½AQž‹ ôäKàßü?ãÍhÊAö/_Eñ[Ó`Ó{ì úg©…í%úû´»ÅÓ|" NèÅÌ…¡ óýÚu'¤l¾»)·oÍ=ÖgMÄ#™Þ1™ÞäM4ýçhÄÄ7,gù[áÐL—5–Å í ä¦ìPŽûÙ’£ôd6#ÅVFO’äמ]O „vWþ}‘¥‰[Rª5ÏHÿqôÇú 2ö©¥Õí2c`ú÷]Ç‘’÷˜WqÂ{ÄÏí2Ǩ«¡é MC ež”Géæõ…Y§¡ñ¼V¤5ŒQj|f;ý¯¸//ÛÓeþÕ`ìõ(tŸ5žM‰ÛýѼŒøösýŽÈ%¿¥v9 _ܦ>¨—o¯ = Å…î—%O0†JK`$˜ÝòúJ ¢Òƒ¨¿ }w¤4A÷X§¤¬–m`Æç».zM忯°~©¸Ü+²1`Ã3ŸrÜ¢ðžd} Ÿ×ñ¬…ÿÝA>´H8æËüþäwÄÈ,øz4§eN%è2ñbøQ›þÙù2sº/Hûršh¿£ð´¹@É1Q_Ø´ÑÇDô‚Òþ–Öñ–öìœòìœî»‡˜ŽD¼£Õ”AoÊ^Þ ޝßê¬äˆ`Žš€ëß¾d7]vÁhc>i¯¨KÜâaÜÂaäÚ¦Äâ¦Â±‚wð¤E¹!øø¶òQze[Íx8]—uÎ?E´= ¶ÊÛžî’ò?ð™Ç\¯6Œw’œ¯"bÀO0+zgþ[l»žµˆ9{$Ä9ßH«nì¡X ·÷DY;ÅïèÃmƒ#uH9y™Q•¿ÂàCµúMíäþcvq}·k¸ßä÷Ý 1iÕ,kðžƒÎÝÕþÏg’õzÿô¸AFLcRþørP{‘çCô¶Ï[l™LvL þø‚ÞÕóHºÉ¿Îô‡«] Åx{Ò¿yw©€ £0_PæØ-þ~õ1“ݤ ja¸™[ŒVÜ?¡)À¦ŸI¬îùÎØöþýÏhõ»ÓãÖ**•Š•c䦽TY@ vGøX«8€kÍåeª©é +üLì@ Íÿ"J¹¥‚r?Bo™îtœl *© fð ±ö…«x1´)ùq]æ‰é0NÄÀ~¶íӜ׮éäœm~ÎmO²m Š|ÄIQÔÒ®r¯©Ü¦3¯Øº?Õì?£‘GàfÈ …}´Ü vYz #ïcXÙWÀjIçëF¿>îù0½y€àUüpÿ¹öå•À¾„øv‚A'gÛ3§üæ-|rFé1fé°º:p‰/(ñ+âü1غ|Ù"qÎVVǾLÕu-yöï÷ä£(€Hñ•*ô…Òˆ âP ÂütºO¯á=ï³GéuÂøj-?·…ç'=°Õ¡ÖíªÖ.1#ÁµçÈdœ:ñìöï‹Ó®¬v0RaØñEü Iij R $Ô!Ň!%€KQé™´5‚·ÕìŠ5øíWèÊÞ9‰W“ßaý­_¼ïŒŽá~GÀ]GPIGOC퇭¡¿;ÒÐ)¾¿uP@d{>Dc( =j±c¼Üb䆜Êc0à 8ßµ.[~©LìFÇ6Xû>e[ÅÊèéxT>@Ñ_™?¿•ÐEòäõâ1Å•Â!÷¤‰  IIkDÅáhtfù󛘎¬ àÅë°pòî2Õn^4¾¼Öß´ rŒIH&¿F0hÏÛvE„R^5tÿ+;nÄÚü‡´heý—4OüOàH#Øí„Þreh/4Pôvª©ŒPÛ ÀBèËv•®-X”ú³ ÃéÝïe/ೌõïtÇ83AOkõ…žzÆó¯ã¹N`ú2Dx1„ú0Ÿ›?½ ÜñéNÜåêªÈY+7 ŒGq$ì­ô÷4“m”äª]³s‹„¦t”ÄÔV,ä'_þ¥5^ ß }½¼µÂ}óe,\Šþwž4hNâŸ#Š„¤9sŠ6s©€11ì&À¶Æ®´§¿›7•ô1ZÃÈ.#„·É̶â…pEAq^Ù »Ö»ÒìO”"zê¨ÃÄ ˜"Ù–MÔ)u\ÁíÌaxq?âiøÅ°ÉŠöŽéÖêa³ùxW÷:üãß“ªö ¬¤Œqzú.0iú­³\ÑúàGݤè[ÿдJsIµ }43òV¹ýÆßQÜeåuܦvxæð?ªFùKæøsO“çšG+ûDoy"BKr&N mLάn'X¬WHÔ·Ì•~'ˆM†uûŸy¦ÕÃ,Ë„²«1­ŸÜ&WäÆ×?b+OÒ¤V2gmÄÉw× ×Ù« -qñʵ÷cˆb?:/.ý!þs+Þ715ª,LEêgJ W§LIS†ÔªÁ=-À;ˆ<ìñËå%-vŒ©W¤ròï9¼ç©wáJúä¶È÷ÏΑˆƒ~$z­ŸÒผ -ÿŠ£ ² Hâ |òy7üãOZv€ÇÅ«õS¬ímBO´Y\’½/ ç”uþȃ’5ìAGÑ c‹GΈkyŽó—‰Ñ* v€?¬ëäâ®ñ‘žñJ.ý´m¸ÍŽàU¡öîlÑdKÿ'ê¾'(Û V¤ƒ .?Çû\\ƒä”ð-;h»ïF¦’®—ùGÿpÚP¬_‰|M 3͆ËÐG—޲E+ì–µ—ê~6¾gµÆÇÀã+±mÍMîñ±€žŸ°‡ê}Évѱð„uó ä5€¼<„–'!‡Xvó‡È·¶Î)ÿN™Ç…tøüÓ¡µï ?ž]Géó+ «ÁjTöm¼?ì‘qJ_Àç™çG!y@ÂqãvþßoôÇÊ]þqmôsŠêަºK’šg¸öÑØ¿—Îê?ñuÛUÔÔ–6·w{džÕƉžX7zÄP{fˆ"ýxðÖ€ôëÑÎÁ´^wÓ’6:sošonäE¼.èº%¨Úp&Ylù¤Š?4÷åR“r°¾ dD¬ÉÛ“±ºWÍX5£Ú+kÝbpÔb;&Vðˆ¤m›†ïƱC‰e ÆF–ùàîw–xA]>RÉdwà§á{ÜLDÈ‚³ðå‘ÿ|6Å…+Þõʾô€×Äbš(§…û˜§V˜§Fq{g¹@½[Äç8Û´X[d;¸'$[dXG¸1·èôÒ\O‘wæPõ( žÑø¼S•ÛRT‘òŠšwy¸‘*²u´˜[›ÆåfFÅŒ¦X“%j%þÑó¨pigÑÀñí´Û)Vž‰„|C1Ð”Æ Î/C– L™>VgÅ)q‘óK§‰fµîÍ~mpOÿQºø}%uèvðfÄL0R‹€P -Šœ<ªå%ˆèàSD‘z `r—°Õ.çæDµ-võ¡ɘ<¡C¾(„Ãè}_<ΙŠRÉàƒœ~CjÖœLì±w2€Íߨ1#Î>>„´hù¤ÄÙ„8x¤âè(´à'GÀ‹µ´!Þ -¸I¥/ÃpëÁkë(þê¯Ä Ф ”nkbIYŒÒ„ÉéÂLqÅÏX8Ýï߿ޟrç¡ò,Dö6ÒÓ.âlÅc†_\Kð/R²œ@!bOÔø>7Xq„V1M´´ójºqÜ5\pšÐ¾ìÜ­tÌu›`õ뚪;!sm<ç-W öL„²‰Ík5%7i-·VJ½òxüm™ ‹Äåãˆíç4FZš ’‘mðïÁ›I ƒHàu(€xúUdl,à…è &úfŒ D#*3ˆ©‚%IS*CY¬»0ù-ÇZ›MÒÔƒ[>ª‰*²É^Ý‹…‹…‰;Gƒ ¿ìc@°B`OHi!:âŠÎHœ41¤8ÊȱEáE[ß¿qP±çP!Åã~á¤Ýˆ\0‘k)d±Abæc`\b§œÏ<Äjî¿08ødE¼”8äR@³ˆ ‘UÔ0\˜Ê*Ö‘¶ÛªÈ5”Ñ LÍ+_› ¬Åfîf2\ZZÜ»Zˆû¹×phê²vÜ71TCÖåûÿ  úöð,.»›Õ€•ÔaÅFlf%VTŠÍÐcÒÔ±©2tJN OœÉD²R"’xáIÜðÄä° Êd#3ÈBð*DF$ñ#“R"“R£Ùé1œLtrV,7Õaxr,Oå*0†-Å$fÇÆgÆÒ…h2?†IŒBÇGFÓ#£hÔðp2BX),ü …ˆ‘‘1q‘`-LBžMæGÓ…Ññ™Ñ ÙQ¬Ü(Ž,Š«Dråaɲ`NN ;Ë?I䛘ᕠð`¦¸1xn ®K\²KÇ…Î8ÓYN40-¯º2’]\·x¾G‚À3QèÍùq²yy!©ê°´ÂpaqdF¹ßp,£ó$i;!·•ÛBÌi$f׳kˆ’J¢¤Œ *$dhðé ¼0+ÈÁ¦faø™±ü 4/Í¢¹i1ɩ׀Ñ.@ËKÇðD,_‚MÉÆ¥äâSeøT%A ! ˆiZˆÔ|"_MàÊ ì\|b>>OOÃQS°Äd ž…Á%Åbb1Lt, šŽ_´0“b@$–ÀÆ9J –ž†‰a³°ì\àËWcR 0m¬@‹N-ˆNÕDðá|Y/7˜›˜,ñg‹üؾ,¡O’Ð;)Í+Ià•HõJHY ^’$¯ú°„¾ìt?ŽÈ?YÀÍâKCRåaudza´¨4F\+1 ªVû"·ÅºÇŽÓäfŠÌD‘µSòZ)y-i%·ž’[KÉ®¤d(’"²XKÎÔD*R†œ˜žGJ iÙ0Yx@‚O/æY`ùµ€LLË%¥ËHéJr†šœ¡!gè(¢"ª¨˜**¡fCõ–’¢&sedŽ”ÄÊ&%ЉŒtb\šAáÈ.þF<èU$ ÄÇ ‰ ™Ä¤,"GJäʉ)j¢@Kê‰éÅ„ @ >£Ù±éÚ˜4MTš*B  ÈCS¤!üÜ`^v/ È“râ€äÀ<´„'A‚SrBR¤aYxš"BJŸ#ÒcÄŒ¤—]ƒÏ© ×ø*CD@ïÄI¦ªsáÁË 3Cab(Úò†¼‰!k`äÕÅI«ãrËãrËârŠéY…tIM’Okhb€š©¤f*n†  ‰Õpp>]\@—èè’¢¸¬Ò¸,#»œ‘U¹€¤‚!60D¥qéEqi:zª†ž¢¢ód´d)CMÊ¢%I¨‰bjB&ŒèÚÌ"ÅP ˆñœ\WFã+i©šPGK/¢‹Ji™š¤‚*©¤fUR²*É’rppãÅ%¸L=6S+*@gh¢34Qéª(¡)”G¤É"Òä7"‹*€èt5ˆG‹òc3µ±')Ågˆ9ÕdiEÚ@•5EˆêÖþ2ÏÉÓ,%QݵèáûðsüÛ•­IÊ–DEc¢¢>A^› ¯NU0ó Li)3·˜™£gæÆçèÈ.€ÑÂÄçh‘å Ž,bæ3sÁŠ`õŠiU‚Ô˜˜W“˜W›”W—¦ÒšÄœêÄìªDIy¢¸,AT”¡g µL&>EŸ¢ˆçÉâyrn€Á•!ÄCä-¼HQ0SUÌTu|Z3½)*fŠË˜’rfv3×È”Ö2¥u̼ºø¼Ú8i -·šš[IÉ)'gHÙ¥¤¬bB–ž )ÄKt8±/ÖâÄØÌ|lfÁ5òñ ˵ /)$HŠˆÙ%Äì2RN9EZEË«‰“×ÇÉŠæxE+ZÒ¸Æ×Ùvžài»}ùP×/3ùÉùædM{²¦£iᨛ8ªFŽªž­¬e+kØŠj¶¢Š%¯dË+Øòr–Ü€p} x•Ul(²’­+Öp”ue=GÙÀQ6%«š!ÀŒИ,¯O–Õr¤FNn'»‚“UΗ°ÅÅl‘ž-*¼+C·˜Å/±EE žVÉ2°³+Ø È&«eËêÙŠF¶¢‰­l°”ÍIÐŽÕÀ”×ÇËëòZ†¬&NVEÏ«ÐòÊa Té×—À¯V@Á²ª8¹‘!¯‰WÔ2•õ ÊÆDUK’º-IÝÎÖ˜p9-«}¡óèìٔžet/}`'~𶉝mç´ñ Z GlC4ñò¹šž¦þ:\MWS ¦7.l‘< XKVlæç·òóÛøù § šjm)`ªn᫚ùÊ&¾¼ž'¯ãÉjù²ž´"·’—Sñ Ù†/1 2ÏÈË«ëòäµ±äwéâWÛЯ¹­•7a'¨û?þƒüÿÿljd<IEND®B`‚PKŽ•–H…I€IPK´j<2/__MACOSX/RLPlot-Icons/._rlplot-icon_128x128.pngUX (ƒBS.úAõc`cg`bÀ 1N 6b(?$àçžæîí¡JPKé4R§$RPKÖj<2"RLPlot-Icons/rlplot-icon_32x32.pngUX ’‚B”.úAõ… zö‰PNG  IHDR üí£ pHYsgŸÒR6tEXtComment© 01-2005 M.Bongard - free for use with RLPlot­ 5tEXtSoftwareGraphicConverter5]HîÐIDATxœ”–yL›çÇi¤VÚ¦I›*mÓ´?ÒmZÛIÛÚ5Šr‡’t(„£B !Áœ¶cs0—¹ ÄÆ`ƒ1 ¾ƒ Æ>À7gÀp¸!&Hâ½â‚ÒLªô‘õõóXïGïïû¾Öãð‚õ”${Ò"k–DàG.æ°¢ðˆ†¡0ìà£zÞùÔÎàšþ ê>¿Š~Ï2îÏåošpõ·oßîÿw?Ÿ1>¤_X][[2›¦…ʦgT«×+Uã™–!šù¹øVòm‚ƒÃו xe±lnm‚¶ý°zjæÅìÄÔ$  ðGÛ„ú™¥-ŽÂÈ–ÍAj0ÓF¦õÆõ‰…M ˆuK§we¶]íÜzT“Ø& Èæ%3+vÁ°n>«st~aáX Öêb±bu÷ðÔÿ¡kxŠ:4Õ)˜  Ù¾‹ÞhÞ™M.®ö«æì#ÒNM×÷ÉŽGÄ—j:“¢C0Ù>h óÔÍŠÎX_Û1h[¿W~J°·¿ŸÑ©X^]· d!W¦9ð$švþä‡ ó -õ}jöÕöØ2:³‰-'quÀºgÙ‘àÕþA÷LÍC:õô {„~ qP;aÜ`Šf»…Ó@V/¶r ª™Uí‹5 ð”Æ±S}?'´«€-³$ªærj%/² pÃÓ³/·í¦|:§KÜÁI:]R—-R ‚Яkè/éîõoËCwôÕ1DlÛïÝK¸g:Ð-¬°Çm,H75“M9{DÕØ§ûIð}º†^MS^ØÉò#ç–¶÷Vw ±¬1|¯Ö­˜ó£`gw/Ž(6¾\[][]Z^œ_˜ÍjbŠ”Z½ô UX–ö'©cŽWuKÊ:xY­d/",—Ð^Dî© aèò;El›àðõšÒønD›+«æ—KK è™ižÎ RëÔ‰¢C¨WÏ®µò&›&€À–ë©Þ<:±”OåúÐaAL„/ z©#2€–@ËxÔ\JÉ‚êŽFô|hZcÚ@°¹.ÕÊh¤Í%–­ÑŠUe ¶ŸÂQTw«Þ§‚ª€’©Ïu$•Y6dägÊ*ŽÃlJžâ”Ûy¦ƒ­í­AÕÄ¢I;=)X™÷SÊ»)ýô±q¡bl”1¨@SÇß§¤CšL$WªÄÆAö +MŒ:·0 ©µM7­'‚C@°¿Gà¨×—’–_Äl/}- ®¤úëÕ(é(§›+.¡(K:ÆÎ¢,l'45£5œV—æǪ§ UØëð–hÊl±l¯­ÌXwý­û·ã`œðÆR‰5Ll¾†¡©¤©ùªÅÖÁ©‚6EÏèClˆo fKK©ú6‚º1FunV<)"“³ŽŽ@±ÜÈš†%.¶“-Ì¿ZQ\{1ý¬@4.²îܰ¾Š>̈́҅ÙU•QKtA]aDÿ„âB¯G® ¥®iµ.°æ;pò :´?)Kc'ûk~Ô5péyöäE‘e£iÙ¤´î\°îøŸfBáœ\Zø»àu®÷±¾>½7na½îc=ýœ¿9Rx.2ˑ̅â€#ûAƒ} w«¶ 7w…¶§h¼ÝúÒº}û4ŒÇ_?v?íeNªe˜²Ãj0ÃCì·>¿ Ìü8zø°7.ŠÒ{—öðNwð'Ç…f;DÔ8Ä¥ö© ÒÉ/W¿¶nÿýÍÆ?WõŽ‹Ê[Õm×ÿü_ÒrrÔV;Ú°ê·VÛÀ#ŸÝôüS@ê§Qàïh!ÌH;¾Œð_¦‡ý",÷\æL™psêß&¹ÇæôåE¥û¼Äà9åæç!PGÿ$StàZ5ÄÎj1(ÙÑóóÀÔó1`wFXxo¼à>~“öiò“èÚW·H—€íÌ]Y=MÕñbXºûƒ”yg3<âXøRRÔÉëBpÚ?â¡>=1ORìDõƒþÿË“ÂßÆÕœ*jx†ãö–œ6§Ÿ¦µÛéV4, <ëzÓãeŠõ6ÅÞ[s7»À¿óvz ½œ˜ñ€ý ‡Ùq¡ŸåD^H,þcüs‡«H6ð¼h&åÁŠË®)ã4ŒÛOá# s>΋‰vLq¾HgŸï£3n§e… $ç çÙIÀ¿Èv—ý„sˆk}×Á¦yqìÍÖ½ƒ Ôiè=ÿù!%7>.ÓäaFDÚY†„–¸ùúÇÃïfdÇð Åâ;9B俊bîÂ*¿HÆÛÿMöv·C"¹ÒeTæ.–º‰Än"‰›Dâ†m ŠE”'CP,÷{Loú]/š»'ÝÝ‹îî™. É+»Òw½!î.ö*6à .Ú©R€ý Òò£€?>—Žã@0䔲ZªüYaiBa…N)Á@Ðh9 ’_—)JLÊà DDRrNrzIj!.Ý_Š/¬~˜_œ[œWŠ,(®O¨é¸ë8GAE‰j“¢Hü""³ © ÙØ „BÕÌA¹(«°¦‰nF–å„‚Š–LG¾¯€ÈËibÃðôt\'Kb;Òq]YM=y$cÓ&мXkèÕ¡Åõ¨–©À2åGA‰c©l0”8š Û-ÅRÅ6€@—ã˜cÀÖsæxCYËcލe(ê™cص+jÀár^ï=4ï=¸§ø[^GØ·¾A°þÿÿTÐÕj—:IEND®B`‚PK¡´eŠ … PKÖj<2-__MACOSX/RLPlot-Icons/._rlplot-icon_32x32.pngUX ’‚B”.úAõc`cg`bÀ 1N 6b(?$àçžæîí¡JPKé4R§$RPKÆj<2"RLPlot-Icons/rlplot-icon_64x64.pngUX ’‚Bt.úAõ^¡å‰PNG  IHDR@@% æ‰ pHYsgŸÒR6tEXtComment© 01-2005 M.Bongard - free for use with RLPlot­ 5tEXtSoftwareGraphicConverter5]Hî©IDATxœÔšT[×ýÇIÒ‘¤Ùnâ8Mš¤uÚ&i=;{:ÓicŒ›e0Æì½‡„’Cˆ)ÄÔ 4 ÄKB!!!±÷Þ`㑘ÿ"0–“üÏé9å|x羯~ïè~ôÞ½÷i˜˜\)øßüתÆûÆ—zÇ»Gçu#óÚáYÍдz`ªN5ü6ŒOªQ·ëFÚº†Z5’ÎþeOSGwƒ¼«N¦vÀU½È5+*›Ú… ²òúV~„\©Îjþ ¤óT›}K·oßþñÇoݺuãæÍë7®_[»Ækë?Èú+Ÿž››ž™™˜š›˜–iº?C—í÷+ίi´Z•Z­P)å Y»\ é-mîû/@¯Õ 4tµô.,-Í/,Ü- íì£5ÈÕZm·n·@K/¯©ï¿­æ.›·nõN.V¯®.¯¬,îèÕ þÁžþ¾îÞž]M2eß”¼GOmÇHIS/ J>dHe’~Cؤ3$’® CØ*ÛóXtÀ6¨FÁnrt‡ÀÜÊÚwØêÃQü{ T)ú^ ãP÷*:¾‰ãÿ3‚3·¼6»¤§½gšÛØ hV€ uÀêF ÉÐÔ²!l•mÛ¨›Y¼¡H>d5Cs`·wlñŽÀôâµCÑeß%× Ï.ï)€)W<ìNw%ˆû‡†ïhU¨Þ)y Ê)KÊš»¹ =ÿ8±¶¸Û€aW϶²‚*ípýdÕvo»è ]ôÍÖØ% ìTû«[ÛÛÁà7m{¾_[Üê×÷l™uZF]£Vmf½Îðû§bªHkl&gæ÷Ä]OF»{óõÏôë`Öé)®Ó×vÕtÒjT…U´j%½¦³¸VS 46 ÅäÊ.c KËIÕ›PÞôìÜžUmê/ãʃ(õ»Jt†§ù¥0µº¢Z-½F]X¥¤ŠääŠV¢@BªR*Û ª@£¨œc£žTqo…å•7 ¼Ã0~[ÏØžgÓþÞæI¨½û pÅàõëþÕèèµZZ¦ JùV±ãÁ¢óéçÿJ?ïÏÉÎ/o$ [©¢ŽÂj5¨)ªÕ?Ahô 0¥}³ K‹÷X8MD‘üîipêµ +¿z¶°ô¾“\©Hàó9Y/ÓÎE³¨X/«´6¯¼™T!§ŠT T‚ú|f·ÀøÂêàô¢‘u whtÏAlÊÛi•-½à~dXOb„V­TÈ €%î1„Ò® C¢è6$…UZÍÐŒj`¢­g¨¤©=†SôšAP)5U+djuau;¹RYP¥nìJµ“;:†ç^dûÓe÷àµvƒ;ŸÂzÕž 2Å!ç0„Ó3 î¦ôÔ*F@ŸÂÖAC`Ö÷B‰f€)߈ºÔƒÓÊþ Y÷ §Qæÿ…f™W&,“6ˆäR±ª³@$'UtPEêÕ8P²] A7¹Ï—ËW]¿±÷4 cÉv£6ƒsp·@[‡ê_ÎWèÒ©ŒQ«ܯ€"ê7‚¤ Un¹ÏkŒf½J³Ä󰌲T–(³DœSÖJv€ª¨ ÔgóÕw–®Þ`ˇ¬áÅRV³ö^ë8vCÛÆ(ªýø5*4Ä 5A¨Ì)oËä5ÂXt½@Q©AW"Îæ·æ :ˆ`h@=žßyÿu`hbÖÈ: ìÒÕ´ªv bZ•†(ü5ÀM²¼üY|Y·ÊÔ $•&—%3+Ó9õøRin™ÔêqÆo§WVW!̶7#y[“zñ-:¹æõŽ)F°K P¤!~ù5 ·L•ÃïÀ—Êq%-©ì:Hqˆ£q輤bA «&Û„/•åð 2¯¼3½DyOñù¥¯E dU*˜ž˜œîgˆÛŸò¦ŸIv¨5m×vj¥:¯üÑ™[Ö™]¦Üèzk§9…U‡)†Ò‰¯Z"( $•WX’X$À2kÒ8¸)¨Ìæw¤p&W¨{ ,®¬zS%ý³?Ù©éÉñ‰Ñѱ¡á‘þÁîú¶Žhz¶»«K§QwiTêÎ-JEgÿ—/Uàxm©œ–dV=¦XOç#©l þåB‹È<4Ÿ#Òf­4±¨ˬMe7g”´aX²ÝàýÀ]³ÐâüÂüÌìôäÔøØøðÈHßÀ ¶¯¯³§G©ëViu`tvvu*Õ*ƒ@[»œY§+¨ÒVʬÒNXq ‡¯6„äÊɧJKªP§sÛìJ›bÌÚªqŽ ;C†|Cöß_xúûüSù¡¦Ä°3äÈs”(»‚8tAi*»6§LšQÈw–®^?•Z‹*U×ÏÔäÔèÊlàøÐ÷Ãÿ¹:ýýäªK+Ótµwj¥R­T¨:bŠê>„ón¯oþÉtSxž PÓ>òS¶:m ¯ÚíÆçRدbÊÛ<‡KbØÕAŠNïJ^.°ˆÊ§ Z›†gú'ÆLœ‰›-ý3oBù`›\XÝX‹ só³`¢Õµ@ÅáxIëK¤ôêŠÁÚ¥V·tjd*µB¡TØá„ aR„ùeÊ îÏ%«HaË0Œ7ZÞ•¸f¦c‹òþò7Øçw%¦šà²!y4µ4†ZmâLØ™[Å×èvM£++Ë óssSÓÓ#ô:I,«¢¿Wt~§²R¥¬R©êTÍÊNY»²Í)SP/•K(¯LçüL:RÙíX¦$ž^s…Šw¬‡¶5mÁѱþÁ²Ú•¼D5÷LN Á£IlYhr9÷ÞëÀêêòòâÂÂÌììøädÿèˆz OÚ£«KÑ^ªh/ëPTvtÔu(›ÒöÐû6™\–S ºõ³Ha+’Ym‰Œ¦ØB‘9á.R:"Þ‚ÙÅøËrWòå¬kB’zNd~„À¿§ÀÕkWÁË?65ež*ìÐuª‡Z{»ë»ÔB  l/lkeȤ,bi‘[YÞ^-oo+ZdrIk›4‹ºõ³À²I̶ø¢FUèHL·¯ oªÞ‚®)ü;ËrWò"ù¬3:Á;ž]žÇ3¹œ}««í½#¯…Ÿˆev õ·ôèjÔª2…œd’ܦFŠˆ{Ä!Æ-5K*-im´Êj¤2±T֔ɕ%1Û“íIL…q0 y"C†¦‰áär{BªMMhm¿` j'ùïL‹] pBÅybqÁxjX×ärÖn›7o¬]_»zuÙ Wy1«üÆÜß~Xx퇅ƒ·æÿrsîÕ³¯³/_Ÿyy çÏ#} ÂWeRrKKi‹´J"­ÏàH‹Á…:×nœ„by|Q+ªP #•Ùå§\¨®èåmAPæÿi±+Ž´{Rz`&98›s/k«+ ³³c3SÝëËûׯ¥ì`é¡õk‰;“gšpõõtq#])¬jø-=eÒBEW\‘]¦.“—!¤Õvó%%ÍÝ‘J(³ÍK±”h[àÛñ¯1ÏíJ^$qˆ‰ ÏÎJf±Ò¹•&Nøí3ç2j——VWææ‡'Ç”ëËÖ×rwÖp;“}µU‰e¼÷ÃÒ^ΑªuÍT;N¯í‰¥ËÄJ­T7eËî0„|É D;Ѩæ5«"óù6¹)æ•~ Máiméçv%@à"<FÈÍò(¢ÚbÝä<‹| %«ú<3?;0>"[_~~} ¿½@êÎd_eyìg¡È£I‚*.–^ƒ,hBJ‘4’Ö¶I¡ìw’VDA ŒTž[j“lVáCU‘ D6¡]j#^*6 iDeÈ3 !¦5ùO¤3öѨ+ ©>i$¿Löw‘Bbcï××Ö€ÀôìtïèPËÎK(dýª·^àªûúµ¨í— 4Æ'’Äb¦@„ 4ÄHb d1­c ÙV§6C‰5a9¥ç³±¦B/‚"×ÀG<Ç#\;a C×’ì`(çøTï4’/޵CàÚõ›úY,×V–—¦ÀlZ_~nýZü&+¬/¿¼ÉªÙ|é>7º´$UTI¬¯c%P*à$q4¥%š*ÕC‘ÂÉ-pr3œÔ¤‡ÜM‘l>D•ÀÈMBuH6ï|ö?,y¦Íh `…º—â•JôÎ`î? ,oè†õW÷aéiVÂI®æ×Õ0âÉ¡.ŠÔ #·è!6ÁbX~,¿vƒ:¡!ŠÔ  ä–(Rcd^U0žk…Oú®Ü-­5ÍQH `…¼„NñH!z¥˜} ëËÏ®¯FÞ‡¥§xìh.;¹BW[]Œ&–Cój „(¡JCsk Ù"(^•Y€f !9U¼ºÈü†HBc$Až# ÊäXeb¾-sI’$!B .@‘ޱÉîÉD4†1•ü_!80@×WïÃÒ“%,‡‰­(Ï­!óøÙ¢ˆÜZ@d–HúÉ ù±õ¼ý÷¼cd2#2‘)Ï® Ï© Ë­ Íf°,2¿â;£›âŒ\ ç!HT²+–àžjT@Ý£ Χƒë{}Åó>f4‡‘$,Í®® !r¸aøò0¼0ô2­$<‰ž/?þ^("†Ê K „%3BÓJB2ËC2…Á8~@j±Ez‰R'¸i¿êðHg¬ H{T²KÁ5ŨÀæXzz}åò}Xz¢„ ã' J²ÒHy/zd<ï–õ¼þy—ô—±ПZ4~çëȬ!/ØÂ^°G¸”pÀ9ùy—ŒýnYûÝ2÷»¤ü1(üSžcdÌž¢àÇrÍž±ÜçyÖ%þî»Ö®ßp&65ë¶ <µ¾ls–/aÀØtL>ù‡Øç¬áß»Z|ïbùogË“Ž–ßØù|~VúÆQ«Vz¾Q]ÜC>AÇØBj"àZéÿHŽ™‰¹ŸÉ…p“‹H“KÉ;–¯Ýø2QôZ8W90¾MàÉõ%óûñ·(*ûˆÄÄñîißîÃo ÛÝbÈüßÝÿ<¼+©?ôÎï­¢²A<`kb‡zÈ'ðµb3{‡_UÈ.|«Bœ…¾O«2 ðÀ9¿¬ÃMP&—Svšú>‹«›_Þy =¾¾tò~òº“÷Óç÷Ù„?k ýö”kß§/q3 t>¢=ø¦aë3†p ^<íñ§sÏ]ˆxÊú¸¯ß!¦…eée#ü§ä⣹f¿½ø»‹ß:Ç=è–¾) šßS ‘ɾ5óDøä¬öÃõ¥W·X?Üßü È ü8ÿøgï‚^´‹ø³ÔÔÔ¥ïã¨ñæócæòàæ‰HC8“ ^1uÙÂïÏÖaì¡û|ý޲,mù®F8ÃsúC®Ù£6ApŒzÔ%þ·wÏBÛ¦&µB³oÍ>9Ð|0£ùôÖÌ‹?ÌXì}g°å´!4p{áñw®ø¼b|Ð>â5{èYS—Þ?˜Ë†a åžv?há÷W›°W.Bøù½Í:ïXîa‹RçÇsÍž° ~Ò ö”kÂÞ¸û¯?Ì=5ÜjaœÛ O|ìêóº]È? ÿr€ž7síýà½l€&!—Àg<Þ°ò{Ã.üЗüßa_¸"ô1Â…2×'rÍöÙ?ëý¼;æ)oü‹+WiMÚmOµÛçö“'<|8„¾} rÌ)ÊîŒ[ÏÛoO!ܦî÷b<ÐN|øØasÏ£ü\ ?ä;äÿÇfûüs7`’}2Ï쇗\à¯z%ýÉ7k·@çÈÜ;ˆò/óó›³Ðü3S*'ãÜ^|ò¤—ï»—B?p†~ä}ÉܽûÐáagÓñp‡Ý„] °õ±¾|·ðz×&à=LjãÎѯ~Àµ»{ØÎ%¡ÏÓyfu {Í=æußä¿dï˜_Y{Ì«Îmß1Îï›ÓyçöâS¦¾þŸ8‡Ÿp…}áwµðè>rtÈþäðÓQo‹;¸Ÿvøä€Ás_4>þ‘•Ï'öŸ^†|ì ?ôqÉÅàšH#¸T<“gö¦søa/Ä[)G‚swŸÕÈÜ]ëÀ¾Å~ãsÿ€/]"¾õˆ>éð²òì~ë­‘+¦z\Në§Ac3Ù`ÈæÛ†#Ç?³öýÂ!èË+Ð/<Ç"‚À½PDÌ¢à}ùgŽºF÷A½œönhÞ¦€¼wæ^ƒøöâW†C³¾Ö€ÀïÜ#OyÃM½~Öž` ìxíïbØñûÆ#Ç¿¶õ=y)ø¤[ÔI/ä{Ïy—`â#øT‡þ1ÿÌ»îüc?Kÿ4‚°)ðbguíæ^ïÈn/>{mfpÇjtÚ bîsÎdãÕsüØX­F\Î69þ{ÿSΡ¦ž0S_ÔÇQ¡_–^F6Æ!°6â9™½ Ÿ¡¿‰Ä}EÜü\H50·ó ¬ÜyK¹ôÜõ™Xã€÷ Ná!¾° Hë@t¸½OÏ;Ç' —Œ0êmÌýÍ]ÂÎyÃÍПG‡}Ϳߜ`„к¨ý„3'|£¾ M8…ÿNÙãƒ-½À˜žîl^_Úk1É8@À f¿ŠvM€:úõ¼÷î$ÂÍc¶ÍG[]<ïií´Iø±ñ–k„1üyâ™oƒà§"1æ19g‘{~6zcmmueyfn¦¿¬¾ÜiÞ^>fœõ¥‡ýËh(Öšã¤{ópÿ×'ŒÐ÷ùÇ-GÛ»†:úF;†Æ;B’ÿ†½Â0çh„·¸¶ˆgOG ,à©¶h‚u|ÑŸNßÜX]™«”*ýÒ˜9¬à¬"/\K:Ù)…蘜ïˆÍsØ$ßì¦ÓI—¼±p¬7çƒÄ‡D`’/y'Ù»$^pгpˆ=g2·GšÛm oƒmqasÙÅ7Ê5í•â†À;¢Ó¾ÃB¾N û"!è3´ÿ§±þŸ ü>A|õ€v¬È¿Š ±ŠÆØ£ñÎI—°ç¼=®­]­Wô…äTg•¥Ó’óüÓ½ÑIž¨wDœ[ Ú ŽÖocâÀ®'2Á;ã—”HN$ÇåÆdD`ü‚QÞ¾Q^Þ‘žá§W¤—ÔÇîç•ê›ã—@ôI$»Çç:Çâ)¶1‰¢ãÎG¡­ €X=Qèó°8kx‚2Ù1.ÓKòJgº§—Ýù†f»@“f Jn†’ÄP‚šËƒdÑ"2ˆa©9!)™ÁØŒ ¤ô ¤4@pR:Ø MƇ¥dG¤"Ó  ÅPšVI"G¢s"àia‘‰¡aq!!¨`=È bCBÑañ¡Plž@O. Kg„f0Óh>)dlž »Ÿî—v ¶NñiÎ W0™nØ\ÏT²§Ü?[tç;²-VÝd,]Ž¢ÉP4 ª E©F’Ê"¯8&—Ï)ŒÎ¦FgSÀžSvcréˆÜ"D™_Š"PùBT^9*«™^ŒH¡Æ$æÃãràè,x,>zЀÇeÃãsc’ˆ1©´˜LvL?&OÏBóÊ"r¸¡ÙÌ <= ³ÐGõË øfPÀÖGõÇâé!9Œ°¼A£Ô…Å;¾¥Ô:Ý3ÌêÀn|w‚eʱŒVlqsR‘8‰^¡Ub ‰ez¨|=úv91…•Zu­KoÀÒ±…b,µ&‰T™”_†Éá&f±ñÌÄLFB&lõm<“ÍIÌáa ¹ SP‡¡5â ëc jÔ*EC.‡“ùÑäR©4šT ÚprY E€ ŠP…5qôÆ„b ¢P²ã{bíð¾´ó'Tzx™%í™%m8n+Ž#ÁqZpœf§)ƒÝ¶íæ<$ÍäÊ2¹r=œ¶Lvk&³ÇhÊ,ãèõ¸ÂZ=Õ¸Â}ƒV‡yq#(À±À±2GŽãÊ38²4vk*[’ÌnIf5cYMz˜†H@žÂ–¤qZÓ¹r\‰Ãl¿#Ð90KÑÿàe•]QEÿ; ¹¢s*r…rc«Ú™«)•=€Nа“,PnС§\qCª(Û$U¨Da'A¨Ú"_ Ü¾ %êËô¿VÉÚúµ ’£ "Kï&,mHn1BÐ2IÐ6~þQ;Ñ?°“;’6˼ò›õ‡¢Jÿ§ù?ÿÿŒo,°¡%ÄIEND®B`‚PKj²Fc^PKÆj<2-__MACOSX/RLPlot-Icons/._rlplot-icon_64x64.pngUX ’‚Bt.úAõc`cg`bÀ 1N 6b(?$àçžæîí¡JPKé4R§$RPK—QH2RLPlot-Icons/RLPlot.bmpUX ¾ƒB‚Bõ•–yLši‡ÛIf’½’Ýdg²Ù?:»›Î&»3³Ó4ÓÛ±µÚ±Þõ˜ªµõDk+Þ "x!â…bAQ9U”ÃAäP¯*¢Rµ¢-êF§e?ÅaíÎv“~y^ò{ß7yxóƒïËçêyþ—§Ž®óÀ8 Œ3Çãô©Àþo?rŒ¯žÂ "Œï!<Á;nùq¼ÂC|¥ <Úx:©ïiÐõ4j» ã<¼Š‹W5¯áÔ‚‚E3ñ2Æ!@P²ñãÜí î5§äÔ+9X§~œÛ íÆ÷£=ÿëׯ-¹š†–·£Å4—\ÒÕ\ÜÙ„—„´ …d4€î¨Cµ`¤ $©ÙZULÇ÷‹Eäb~s>›ë$dÑð:ÚEÈênΤr ]þýƒƒ… ±€EÅBê+Ò*ÑàrÔã T Æ–¥‘0J%W)¤å¥$ÃÁ`D28?5¥,+•€JoäËkQQE÷Ê ÂÊ Ã*‘ ¥Ñôº$:ìk§kgW:ÄqW+=c·ä²[2é­Q€ÑÐ6|%" Iõõäùyq}n³½=Y>žÀ';*¤°$3º¢0<¡ñbBã•xÂeþ@ábf‰+¾8¼òÅXK¡ßj³/[|·^¡7÷OòÏnvAÚ÷9 ‰^¡¦„ÅId5àV<1(/û6T*“•:AJòA%ŸWÃnSÏò‘—^ýpø7m6µyÕ}m?Û¼s’œNø#/Hô7ÿ…äe' f7dvÜw¹7Rû# ‡óÀ³âŠÎVdºÀúôQÝó#¿ëÊîãYëI\™m°¸ë™Á×<æ}@f¿x³o¼Ù3rÉ=Ìä÷-úÀ5;ùÂcþ]˜â*ÇäRš|îIâïý/ë…%ð_\x1±zFsVäù´»žnþ‹Ñp‹ƒ(˜%4eÅÇšvšø7P·Zÿ#'à¾Ø(øÇ¨‡Â%üæø÷ÝßÎ/Qþ1cõRš/ÌZ=ÕË~£‹×hO áŸ¦¹„Ä™!µNÀ¥ëÞ.©é!Ÿf‚ÎDr<{¢œÄw‡Gæüûa}Ür2Èé—4ŸMo~¹~ð×mûß7_¹L­_W/_i¯Í¼ûQJàW±©«˜Ž­àHs`ĬfIÜô¾ö8=ø™±†³¾á†8‰âDfý¼ ògØØ÷€óïX—-3GÿŸm½¾±m?‰K?'óî¯2î|’žÿŒ6lkä½H†YÁÿ›øœ_@cÞa\Nè¹—ÄN~u;Œyó䃼ˆÓuѧ?ðÿQPÁf“ðŸ{az7•Už ÿþww”T«¬sR./}XyWGÊ>|þX¦„n¡Õ¶3¹ú,pÇ^»g/Ú³c³cö³çä\eYL‡"k-TP ””ÅŽ0LFðñÈQC÷Ds¯bUµXö!æJCE9çÂñóyFºm³Í­míØ±{‡Ü²?£‰ÌÀrëÇÅ“œ:-«zY#žhSµ/Œudrcb¹<¯}ŠÑ¤%å‚áaÕ5 µ„Væåðìîí‰I Éš‘”•ç §«_®l‡1ªÑÚ)Á˜\&dªieãô7PÓËdí¨–æ¤:š7' º %`GxTクIj…_ùÑ¿¿÷¯½­í-£f@g^œž \\c*Õì>šdb|l\¥àL00?EN/£’S5Õ&oŽ–e8Bözs}zâàŸz²ižü6›í¹ÕjÐË)¬ ÿ+_§—é&Õ“š>k[º‰ÈÉ#+CAyôI*®Ö—‘™'ëãOaÔìµ”Šu>&Ü™XTþzxלÂ&d ‘b N8ñÁ\þŸ~­[Z†GÙ(¼|?g—øÜ,=ž;_×ÚCd^9Ù‰ÔÄ{P§ð 6Áƒê¸9T ³×Ü©Œs#.Ê÷*[ÂÃõªà`ÈR¢‚,Ip™[ÿÇ:KÑ(½ÄúûˆöÑÛìxôœ°éçx >þ¡Ósç†íý„šS›ˆê²—øîiê|£«Å¸äÖø\“«I5ß&æÂr"šÂ ]Æ…`'¿|þöÖr_Äßg‚Â?bzŽõ_ê-Ý(Äs¾Rέ–rÚsÃiË>ǰ¦œÞŠ$šR|¹ÙO—*EÌ!ë)R:3ˆkKÀ­ÒJ§ž]AbòR7êüŸˆçßãéiÊl8ª¹†ýÈ]¬nŒòÞÈ}ŒêØ™qÿ¶NJêQ•f‰½B -iói¨Rľ Þ–ð&±Oè/!µ+¯;>|Þùy[.»/û–ÿ Óÿ™fêþÝš :††©ìécÇ­;d56“S”JMk -M4UäÒšúƒÔ‹1$+ˆÑœ£b@%| ñW×iÛˆUÄGŠ=‚Ç É¿¯ê"÷†Ú%ÿ‡¢w''éÒÖ“˜ÌÖ‘I ;´¨:Úin×P$·¢©$MVØÒ”q–ŒdgµQi(¨â¬ú¤N;Ê×ëFú镺õg 9û…ÿWLNM26~‡¸‘Û„ŽPÖצKK›¶¦º:kÒ˜¸ÞFOYÝÅ—$= .ó!JÌåzFº(ÍðÆ5g+ʽ8goÃ<íCNfïÂEti?êÚJ£öêåÿñ£¨6LÜ`|bœáѮޢ*ÅæZ%ÚÎZ5Íhj®Ò!ö§ÿ‹VeuYç)K &9I¬; #®$œ&_Ì»*‘ŸÆœ Ϭ™Wÿ;ƒZ±,dBø284@¯–k©§èüÆÿZ!Ú«q?B,íb/Ý(Æ‘—îÇéä\ ¢FÔgvoÝQKIÀú¹úWGsÿöu]þ§Dþû•¨3=%ÿë7úééíF+ò_oO[m!]ÅŠE[”@ëÕ ²ñJÙÉÕ´PjEÚ ã¤öÒ@CÉfú+ºJÏëùÏÆ¯­ºÄ¾6ÿlüuâž î ts]Ô¤¯&KÒÃmÕâIŒ÷kÄûD‡¤šËêo¡¤è¾™&¨ ÑÔåÑ.æÌÞfjcèçú1Mé.Ü}‘ÿ)þšdíêR]þÛëÊè)¿ò£t•%ÓVr™SÛ±¾²eN0…ñhK¥ö²àMóê?>ÜÃMM‘ž_oê«^ú×—ÓS™þH£«â mbM"æ1–Žòz*Ò¤ö²Í’ÿ-u*wúëôòK[MCºƒbþëêßÑF±X×ÛTÅôVgýD2é­Ê [øuWfHZº&ÚÊB·¼Üÿ–œ›WÿÎk)ôŠº~»þ å©â÷ŸÂÔH?M%Ü¿ûY=ûþÖw-›»LvKzD«šß¯[=×ïfªx‹yùoÍõf°³J/ÿêüs4äGèòß¡®¤¿6÷gS~n›x~WCýåƒÔ‰w¡k±fäy~@M¬U1fTÈM)»°Ÿôc ) 7æjØ^ŠÎî TÌŸK¶ì¯?øÿ×ñ_PKÆ´ÇŒÇ ¾PK¤QH2"__MACOSX/RLPlot-Icons/._RLPLOT.icoUX ܃B£‚Bõc`cg`bÀ 1N 6b(?$áéì¯àîí¡JPK¬–$5$RPK´QH2RLPlot-Icons/RLPlot.xpmUX úƒBÂBõ…˜ÛŠÉ†ïz‡F¾6ÒœgX|‘çS. fY–±°ÄJH6¿»ÿˆèŒìÔ;UÕÝßdEFü]¥ïO;ÖÓûoßüxýýõåùôüù÷ï§÷ß¿|ûòõõ//Ï_ÿøû¯§¿žþóö͇÷§½üãõóéó§—~~=ýñüõË×ï?ø‚¿}ûôý·o/ÿþô…m½»¹>áßÕýÓéúÝŸùÚólþ«1§çÓŸâÅ‹&½³?ć§Û§[Æn·‚ý„nn‡ ß]ß±ïâ„o¯o§ ß<Ý<1ΊÆ£{tŒË„oÍ­a\'|ýt-Fš`Ø öÁ2^»{wo¼ñŒWÅöÎÞ=¹'YrSL3U“1-G¢Áø˜0½36¶ã>Dï ûàƒè=0ü6wæNôVL3‡ÞVã„U“4ð½¿×4dÅ´ÜÐ[1® VÅT êI›ðýͽàE1ÐÙ«à.8 ~›ðÐ[1…soïÅ“cÂZlÆuLv[Åä‰:è†sˆ_ªÊ+¦åÔHPL3µ#cò‚þ¤‘&¬™ÏŠû½'l½•Ò¬Š)]²)&¤™_#½´œ »*foº'Û„uöΘ¾Nã m|Ç4hÿˆÞVa`l>ÎÞEoÅ“ƒa` -Ÿ¨xÒ$1&åXÁîIVL³iYÑ{ÂNø¼¬è­˜´Ö½³ÆR´äè'Š»}Ñ{Âjdø²ûŒÉ&y¡¶Mè¸gHôVL¶5x70.é“z£¾#[]EÑ{ÂNRÜí‹ÞÖ%‹bÚ|£Ÿ0¦ 9ÊÞðšbö¤§a™°n’Uq×Eôž°ÚÞSàü¡xÒÄDÆhFdW³cS຤SLKŽ~2aÝ®1µ\¶Ý^œ°v䤸׊譸׊è=áQßV#mÂ*Õ¢˜5ï³× kinŠÙê­˜DÕÖ{(¦z'Æø™„µŒ©l&©ÜÀØ®ãþdÂZlA1kÒ»Oœ°†“S”:;OX5)V#U19§åÓOÁ/‚Ñèh¶f~UÜÿ$z+¦ŠR#;cúáš49Ó¾QMLî˜6ôVÜw›è=áq202£QÅSAÄ ë줘†:˜ORÁ¨&rNï êÀÈŒ*ØO79‹â)Å+cÚ½dD+vS+6õkðV1y¢³bî@]¯¸w Ñ{šâ80mØN|us5¥8+îµ"z3¦›w¾£ÖúV< Û_]_Ò¦´ Ot®Ï;ŠûÞ½SeiÆWWÓ-¿iOZÅS.àW{O½ó¶ÒúfüññããtO &ÁxM¶óÀ—i(ŠûN&Œ‡g~²>?<»j²Œ\–¼d‹c©[¦‘Êÿ;Z=w\#¯”½±Ö&g£ÙnÇýiöwÀtȧËïô¾åa$á°4ZØ]vd‚žA09:K½_]õô-ãœÎlÉçßC<|Øak'1‘ÍUW•Ãð» —tÉS8´NrÆ’wºœl½Ä€<ôÒ W” #B"Ö®ð±ÂÈáÂô"d—£¤(†¶ÎnZ M`šd'c 6KA¬,ñêVè´C‹%´\|IÕdÉ4í,l(1Ÿ…µyw-4^{ ¦|iqåïS8©Åª”`È›™Y9~1ÓΟȿ}IXÎ"¤Ÿ5É]“W/®|‘³|*ðÿJIoëd$H8Émèh»Û0È•¥¥¼5Ä¢ƒÂÒ»/ÅFØ\Þâa‹£Üä±’ŒWö¢Æç¼KÖ:¿ÀŸ\z±ñî[\Ž>šy‚Ë!u”÷5¸\ÃáoSò‰øŸöN¾™ÝK$»/0SøR:Ëp9ÄÅ~‡‘ï°Ÿ‡&;$]mà,G>'»…ûuñìC¡P®’KdäH8¼©kT#˜”(/dıg62¥1%9äì³K5¬ˆ Ó"âÏe®òugèŽùÝÛÏ&r’34ÉtyÀŒ¬³&6¾{m†~µ“ÝýR‚™PÂéSJ;zÀøŸ?S÷KMH†Ã%3ÞDxBçbÊ ^ô9TWb$CHNªÈ¸kÃHƆ³‰ƒ 䯩nI±FótÞKi¹-….?p”Zi©ë„:—1šmѱyÛöZíb0p^Í£¹Å²æ#‘´K -v# kbQfÛÐÈdĺ 7ÿÞ›í–l3l¤t„n¤gÇø`«#PUeÛV¬«¶ÂŸ3<«Ä9 ”l© #»£^컥‘ÑȶÒÜb¶I³Îµ”adͤF×$\ ‹ÎFu½ÝÈišóç`¤aÿc÷"7KbyëVÏu= uzkQ'6óѰ‘L±….‡8;wÄVj9úÅ9ÉøZæbƒ'…„±V~a$åM()™ŒÄØë­ÔZ–ŸŒøˆ´x¤×c»æšúÿ9ítÄ#¯‰46••®kA׋~‚m¶1.^SÀy‹[\SKªØ;ØÔ™Œí8£ {?Y8;Ò/Œ£âúvNZc9¢ Ï q ZôY×=ñ^š0ýÓO‘:³QæÉ7ºêܨ[]ôVaÜPlŒ–½¤Ð;<ùï/oßüPKA?oßSPK´QH2"__MACOSX/RLPlot-Icons/._RLPlot.xpmUX úƒBÂBõc`cg`bÀ 1N 6b(?$ââîí¡JPKùPÙ$RPK àQH2 @íARLPlot-Icons/UXö€BƒBPKêQH2‡H @¤;RLPlot-Icons/.DS_StoreUXó‚B(ƒBPK SI2 @ýA×__MACOSX/UX¯Ö B¯Ö BPK SI2 @ýA__MACOSX/RLPlot-Icons/UX¯Ö B¯Ö BPKêQH2 Ž#wR! @¤R__MACOSX/RLPlot-Icons/._.DS_StoreUXó‚B(ƒBPK´j<2Ž•–H…I€I$ @¤ÍRLPlot-Icons/rlplot-icon_128x128.pngUX(ƒBS.úAPK´j<2é4R§$R/ @¤´L__MACOSX/RLPlot-Icons/._rlplot-icon_128x128.pngUX(ƒBS.úAPKÖj<2¡´eŠ … " @¤EMRLPlot-Icons/rlplot-icon_32x32.pngUX’‚B”.úAPKÖj<2é4R§$R- @¤/W__MACOSX/RLPlot-Icons/._rlplot-icon_32x32.pngUX’‚B”.úAPKÆj<2j²Fc^" @¤¾WRLPlot-Icons/rlplot-icon_64x64.pngUX’‚Bt.úAPKÆj<2é4R§$R- @¤r__MACOSX/RLPlot-Icons/._rlplot-icon_64x64.pngUX’‚Bt.úAPK—QH2„Ú›ØÑ6  @¤sRLPlot-Icons/RLPlot.bmpUX¾ƒB‚BPK—QH2ø³$R" @¤6|__MACOSX/RLPlot-Icons/._RLPlot.bmpUX¾ƒB‚BPK¤QH2Æ´ÇŒÇ ¾ @¤º|RLPlot-Icons/RLPLOT.icoUX܃B£‚BPK¤QH2¬–$5$R" @¤Ö†__MACOSX/RLPlot-Icons/._RLPLOT.icoUX܃B£‚BPK´QH2A?oßS @¤Z‡RLPlot-Icons/RLPlot.xpmUXúƒBÂBPK´QH2ùPÙ$R" @¤²__MACOSX/RLPlot-Icons/._RLPlot.xpmUXúƒBÂBPKÙ6rlplot/RLPLOT.RC0000775000076400007640000002433110771205637012130 0ustar c71960c71960//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 #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 rlplot/mfcalc.y0000755000076400007640000032052710775137236012314 0ustar c71960c71960%{ /* 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. 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 #include #include #include #include #include "rlplot.h" class symrec { public: int type, row, col, a_count; unsigned int h_name, h2_name; char *name, *text; double (*fnctptr)(...); symrec *next; double var, *a_data; symrec(unsigned int h_n, unsigned int h2_n, int typ, symrec *nxt); ~symrec(); double GetValue(); void GetValue(void *res); double SetValue(double v); void SetValue(void* dest, void* src); void SetName(char *nam); void InitSS(); void NoInit(); private: bool isSSval, isValid; }; // syntactical information struct syntax_info { int last_tok; //resolve ambiguous ':' double clval; //current value for where - clause int cl1, cl2; //limits of clause formula in buffer struct syntax_info *next; }; static syntax_info *syntax_level = 0L; typedef struct{ double val; int type; symrec *tptr; double *a_data; char *text; int a_count; }YYSTYPE; static int yy_maxiter = 100000; //maximum loop count 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); static double *ReallocArray(double *arr, int size); static char *add_strings(char *st1, char *st2); static char *string_value(YYSTYPE *exp); static int eval(YYSTYPE *dst, YYSTYPE *sr); static int range_array(YYSTYPE * res, char *range); static int range_array2(YYSTYPE *res1, YYSTYPE *res2); static void exec_clause(YYSTYPE *res); static YYSTYPE *proc_clause(YYSTYPE *res); 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 int for_loop(char *block1, char *block2); static char res_txt[1000]; static anyResult line_res = {ET_UNKNOWN, 0.0, res_txt, 0L, 0}; static DataObj *curr_data; static char *last_error = 0L; //error text 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, bNoSS; //while editing ... static int parse_level = 0; //count reentrances into parser #define MAX_PARSE 50 //maximum number of recursive reentances %} %token NUM BOOLVAL STR ARR BLOCK PBLOCK IBLOCK PI E CLVAL PSEP IF ELSE %token BTRUE BFALSE DATE1 TIME1 DATETIME1 DIM WHILE FOR INARR RANGEARR %token RETURN BREAK %token VAR FNCT BFNCT AFNCT SFNCT FUNC1 TXT SRFUNC YYFNC %token FUNC4 YYFNC2 YYFNC3 %type exp str_exp arr bool block anyarg %right '=' ADDEQ SUBEQ MULEQ DIVEQ %left LSEP /* list separator */ %left CLAUSE /* clause (where) operator */ %left SER %right COLC /* conditional sep. */ %right '?' /* conditional assignment */ %left AND OR %left EQ NE GT GE LT LE %left '-' '+' %left '*' '/' %left '^' /* exponentiation */ %left '[' %left NEG /* negation-unary minus */ %left INC DEC /* increment, decrement */ %left PINC PDEC /* pre- increment, decrement */ %left PDIM /* dimension array */ /* Grammar follows */ %% input: /* empty string */ | input line ; anysep: ';' | ','; line: '\n' | ';' | ',' | exp '\n' {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; if(yyval.val != 0.0) if(block_res = eval(&yyval, &yyvsp[0]))return block_res;} | 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 {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;} | BREAK {return 3;} | error '\n' {yyerrok;} ; str_exp: STR {;} |str_exp '+' exp {yyval.text=add_strings(yyvsp[-2].text, string_value(&yyvsp[0])); yyval.type = STR;} |exp '+' str_exp {yyval.text=add_strings(string_value(&yyvsp[-2]), yyvsp[0].text); yyval.type = STR;} |str_exp '+' str_exp {yyval.text=add_strings(yyvsp[-2].text, yyvsp[0].text); yyval.type = STR;} |SRFUNC '(' exp ')' {if($1->fnctptr)(($1->fnctptr)(&yyval, &yyvsp[-1], 0L)); yyval.type = STR;} |SRFUNC '(' exp anysep str_exp ')' {if($1->fnctptr)(($1->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;} ; range: str_exp {;} ; arr: ARR {;} |exp {if(!yyval.a_data) {yyval.a_data = PushArray((double*)malloc(sizeof(double))); yyval.a_count = 1; yyval.a_data[0] = yyval.val;}} |arr LSEP arr {push(&yyval, &yyvsp[0]);yyval.type = ARR;} |arr CLAUSE exp {exec_clause(&yyval);} |range {range_array(&yyval, yyvsp[0].text);} |NUM SER NUM {if($1 < $3 && (yyval.a_data = PushArray((double*)malloc((int)($3-$1+2)*sizeof(double))))) for(yyval.a_count=0; $1<=$3; yyval.a_data[yyval.a_count++] = $1, $1 += 1.0 ); yyval.type = ARR;} ; 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 {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; anyarg: exp | str_exp; exp: NUM {$$ = $1; yyval.type = NUM;} |RANGEARR |bool {$$ = $1; yyval.type = BOOLVAL;} |TXT {$$ = 0.0;} |CLVAL {$$ = syntax_level ? syntax_level->clval : 0.0; yyval.type = NUM;} |PI {$$ = _PI; yyval.type = NUM;} |E {$$ = 2.71828182845905; yyval.type = NUM;} |VAR {if($1)$1->GetValue(&yyval);} |block {if(block_res = eval(&yyval, &yyvsp[0]))return block_res;} |VAR '=' exp {if($1)$1->SetValue(&yyval, &yyvsp[0]);} |VAR '=' str_exp {if($1)$1->SetValue(&yyval, &yyvsp[0]);} |VAR ADDEQ exp {if($1){$1->GetValue(&yyval); $1->SetValue(yyval.val + $3);}} |VAR SUBEQ exp {if($1){$1->GetValue(&yyval); $1->SetValue(yyval.val - $3);}} |VAR MULEQ exp {if($1){$1->GetValue(&yyval); $1->SetValue(yyval.val * $3);}} |VAR DIVEQ exp {if($1){$1->GetValue(&yyval); $1->SetValue($3 != 0.0 ? yyval.val / $3 : (getsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv")))->GetValue());}} |FNCT '(' exp ')' {$$ = $1->fnctptr ? (($1->fnctptr)($3)): 0.0; yyval.type = NUM;} |AFNCT '(' arr ')' {$$ = $1->fnctptr ? (($1->fnctptr)(proc_clause(&yyvsp[-1]))) : 0.0; yyval.type = NUM; yyval.a_data = 0L; yyval.a_count = 0; yyval.text = 0L;} |AFNCT '(' exp PSEP arr ')' { if(!yyval.a_data){yyval.a_data=PushArray((double*)malloc(sizeof(double)));yyval.a_data[0]=$3;yyval.a_count=1;} push(&yyval, &yyvsp[-1]);$$ = $1->fnctptr ?(($1->fnctptr)(&yyval)):0.0; yyval.type = NUM;} |AFNCT '(' exp PSEP exp PSEP exp ')' { yyval.a_data = PushArray((double*)malloc(3*sizeof(double))); yyval.a_count = 3; yyval.a_data[0] = $3; yyval.a_data[1] = $5; yyval.a_data[2] = $7; $$ = $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 '(' 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;} |YYFNC '(' ')' {if($1->fnctptr)(*$1->fnctptr)(&yyval, 0L);} |YYFNC '(' arr ')' {if($1->fnctptr)(*$1->fnctptr)(&yyval, &yyvsp[-1]);} |YYFNC2 '(' anyarg PSEP anyarg ')' {if($1->fnctptr)(*$1->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);} |YYFNC2 '(' anyarg ')' {if($1->fnctptr)(*$1->fnctptr)(&yyval, &yyvsp[-1], 0L);} |YYFNC3 '(' anyarg PSEP anyarg PSEP anyarg ')' {if($1->fnctptr)(*$1->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);} |YYFNC3 '(' anyarg PSEP anyarg ')' {if($1->fnctptr)(*$1->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1], 0L);} |exp '+' exp {$$ = $1 + $3; 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;} |exp '-' exp {$$ = $1 - $3; 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;} |exp '*' exp {$$ = $1 * $3; yyval.type = NUM;} |exp '/' exp {yyval.type = NUM; if($3 != 0.0) $$ = $1 / $3; else $$ = (getsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv")))->GetValue(); } |VAR INC {$$=$1->GetValue(); $1->SetValue($$+1.0); $$ -= 1.0; yyval.type = NUM;} |VAR DEC {$$=$1->GetValue(); $1->SetValue($$-1.0); $$ += 1.0; yyval.type = NUM;} |INC VAR %prec PINC {$$=$2->GetValue(); $2->SetValue($$+1.0); yyval.type = NUM;} |DEC VAR %prec PDEC {$$=$2->GetValue(); $2->SetValue($$-1.0); yyval.type = NUM;} |exp '^' exp {$$ = ($3 >0 && $3/2.0 == floor($3/2.0)) ? fabs(pow($1,$3) ): pow($1, $3); yyval.type = NUM;} |'-' exp %prec NEG {$$ = -$2; yyval.type = NUM;} |'(' anyarg ')' {memcpy(&yyval, &yyvsp[-1], sizeof(YYSTYPE)); yyvsp[-1].a_data = 0L; yyvsp[-1].a_count = 0;} |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.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]);} else {$$ = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;} |exp '[' exp ']' ADDEQ 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]);} else {$$ = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;} |exp '[' exp ']' SUBEQ 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]);} else {$$ = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;} |exp '[' exp ']' MULEQ 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]);} else {$$ = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;} |exp '[' exp ']' DIVEQ exp {if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count){ if($6 != 0.0) {$$ = 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]);} else {$$ = (getsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv")))->GetValue();}} else {$$ = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;} |NUM ':' NUM ':' NUM {make_time(&yyval, $1, $3, $5+1.0e-10);} |NUM ':' NUM {make_time(&yyval, $1, $3, 1.0e-10);} |exp '?' exp COLC exp {memcpy(&yyval, $1 != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE))} |exp '?' STR COLC STR {memcpy(&yyval, $1 != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE))} |exp '?' STR COLC exp {memcpy(&yyval, $1 != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE))} |exp '?' exp COLC STR {memcpy(&yyval, $1 != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE))} ; %% //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Cache spreadsheet data for repeated access //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class SsRangeData { typedef struct _rng_data { _rng_data *next; unsigned int h1, h2; RECT rec; double *vals; char *name; int nvals; double dSum, dMean, dQuart1, dQuart2, dQuart3; bool bSum, bMean, bQuart1, bQuart2, bQuart3; }rng_data; public: SsRangeData(); ~SsRangeData(); void Clear(); bool GetData(char *rng_desc, double **vals, int *nvals, char **name); void rmData(double *vals, int nvals); void cellModified(int row, int col); double sum(double *vals, int nvals); double mean(double *vals, int nvals); double quartile1(double *vals, int nvals); double quartile2(double *vals, int nvals); double quartile3(double *vals, int nvals); private: rng_data *RngData; bool FindData(unsigned int h1, unsigned int h2, rng_data **rda); bool FindData(double *vals, int nvals, rng_data **rda); bool SetArray(rng_data *rda, char *range); void do_quartiles(rng_data *rda); }; SsRangeData::SsRangeData() { RngData = 0L; } SsRangeData::~SsRangeData() { Clear(); } void SsRangeData::Clear() { rng_data *nxt; nxt = RngData; while(nxt) { nxt = RngData->next; if(RngData->vals) free(RngData->vals); if(RngData->name) free(RngData->name); free(RngData); RngData = nxt; } } bool SsRangeData::FindData(unsigned int h1, unsigned int h2, rng_data **rda) { rng_data *nxt; nxt = RngData; while(nxt) { if(nxt->h1 == h1 && nxt->h2 == h2) { *rda = nxt; return true; } nxt = nxt->next; } return false; } bool SsRangeData::FindData(double *vals, int nvals, rng_data **rda) { rng_data *nxt; nxt = RngData; while(nxt) { if(nxt->vals == vals && nxt->nvals == nvals) { *rda = nxt; return true; } nxt = nxt->next; } return false; } bool SsRangeData::SetArray(rng_data *rda, char *range) { AccRange *r; int row, col; anyResult ares; if(!range || !range[0] || !(r = new AccRange(range))) return false; if(!r->GetFirst(&col, &row) || !(rda->vals = (double*)malloc(r->CountItems() * sizeof(double)))) { delete(r); return false; } r->BoundRec(&rda->rec); parse_level++; r->GetFirst(&col, &row); for(rda->nvals = 0; r->GetNext(&col, &row); ) { if(curr_data->GetResult(&ares, row, col, parse_level > MAX_PARSE)) { switch(ares.type) { case ET_VALUE: case ET_TIME: case ET_DATE: case ET_DATETIME: case ET_BOOL: rda->vals[rda->nvals++] = ares.value; break; } } } rda->name = (char*)memdup(range, (int)strlen(range)+1, 0); parse_level--; delete(r); return true; } void SsRangeData::rmData(double *vals, int nvals) { rng_data *rda, *rmrda; if(!FindData(vals, nvals, &rmrda)) return; if(rmrda == RngData) RngData = RngData->next; else { rda = RngData; while(rda->next && rda->next != rmrda) rda = rda->next; if(rda->next == rmrda) rda->next = rmrda->next; else return; } rda = RngData; while(rda) { if(((rda->rec.top <= rmrda->rec.top && rda->rec.bottom >= rmrda->rec.top) || (rda->rec.top <= rmrda->rec.bottom && rda->rec.top >= rmrda->rec.top)) &&((rda->rec.left <= rmrda->rec.left && rda->rec.right >= rmrda->rec.left) || (rda->rec.left <= rmrda->rec.right && rda->rec.left >= rmrda->rec.left))){ rmData(rda->vals, rda->nvals); rda = RngData; } else rda = rda->next; } if(rmrda->vals) free(rmrda->vals); if(rmrda->name) free(rmrda->name); free(rmrda); } void SsRangeData::cellModified(int row, int col) { rng_data *nxt; nxt = RngData; while(nxt) { if(col >= nxt->rec.left && col <= nxt->rec.right && row >= nxt->rec.top && col <= nxt->rec.bottom){ rmData(nxt->vals, nxt->nvals); nxt = RngData; } else nxt = nxt->next; } return; } void SsRangeData::do_quartiles(rng_data *rda) { double *vals; if(rda->vals && rda->nvals && (vals = (double*)memdup(rda->vals, rda->nvals*sizeof(double), 0))){ d_quartile(rda->nvals, vals, &rda->dQuart1, &rda->dQuart2, &rda->dQuart3); free(vals); } rda->bQuart1 = rda->bQuart2 = rda->bQuart3 = true; } bool SsRangeData::GetData(char *rng_desc, double **vals, int *nvals, char **name) { rng_data *rda; unsigned int h1, h2; h1 = HashValue((unsigned char*) rng_desc); h2 = Hash2((unsigned char*) rng_desc); if(FindData(h1, h2, &rda)) { *vals = rda->vals; *nvals = rda->nvals; if(name) *name = rda->name; return true; } if(!(rda = (rng_data*) calloc(1, sizeof(rng_data))))return false; SetArray(rda, rng_desc); *vals = rda->vals; *nvals = rda->nvals; if(name) *name = rda->name; rda->h1 = h1; rda->h2 = h2; rda->next = RngData; RngData = rda; return true; } double SsRangeData::sum(double *vals, int nvals) { rng_data *rda; int i; double tmp; if(FindData(vals, nvals, &rda)) { if(rda->bSum) return rda->dSum; for(i = 0, tmp = 0.0; i < nvals; i++) tmp += vals[i]; rda->dSum = tmp; rda->bSum = true; return rda->dSum; } for(i = 0, tmp = 0.0; i < nvals; i++) tmp += vals[i]; return tmp; } double SsRangeData::mean(double *vals, int nvals) { rng_data *rda; if(FindData(vals, nvals, &rda)) { if(rda->bMean) return rda->dMean; rda->dMean = d_amean(nvals, vals); rda->bMean = true; return rda->dMean; } return d_amean(nvals, vals); } double SsRangeData::quartile1(double *vals, int nvals) { rng_data *rda; if(FindData(vals, nvals, &rda)) { if(rda->bQuart1) return rda->dQuart1; do_quartiles(rda); return rda->dQuart1; } return HUGE_VAL; } double SsRangeData::quartile2(double *vals, int nvals) { rng_data *rda; if(FindData(vals, nvals, &rda)) { if(rda->bQuart2) return rda->dQuart2; do_quartiles(rda); return rda->dQuart2; } return HUGE_VAL; } double SsRangeData::quartile3(double *vals, int nvals) { rng_data *rda; if(FindData(vals, nvals, &rda)) { if(rda->bQuart3) return rda->dQuart3; do_quartiles(rda); return rda->dQuart3; } return HUGE_VAL; } static SsRangeData RangeData; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // The symrec class //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ symrec::symrec(unsigned int h_n, unsigned int h2_n, int typ, symrec *nxt) { h_name = h_n; h2_name = h2_n; type = typ; next = nxt; row = col = -1; name = text = 0L; var = 0.0; isSSval = isValid = false; a_data = 0L; a_count = 0; fnctptr = (double (*)(...))nop; } symrec::~symrec() { if(name) free(name); name = 0L; if(text) free(text); text = 0L; } double symrec::GetValue() { anyResult ares; 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)){ return var = ares.value; } isSSval = false; row = col = -1; } if(!isValid) NoInit(); return var; } void symrec::GetValue(void *re) { anyResult ares; YYSTYPE *res = (YYSTYPE*)re; int i; if(!res) return; if(isSSval && !bNoSS) { if(row < 0 && col < 0) InitSS(); res->a_data = 0L; res->a_count = 0; //GetResult( , , ,true) inhibits reentrance into parser ! if(curr_data->GetResult(&ares, row, col, parse_level > MAX_PARSE)){ isValid = true; if(text) free(text); text = 0L; switch(ares.type) { case ET_VALUE: res->type = NUM; res->val = ares.value; res->text = 0L; break; case ET_BOOL: res->type = BOOLVAL; res->val = ares.value; res->text = 0L; break; case ET_DATE: res->type = DATE1; res->val = ares.value; res->text = 0L; break; case ET_TIME: res->type = TIME1; res->val = ares.value; res->text = 0L; break; case ET_DATETIME: res->type = DATETIME1; res->val = ares.value; res->text = 0L; break; case ET_TEXT: 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; } var = res->val; return; } isSSval = false; row = col = -1; } if(!isValid) NoInit(); if(a_data && a_count) { res->text = 0L; res->a_count = a_count; res->a_data = a_data; res->val = 0.0; res->type = ARR; } else if(text && text[0]) { res->text = text; res->a_data = 0L; res->a_count = 0; res->val = 0.0; res->type = STR; } else { res->type = NUM; res->val = var; res->a_data = 0L; res->a_count = 0; res->text = 0L; } } double symrec::SetValue(double v) { if(isSSval && !bNoWrite) { if(row < 0 && col < 0) InitSS(); if(curr_data->SetValue(row, col, v)){ if(curr_data) curr_data->Command(CMD_UPDATE, 0L, 0L); RangeData.cellModified(row, col); return var = v; } isSSval = false; row = col = -1; } isValid = true; a_data = 0L; a_count = 0; return var = v; } void symrec::SetValue(void* d, void* s) { YYSTYPE *dest = (YYSTYPE*)d; YYSTYPE *src = (YYSTYPE*)s; if(isSSval && curr_data && !bNoWrite) { if(row < 0 && col < 0) InitSS(); if(last_err_desc) curr_data->SetText(row, col, last_err_desc); else if(src->type == STR) curr_data->SetText(row, col, src->text); else if(src->type == ARR || src->type == RANGEARR || (src->a_data)) curr_data->SetText(row, col, "#ARRAY"); else if(src->type == VAR && src->tptr->type == TXT) curr_data->SetText(row, col, src->tptr->text); else { if(curr_data->SetValue(row, col, src->val)) switch(src->type) { case BOOLVAL: curr_data->etRows[row][col]->type = ET_BOOL; break; } } curr_data->Command(CMD_UPDATE, 0L, 0L); RangeData.cellModified(row, col); } isValid = true; var = src->val; if(src->a_data && src->a_count) { a_data = src->a_data; a_count = src->a_count; } else if(src->text && src->text[0] && src->text != text) { if(text) free(text); text = 0L; text =(char*)memdup(src->text, (int)strlen(src->text)+1, 0); } if(d) GetValue(d); return; } void symrec::SetName(char *nam) { if(name || !nam || !nam[0]) return; name = (char*)memdup(nam, (int)strlen(nam)+1, 0); isValid = false; if((name && curr_data) && (isalpha(name[0]) || name[0] == '$') && isdigit(name[strlen(name)-1])) isSSval=true; } void symrec::InitSS() { AccRange *ar; if(row<0 && col<0 &&(ar = new AccRange(name))) { ar->GetFirst(&col, &row); delete(ar); } } void symrec::NoInit() { char message[200]; #ifdef USE_WIN_SECURE sprintf_s(message, 80, "Accessing variable '%s'\nwithout initialization!\n", name); #else sprintf(message, "Accessing variable '%s'\nwithout initialization!\n", name); #endif yywarn(message, true); } void LockData(bool lockExec, bool lockWrite) { RangeData.Clear(); bNoWrite = lockWrite; bNoExec = lockExec; bNoSS = false; } static void yyerror(char *s) { //called by yyparse on error if(curr_data) curr_data->Command(CMD_ERROR, last_error = s, 0L); else printf("%s\n", s); } static void yyargserr(char *s) { //call from function on argument type mismatch yyerror(s); last_err_desc = "#ARGS"; } static void yyargcnterr(char *s) { //call from function on argument number mismatch static char arg_cnt_err[80]; int cb; cb = rlp_strcpy(arg_cnt_err, 80, "Wrong number of arguments\nin call to "); cb += rlp_strcpy(arg_cnt_err+cb, 80-cb, s); rlp_strcpy(arg_cnt_err+cb, 80-cb, "."); yyargserr(arg_cnt_err); } static void yybadargerr(char *s) { //call from function on argument number mismatch static char bad_arg_err[80]; int cb; cb = rlp_strcpy(bad_arg_err, 80, "Bad arguments in call to function\n"); cb += rlp_strcpy(bad_arg_err+cb, 80-cb, s); rlp_strcpy(bad_arg_err+cb, 80-cb, "."); yyargserr(bad_arg_err); } static char txt_tokenerr[80]; static void yytokenerr(int c) { #ifdef USE_WIN_SECURE sprintf_s(txt_tokenerr, 80, "Illegal character\nor token '%c'\n", (char)c); #else sprintf(txt_tokenerr, "Illegal character\nor token '%c'\n", (char)c); #endif yyerror(txt_tokenerr); } static void make_time(YYSTYPE *dst, double h, double m, double s) { if(!dst || h < 0.0 || 24.0 < h || m < 0.0 || 60.0 < m || s < 0.0 || 60.0 < s) { yyerror("parse error"); return; } dst->val = s/60.0 + m; dst->val = dst->val/60.0 + h; dst->val /= 24.0; dst->type = TIME1; } static char yywarn_text[200]; char *yywarn(char *txt, bool bNew) { if(bNew) { if(txt && txt[0]) { rlp_strcpy(yywarn_text, 200, txt); return yywarn_text; } else { yywarn_text[0] = 0; return 0L; } } else if(yywarn_text[0]) return yywarn_text; 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) { line_res.type = ET_TEXT; line_res.value = 0.0; rlp_strcpy(res_txt, 1000, last_err_desc); } else if(res->type == NUM){ line_res.type = ET_VALUE; line_res.value = res->val; } else if(res->type == BOOLVAL){ line_res.type = ET_BOOL; line_res.value = res->val; } else if(res->type == DATE1){ line_res.type = ET_DATE; line_res.value = res->val; } else if(res->type == TIME1){ line_res.type = ET_TIME; line_res.value = res->val; } else if(res->type == DATETIME1){ line_res.type = ET_DATETIME; line_res.value = res->val; } else if(res->type == STR) { line_res.type = ET_TEXT; line_res.value = 0.0; if(res->text) rlp_strcpy(res_txt, 1000, res->text); } else if((res->type == ARR || res->type == RANGEARR || (res->a_data)) && res->a_count == 1) { line_res.type = ET_VALUE; line_res.value = res->a_data[0]; } else if(res->type == ARR && !(res->a_data) && !(res->a_count)) { line_res.type = ET_VALUE; line_res.value = res->val; } else if(res->type == ARR || res->type == RANGEARR || (res->a_data)) { line_res.type = ET_TEXT; line_res.value = 0.0; line_res.a_data = res->a_data; line_res.a_count = res->a_count; 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; line_res.value = 0.0; if(res->tptr->text) rlp_strcpy(res_txt, 1000, res->tptr->text); } else { line_res.type = ET_VALUE; line_res.value = res->val; } } static char *add_strings(char *st1, char *st2) { char *newstr, *ret; int cb; if(st1 && st2) { if(newstr = (char*)malloc(cb = (int)(strlen(st1) +strlen(st2) +4))) { #ifdef USE_WIN_SECURE sprintf_s(newstr, cb, "%s%s", st1, st2); #else sprintf(newstr, "%s%s", st1, st2); #endif ret = PushString(newstr); free(newstr); return ret; } else return 0L; } if(st1) return st1; if(st2) return st2; return 0L; } static char *string_value(YYSTYPE *exp) { char *st1, tmp[50]; if(exp->type == STR){ st1 = exp->text; } else if(exp->tptr && exp->tptr->type == TXT) { st1 = exp->tptr->text; } else { #ifdef USE_WIN_SECURE sprintf_s(tmp, 50, "%g", exp->val); #else sprintf(tmp,"%g", exp->val); #endif st1 = tmp; } return PushString(st1); } // store syntactical information static void push_syntax() { syntax_info *next; if(!(next = (syntax_info*)calloc(1, sizeof(syntax_info)))) return; if(syntax_level)memcpy(next, syntax_level, sizeof(syntax_info)); next->next=syntax_level; syntax_level = next; } static void pop_syntax() { syntax_info *si; if(si = syntax_level) { syntax_level = si->next; free(si); } } static int eval(YYSTYPE *dst, YYSTYPE *sr) { char *s_buffer; int s_buff_pos, s_yychar, s_yynerrs, length, parse_res; anyResult *ar; if(bNoExec) return 0; if(!sr || !sr->text || !sr->text[0]) return 1; s_buffer = buffer; s_buff_pos = buff_pos; s_yychar = yychar; s_yynerrs = yynerrs; if(!(length = (int)strlen(sr->text)))return 1; parse_level++; if(sr->text[length-1] == ';') buffer = sr->text; else { buffer = (char*)malloc(length+2); rlp_strcpy(buffer, length+1, sr->text); buffer[length++] = ';'; buffer[length] = 0; } if(buffer && buffer[0]){ buff_pos = 0; while(!(parse_res = yyparse()) && buff_pos < length); if(buffer != sr->text) free(buffer); ar = &line_res; buffer = s_buffer; buff_pos = s_buff_pos; yychar = s_yychar; yynerrs = s_yynerrs; } else return 1; dst->a_data = ar->a_data; dst->a_count = ar->a_count; if(parse_res == 2) return 2; else if(parse_res == 3 && sr->type == IBLOCK) return 3; else if(parse_res == 1) return 1; switch(ar->type) { case ET_BOOL: dst->type = BOOLVAL; dst->val = ar->value; dst->text = 0L; break; case ET_VALUE: dst->type = NUM; dst->val = ar->value; dst->text = 0L; break; case ET_TEXT: dst->type = STR; dst->val = 0.0; dst->text = PushString(ar->text); break; default: dst->type = NUM; dst->val = 0.0; dst->text = 0L; break; } parse_level--; return 0; } // more functions static double sign(double v) { if(v > 0.0) return 1.0; if(v < 0.0) return -1.0; return 0.0; } static long idum=0; static double rand1(YYSTYPE *dst, YYSTYPE *src) { if(!dst) return 0.0; dst->type = NUM; return(dst->val = ran2(&idum)); } static double srand(double v) { idum = (long)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); } static double _strlen(YYSTYPE *sr, YYSTYPE *dst, char *dum) { if(dum) yyerror("parse error"); if(!sr || !sr->text) return 0.0; return (double)strlen(sr->text); } #undef min static double min(YYSTYPE *sr) { int i; if(!sr || !sr->a_count) return 0.0; if(sr->a_data && sr->a_data){ for(i = 1, sr->val = sr->a_data[0]; i < sr->a_count; i++) if(sr->a_data[i] < sr->val) sr->val = sr->a_data[i]; } return sr->val; } #undef max static double max(YYSTYPE *sr) { int i; if(!sr || !sr->a_count) return 0.0; if(sr->a_data){ for(i = 1, sr->val = sr->a_data[0]; i < sr->a_count; i++) if(sr->a_data[i] > sr->val) sr->val = sr->a_data[i]; } return sr->val; } static double count(YYSTYPE *sr) { if(!sr) return 0.0; if(sr->a_data) sr->val = (double)sr->a_count; else sr->val = 0.0; return sr->val; } static double sum(YYSTYPE *sr) { int i; if(!sr) return 0.0; if(sr->type == RANGEARR && sr->a_data) { sr->val = RangeData.sum(sr->a_data, sr->a_count); } else if(sr->a_data){ for(i = 0, sr->val = 0.0; i < sr->a_count; i++) sr->val += sr->a_data[i]; } else sr->val = 0.0; return sr->val; } static double mean(YYSTYPE *sr) { if(!sr) return 0.0; if(sr->type == RANGEARR && sr->a_data) { sr->val = RangeData.mean(sr->a_data, sr->a_count); } else if(sr->a_data && sr->a_count){ sr->val = d_amean(sr->a_count, sr->a_data ); } else sr->val = 0.0; return sr->val; } static double kurt(YYSTYPE *sr) { if(!sr) return 0.0; if(sr->a_data && sr->a_count > 3){ sr->val = d_kurt(sr->a_count, sr->a_data ); } else sr->val = 0.0; return sr->val; } static double skew(YYSTYPE *sr) { if(!sr) return 0.0; if(sr->a_data && sr->a_count > 2){ sr->val = d_skew(sr->a_count, sr->a_data ); } else sr->val = 0.0; return sr->val; } static double gmean(YYSTYPE *sr) { int i; if(!sr) return 0.0; if(sr->a_data && sr->a_count){ for(i = 0; i < sr->a_count; i++) if(sr->a_data[i] <= 0.0) { last_err_desc = "#VALUE"; return sr->val = 0.0; } sr->val = d_gmean(sr->a_count, sr->a_data ); } else sr->val = 0.0; return sr->val; } static double hmean(YYSTYPE *sr) { int i; if(!sr) return 0.0; if(sr->a_data && sr->a_count){ for(i = 0; i < sr->a_count; i++) if(sr->a_data[i] <= 0.0) { last_err_desc = "#VALUE"; return sr->val = 0.0; } sr->val = d_hmean(sr->a_count, sr->a_data ); } else sr->val = 0.0; return sr->val; } static double quartile1(YYSTYPE *sr) { if(!sr) return 0.0; if(sr->type == RANGEARR && sr->a_data) { sr->val = RangeData.quartile1(sr->a_data, sr->a_count); } else if(sr->a_data && sr->a_count){ d_quartile(sr->a_count, sr->a_data, &sr->val, 0L, 0L); } else sr->val = 0.0; return sr->val; } static double quartile2(YYSTYPE *sr) { if(!sr) return 0.0; if(sr->type == RANGEARR && sr->a_data) { sr->val = RangeData.quartile2(sr->a_data, sr->a_count); } else if(sr->a_data && sr->a_count){ d_quartile(sr->a_count, sr->a_data, 0L, &sr->val, 0L); } else sr->val = 0.0; return sr->val; } static double quartile3(YYSTYPE *sr) { if(!sr) return 0.0; if(sr->type == RANGEARR && sr->a_data) { sr->val = RangeData.quartile3(sr->a_data, sr->a_count); } else if(sr->a_data && sr->a_count){ d_quartile(sr->a_count, sr->a_data, 0L, 0L, &sr->val); } else sr->val = 0.0; return sr->val; } static double variance(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count){ sr->val = d_variance(sr->a_count, sr->a_data); } return sr->val; } static double stdev(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count){ sr->val = sqrt(d_variance(sr->a_count, sr->a_data)); } return sr->val; } static double sterr(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count){ sr->val = sqrt(d_variance(sr->a_count, sr->a_data))/sqrt((double)sr->a_count); } return sr->val; } static double beta(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = betaf(sr->a_data[0], sr->a_data[1]); } else yyargcnterr("beta(u, v)"); return sr->val; } static double _gammp(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = gammp(sr->a_data[0], sr->a_data[1]); } else yyargcnterr("gammp(a, x)"); return sr->val; } static double _gammq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = gammq(sr->a_data[0], sr->a_data[1]); } else yyargcnterr("gammq(a, x)"); return sr->val; } static double _betai(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 3){ if(sr->a_data[2] < 0.0 || sr->a_data[2] > 1.0) { last_err_desc = "#VALUE"; return sr->val = 0.0; } sr->val = betai(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("betai(a, b, x)"); return sr->val; } static double _bincof(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = bincof(sr->a_data[0], sr->a_data[1]); } else yyargcnterr("bincof(n, k)"); return sr->val; } static double binomdist(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 3){ sr->val = binomdistf(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("binomdist(s, n, p)"); return sr->val; } static double binomfreq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 3){ sr->val = bincof(sr->a_data[1], sr->a_data[0]); sr->val *= pow(sr->a_data[2], sr->a_data[0]); sr->val *= pow(1.0 - sr->a_data[2], sr->a_data[1] - sr->a_data[0]); } else yyargcnterr("binomfreq(s, n, p)"); return sr->val; } static double normdist(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 3){ sr->val = norm_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("normdist(x, mean, SD)"); return sr->val; } static double norminv(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 3) { sr->val = distinv(norm_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], sr->a_data[1]); } else yyargcnterr("norminv(p, mean, SD)"); return sr->val; } static double normfreq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 3){ sr->val = norm_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("normfreq(x, mean, SD)"); return sr->val; } static double expdist(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = exp_dist(sr->a_data[0], sr->a_data[1], 0.0); } else yyargcnterr("expdist(x, l)"); return sr->val; } static double expinv(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2) { sr->val = exp_inv(sr->a_data[0], sr->a_data[1], 0.0); } else yyargcnterr("expinv(p, l)"); return sr->val; } static double expfreq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = exp_freq(sr->a_data[0], sr->a_data[1], 0.0); } else yyargcnterr("expfreq(x, l)"); return sr->val; } static double lognormdist(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 3){ sr->val = lognorm_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("lognormdist(x, mean, SD)"); return sr->val; } static double lognormfreq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 3){ sr->val = lognorm_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("lognormfreq(x, mean, SD)"); return sr->val; } static double lognorminv(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 3) { sr->val = distinv(lognorm_dist, sr->a_data[1], sr->a_data[2], sr->a_data[0], exp(sr->a_data[1])); } else yyargcnterr("lognorminv(p, mean, SD)"); return sr->val; } static double chidist(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = chi_dist(sr->a_data[0], sr->a_data[1], 1.0); } else yyargcnterr("chidist(x, df)"); return sr->val; } static double chifreq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = chi_freq(sr->a_data[0], sr->a_data[1]); } else yyargcnterr("chifreq(x, df)"); return sr->val; } static double chiinv(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2) { sr->val = distinv(chi_dist,sr->a_data[1], 1.0, sr->a_data[0], 2.0); } else yyargcnterr("chiinv(p, df)"); return sr->val; } static double tdist(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = t_dist(sr->a_data[0], sr->a_data[1], 1.0); } else yyargcnterr("tdist(x, df)"); return sr->val; } static double tfreq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = t_freq(sr->a_data[0], sr->a_data[1]); } else yyargcnterr("tfreq(x, df)"); return sr->val; } static double tinv(YYSTYPE *sr) { double dtmp; if(!sr) return 0.0; sr->val = 0.0; dtmp = sr->a_data[1] > 1.0E+10 ? 1.0E+10 : sr->a_data[1]; if(sr->a_data && sr->a_count == 2) { sr->val = fabs(distinv(t_dist,dtmp, 1.0, sr->a_data[0], 2.0)); } else yyargcnterr("tinv(p, df)"); return sr->val; } static double poisdist(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = pois_dist(sr->a_data[0], sr->a_data[1], 1.0); } else yyargcnterr("poisdist(x, mean)"); return sr->val; } static double poisfreq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = exp(log(sr->a_data[1])*sr->a_data[0] - sr->a_data[1] - gammln(1.0 + sr->a_data[0])); } else yyargcnterr("poisfreq(x, mean)"); return sr->val; } static double fdist(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 3){ sr->val = f_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("fdist(x, df1, df2)"); return sr->val; } static double ffreq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 3){ sr->val = f_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("ffreq(x, df1, df2)"); return sr->val; } static double finv(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0; if(sr->a_data && sr->a_count == 3){ sr->val = distinv(f_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], 2.0); } else yyargcnterr("finv(p, df1, df2)"); return sr->val; } static double weibdist(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = weib_dist(sr->a_data[0], sr->a_data[1], 1.0); } if(sr->a_data && sr->a_count == 3){ sr->val = weib_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("weibdist(x, shape[, scale=1])"); return sr->val; } static double weibfreq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = weib_freq(sr->a_data[0], sr->a_data[1], 1.0); } if(sr->a_data && sr->a_count == 3){ sr->val = weib_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("weibfreq(x, shape[, scale=1])"); return sr->val; } static double weibinv(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0; if(sr->a_data && sr->a_count == 2){ sr->val = distinv(weib_dist,sr->a_data[1], 1.0, sr->a_data[0], 1.0); } else if(sr->a_data && sr->a_count == 3){ sr->val = distinv(weib_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0],sr->a_data[2]); } else yyargcnterr("weibinv(p, shape[, scale=1])"); 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; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = cauch_dist(sr->a_data[0], sr->a_data[1], 1.0); } else if(sr->a_data && sr->a_count == 3){ sr->val = cauch_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("cauchydist(x, location[, scale=1])"); return sr->val; } static double cauchyfreq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = cauch_freq(sr->a_data[0], sr->a_data[1], 1.0); } else if(sr->a_data && sr->a_count == 3){ sr->val = cauch_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("cauchyfreq(x, location[, scale=1])"); return sr->val; } static double cauchyinv(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0; if(sr->a_data && sr->a_count == 2){ sr->val = distinv(cauch_dist,sr->a_data[1], 1.0, sr->a_data[0], sr->a_data[1]); } else if(sr->a_data && sr->a_count == 3){ sr->val = distinv(cauch_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], sr->a_data[1]); } else yyargcnterr("cauchyinv(p, location[, scale=1])"); return sr->val; } static double logisdist(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = logis_dist(sr->a_data[0], sr->a_data[1], 1.0); } else if(sr->a_data && sr->a_count == 3){ sr->val = logis_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("logisdist(x, location[, scale=1])"); return sr->val; } static double logisfreq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = logis_freq(sr->a_data[0], sr->a_data[1], 1.0); } else if(sr->a_data && sr->a_count == 3){ sr->val = logis_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("logisfreq(x, location[, scale=1])"); return sr->val; } static double logisinv(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0; if(sr->a_data && sr->a_count == 2){ sr->val = distinv(logis_dist,sr->a_data[1], 1.0, sr->a_data[0], sr->a_data[1]); } else if(sr->a_data && sr->a_count == 3){ sr->val = distinv(logis_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], sr->a_data[1]); } else yyargcnterr("logisinv(p, location[, scale=1])"); return sr->val; } static void pearson(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst) { char *dest; double *arr; if(!sr1 || !sr2) return; if(dst && !bNoWrite) dest = dst->text; else dest = 0L; if(dst && dst->a_data && dst->a_count > 3) arr = dst->a_data; else arr = 0L; lval->val = 0.0; lval->type = NUM; if(sr1->text && sr2->text)range_array2(sr1, sr2); if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){ lval->val = d_pearson(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr); } else yybadargerr("pearson(range1; range2 [;\"dest\"])"); if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count); } static void spearman(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst) { char *dest; double *arr; if(!sr1 || !sr2) return; if(dst && !bNoWrite) dest = dst->text; else dest = 0L; if(dst && dst->a_data && dst->a_count > 5) arr = dst->a_data; else arr = 0L; lval->val = 0.0; lval->type = NUM; if(sr1->text && sr2->text)range_array2(sr1, sr2); if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){ lval->val = d_spearman(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr); } else yybadargerr("spearman(range1; range2 [;\"dest\"])"); if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count); } static void kendall(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst) { char *dest; double *arr; if(!sr1 || !sr2) return; if(dst && !bNoWrite) dest = dst->text; else dest = 0L; if(dst && dst->a_data && dst->a_count > 5) arr = dst->a_data; else arr = 0L; lval->val = 0.0; lval->type = NUM; if(sr1->text && sr2->text)range_array2(sr1, sr2); if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){ lval->val = d_kendall(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr); } else yybadargerr("kendall(range1; range2 [;\"dest\"])"); if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count); } static void regression(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst) { char *dest; double *arr; if(!sr1 || !sr2) return; if(dst && !bNoWrite) dest = dst->text; else dest = 0L; if(dst && dst->a_data && dst->a_count > 9) arr = dst->a_data; else arr = 0L; lval->val = 0.0; lval->type = NUM; if(sr1->text && sr2->text)range_array2(sr1, sr2); if(!dest && !arr) yyargserr("No destination range in call to function\nregression(range1; range2; \"dest\")."); if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){ lval->val = d_regression(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr); } else yybadargerr("regression(range1; range2; \"dest\")"); if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count); } static void _covar(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2) { if(!sr1 || !sr2) return; lval->val = 0.0; if(sr1->text && sr2->text)range_array2(sr1, sr2); if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){ lval->val = d_covar(sr1->a_data, sr2->a_data, sr1->a_count, 0L, curr_data); } else yybadargerr("covar(range1; range2)"); return; } static void ttest(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst) { char *dest; double *arr; if(!sr1 || !sr2) return; if(dst && !bNoWrite) dest = dst->text; else dest = 0L; if(dst && dst->a_data && dst->a_count > 9) arr = dst->a_data; else arr = 0L; lval->val = 0.0; lval->type = NUM; if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr2->a_count > 1){ lval->val = d_ttest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data, arr); } else yybadargerr("ttest(array1; array2[;\"dest\"])"); if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count); } static void ttest2(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst) { char *dest; double *arr; if(!sr1 || !sr2) return; if(dst && !bNoWrite) dest = dst->text; else dest = 0L; if(dst && dst->a_data && dst->a_count > 6) arr = dst->a_data; else arr = 0L; lval->val = 0.0; lval->type = NUM; if(sr1->text && sr2->text)range_array2(sr1, sr2); if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr2->a_count == sr1->a_count){ lval->val = sr2->val = d_ttest2(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr); } else yybadargerr("ttest2(range1; range2[;\"dest\"])"); if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count); } static void utest(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst) { char *dest; double *arr; if(!sr1 || !sr2) return; if(dst && !bNoWrite) dest = dst->text; else dest = 0L; if(dst && dst->a_data && dst->a_count > 9) arr = dst->a_data; else arr = 0L; lval->val = 0.0; lval->type = NUM; if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr2->a_count > 1){ lval->val = d_utest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data, arr); } else yybadargerr("utest2(array1; array2[;\"dest\"])"); if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count); } static void ftest(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst) { char *dest; double *arr; if(!sr1 || !sr2) return; if(dst && !bNoWrite) dest = dst->text; else dest = 0L; if(dst && dst->a_data && dst->a_count > 9) arr = dst->a_data; else arr = 0L; lval->val = 0.0; lval->type = NUM; if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count > 1){ lval->val = d_ftest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data, arr); } else yybadargerr("ftest(range1; range2[;\"dest\"])"); } static double p_tukey(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0; if(sr->a_data && sr->a_count == 4){ sr->val = ptukey(sr->a_data[0], sr->a_data[3], sr->a_data[1], sr->a_data[2], 1, 0); } else if(sr->a_data && sr->a_count == 3){ sr->val = ptukey(sr->a_data[0], 1.0, sr->a_data[1], sr->a_data[2], 1, 0); } else yyargcnterr("ptukey(q, nm, df[, nr = 1])"); return sr->val; } static double q_tukey(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0; if(sr->a_data && sr->a_count == 4){ sr->val = qtukey(sr->a_data[0], sr->a_data[3], sr->a_data[1], sr->a_data[2], 1, 0); } else if(sr->a_data && sr->a_count == 3){ sr->val = qtukey(sr->a_data[0], 1.0, sr->a_data[1], sr->a_data[2], 1, 0); } else yyargcnterr("qtukey(p, nm, df[, nr = 1])"); return sr->val; } static double fill(YYSTYPE *sr, char *dest) { AccRange *ar; int i, r, c; if(!sr || !sr->a_data || !sr->a_count || !dest || !dest[0] || bNoWrite) return 0.0; if(ar = new AccRange(dest)) { for(i=0, ar->GetFirst(&c, &r); ar->GetNext(&c, &r) && i < sr->a_count; i++) { curr_data->SetValue(r, c, sr->a_data[i]); } delete ar; } return sr->val = i; } static void datestr(YYSTYPE *dst, YYSTYPE *src, char *fmt) { dst->text = PushString(value_date(src->val, fmt)); } static double dateval(YYSTYPE *sr, YYSTYPE *dst, char *fmt) { if(!sr || !sr->text) return 0.0; if(fmt && fmt[0] && date_value(sr->text, fmt, &dst->val)) return dst->val; if(date_value(sr->text, 0L, &dst->val)) return dst->val; else return dst->val = 0.0; } static double leapyear(double year) { int y = (int)year; return (double)((y % 4 == 0 && y % 100 != 0) || y % 400 == 0); } static void today(YYSTYPE *dst, YYSTYPE *src) { if(src) yyerror("parse error"); if(!dst) return; dst->val = floor(now_today()); dst->type = DATE1; } static void now(YYSTYPE *dst, YYSTYPE *src) { if(src) yyerror("parse error"); if(!dst) return; dst->val = now_today(); dst->val -= floor(dst->val); dst->type = TIME1; } static double year(double dv) { int res; split_date(dv, &res, 0L, 0L, 0L, 0L, 0L, 0L, 0L); return (double)res; } static double month(double dv) { int res; split_date(dv, 0L, &res, 0L, 0L, 0L, 0L, 0L, 0L); return (double)res; } static double dom(double dv) { int res; split_date(dv, 0L, 0L, &res, 0L, 0L, 0L, 0L, 0L); return (double)res; } static double dow(double dv) { int res; split_date(dv, 0L, 0L, 0L, &res, 0L, 0L, 0L, 0L); return (double)res; } static double doy(double dv) { int res; split_date(dv, 0L, 0L, 0L, 0L, &res, 0L, 0L, 0L); return (double)res; } static double hours(double dv) { int res; split_date(dv, 0L, 0L, 0L, 0L, 0L, &res, 0L, 0L); return (double)res; } static double minutes(double dv) { int res; split_date(dv, 0L, 0L, 0L, 0L, 0L, 0L, &res, 0L); return (double)res; } static double seconds(double dv) { double res; split_date(dv, 0L, 0L, 0L, 0L, 0L, 0L, 0L, &res); if(res < 0.0005) res = 0.0; return res; } static void fdate(YYSTYPE *dst, YYSTYPE *src) { if(!dst || !src || src->type == ARR || src->type == RANGEARR || src->type == STR) { yyerror("parse error"); return; } dst->type = DATE1; dst->val = src->val; } static void fdatetime(YYSTYPE *dst, YYSTYPE *src) { if(!dst || !src || src->type == ARR || src->type == RANGEARR || src->type == STR) { yyerror("parse error"); return; } dst->type = DATETIME1; dst->val = src->val; } static void ftime(YYSTYPE *dst, YYSTYPE *src) { if(!dst || !src || src->type == ARR || src->type == RANGEARR || src->type == STR) { yyerror("parse error"); return; } dst->type = TIME1; dst->val = src->val; } static void invert(YYSTYPE *dst, YYSTYPE *src) { int i; if(!dst || !src) return; switch(src->a_count) { case 0: dst->a_data = PushArray((double*)malloc(sizeof(double))); dst->a_count = 1; dst->a_data[0] = dst->val = src->val; break; case 1: dst->a_data = PushArray((double*)malloc(sizeof(double))); dst->a_count = 1; dst->a_data[0] = dst->val = src->a_data[0]; break; default: dst->a_data = PushArray((double*)memdup(src->a_data, src->a_count * sizeof(double), 0)); dst->a_count = src->a_count; for(i = 0; i < src->a_count; i++) dst->a_data[i] = src->a_data[src->a_count-1-i]; } } static void asort(YYSTYPE *dst, YYSTYPE *src) { if(!dst || !src) return; dst->type = ARR; switch(src->a_count) { case 0: dst->a_data = PushArray((double*)malloc(sizeof(double))); dst->a_count = 1; dst->a_data[0] = dst->val = src->val; break; case 1: dst->a_data = PushArray((double*)malloc(sizeof(double))); dst->a_count = 1; dst->a_data[0] = dst->val = src->a_data[0]; break; default: dst->a_data = PushArray((double*)memdup(src->a_data, src->a_count * sizeof(double), 0)); dst->a_count = src->a_count; SortArray(dst->a_count, dst->a_data); } } static void _randarr(YYSTYPE *dst, YYSTYPE *src) { if(!dst || !src) return; dst->type = ARR; switch(src->a_count) { case 0: dst->a_data = PushArray((double*)malloc(sizeof(double))); dst->a_count = 1; dst->a_data[0] = dst->val = src->val; break; case 1: dst->a_data = PushArray((double*)malloc(sizeof(double))); dst->a_count = 1; dst->a_data[0] = dst->val = src->a_data[0]; break; default: dst->a_data = randarr(src->a_data, src->a_count, &idum); dst->a_count = src->a_count; } } static void _resample(YYSTYPE *dst, YYSTYPE *src) { if(!dst || !src) return; dst->type = ARR; switch(src->a_count) { case 0: dst->a_data = PushArray((double*)malloc(sizeof(double))); dst->a_count = 1; dst->a_data[0] = dst->val = src->val; break; case 1: dst->a_data = PushArray((double*)malloc(sizeof(double))); dst->a_count = 1; dst->a_data[0] = dst->val = src->a_data[0]; break; default: dst->a_data = resample(src->a_data, src->a_count, &idum); dst->a_count = src->a_count; } } static void mkarr(YYSTYPE *res, YYSTYPE *sr1, YYSTYPE *sr2, char*fmt) { AccRange *rD; int i, n, r, c; anyResult ares; if(fmt || !sr2 || !sr1 || !sr1->text) yyargcnterr("mkarr(range, MD)"); if(!(rD = new AccRange(sr1->text)) || !(n = rD->CountItems())) { yybadargerr("mkarr(range, MD)"); } res->a_data = PushArray((double*)calloc(n, sizeof(double))); for(i = 0, rD->GetFirst(&c, &r); i < n; i++) { rD->GetNext(&c, &r); if(curr_data->GetResult(&ares, r, c,false) && ares.type == ET_VALUE) res->a_data[i] = ares.value; else res->a_data[i] = sr2->val; res->a_count = i; } if(rD) delete rD; } static void asort2(YYSTYPE *res, YYSTYPE *sr1, YYSTYPE *sr2, char *fmt) { int n; res->val = 0.0; res->type = NUM; if(!sr1 || !sr2 || !sr1->a_data || !sr2->a_data) return; n = sr1->a_count > sr2->a_count ? sr2->a_count : sr1->a_count; res->val = (double)n; if(n >1) SortArray2(n, sr1->a_data, sr2->a_data); return; } static double _crank(YYSTYPE *src) { double tmp = -1.0; if(!src) return tmp; tmp = 0.0; if(src->a_data && src->a_count > 1.0)crank(src->a_count, src->a_data, &tmp); if(src->type == RANGEARR) RangeData.rmData(src->a_data, src->a_count); return tmp; } static void subarr(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2, YYSTYPE *src3) { int i, pos2; if(!src1->a_data) yybadargerr("subarr(array; pos1[; pos2])"); else { if(src3) pos2 = (int)(src3->val); else pos2 = src1->a_count; dst->type = ARR; dst->a_data = PushArray((double*)malloc(src1->a_count*sizeof(double))); for(i = (int)(src2->val), dst->a_count = 0; i <= pos2 && i < src1->a_count; i++) { dst->a_data[dst->a_count++] = src1->a_data[i]; } } } static void ltrim(YYSTYPE *dst, YYSTYPE *src) { if(!src || !dst || !src->text) return; dst->text = PushString(str_ltrim(src->text)); dst->type = STR; dst->val = 0.0; } static void rtrim(YYSTYPE *dst, YYSTYPE *src) { if(!src || !dst || !src->text) return; dst->text = PushString(str_rtrim(src->text)); dst->type = STR; dst->val = 0.0; } static void trim(YYSTYPE *dst, YYSTYPE *src) { if(!src || !dst || !src->text) return; dst->text = PushString(str_trim(src->text)); dst->type = STR; dst->val = 0.0; } static double rank(YYSTYPE *sr) { if(sr->a_count < 2 || !sr->a_data) return 0.0; return d_rank(sr->a_count-1, sr->a_data+1, sr->a_data[0]); } static double classes(double start, double step, YYSTYPE *src, YYSTYPE *dest) { return d_classes(curr_data, start, step, src->a_data, src->a_count, dest->text); } static void _strpos(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2) { dst->type = NUM; dst->val = (double)strpos(src1->text, src2->text); } static void strrepl(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2, YYSTYPE *src3) { if(src3) { dst->type = STR; dst->text = PushString(strreplace(src1->text, src2->text, src3->text)); } else yyargcnterr("strrepl(search; replace; haystack)"); } static void _substr(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2, YYSTYPE *src3) { if(src3) { dst->type = STR; dst->text = PushString(substr(src1->text, (int)(src2->val), (int)(src3->val))); } else yyargcnterr("substr(text; pos1; pos2)"); } static double asc(YYSTYPE *sr, YYSTYPE *dst, char *dum) { if(dum) yyerror("parse error"); if(!sr || !sr->text) return 0.0; return (double)((unsigned char)(sr->text[0])); } static void chr(YYSTYPE *dst, YYSTYPE *src) { char tpl[] = "?\0"; if(!dst || !src) return; tpl[0] = (src->val >=32.0 && src->val <= 255.0) ? (char)(src->val) : '?'; dst->type = STR; dst->text = PushString(tpl); } static void to_upper(YYSTYPE *dst, YYSTYPE *src) { int i; if(!dst || !src) return; dst->type = STR; if(src->text && src->text[0]) { dst->text = PushString(src->text); for(i = 0; src->text[i]; i++) dst->text[i] = toupper(src->text[i]); } else dst->text = 0L; } static void to_lower(YYSTYPE *dst, YYSTYPE *src) { int i; if(!dst || !src) return; dst->type = STR; if(src->text && src->text[0]) { dst->text = PushString(src->text); for(i = 0; src->text[i]; i++) dst->text[i] = tolower(src->text[i]); } else dst->text = 0L; } static void uc_first(YYSTYPE *dst, YYSTYPE *src) { if(!dst || !src) return; dst->type = STR; if(src->text && src->text[0]) { dst->text = PushString(src->text); dst->text[0] = toupper(src->text[0]); } else dst->text = 0L; } static void uc_word(YYSTYPE *dst, YYSTYPE *src) { int i; if(!dst || !src) return; dst->type = STR; if(src->text && src->text[0]) { dst->text = PushString(src->text); dst->text[0] = toupper(src->text[0]); for(i = 1; src->text[i]; i++) { if(isalpha(src->text[i]) && src->text[i-1] < 'A') dst->text[i] = toupper(src->text[i]); } } else dst->text = 0L; } static void exec_block(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2, bool namespc) { char *cmd = 0L; int cmd_pos = 0, cmd_size, r, c; AccRange *ar = 0L; anyResult res, *eres; YYSTYPE evsrc, evdst; if(bNoExec) return; if(!src1 || !src1->text || !src1->text[0]) return; if((cmd =(char*)malloc((cmd_size = 1000) * sizeof(char))) && (ar = new AccRange(src1->text))) { if(src2 && src2->text[0] && src2->text[0]) { add_to_buff(&cmd, &cmd_pos, &cmd_size, src2->text, 0); while(cmd_pos && cmd[cmd_pos-1] < 33) cmd_pos--; if(cmd_pos && cmd[cmd_pos-1] != ';') cmd[cmd_pos++] = ';'; } cmd[cmd_pos] = 0; ar->GetFirst(&c, &r); ar->GetNext(&c, &r); do { curr_data->GetResult(&res, r, c, false); switch(res.type) { case ET_VALUE: //numerical value if(res.value == -HUGE_VAL) add_to_buff(&cmd, &cmd_pos, &cmd_size, "-inf", 4); else if(res.value == HUGE_VAL) add_to_buff(&cmd, &cmd_pos, &cmd_size, "inf", 3); else add_dbl_to_buff(&cmd, &cmd_pos, &cmd_size, res.value, false); break; case ET_TEXT: //text cell if(res.text && res.text[0]) { if(res.text[0] == res.text[1] && res.text[0] == '/') ar->NextRow(&r); else add_to_buff(&cmd, &cmd_pos, &cmd_size, res.text, 0); } break; } }while(ar->GetNext(&c, &r)); if(namespc) { eres = do_formula(curr_data, cmd); } else { memset(&evsrc, 0, sizeof(YYSTYPE)); memset(&evdst, 0, sizeof(YYSTYPE)); evsrc.text = cmd; eval(&evdst, &evsrc); eres = &line_res; } switch(eres->type) { case ET_BOOL: dst->type = BOOLVAL; dst->val = eres->value; dst->text = 0L; break; case ET_VALUE: dst->type = NUM; dst->val = eres->value; dst->text = 0L; break; case ET_TEXT: dst->type = STR; dst->val = 0.0; dst->text = PushString(eres->text); break; default: dst->type = NUM; dst->val = 0.0; dst->text = 0L; break; } } if(cmd) free(cmd); if(ar) delete ar; } static void exec(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2) { exec_block(dst, src1, src2, true); } static void call(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2) { exec_block(dst, src1, src2, false); } // Store strings in a list static char **str_list = 0L; static int n_str = 0; static char *PushString(char *text) { if(text && text[0]) { if(str_list = (char**)realloc(str_list, sizeof(char*)*(n_str+1))) str_list[n_str] = (char*)memdup(text, (int)strlen(text)+1, 0); return str_list[n_str++]; } return 0L; } //Store arrays in a list static double **arr_list = 0L; static int n_arr = 0; static double *PushArray(double *arr) { if(arr) { if(arr_list = (double**)realloc(arr_list, sizeof(double*)*(n_arr+1))){ arr_list[n_arr] = arr; return arr_list[n_arr++]; } } return 0L; } static double *ReallocArray(double *arr, int size) { int i; if(arr && size) { for(i = 0; i < n_arr; i++) if(arr_list[i] == arr) { arr_list[i] = (double*)realloc(arr, size); return arr_list[i]; } arr = (double*)realloc(arr, size); return PushArray(arr); } return 0L; } //The symbol table: a chain of `struct symrec' static symrec *sym_table, *sym_tab_first; //Rearrange function table with previously used functions in front void ArrangeFunctions() { symrec *ptr, *ptr1, *ptr2, *next; for(ptr = sym_table, ptr1 = ptr2 = 0L; (ptr); ) { next = ptr->next; if(ptr->name) { ptr->next = ptr1; ptr1 = ptr; } else { ptr->next = ptr2; ptr2 = ptr; } ptr = next; } for(sym_table = 0L, ptr = ptr2; (ptr); ){ next = ptr->next; ptr->next = sym_table; sym_table = ptr; ptr = next; } for(ptr = ptr1; (ptr); ){ next = ptr->next; ptr->next = sym_table; sym_table = ptr; ptr = next; } sym_tab_first = sym_table; bRecent = false; } // Put arithmetic functions and predifened variables in table #define INIT_SYM(TYP,NAM,FNC) {TYP,NAM,(double(*)(double))&FNC} void InitArithFuncs(DataObj *d) { struct fdef { int f_type; char *name; double (*fnct)(double); }; fdef fncts[] = { 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), INIT_SYM(AFNCT, "cauchyfreq", cauchyfreq), INIT_SYM(AFNCT, "cauchyinv", cauchyinv), INIT_SYM(AFNCT, "logisdist", logisdist), INIT_SYM(AFNCT, "logisfreq", logisfreq), INIT_SYM(AFNCT, "logisinv", logisinv), INIT_SYM(YYFNC2, "call", call), INIT_SYM(AFNCT, "ptukey", p_tukey), INIT_SYM(AFNCT, "qtukey", q_tukey), INIT_SYM(YYFNC, "toupper", to_upper), INIT_SYM(YYFNC, "tolower", to_lower), INIT_SYM(YYFNC, "ucfirst", uc_first), INIT_SYM(YYFNC, "ucword", uc_word), INIT_SYM(SFNCT, "asc", asc), INIT_SYM(YYFNC, "chr", chr), INIT_SYM(YYFNC3, "strrepl",strrepl), INIT_SYM(YYFNC3, "substr", _substr), INIT_SYM(YYFNC2, "strpos",_strpos), INIT_SYM(FUNC4, "classes", classes), INIT_SYM(AFNCT, "rank", rank), INIT_SYM(YYFNC, "ltrim", ltrim), INIT_SYM(YYFNC, "rtrim", rtrim), INIT_SYM(YYFNC, "trim", trim), INIT_SYM(YYFNC, "asort", asort), INIT_SYM(AFNCT, "crank", _crank), INIT_SYM(SRFUNC, "datestr", datestr), INIT_SYM(SFNCT, "dateval", dateval), INIT_SYM(BFNCT, "leapyear", leapyear), INIT_SYM(YYFNC, "today", today), INIT_SYM(YYFNC, "now", now), INIT_SYM(FNCT, "year", year), INIT_SYM(FNCT, "month", month), INIT_SYM(FNCT, "dom", dom), INIT_SYM(FNCT, "dow", dow), INIT_SYM(FNCT, "doy", doy), INIT_SYM(FNCT, "hours", hours), INIT_SYM(FNCT, "minutes", minutes), INIT_SYM(FNCT, "seconds", seconds), INIT_SYM(YYFNC, "date", fdate), INIT_SYM(YYFNC, "datetime", fdatetime), INIT_SYM(YYFNC, "time", ftime), INIT_SYM(FUNC1, "fill", fill), INIT_SYM(YYFNC3, "pearson", pearson), INIT_SYM(YYFNC3, "spearman", spearman), INIT_SYM(YYFNC3, "kendall", kendall), INIT_SYM(YYFNC3, "correl", pearson), INIT_SYM(YYFNC3, "regression", regression), INIT_SYM(YYFNC2, "covar", _covar), INIT_SYM(YYFNC2, "exec", exec), INIT_SYM(YYFNC3, "utest", utest), INIT_SYM(YYFNC3, "ttest2", ttest2), INIT_SYM(YYFNC3, "ttest", ttest), INIT_SYM(YYFNC3, "ftest", ftest), INIT_SYM(AFNCT, "variance", variance), INIT_SYM(AFNCT, "stdev", stdev), INIT_SYM(AFNCT, "sterr", sterr), INIT_SYM(AFNCT, "min", min), INIT_SYM(AFNCT, "max", max), INIT_SYM(AFNCT, "count", count), INIT_SYM(AFNCT, "sum", sum), INIT_SYM(AFNCT, "mean", mean), INIT_SYM(AFNCT, "kurt", kurt), INIT_SYM(AFNCT, "skew", skew), INIT_SYM(AFNCT, "median", quartile2), INIT_SYM(AFNCT, "quartile1", quartile1), INIT_SYM(AFNCT, "quartile2",quartile2), INIT_SYM(AFNCT, "quartile3", quartile3), INIT_SYM(AFNCT, "gmean", gmean), INIT_SYM(AFNCT, "hmean", hmean), INIT_SYM(AFNCT, "tdist", tdist), INIT_SYM(AFNCT, "tfreq", tfreq), INIT_SYM(AFNCT, "tinv", tinv), INIT_SYM(YYFNC, "invert", invert), INIT_SYM(AFNCT, "poisdist", poisdist), INIT_SYM(AFNCT, "poisfreq", poisfreq), INIT_SYM(AFNCT, "expdist", expdist), INIT_SYM(AFNCT, "expfreq", expfreq), INIT_SYM(AFNCT, "expinv", expinv), INIT_SYM(AFNCT, "fdist", fdist), INIT_SYM(AFNCT, "ffreq", ffreq), INIT_SYM(YYFNC3, "subarr", subarr), INIT_SYM(AFNCT, "finv", finv), INIT_SYM(AFNCT, "gammp", _gammp), INIT_SYM(AFNCT, "gammq", _gammq), INIT_SYM(AFNCT, "beta", beta), INIT_SYM(AFNCT, "betai", _betai), INIT_SYM(AFNCT, "bincof", _bincof), INIT_SYM(AFNCT, "binomdist",binomdist), INIT_SYM(AFNCT, "binomfreq",binomfreq), INIT_SYM(AFNCT, "normdist", normdist), INIT_SYM(AFNCT, "average", mean), INIT_SYM(AFNCT, "norminv", norminv), INIT_SYM(AFNCT, "normfreq", normfreq), INIT_SYM(AFNCT, "lognormdist", lognormdist), INIT_SYM(AFNCT, "lognormfreq", lognormfreq), INIT_SYM(AFNCT, "lognorminv",lognorminv), INIT_SYM(AFNCT, "chidist", chidist), INIT_SYM(AFNCT, "chifreq", chifreq), INIT_SYM(YYFNC2, "asort2", asort2), INIT_SYM(AFNCT, "chiinv", chiinv), INIT_SYM(SFNCT, "strlen", _strlen), INIT_SYM(YYFNC, "eval", eval), INIT_SYM(FNCT, "erf", errf), INIT_SYM(FNCT, "erfc", errfc), INIT_SYM(FNCT, "sign", sign), INIT_SYM(FNCT, "gammaln", gammln), INIT_SYM(FNCT, "factorial", factorial), INIT_SYM(YYFNC, "rand", rand1), INIT_SYM(FNCT, "srand", srand), INIT_SYM(FNCT, "floor", floor), INIT_SYM(FNCT, "abs", fabs), INIT_SYM(FNCT, "asin", asin), INIT_SYM(FNCT, "acos", acos), INIT_SYM(FNCT, "atan", atan), INIT_SYM(FNCT, "sinh", sinh), INIT_SYM(FNCT, "cosh", cosh), INIT_SYM(FNCT, "tanh", tanh), INIT_SYM(FNCT, "sin", sin), INIT_SYM(FNCT, "cos", cos), INIT_SYM(FNCT, "tan", tan), INIT_SYM(FNCT, "log10", log10), INIT_SYM(FNCT, "ln", log), INIT_SYM(FNCT, "log", log), INIT_SYM(FNCT, "exp", exp), INIT_SYM(FNCT, "sqrt", sqrt), INIT_SYM(0, 0L, nop)}; int i; symrec *ptr, *next; if(d) curr_data = d; if(sym_table) { for (ptr = sym_table; ptr != (symrec *) 0;){ if(ptr) { next = ptr->next; delete (ptr); } ptr = next; } sym_table = sym_tab_first = (symrec *) 0; } for (i = 0; fncts[i].name; i++) { ptr = putsym (HashValue((unsigned char*) fncts[i].name), Hash2((unsigned char*) fncts[i].name), fncts[i].f_type); ptr->fnctptr = (double (*)(...))fncts[i].fnct; } ptr = putsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv"), VAR); ptr->SetValue(1.0); sym_tab_first = sym_table; } #undef INIT_SYM static void init_table (void) { str_list = 0L; n_str = 0; arr_list = 0L; n_arr = 0; push_syntax(); } static void clear_table() { int i; if(str_list) { for(i = 0; i < n_str; i++) if(str_list[i]) free(str_list[i]); free(str_list); str_list = 0L; n_str = 0; } if(arr_list) { for(i = 0; i < n_arr; i++) if(arr_list[i]) free(arr_list[i]); free(arr_list); arr_list = 0L; n_arr = 0; } pop_syntax(); } static symrec * putsym (unsigned int h_name, unsigned int h2_name, int sym_type) { sym_table = new symrec(h_name, h2_name, sym_type, sym_table); return sym_table; } static symrec * getsym (unsigned int h_name, unsigned int h2_name, char *sym_name) { symrec *ptr; if(!h_name) return 0; for (ptr = sym_table; ptr != (symrec *) 0; ptr = (symrec *)ptr->next) { if (ptr->h_name == h_name && ptr->h2_name == h2_name){ if(sym_name && !ptr->name) { ptr->SetName(sym_name); bRecent = true; } return ptr; } //predefined variables rarely end on a digit else if(ptr == sym_tab_first) { if(sym_name && isdigit(sym_name[strlen(sym_name)-1]) && strlen(sym_name) < 5) return 0; } } return 0; } static int push(YYSTYPE *res, YYSTYPE *val) { double *tmparr; if(res->type == RANGEARR || res->text) { if((tmparr = res->a_data) && (res->a_data = PushArray((double*)malloc((res->a_count+1)*sizeof(double))))){ memcpy(res->a_data, tmparr, res->a_count * sizeof(double)); res->type = ARR; res->text = 0L; } } if(val->a_data) { if(!(res->a_data)) { if(!(val->a_data=ReallocArray(val->a_data, (val->a_count+2)*sizeof(double))))return 0; val->a_data[val->a_count++] = res->val; res->a_data = val->a_data; res->a_count = val->a_count; val->a_data = 0L; val->a_count = 0; val->val = res->val; return 1; } else { if(!(res->a_data=ReallocArray(res->a_data, (val->a_count+res->a_count)*sizeof(double))))return 0; memcpy(&res->a_data[res->a_count], val->a_data, val->a_count*sizeof(double)); res->a_count += val->a_count; val->a_data = 0L; val->a_count = 0; return 1; } } if(!(res->a_data )){ if(!(res->a_data = PushArray((double*)malloc(2*sizeof(double)))))return 0; res->a_data[0] = res->val; res->a_data[1] = val->val; res->a_count = 2; return 1; } else { if(!(res->a_data = ReallocArray(res->a_data, (res->a_count+2)*sizeof(double))))return 0; res->a_data[res->a_count] = val->val; res->a_count++; return 1; } return 0; } static int range_array(YYSTYPE *res, char *range) { RangeData.GetData(range, &res->a_data, &res->a_count, &res->text); res->val = 0.0; res->type = RANGEARR; return 1; } static int range_array2(YYSTYPE *res1, YYSTYPE *res2) { AccRange *r1, *r2; int row1, col1, row2, col2; anyResult ares1, ares2; char *range1, *range2; range1 = res1->text; range2 = res2->text; if(!range1 || !range1[0] || !range2 || !range2[0] || !(r1 = new AccRange(range1)) || !(r2 = new AccRange(range2))) return 0; if(!r1->GetFirst(&col1, &row1) || !(res1->a_data = PushArray((double*)malloc(r1->CountItems() * sizeof(double))))) { delete(r1); delete(r2); return 0; } if(!r2->GetFirst(&col2, &row2) || !(res2->a_data = PushArray((double*)malloc(r2->CountItems() * sizeof(double))))) { delete(r1); delete(r2); return 0; } parse_level++; for(res1->a_count = res2->a_count = 0; r1->GetNext(&col1, &row1) && r2->GetNext(&col2, &row2); ) { if(curr_data->GetResult(&ares1, row1, col1, parse_level > MAX_PARSE) && curr_data->GetResult(&ares2, row2, col2, parse_level > MAX_PARSE) && (ares1.type==ET_VALUE || ares1.type==ET_TIME || ares1.type==ET_DATE || ares1.type==ET_DATETIME || ares1.type==ET_BOOL) && (ares2.type==ET_VALUE || ares2.type==ET_TIME || ares2.type==ET_DATE || ares2.type==ET_DATETIME || ares2.type==ET_BOOL)){ res1->a_data[res1->a_count++] = ares1.value; res2->a_data[res2->a_count++] = ares2.value; } } parse_level--; res1->type = res2->type = ARR; delete(r1); delete(r2); return 1; } static YYSTYPE *proc_clause(YYSTYPE *res) { int i, n, o_pos; char *o_cmd; double *n_data; if(!(syntax_level) || !syntax_level->cl1 || syntax_level->cl2 <= syntax_level->cl1) return res; if(!res->text) return res; if(!res->a_data && (res->a_data = PushArray((double*)malloc(sizeof(double))))) { res->a_data[0] = res->type == VAR && res->tptr ? res->tptr->GetValue() : res->val; res->a_count = 1; } else if(!res->a_data) return res; if(!(n_data = PushArray((double*)malloc(res->a_count * sizeof(double))))) return res; o_pos = buff_pos; o_cmd = buffer; for(i = n = 0; i < res->a_count; i++) { buffer = res->text; buff_pos = 0; if(!syntax_level) break; syntax_level->clval = res->a_data[i]; yyparse(); if((line_res.type == ET_VALUE || line_res.type == ET_BOOL) && line_res.value != 0.0) n_data[n++] = res->a_data[i]; } res->a_data = n_data; res->a_count = n; res->text=0L; syntax_level->cl1 = syntax_level->cl2 = 0; buffer = o_cmd; buff_pos = o_pos; return res; } static void exec_clause(YYSTYPE *res) { int i, j; char *cmd; if((!res->a_data || res->a_count <2) && res->text && res->text[0]) range_array(res, res->text); if(!res->a_data) { if(res->a_data = PushArray((double*)malloc(2*sizeof(double)))) { res->a_data[0] = res->val; res->a_count = 1; InfoBox("fixed data"); } } if(!(syntax_level) || !syntax_level->cl1 || syntax_level->cl2 <= syntax_level->cl1) return; if(!(cmd = (char*)malloc(syntax_level->cl2 - syntax_level->cl1 +2)))return; while(buffer[syntax_level->cl1] <= ' ' && syntax_level->cl1 < syntax_level->cl2) syntax_level->cl1++; for(j = 0, i = syntax_level->cl1; i< syntax_level->cl2; i++) { cmd[j++] = buffer[i]; } cmd[j++] = ';'; cmd[j++] = 0; res->text = PushString(cmd); free(cmd); } struct parse_info { char *buffer; int buff_pos; DataObj *curr_data; symrec *sym_table; YYSTYPE yylval; struct parse_info *next; char **str_list; double **arr_list; char *last_err_desc; int n_str, n_arr, yychar, yynerrs; }; static parse_info *parse_stack = 0L; static void push_parser() { parse_info *ptr; if(!sym_table) InitArithFuncs(0L); else if(!parse_level && bRecent) ArrangeFunctions(); ptr = (parse_info *) malloc(sizeof(parse_info)); ptr->buffer = buffer; ptr->buff_pos = buff_pos; ptr->curr_data = curr_data; ptr->last_err_desc = last_err_desc; ptr->sym_table = sym_table; sym_table = sym_tab_first; memcpy(&ptr->yylval, &yylval, sizeof(YYSTYPE)); ptr->next = parse_stack; ptr->str_list = str_list; str_list = 0L; ptr->n_str = n_str; n_str = 0; ptr->arr_list = arr_list; arr_list = 0L; ptr->n_arr = n_arr; n_arr = 0; ptr->yychar = yychar; ptr->yynerrs = yynerrs; parse_stack = ptr; last_err_desc = 0L; parse_level++; //reenter ? push_syntax(); syntax_level->last_tok = 0; } static void pop_parser() { parse_info *ptr; symrec *n; if(ptr = parse_stack) { while(sym_table && sym_table != sym_tab_first) { n = sym_table->next; delete(sym_table); sym_table = n; } if(sym_table) sym_table = ptr->sym_table; parse_stack = ptr->next; buffer = ptr->buffer; buff_pos = ptr->buff_pos; curr_data = ptr->curr_data; last_err_desc = ptr->last_err_desc; memcpy(&yylval, &ptr->yylval, sizeof(YYSTYPE)); str_list = ptr->str_list; n_str = ptr->n_str; arr_list = ptr->arr_list; n_arr = ptr->n_arr; yychar = ptr->yychar; yynerrs = ptr->yynerrs; free(ptr); parse_level--; } pop_syntax(); } static int is_ttoken(unsigned int h_nam, unsigned int h2_nam) { switch(h_nam) { case 69: if(h2_nam == 101) return E; break; case 393: if(h2_nam == 47081) return PI; break; case 28381: if((h2_nam & 0x7fffffff) == 0x7c2706ed) { if(syntax_level) syntax_level->cl1 = buff_pos; return CLAUSE; } break; case 20: if(h2_nam == 5220) return CLVAL; break; case 362: if(h2_nam == 42878) return (syntax_level->last_tok = IF); break; case 28421: if(h2_nam == 82147317) return (syntax_level->last_tok = WHILE); break; case 1518: if(h2_nam == 20654586) return (syntax_level->last_tok = FOR); break; case 370: if(h2_nam == 46206) return INARR; break; case 1457: if(h2_nam == 18357885) return DIM; break; case 108774: if(h2_nam == 0x27d5d1fe) return (syntax_level->last_tok = RETURN); break; case 23583: if(h2_nam == 0x954f67ff) return BREAK; break; case 6033: if((h2_nam & 0x7fffffff) == 0x6371377d) return (syntax_level->last_tok = ELSE); break; case 7097: if((h2_nam & 0x7fffffff) == 0x550a2d65) return BTRUE; break; case 23697: if((h2_nam & 0x7fffffff) == 0x155f977d) return BFALSE; break; } return 0; } static char *copy_block() { char first[50], last[50], *res, *src; int i, j, level, mode; src = buffer + buff_pos-1; switch(*src){ case '{': first[0] = '{'; last[0] = '}'; break; case '(': first[0] = '('; last[0] = ')'; break; default: first[0] = '\0'; last[0] = ';'; break; } if(!(res = (char*)malloc(strlen(src)+2))) return 0L; for(i = 1, level = mode = j = 0; src[i]; i++) { res[j++] = src[i]; if(mode && level) { //embeded string if(src[i] == last[level]) { mode = 0; level--; } res[j++] = src[i]; } else { if(src[i] == last[level]) { if(level) level--; else { if(res[j-2] == ';'){ res[j-1] = 0; } else { res[j-1] = ';'; res[j] = 0; } buff_pos += j; return res; } } else switch(src[i]) { case '"': level++; first[level] = last[level] = '"'; break; case '\'': level++; first[level] = last[level] = '\''; break; case '{': level++; first[level] = '{'; last[level] = '}'; break; case '(': level++; first[level] = '('; last[level] = ')'; break; } } } if(res[j-1] == ';') j--; res[j] = ';'; res[j+1] = 0; buff_pos += j; return res; } static symrec *curr_sym; static int for_loop(char *block1, char *block2) { char *last_buffer, *bb1, *bb2, *bb3; int i, a_count, last_buff_pos, cb1, bres; double *a_data; YYSTYPE yyres, yysrc; symrec *var; if(!block1 || !block1[0] || bNoExec) return 0; bb1 = bb2 = bb3 = 0L; parse_level++; cb1 = (int)strlen(block1); bres = 0; last_buffer = buffer; last_buff_pos = buff_pos; buffer = block1; buff_pos = 0; //test for syntax 1 bb1 = copy_block(); 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]) bres = eval(&yyres, &yysrc); for(i = 0; !bres && i < yy_maxiter; i++) { yysrc.text = bb2; if(bb2[0]) { 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; bres = eval(&yyres, &yysrc); } yysrc.text = bb3; bres = eval(&yyres, &yysrc); } else break; } if(i) last_error = 0L; } //test for syntax 2 else if(!bb2) { buff_pos = 0; if (VAR == yylex() && (var = curr_sym) && INARR == yylex() && buffer[buff_pos]){ yysrc.text = buffer + buff_pos; bres = eval(&yyres, &yysrc); a_count = yyres.a_count; a_data = yyres.a_data; for(i = 0; !bres && i < a_count && i < yy_maxiter; i++) { var->SetValue(a_data[i]); if(block2 && block2[0]) { yysrc.text = block2; bres = eval(&yyres, &yysrc); } } last_error = 0; } else yyerror("parse error"); } else yyerror("parse error"); if(bb1) free(bb1); if(bb2) free(bb2); if(bb3) free(bb3); buffer = last_buffer; buff_pos = last_buff_pos; parse_level--; return bres; } static int yylex() { int i, c, tok; unsigned int h_nam, h2_nam; char tmp_txt[80], *block; symrec *s; memset(&yylval, 0, sizeof(YYSTYPE)); while((c = buffer[buff_pos++]) == ' ' || c == '\t'); //get first nonwhite char if(!c) return 0; //test for implicit block statement if(syntax_level && (syntax_level->last_tok == PBLOCK || syntax_level->last_tok == ELSE || syntax_level->last_tok == RETURN) && c != '{'){ buff_pos--; if(block = copy_block()) { yylval.text = PushString(block); free(block); } syntax_level->last_tok = 0; return yylval.type = IBLOCK; } //test for block statement if(c == '{') { if(block = copy_block()) { yylval.text = PushString(block); free(block); } syntax_level->last_tok = 0; return yylval.type = BLOCK; } //test for '..' operator if(c == '.' && buffer[buff_pos] == '.') { buff_pos++; return yylval.type = SER; } //test for number if(c > 31 &&(c == '.' || isdigit(c))) { for(buff_pos--, i = 0; i < 79 && ((c = buffer[buff_pos]) == '.' || isdigit(c)); buff_pos++) { tmp_txt[i++] = (char)c; if(i && buffer[buff_pos+1] == 'e' && (buffer[buff_pos+2] == '-' || buffer[buff_pos+2] == '+')){ tmp_txt[i++] = buffer[++buff_pos]; tmp_txt[i++] = buffer[++buff_pos]; } if(i && buffer[buff_pos+1] == '.' && buffer[buff_pos+2] == '.') { //operator '..' buff_pos++; break; } } tmp_txt[i] = 0; #ifdef USE_WIN_SECURE sscanf_s(tmp_txt, "%lf", &yylval.val); #else sscanf(tmp_txt, "%lf", &yylval.val); #endif return yylval.type = NUM; } //test for name or stringtoken if(c > 31 && (isalpha(c) || c=='$' || c =='_')) { for(buff_pos--, i = 0; i < 79 && ((c = buffer[buff_pos]) && c > 31 && (isalnum(c) || c == '$' || c == '_')); buff_pos++) { tmp_txt[i++] = (char)c; } while(buffer[buff_pos] == ' ' || buffer[buff_pos] == '\t') buff_pos++; if(buffer[buff_pos] == ':' && !(syntax_level && syntax_level->last_tok == '?')){ tmp_txt[i++] = buffer[buff_pos++]; for(; i < 79 && ((c = buffer[buff_pos]) && c > 31 && (isalnum(c) || c == '$')); buff_pos++) { tmp_txt[i++] = (char)c; } tmp_txt[i] = 0; RangeData.GetData(tmp_txt, &yylval.a_data, &yylval.a_count, &yylval.text); yylval.val = 0.0; return yylval.type = (yylval.a_data && yylval.a_count) ? RANGEARR : STR; } tmp_txt[i] = 0; h_nam = HashValue((unsigned char*)tmp_txt); h2_nam = Hash2((unsigned char*)tmp_txt); if(h_nam == 1550 && h2_nam == 18852086) { //'inf' = huge value yylval.val = HUGE_VAL; return yylval.type = NUM; } if(tok = is_ttoken(h_nam, h2_nam)) return tok; if(!(s = getsym(h_nam, h2_nam, tmp_txt))){ s = putsym(h_nam, h2_nam, VAR); s->SetName(tmp_txt); } curr_sym = yylval.tptr = s; return s->type; } //test for string if(c == '"' || c == '\'') { for(i= 0; i < 79 && ((tok = buffer[buff_pos]) && (tok != c)); buff_pos++) { tmp_txt[i++] = (char)tok; } if(buffer[buff_pos] == c)buff_pos++; tmp_txt[i] = 0; yylval.text = PushString(tmp_txt); return yylval.type = STR; } tok = 0; switch(c) { case '=': if(buffer[buff_pos] == '=') tok = EQ; break; case '!': if(buffer[buff_pos] == '=') tok = NE; break; case '>': if(buffer[buff_pos] == '=') tok = GE; else return GT; break; case '<': if(buffer[buff_pos] == '=') tok = LE; else if(buffer[buff_pos] == '>') tok = NE; else return LT; break; case '&': if(buffer[buff_pos] == '&') tok = AND; break; case '|': if(buffer[buff_pos] == '|') tok = OR; break; case ')': if(syntax_level) { if(syntax_level->cl1 && syntax_level->next) { syntax_level->next->cl1 = syntax_level->cl1; syntax_level->next->cl2 = buff_pos-1; } } pop_syntax(); break; case '(': if(syntax_level->last_tok == WHILE || syntax_level->last_tok == FOR || syntax_level->last_tok == IF){ if(block = copy_block()) { yylval.text = PushString(block); free(block); } return yylval.type = syntax_level->last_tok = PBLOCK; } push_syntax(); if(syntax_level) syntax_level->last_tok = c; break; case '?': if(syntax_level) syntax_level->last_tok = c; break; case ':': if(syntax_level) { if(syntax_level->last_tok == '?') return COLC; } break; case ';': if(buff_pos <2)return yylex(); if(syntax_level) { if(syntax_level->last_tok == '(') return PSEP; else syntax_level->last_tok = 0; } break; case ',': if(syntax_level && syntax_level->last_tok == '(') return LSEP; break; case '*': if(buffer[buff_pos] == '=') tok = MULEQ; break; case '/': if(buffer[buff_pos] == '=') tok = DIVEQ; break; case '+': if(buffer[buff_pos] == '+') tok = INC; else if(buffer[buff_pos] == '=') tok = ADDEQ; break; case '-': if(buffer[buff_pos] == '-') tok = DEC; else if(buffer[buff_pos] == '=') tok = SUBEQ; break; } if(tok) { buff_pos++; return tok; } //Any other character is a token by itself if(c < 0 || c > 127)yytokenerr(c); return c; } static unsigned int hn_x = HashValue((unsigned char *)"x"); static unsigned int hn_y = HashValue((unsigned char *)"y"); static unsigned int hn_z = HashValue((unsigned char *)"z"); static unsigned int h2_x = Hash2((unsigned char *)"x"); static unsigned int h2_y = Hash2((unsigned char *)"y"); static unsigned int h2_z = Hash2((unsigned char *)"z"); bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOINT **pts, long *npts, char *param) { double x, y; symrec *sx, *sy; lfPOINT *new_points; long npoints = 0; int length, parse_res, res_mode = 0; if(x1 < x2) step = fabs(step); else if(x1 == x2) return false; else step = -fabs(step); if(!(new_points = (lfPOINT*)calloc((iround(fabs(x2-x1)/fabs(step))+2), sizeof(lfPOINT)))) return false; if(d) curr_data = d; push_parser(); init_table(); if(param) { length = (int)strlen(param); if(!(buffer = (char*)malloc(length+2))){ pop_parser(); return false; } rlp_strcpy(buffer, length+1, param); buffer[length++] = ';'; buffer[length] = 0; buff_pos = 0; while(!(parse_res = yyparse()) && buff_pos < length); free(buffer); buffer = 0L; } length = (int)strlen(expr); buffer = expr; sx = putsym(hn_x, h2_x, VAR); for(x = x1; step > 0.0 ? x <= x2 : x >= x2; x += step) { if(sx){ sx->SetValue(x); buff_pos = 0; while(!(parse_res = yyparse()) && buff_pos < length); switch (res_mode) { case 1: y = sy->GetValue(); break; case 2: y = line_res.value; break; default: if(sy = getsym(hn_y, h2_y)) { y = sy->GetValue(); res_mode = 1; } else { y = line_res.value; res_mode = 2; } break; } new_points[npoints].fx = (getsym(hn_x, h2_x))->GetValue(); new_points[npoints++].fy = y; } } *pts = new_points; *npts = npoints; clear_table(); pop_parser(); if(d) { d->Command(CMD_CLEAR_ERROR, 0L, 0L); d->Command(CMD_REDRAW, 0L, 0L); } return true; } bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double z2, double zstep, char *expr, char *param) { int length, parse_res, nr, nc, r, c, res_mode=0; symrec *sx, *sz, *sy; double x, y, z; if(!d || x2 <= x1 || z2 <= z1 || xstep <= 0.0 || zstep <= 0.0) return false; push_parser(); init_table(); if(param) { length = (int)strlen(param); if(!(buffer = (char*)malloc(length+2))){ pop_parser(); return false; } rlp_strcpy(buffer, length+1, param); buffer[length++] = ';'; buffer[length] = 0; buff_pos = 0; while(!(parse_res = yyparse()) && buff_pos < length); free(buffer); buffer = 0L; } length = (int)strlen(expr); buffer = expr; sx = putsym(hn_x, h2_x, VAR); sz = putsym(hn_z, h2_z, VAR); nr = iround((z2-z1)/zstep)+1; nc = iround((x2-x1)/xstep)+1; d->Init(nr, nc); for(r = 0, x = x1; r < nr; r++, x += xstep) { for(c = 0, z = z1; c < nc; c++, z+= zstep) { sx->SetValue(x); sz->SetValue(z); buff_pos = 0; while(!(parse_res = yyparse()) && buff_pos < length); switch (res_mode) { case 1: y = sy->GetValue(); break; case 2: y = line_res.value; break; default: if(sy = getsym(hn_y, h2_y)) { y = sy->GetValue(); res_mode = 1; } else { y = line_res.value; res_mode = 2; } break; } d->SetValue(r, c, y); } } clear_table(); pop_parser(); return true; } anyResult *do_formula(DataObj *d, char *expr) { int length, parse_res; static anyResult ret, *pret = 0L; if(d) curr_data = d; ret.type = ET_ERROR; ret.text = 0L; ret.a_data = 0L; ret.a_count = 0; if(!expr || !expr[0]) { if(!sym_table) InitArithFuncs(0L); last_error = 0L; return &ret; } push_parser(); //make code reentrant init_table(); length = (int)strlen(expr); if(!(buffer = (char*)malloc(length+2))){ pop_parser(); return &ret; } rlp_strcpy(buffer, length+1, expr); if(buffer[length-1] != ';') buffer[length++] = ';'; buffer[length] = 0; buff_pos = 0; while(!(parse_res= yyparse()) && buff_pos < length); ret.type = ET_ERROR; ret.text = 0L; if(parse_res == 1 && curr_data) { if(last_error && (!(strcmp(last_error, "parse error")))) curr_data->Command(CMD_ERROR, 0L, 0L); if(last_err_desc) pret = &line_res; else pret = &ret; } else pret = &line_res; last_error = last_err_desc = 0L; free(buffer); buffer = 0L; clear_table(); pop_parser(); return pret; } bool MoveFormula(DataObj *d, char *of, char *nf, int nfsize, int dx, int dy, int r0, int c0) { int length, length2, tok, pos, i; char *res, desc1[2], desc2[2]; if(d) curr_data = d; 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))){ pop_parser(); return false; } rlp_strcpy(buffer, length+1, of); buffer[length++] = ';'; buffer[length] = 0; buff_pos = pos = 0; if(!(res = (char *)calloc(length2 = (length*2+10), sizeof(char))))return false; length2--; do { tok = yylex (); if(tok && tok < 256) { if(res[pos-1] == ' ') pos--; res[pos++] = (char)tok; } else switch(tok) { case NUM: #ifdef USE_WIN_SECURE pos += sprintf_s(res+pos, 20, "%g", yylval.val); #else pos += sprintf(res+pos, "%g", yylval.val); #endif break; case FNCT: case FUNC1: case AFNCT: case SFNCT: case SRFUNC: case BFNCT: case YYFNC: case FUNC4: case YYFNC2: case YYFNC3: pos += rlp_strcpy(res+pos, length2-pos, curr_sym->name); break; case COLC: res[pos++] = ':'; break; case PSEP: res[pos++] = ';'; break; case LSEP: res[pos++] = ','; break; case CLVAL: res[pos++] = '$'; res[pos++] = '$'; break; case CLAUSE: pos += rlp_strcpy(res+pos, length2-pos, " where "); break; case DIM: pos += rlp_strcpy(res+pos, length2-pos, "dim "); break; case VAR: curr_sym->InitSS(); if(curr_sym->col >= 0 && curr_sym->row >= 0) { desc1[0] = desc1[1] = desc2[0] = desc2[1] = 0; for(i=(int)strlen(curr_sym->name)-1; i>0 && isdigit(curr_sym->name[i]); i--); if(curr_sym->name[0] == '$') desc1[0] = '$'; if(curr_sym->name[i] == '$') desc2[0] = '$'; #ifdef USE_WIN_SECURE pos += sprintf_s(res+pos, length2-pos, "%s%s%s%d", desc1, #else pos += sprintf(res+pos, "%s%s%s%d", desc1, #endif Int2ColLabel(desc1[0] || curr_sym->col < c0 ? curr_sym->col : curr_sym->col+dx >=0 ? curr_sym->col+dx > c0 ? curr_sym->col+dx : c0 : 0, false), desc2, desc2[0] || curr_sym->row < r0 ? curr_sym->row+1 : curr_sym->row + dy >= 0 ? curr_sym->row+dy > r0 ? curr_sym->row+1+dy : r0 : 1); } else pos += rlp_strcpy(res+pos, length2-pos, curr_sym->name); break; case STR: pos += rlp_strcpy(res+pos, length2-pos, "\""); pos += rlp_strcpy(res+pos, length2-pos, yylval.text); pos += rlp_strcpy(res+pos, length2-pos, "\""); break; case SER: res[pos++] = '.'; res[pos++] = '.'; break; case INC: res[pos++] = '+'; res[pos++] = '+'; break; case DEC: res[pos++] = '-'; res[pos++] = '-'; break; case PI: res[pos++] = 'p'; res[pos++] = 'i'; break; case E: res[pos++] = 'e'; break; case BTRUE: pos += rlp_strcpy(res+pos, length2-pos, "true"); break; case BFALSE: pos += rlp_strcpy(res+pos, length2-pos, "false"); break; case AND: pos += rlp_strcpy(res+pos, length2-pos, " && "); break; case OR: pos += rlp_strcpy(res+pos, length2-pos, " || "); break; case EQ: pos += rlp_strcpy(res+pos, length2-pos, " == "); break; case NE: pos += rlp_strcpy(res+pos, length2-pos, " != "); break; case GT: res[pos++] = '>'; break; case GE: res[pos++] = '>'; res[pos++] = '='; break; case LT: res[pos++] = '<'; break; case LE: res[pos++] = '<'; res[pos++] = '='; break; case IF: res[pos++] = 'i'; res[pos++] = 'f'; break; case ADDEQ: res[pos++] = '+'; res[pos++] = '='; break; case SUBEQ: res[pos++] = '-'; res[pos++] = '='; break; case MULEQ: res[pos++] = '*'; res[pos++] = '='; break; case DIVEQ: res[pos++] = '/'; res[pos++] = '='; break; case WHILE: pos += rlp_strcpy(res+pos, length2-pos, "while"); break; case FOR: pos += rlp_strcpy(res+pos, length2-pos, "for"); break; case INARR: pos += rlp_strcpy(res+pos, length2-pos, "in"); break; case ELSE: pos += rlp_strcpy(res+pos, length2-pos, "else"); break; case RETURN: pos += rlp_strcpy(res+pos, length2-pos, " return"); break; case BREAK: pos += rlp_strcpy(res+pos, length2-pos, " break"); break; case RANGEARR: 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); } while(res[pos]) { pos++; if(res[pos] == ';') res[pos] = ':'; } break; case BLOCK: res[pos++] = '{'; MoveFormula(d, yylval.text, res+pos, nfsize-pos-2, dx, dy, r0, c0); pos += (int)strlen(res+pos); res[pos++] = '}'; break; case IBLOCK: MoveFormula(d, yylval.text, res+pos, nfsize-pos-2, dx, dy, r0, c0); pos += (int)strlen(res+pos); res[pos++] = ';'; break; case PBLOCK: res[pos++] = '('; MoveFormula(d, yylval.text, res+pos, nfsize-pos-2, dx, dy, r0, c0); pos += (int)strlen(res+pos); res[pos++] = ')'; break; } res[pos] = 0; }while(buff_pos < length); while((res[pos-1] == ';' || res[pos-1] == ' ') && pos > 0) { res[pos-1] = 0; pos--;} rlp_strcpy(nf, nfsize, res); free(res); free(buffer); buffer = 0L; clear_table(); pop_parser(); return true; } static char *txt_formula; //function to fit static double **parval; //pointers to parameter values static void fcurve(double x, double z, double **a, double *y, double dyda[], int ma) { int i, length, parse_res; double tmp, y1, y2; symrec *symx, *symz, *sy=0L; if(!(symx = getsym(hn_x, h2_x))) symx = putsym(hn_x, h2_x, VAR); if(!(symz = getsym(hn_z, h2_z))) symz = putsym(hn_z, h2_z, VAR); //swap parameters to requested set if(a != parval) for(i = 0; i < ma; i++) { tmp = *parval[i]; *parval[i] = *a[i]; *a[i] = tmp; } //calc result symx->SetValue(x); symz->SetValue(z); 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(); else *y = line_res.value; if(*y == HUGE_VAL || *y == -HUGE_VAL) { for(i = 0, *y = 0.0; i < ma; dyda[i++] = 0.0); return; } //partial derivatives for each parameter by numerical differentiation for(i = 0; i < ma; i++) { if(*parval[i] != 0.0) { tmp = *parval[i]; *parval[i] = tmp*.995; buff_pos = 0; while(!(parse_res = yyparse()) && buff_pos < length); y1 = sy ? sy->GetValue() : line_res.value; *parval[i] = tmp*1.005; buff_pos = 0; while(!(parse_res = yyparse()) && buff_pos < length); y2 = sy ? sy->GetValue() : line_res.value; *parval[i] = tmp; dyda[i] = (y2-y1)*100.0/tmp; } else dyda[i] = 0.0; } //swap parameters back to original if(a != parval) for(i = 0; i < ma; i++) { tmp = *parval[i]; *parval[i] = *a[i]; *a[i] = tmp; } bNoSS = false; } int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr, double conv, int maxiter, double *chi_2) { int length, i, j, k, l, ndata, nparam, r1, r2, r3, c1, c2, c3; int *lista, itst, itst1, parse_res; symrec *tab1, *tab2, *csr, **parsym; AccRange *arx, *ary, *arz; double *x, *y, *z, currx, curry, currz, alamda, chisq, ochisq; double **covar, **alpha; char tmp_txt[500]; if(d) curr_data = d; if(chi_2) *chi_2 = 0.0; txt_formula = expr; if(!curr_data || !par || !expr || !rx || !ry) return 0; //process ranges and create arrays arx = ary = arz = 0L; x = y = z = 0L; parval = 0L; parsym = 0L; if(!(arx = new AccRange(rx)))return 0; i = arx->CountItems()+1; if(!(ary = new AccRange(ry))){ delete arx; return 0; } if(rz && !(arz = new AccRange(rz))){ delete ary; delete arx; return 0; } if(!(x = (double*)malloc(i * sizeof(double)))){ if(arz) delete arz; delete ary; delete arx; return 0; } if(!(y = (double*)malloc(i * sizeof(double)))){ if(arz) delete arz; free(x); delete arx; delete ary; return 0; } if(rz && !(z = (double*)malloc(i * sizeof(double)))){ if(arz) delete arz; free(y); free(x); delete arx; delete ary; return 0; } arx->GetFirst(&c1, &r1); ary->GetFirst(&c2, &r2); if(rz) arz->GetFirst(&c3, &r3); for(ndata = j = 0; j < i; j++) { if(rz) { if(arx->GetNext(&c1, &r1) && ary->GetNext(&c2, & r2) && arz->GetNext(&c3, &r3) && curr_data->GetValue(r1, c1, &currx) && curr_data->GetValue(r2, c2, &curry) && curr_data->GetValue(r3, c3, &currz)) { x[ndata] = currx; y[ndata] = curry; z[ndata] = currz; ndata++; } } else { if(arx->GetNext(&c1, &r1) && ary->GetNext(&c2, & r2) && curr_data->GetValue(r1, c1, &currx) && curr_data->GetValue(r2, c2, &curry)) { x[ndata] = currx; y[ndata] = curry; ndata++; } } } //common initialization for parser tasks push_parser(); //make code reentrant init_table(); length = (int)strlen(*par); //process parameters if(!(buffer = (char*)malloc(length+2))){ clear_table(); pop_parser(); if(arz) delete arz; free(y); free(x); delete arx; delete ary; return 0; } rlp_strcpy(buffer, length, *par); buffer[length++] = ';'; buffer[length] = 0; buff_pos = 0; tab1 = sym_table; while(!(parse_res = yyparse()) && buff_pos < length); tab2 = sym_table; free(buffer); buffer =0L; for(nparam = 0, csr=tab2; csr != tab1; nparam++, csr = csr->next); parsym = (symrec**)malloc((nparam+1)*sizeof(symrec*)); parval = (double**)malloc((nparam+1)*sizeof(double*)); for(i = 0, csr=tab2; csr != tab1 && i < nparam; i++, csr = csr->next){ parsym[i] = csr; parval[i] = &csr->var; } //do iteratations to optimize fit lista = (int*)malloc(sizeof(int)*nparam); for(i = 0; i< nparam; i++) lista[i] = i; covar = dmatrix(1, nparam, 1, nparam); alpha = dmatrix(1, nparam, 1, nparam); alamda = -1.0; itst = 0; mrqmin(x, y, z, ndata, parval, nparam, lista, nparam, covar, alpha, &chisq, fcurve, &alamda); if(!Check_MRQerror()) { for(itst = itst1 = 0, ochisq = chisq; itst < maxiter && chisq > conv && ochisq >= chisq && itst1 < 9; itst++) { ochisq = chisq; mrqmin(x, y, z, ndata, parval, nparam, lista, nparam, covar, alpha, &chisq, fcurve, &alamda); if(ochisq == chisq) itst1++; else itst1 = 0; } alamda = 0.0; mrqmin(x, y, z, ndata, parval, nparam, lista, nparam, covar, alpha, &chisq, fcurve, &alamda); Check_MRQerror(); } bNoSS = true; for(i = nparam-1, j = k = l = 0; i >= 0; l = 0, i--) { if(k > 20) { if(tmp_txt[j-1] == ' ') j--; if(tmp_txt[j-1] == ';') j--; #ifdef USE_WIN_SECURE l = sprintf_s(tmp_txt+j, 500-j, "\n"); #else l = sprintf(tmp_txt+j, "\n"); #endif j += l; k = 0; } #ifdef USE_WIN_SECURE l += sprintf_s(tmp_txt+j, 500-j, "%s%s=%g;", j && k ? " " : "", parsym[i]->name, parsym[i]->GetValue()); #else l += sprintf(tmp_txt+j, "%s%s=%g;", j && k ? " " : "", parsym[i]->name, parsym[i]->GetValue()); #endif j += l; k += l; } free(*par); *par = (char*)memdup(tmp_txt, (int)strlen(tmp_txt)+1, 0); if(chi_2) *chi_2 = chisq; //write back spreadsheet data if necessary buffer = *par; length = (int)strlen(buffer); while(!(parse_res = yyparse()) && buff_pos < length); buffer = 0L; free_dmatrix(alpha, 1, nparam, 1, nparam); free_dmatrix(covar, 1, nparam, 1, nparam); if(arz) delete arz; if(z) free(z); free(y); free(x); delete arx; delete ary; if(parval) free(parval); if(parsym) free(parsym); clear_table(); pop_parser(); if(d){ d->Command(CMD_CLEAR_ERROR, 0L, 0L); d->Command(CMD_REDRAW, 0L, 0L); } bNoSS = false; return itst < maxiter ? itst+1 : maxiter; } rlplot/Utils.cpp0000755000076400007640000022524610770264251012474 0ustar c71960c71960//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 #include #include #include #include #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[] = {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 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<= 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, "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; } rlplot/TheDialog.h0000775000076400007640000003747410755777455012731 0ustar c71960c71960//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); rlplot/rlplot.rc0000755000076400007640000002474310665227256012540 0ustar c71960c71960//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 #include "Version.h" #include "menu.h" #endif MENU_1 MENU DISCARDABLE BEGIN POPUP "&File" BEGIN MENUITEM "&Open", CM_OPEN MENUITEM "&Save as", CM_SAVEGRAPHAS MENUITEM SEPARATOR MENUITEM "&Print", CM_PRINT MENUITEM "&Export", CM_EXPORT MENUITEM SEPARATOR MENUITEM "&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 "&Open", CM_OPEN MENUITEM "&Save", CM_SAVEDATA MENUITEM "Save &as", CM_SAVEDATAAS 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_SAVEGRAPHAS 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 rlplot/mfcalc.cpp0000755000076400007640000045470310775137600012625 0ustar c71960c71960 /* A Bison parser, made from ../../rlplot/mfcalc.y by GNU Bison version 1.28 */ #define YYBISON 1 /* Identify Bison output. */ #define NUM 257 #define BOOLVAL 258 #define STR 259 #define ARR 260 #define BLOCK 261 #define PBLOCK 262 #define IBLOCK 263 #define PI 264 #define E 265 #define CLVAL 266 #define PSEP 267 #define IF 268 #define ELSE 269 #define BTRUE 270 #define BFALSE 271 #define DATE1 272 #define TIME1 273 #define DATETIME1 274 #define DIM 275 #define WHILE 276 #define FOR 277 #define INARR 278 #define RANGEARR 279 #define RETURN 280 #define BREAK 281 #define VAR 282 #define FNCT 283 #define BFNCT 284 #define AFNCT 285 #define SFNCT 286 #define FUNC1 287 #define TXT 288 #define SRFUNC 289 #define YYFNC 290 #define FUNC4 291 #define YYFNC2 292 #define YYFNC3 293 #define ADDEQ 294 #define SUBEQ 295 #define MULEQ 296 #define DIVEQ 297 #define LSEP 298 #define CLAUSE 299 #define SER 300 #define COLC 301 #define AND 302 #define OR 303 #define EQ 304 #define NE 305 #define GT 306 #define GE 307 #define LT 308 #define LE 309 #define NEG 310 #define INC 311 #define DEC 312 #define PINC 313 #define PDEC 314 #define PDIM 315 /* 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. 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 #include #include #include #include #include "rlplot.h" class symrec { public: int type, row, col, a_count; unsigned int h_name, h2_name; char *name, *text; double (*fnctptr)(...); symrec *next; double var, *a_data; symrec(unsigned int h_n, unsigned int h2_n, int typ, symrec *nxt); ~symrec(); double GetValue(); void GetValue(void *res); double SetValue(double v); void SetValue(void* dest, void* src); void SetName(char *nam); void InitSS(); void NoInit(); private: bool isSSval, isValid; }; // syntactical information struct syntax_info { int last_tok; //resolve ambiguous ':' double clval; //current value for where - clause int cl1, cl2; //limits of clause formula in buffer struct syntax_info *next; }; static syntax_info *syntax_level = 0L; typedef struct{ double val; int type; symrec *tptr; double *a_data; char *text; int a_count; }YYSTYPE; static int yy_maxiter = 100000; //maximum loop count 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); static double *ReallocArray(double *arr, int size); static char *add_strings(char *st1, char *st2); static char *string_value(YYSTYPE *exp); static int eval(YYSTYPE *dst, YYSTYPE *sr); static int range_array(YYSTYPE * res, char *range); static int range_array2(YYSTYPE *res1, YYSTYPE *res2); static void exec_clause(YYSTYPE *res); static YYSTYPE *proc_clause(YYSTYPE *res); 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 int for_loop(char *block1, char *block2); static char res_txt[1000]; static anyResult line_res = {ET_UNKNOWN, 0.0, res_txt, 0L, 0}; static DataObj *curr_data; static char *last_error = 0L; //error text 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, bNoSS; //while editing ... static int parse_level = 0; //count reentrances into parser #define MAX_PARSE 50 //maximum number of recursive reentances #include #ifndef __cplusplus #ifndef __STDC__ #define const #endif #endif #define YYFINAL 221 #define YYFLAG -32768 #define YYNTBASE 77 #define YYTRANSLATE(x) ((unsigned)(x) <= 315 ? yytranslate[x] : 87) static const char yytranslate[] = { 0, 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, 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, 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, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 57, 64, 65, 66, 67, 68, 69 }; #if YYDEBUG != 0 static const short yyprhs[] = { 0, 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, 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, 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 #if YYDEBUG != 0 || defined (YYERROR_VERBOSE) static const char * const yytname[] = { "$","error","$undefined.","NUM","BOOLVAL", "STR","ARR","BLOCK","PBLOCK","IBLOCK","PI","E","CLVAL","PSEP","IF","ELSE","BTRUE", "BFALSE","DATE1","TIME1","DATETIME1","DIM","WHILE","FOR","INARR","RANGEARR", "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","anysep","line","str_exp","range","arr","bool", "block","anyarg","exp", NULL }; #endif static const short yyr1[] = { 0, 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, 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, 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, 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, 95, 39, 111, 112, 113, 41, 42, 72, 73 }; static const short yypact[] = {-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, -95,-32768, 54, -147, -58,-32768, -37, -59, -1 }; #define YYLAST 932 static const short yytable[] = { 43, 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, 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, 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, 215, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 0, 0, 0, 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, 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, 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, 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, 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, -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, 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. */ /* This file comes from bison-1.28. */ /* Skeleton output parser for bison, Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* As a special exception, when this file is copied by Bison into a Bison output file, you may use that output file without restriction. This special exception was added by the Free Software Foundation in version 1.24 of Bison. */ /* This is the parser code that is written into each bison parser when the %semantic_parser declaration is not specified in the grammar. It was written by Richard Stallman by simplifying the hairy parser used when %semantic_parser is specified. */ #ifndef YYSTACK_USE_ALLOCA #ifdef alloca #define YYSTACK_USE_ALLOCA #else /* alloca not defined */ #ifdef __GNUC__ #define YYSTACK_USE_ALLOCA #define alloca __builtin_alloca #else /* not GNU C. */ #if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386)) #define YYSTACK_USE_ALLOCA #include #else /* not sparc */ /* We think this test detects Watcom and Microsoft C. */ /* This used to test MSDOS, but that is a bad idea since that symbol is in the user namespace. */ #if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__) #if 0 /* No need for malloc.h, which pollutes the namespace; instead, just don't use alloca. */ #include #endif #else /* not MSDOS, or __TURBOC__ */ #if defined(_AIX) /* I don't know what this was needed for, but it pollutes the namespace. So I turned it off. rms, 2 May 1997. */ /* #include */ #pragma alloca #define YYSTACK_USE_ALLOCA #else /* not MSDOS, or __TURBOC__, or _AIX */ #if 0 #ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up, and on HPUX 10. Eventually we can turn this on. */ #define YYSTACK_USE_ALLOCA #define alloca __builtin_alloca #endif /* __hpux */ #endif #endif /* not _AIX */ #endif /* not MSDOS, or __TURBOC__ */ #endif /* not sparc */ #endif /* not GNU C */ #endif /* alloca not defined */ #endif /* YYSTACK_USE_ALLOCA not defined */ #ifdef YYSTACK_USE_ALLOCA #define YYSTACK_ALLOC alloca #else #define YYSTACK_ALLOC malloc #endif /* Note: there must be only one dollar sign in this file. It is replaced by the list of actions, each action as one case of the switch. */ #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY -2 #define YYEOF 0 #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrlab1 /* Like YYERROR except do call yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. Once GCC version 2 has supplanted version 1, this can go. */ #define YYFAIL goto yyerrlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(token, value) \ do \ if (yychar == YYEMPTY && yylen == 1) \ { yychar = (token), yylval = (value); \ yychar1 = YYTRANSLATE (yychar); \ YYPOPSTACK; \ goto yybackup; \ } \ else \ { yyerror ("syntax error: cannot back up"); YYERROR; } \ while (0) #define YYTERROR 1 #define YYERRCODE 256 #ifndef YYPURE #define YYLEX yylex() #endif #ifdef YYPURE #ifdef YYLSP_NEEDED #ifdef YYLEX_PARAM #define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM) #else #define YYLEX yylex(&yylval, &yylloc) #endif #else /* not YYLSP_NEEDED */ #ifdef YYLEX_PARAM #define YYLEX yylex(&yylval, YYLEX_PARAM) #else #define YYLEX yylex(&yylval) #endif #endif /* not YYLSP_NEEDED */ #endif /* If nonreentrant, generate the variables here */ #ifndef YYPURE int yychar; /* the lookahead symbol */ YYSTYPE yylval; /* the semantic value of the */ /* lookahead symbol */ #ifdef YYLSP_NEEDED YYLTYPE yylloc; /* location data for the lookahead */ /* symbol */ #endif int yynerrs; /* number of parse errors so far */ #endif /* not YYPURE */ #if YYDEBUG != 0 int yydebug; /* nonzero means print parse trace */ /* Since this is uninitialized, it does not stop multiple parsers from coexisting. */ #endif /* YYINITDEPTH indicates the initial size of the parser's stacks */ #ifndef YYINITDEPTH #define YYINITDEPTH 200 #endif /* YYMAXDEPTH is the maximum size the stacks can grow to (effective only if the built-in stack extension method is used). */ #if YYMAXDEPTH == 0 #undef YYMAXDEPTH #endif #ifndef YYMAXDEPTH #define YYMAXDEPTH 10000 #endif /* Define __yy_memcpy. Note that the size argument should be passed with type unsigned int, because that is what the non-GCC definitions require. With GCC, __builtin_memcpy takes an arg of type size_t, but it can handle unsigned int. */ #if __GNUC__ > 1 /* GNU C and GNU C++ define this. */ #define __yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT) #else /* not GNU C or C++ */ #ifndef __cplusplus /* This is the most reliable way to avoid incompatibilities in available built-in functions on various systems. */ static void __yy_memcpy (to, from, count) char *to; char *from; unsigned int count; { register char *f = from; register char *t = to; register int i = count; while (i-- > 0) *t++ = *f++; } #else /* __cplusplus */ /* This is the most reliable way to avoid incompatibilities in available built-in functions on various systems. */ static void __yy_memcpy (char *to, char *from, unsigned int count) { register char *t = to; register char *f = from; register int i = count; while (i-- > 0) *t++ = *f++; } #endif #endif /* The user can define YYPARSE_PARAM as the name of an argument to be passed into yyparse. The argument should have type void *. It should actually point to an object. Grammar actions can access the variable by casting it to the proper pointer type. */ #ifdef YYPARSE_PARAM #ifdef __cplusplus #define YYPARSE_PARAM_ARG void *YYPARSE_PARAM #define YYPARSE_PARAM_DECL #else /* not __cplusplus */ #define YYPARSE_PARAM_ARG YYPARSE_PARAM #define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; #endif /* not __cplusplus */ #else /* not YYPARSE_PARAM */ #define YYPARSE_PARAM_ARG #define YYPARSE_PARAM_DECL #endif /* not YYPARSE_PARAM */ /* Prevent warning if -Wstrict-prototypes. */ #ifdef __GNUC__ #ifdef YYPARSE_PARAM int yyparse (void *); #else int yyparse (void); #endif #endif int yyparse(YYPARSE_PARAM_ARG) YYPARSE_PARAM_DECL { register int yystate; register int yyn; register short *yyssp; register YYSTYPE *yyvsp; int yyerrstatus; /* number of tokens to shift before error messages enabled */ int yychar1 = 0; /* lookahead token as an internal (translated) token number */ short yyssa[YYINITDEPTH]; /* the state stack */ YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */ short *yyss = yyssa; /* refer to the stacks thru separate pointers */ YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */ #ifdef YYLSP_NEEDED YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */ YYLTYPE *yyls = yylsa; YYLTYPE *yylsp; #define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) #else #define YYPOPSTACK (yyvsp--, yyssp--) #endif int yystacksize = YYINITDEPTH; int yyfree_stacks = 0; #ifdef YYPURE int yychar; YYSTYPE yylval; int yynerrs; #ifdef YYLSP_NEEDED YYLTYPE yylloc; #endif #endif YYSTYPE yyval; /* the variable used to return */ /* semantic values from the action */ /* routines */ int yylen; #if YYDEBUG != 0 if (yydebug) fprintf(stderr, "Starting parse\n"); #endif yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ /* Initialize stack pointers. Waste one element of value and location stack so that they stay on the same level as the state stack. The wasted elements are never initialized. */ yyssp = yyss - 1; yyvsp = yyvs; #ifdef YYLSP_NEEDED yylsp = yyls; #endif /* Push a new state, which is found in yystate . */ /* In all cases, when you get here, the value and location stacks have just been pushed. so pushing a state here evens the stacks. */ yynewstate: *++yyssp = yystate; if (yyssp >= yyss + yystacksize - 1) { /* Give user a chance to reallocate the stack */ /* Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; short *yyss1 = yyss; #ifdef YYLSP_NEEDED YYLTYPE *yyls1 = yyls; #endif /* Get the current used size of the three stacks, in elements. */ int size = (int)(yyssp - yyss + 1); #ifdef yyoverflow /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. */ #ifdef YYLSP_NEEDED /* This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow("parser stack overflow", &yyss1, size * sizeof (*yyssp), &yyvs1, size * sizeof (*yyvsp), &yyls1, size * sizeof (*yylsp), &yystacksize); #else yyoverflow("parser stack overflow", &yyss1, size * sizeof (*yyssp), &yyvs1, size * sizeof (*yyvsp), &yystacksize); #endif yyss = yyss1; yyvs = yyvs1; #ifdef YYLSP_NEEDED yyls = yyls1; #endif #else /* no yyoverflow */ /* Extend the stack our own way. */ if (yystacksize >= YYMAXDEPTH) { yyerror("parser stack overflow"); if (yyfree_stacks) { free (yyss); free (yyvs); #ifdef YYLSP_NEEDED free (yyls); #endif } return 2; } yystacksize *= 2; if (yystacksize > YYMAXDEPTH) yystacksize = YYMAXDEPTH; #ifndef YYSTACK_USE_ALLOCA yyfree_stacks = 1; #endif yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp)); __yy_memcpy ((char *)yyss, (char *)yyss1, size * (unsigned int) sizeof (*yyssp)); yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp)); __yy_memcpy ((char *)yyvs, (char *)yyvs1, size * (unsigned int) sizeof (*yyvsp)); #ifdef YYLSP_NEEDED yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp)); __yy_memcpy ((char *)yyls, (char *)yyls1, size * (unsigned int) sizeof (*yylsp)); #endif #endif /* no yyoverflow */ yyssp = yyss + size - 1; yyvsp = yyvs + size - 1; #ifdef YYLSP_NEEDED yylsp = yyls + size - 1; #endif #if YYDEBUG != 0 if (yydebug) fprintf(stderr, "Stack size increased to %d\n", yystacksize); #endif if (yyssp >= yyss + yystacksize - 1) YYABORT; } #if YYDEBUG != 0 if (yydebug) fprintf(stderr, "Entering state %d\n", yystate); #endif goto yybackup; yybackup: /* Do appropriate processing given the current state. */ /* Read a lookahead token if we need one and don't already have one. */ /* yyresume: */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yyn == YYFLAG) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* yychar is either YYEMPTY or YYEOF or a valid token in external form. */ if (yychar == YYEMPTY) { #if YYDEBUG != 0 if (yydebug) fprintf(stderr, "Reading a token: "); #endif yychar = YYLEX; } /* Convert token to internal form (in yychar1) for indexing tables with */ if (yychar <= 0) /* This means end of input. */ { yychar1 = 0; yychar = YYEOF; /* Don't call YYLEX any more */ #if YYDEBUG != 0 if (yydebug) fprintf(stderr, "Now at end of input.\n"); #endif } else { yychar1 = YYTRANSLATE(yychar); #if YYDEBUG != 0 if (yydebug) { fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]); /* Give the individual parser a way to print the precise meaning of a token, for further debugging info. */ #ifdef YYPRINT YYPRINT (stderr, yychar, yylval); #endif fprintf (stderr, ")\n"); } #endif } yyn += yychar1; if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) goto yydefault; yyn = yytable[yyn]; /* yyn is what to do for this token type in this state. Negative => reduce, -yyn is rule number. Positive => shift, yyn is new state. New state is final state => don't bother to shift, just return success. 0, or most negative number => error. */ if (yyn < 0) { if (yyn == YYFLAG) goto yyerrlab; yyn = -yyn; goto yyreduce; } else if (yyn == 0) goto yyerrlab; if (yyn == YYFINAL) YYACCEPT; /* Shift the lookahead token. */ #if YYDEBUG != 0 if (yydebug) fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]); #endif /* Discard the token being shifted unless it is eof. */ if (yychar != YYEOF) yychar = YYEMPTY; *++yyvsp = yylval; #ifdef YYLSP_NEEDED *++yylsp = yylloc; #endif /* count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; yystate = yyn; goto yynewstate; /* Do the default action for the current state. */ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; /* Do a reduction. yyn is the number of a rule to reduce with. */ yyreduce: yylen = yyr2[yyn]; if (yylen > 0) yyval = yyvsp[1-yylen]; /* implement default value of the action */ #if YYDEBUG != 0 if (yydebug) { int i; fprintf (stderr, "Reducing via rule %d (line %d), ", yyn, yyrline[yyn]); /* Print the symbols being reduced, and their result. */ for (i = yyprhs[yyn]; yyrhs[i] > 0; i++) fprintf (stderr, "%s ", yytname[yyrhs[i]]); fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]); } #endif switch (yyn) { case 8: {store_res(&yyvsp[-1]); return 0;; break;} case 9: {store_res(&yyvsp[-1]); return 0;; break;} 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 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 14: {block_res = for_loop(yyvsp[-1].text, yyvsp[0].text); if(block_res == 1 || block_res == 2) return block_res;; break;} case 15: {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: {if(block_res = eval(&yyval, &yyvsp[0]) == 1) return 1; else return 2;; break;} case 17: {return 3;; break;} case 18: {yyerrok;; break;} case 19: {;; break;} case 20: {yyval.text=add_strings(yyvsp[-2].text, string_value(&yyvsp[0])); yyval.type = STR;; break;} case 21: {yyval.text=add_strings(string_value(&yyvsp[-2]), yyvsp[0].text); yyval.type = STR;; break;} case 22: {yyval.text=add_strings(yyvsp[-2].text, yyvsp[0].text); yyval.type = STR;; break;} case 23: {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: {;; break;} case 26: {;; break;} 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 28: {push(&yyval, &yyvsp[0]);yyval.type = ARR;; break;} case 29: {exec_clause(&yyval);; break;} case 30: {range_array(&yyval, yyvsp[0].text);; break;} 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 33: {yyval.val = yyvsp[-3].tptr->fnctptr ? ((yyvsp[-3].tptr->fnctptr)(yyvsp[-1].val)): 0.0; yyval.type = BOOLVAL;; break;} case 34: {yyval.val = 1.0; yyval.type = BOOLVAL;; break;} 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: {yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], EQ);; break;} case 39: {yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], NE);; break;} case 40: {yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], GT);; break;} case 41: {yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], GE);; break;} case 42: {yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], LT);; break;} case 43: {yyCompare(&yyval, &yyvsp[-2], &yyvsp[0], LE);; break;} case 48: {yyval.val = yyvsp[0].val; yyval.type = NUM;; break;} case 50: {yyval.val = yyvsp[0].val; yyval.type = BOOLVAL;; break;} case 51: {yyval.val = 0.0;; break;} case 52: {yyval.val = syntax_level ? syntax_level->clval : 0.0; yyval.type = NUM;; break;} case 53: {yyval.val = _PI; yyval.type = NUM;; break;} case 54: {yyval.val = 2.71828182845905; yyval.type = NUM;; break;} case 55: {if(yyvsp[0].tptr)yyvsp[0].tptr->GetValue(&yyval);; break;} case 56: {if(block_res = eval(&yyval, &yyvsp[0]))return block_res;; break;} case 57: {if(yyvsp[-2].tptr)yyvsp[-2].tptr->SetValue(&yyval, &yyvsp[0]);; break;} case 58: {if(yyvsp[-2].tptr)yyvsp[-2].tptr->SetValue(&yyval, &yyvsp[0]);; break;} case 59: {if(yyvsp[-2].tptr){yyvsp[-2].tptr->GetValue(&yyval); yyvsp[-2].tptr->SetValue(yyval.val + yyvsp[0].val);}; break;} case 60: {if(yyvsp[-2].tptr){yyvsp[-2].tptr->GetValue(&yyval); yyvsp[-2].tptr->SetValue(yyval.val - yyvsp[0].val);}; break;} case 61: {if(yyvsp[-2].tptr){yyvsp[-2].tptr->GetValue(&yyval); yyvsp[-2].tptr->SetValue(yyval.val * yyvsp[0].val);}; break;} 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 63: {yyval.val = yyvsp[-3].tptr->fnctptr ? ((yyvsp[-3].tptr->fnctptr)(yyvsp[-1].val)): 0.0; yyval.type = NUM;; break;} 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 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 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 67: {yyval.type = NUM; yyval.val = yyvsp[-3].tptr->fnctptr ? ((yyvsp[-3].tptr->fnctptr)(&yyvsp[-1], &yyval, 0L)) : 0.0;; break;} 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 69: {yyval.val = yyvsp[-5].tptr->fnctptr ? ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;; break;} 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 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 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 73: {if(yyvsp[-2].tptr->fnctptr)(*yyvsp[-2].tptr->fnctptr)(&yyval, 0L);; break;} case 74: {if(yyvsp[-3].tptr->fnctptr)(*yyvsp[-3].tptr->fnctptr)(&yyval, &yyvsp[-1]);; break;} case 75: {if(yyvsp[-5].tptr->fnctptr)(*yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);; break;} case 76: {if(yyvsp[-3].tptr->fnctptr)(*yyvsp[-3].tptr->fnctptr)(&yyval, &yyvsp[-1], 0L);; break;} case 77: {if(yyvsp[-7].tptr->fnctptr)(*yyvsp[-7].tptr->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);; break;} case 78: {if(yyvsp[-5].tptr->fnctptr)(*yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1], 0L);; break;} 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 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 81: {yyval.val = yyvsp[-2].val * yyvsp[0].val; yyval.type = NUM;; break;} 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 83: {yyval.val=yyvsp[-1].tptr->GetValue(); yyvsp[-1].tptr->SetValue(yyval.val+1.0); yyval.val -= 1.0; yyval.type = NUM;; break;} 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 85: {yyval.val=yyvsp[0].tptr->GetValue(); yyvsp[0].tptr->SetValue(yyval.val+1.0); yyval.type = NUM;; break;} case 86: {yyval.val=yyvsp[0].tptr->GetValue(); yyvsp[0].tptr->SetValue(yyval.val-1.0); yyval.type = NUM;; break;} 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 88: {yyval.val = -yyvsp[0].val; yyval.type = NUM;; break;} case 89: {memcpy(&yyval, &yyvsp[-1], sizeof(YYSTYPE)); yyvsp[-1].a_data = 0L; yyvsp[-1].a_count = 0;; break;} 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 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.a_data = 0L; yyval.a_count = 0; yyval.type = NUM;; break;} 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 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 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 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 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 97: {make_time(&yyval, yyvsp[-4].val, yyvsp[-2].val, yyvsp[0].val+1.0e-10);; break;} case 98: {make_time(&yyval, yyvsp[-2].val, yyvsp[0].val, 1.0e-10);; break;} case 99: {memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE)); break;} case 100: {memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE)); break;} case 101: {memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE)); break;} case 102: {memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE)); break;} } /* the action file gets copied in in place of this dollarsign */ yyvsp -= yylen; yyssp -= yylen; #ifdef YYLSP_NEEDED yylsp -= yylen; #endif #if YYDEBUG != 0 if (yydebug) { short *ssp1 = yyss - 1; fprintf (stderr, "state stack now"); while (ssp1 != yyssp) fprintf (stderr, " %d", *++ssp1); fprintf (stderr, "\n"); } #endif *++yyvsp = yyval; #ifdef YYLSP_NEEDED yylsp++; if (yylen == 0) { yylsp->first_line = yylloc.first_line; yylsp->first_column = yylloc.first_column; yylsp->last_line = (yylsp-1)->last_line; yylsp->last_column = (yylsp-1)->last_column; yylsp->text = 0; } else { yylsp->last_line = (yylsp+yylen-1)->last_line; yylsp->last_column = (yylsp+yylen-1)->last_column; } #endif /* Now "shift" the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTBASE] + *yyssp; if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTBASE]; goto yynewstate; yyerrlab: /* here on detecting error */ if (! yyerrstatus) /* If not already recovering from an error, report this error. */ { ++yynerrs; #ifdef YYERROR_VERBOSE yyn = yypact[yystate]; if (yyn > YYFLAG && yyn < YYLAST) { int size = 0; char *msg; int x, count; count = 0; /* Start X at -yyn if nec to avoid negative indexes in yycheck. */ for (x = (yyn < 0 ? -yyn : 0); x < (sizeof(yytname) / sizeof(char *)); x++) if (yycheck[x + yyn] == x) size += strlen(yytname[x]) + 15, count++; msg = (char *) malloc(size + 15); if (msg != 0) { strcpy(msg, "parse error"); if (count < 5) { count = 0; for (x = (yyn < 0 ? -yyn : 0); x < (sizeof(yytname) / sizeof(char *)); x++) if (yycheck[x + yyn] == x) { strcat(msg, count == 0 ? ", expecting `" : " or `"); strcat(msg, yytname[x]); strcat(msg, "'"); count++; } } yyerror(msg); free(msg); } else yyerror ("parse error; also virtual memory exceeded"); } else #endif /* YYERROR_VERBOSE */ yyerror("parse error"); } goto yyerrlab1; yyerrlab1: /* here on error raised explicitly by an action */ if (yyerrstatus == 3) { /* if just tried and failed to reuse lookahead token after an error, discard it. */ /* return failure if at end of input */ if (yychar == YYEOF) YYABORT; #if YYDEBUG != 0 if (yydebug) fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]); #endif yychar = YYEMPTY; } /* Else will try to reuse lookahead token after shifting the error token. */ yyerrstatus = 3; /* Each real token shifted decrements this */ goto yyerrhandle; yyerrdefault: /* current state does not do anything special for the error token. */ #if 0 /* This is wrong; only states that explicitly want error tokens should shift them. */ yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ if (yyn) goto yydefault; #endif yyerrpop: /* pop the current state because it cannot handle the error token */ if (yyssp == yyss) YYABORT; yyvsp--; yystate = *--yyssp; #ifdef YYLSP_NEEDED yylsp--; #endif #if YYDEBUG != 0 if (yydebug) { short *ssp1 = yyss - 1; fprintf (stderr, "Error: state stack now"); while (ssp1 != yyssp) fprintf (stderr, " %d", *++ssp1); fprintf (stderr, "\n"); } #endif yyerrhandle: yyn = yypact[yystate]; if (yyn == YYFLAG) goto yyerrdefault; yyn += YYTERROR; if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) goto yyerrdefault; yyn = yytable[yyn]; if (yyn < 0) { if (yyn == YYFLAG) goto yyerrpop; yyn = -yyn; goto yyreduce; } else if (yyn == 0) goto yyerrpop; if (yyn == YYFINAL) YYACCEPT; #if YYDEBUG != 0 if (yydebug) fprintf(stderr, "Shifting error token, "); #endif *++yyvsp = yylval; #ifdef YYLSP_NEEDED *++yylsp = yylloc; #endif yystate = yyn; goto yynewstate; yyacceptlab: /* YYACCEPT comes here. */ if (yyfree_stacks) { free (yyss); free (yyvs); #ifdef YYLSP_NEEDED free (yyls); #endif } return 0; yyabortlab: /* YYABORT comes here. */ if (yyfree_stacks) { free (yyss); free (yyvs); #ifdef YYLSP_NEEDED free (yyls); #endif } return 1; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Cache spreadsheet data for repeated access //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class SsRangeData { typedef struct _rng_data { _rng_data *next; unsigned int h1, h2; RECT rec; double *vals; char *name; int nvals; double dSum, dMean, dQuart1, dQuart2, dQuart3; bool bSum, bMean, bQuart1, bQuart2, bQuart3; }rng_data; public: SsRangeData(); ~SsRangeData(); void Clear(); bool GetData(char *rng_desc, double **vals, int *nvals, char **name); void rmData(double *vals, int nvals); void cellModified(int row, int col); double sum(double *vals, int nvals); double mean(double *vals, int nvals); double quartile1(double *vals, int nvals); double quartile2(double *vals, int nvals); double quartile3(double *vals, int nvals); private: rng_data *RngData; bool FindData(unsigned int h1, unsigned int h2, rng_data **rda); bool FindData(double *vals, int nvals, rng_data **rda); bool SetArray(rng_data *rda, char *range); void do_quartiles(rng_data *rda); }; SsRangeData::SsRangeData() { RngData = 0L; } SsRangeData::~SsRangeData() { Clear(); } void SsRangeData::Clear() { rng_data *nxt; nxt = RngData; while(nxt) { nxt = RngData->next; if(RngData->vals) free(RngData->vals); if(RngData->name) free(RngData->name); free(RngData); RngData = nxt; } } bool SsRangeData::FindData(unsigned int h1, unsigned int h2, rng_data **rda) { rng_data *nxt; nxt = RngData; while(nxt) { if(nxt->h1 == h1 && nxt->h2 == h2) { *rda = nxt; return true; } nxt = nxt->next; } return false; } bool SsRangeData::FindData(double *vals, int nvals, rng_data **rda) { rng_data *nxt; nxt = RngData; while(nxt) { if(nxt->vals == vals && nxt->nvals == nvals) { *rda = nxt; return true; } nxt = nxt->next; } return false; } bool SsRangeData::SetArray(rng_data *rda, char *range) { AccRange *r; int row, col; anyResult ares; if(!range || !range[0] || !(r = new AccRange(range))) return false; if(!r->GetFirst(&col, &row) || !(rda->vals = (double*)malloc(r->CountItems() * sizeof(double)))) { delete(r); return false; } r->BoundRec(&rda->rec); parse_level++; r->GetFirst(&col, &row); for(rda->nvals = 0; r->GetNext(&col, &row); ) { if(curr_data->GetResult(&ares, row, col, parse_level > MAX_PARSE)) { switch(ares.type) { case ET_VALUE: case ET_TIME: case ET_DATE: case ET_DATETIME: case ET_BOOL: rda->vals[rda->nvals++] = ares.value; break; } } } rda->name = (char*)memdup(range, (int)strlen(range)+1, 0); parse_level--; delete(r); return true; } void SsRangeData::rmData(double *vals, int nvals) { rng_data *rda, *rmrda; if(!FindData(vals, nvals, &rmrda)) return; if(rmrda == RngData) RngData = RngData->next; else { rda = RngData; while(rda->next && rda->next != rmrda) rda = rda->next; if(rda->next == rmrda) rda->next = rmrda->next; else return; } rda = RngData; while(rda) { if(((rda->rec.top <= rmrda->rec.top && rda->rec.bottom >= rmrda->rec.top) || (rda->rec.top <= rmrda->rec.bottom && rda->rec.top >= rmrda->rec.top)) &&((rda->rec.left <= rmrda->rec.left && rda->rec.right >= rmrda->rec.left) || (rda->rec.left <= rmrda->rec.right && rda->rec.left >= rmrda->rec.left))){ rmData(rda->vals, rda->nvals); rda = RngData; } else rda = rda->next; } if(rmrda->vals) free(rmrda->vals); if(rmrda->name) free(rmrda->name); free(rmrda); } void SsRangeData::cellModified(int row, int col) { rng_data *nxt; nxt = RngData; while(nxt) { if(col >= nxt->rec.left && col <= nxt->rec.right && row >= nxt->rec.top && col <= nxt->rec.bottom){ rmData(nxt->vals, nxt->nvals); nxt = RngData; } else nxt = nxt->next; } return; } void SsRangeData::do_quartiles(rng_data *rda) { double *vals; if(rda->vals && rda->nvals && (vals = (double*)memdup(rda->vals, rda->nvals*sizeof(double), 0))){ d_quartile(rda->nvals, vals, &rda->dQuart1, &rda->dQuart2, &rda->dQuart3); free(vals); } rda->bQuart1 = rda->bQuart2 = rda->bQuart3 = true; } bool SsRangeData::GetData(char *rng_desc, double **vals, int *nvals, char **name) { rng_data *rda; unsigned int h1, h2; h1 = HashValue((unsigned char*) rng_desc); h2 = Hash2((unsigned char*) rng_desc); if(FindData(h1, h2, &rda)) { *vals = rda->vals; *nvals = rda->nvals; if(name) *name = rda->name; return true; } if(!(rda = (rng_data*) calloc(1, sizeof(rng_data))))return false; SetArray(rda, rng_desc); *vals = rda->vals; *nvals = rda->nvals; if(name) *name = rda->name; rda->h1 = h1; rda->h2 = h2; rda->next = RngData; RngData = rda; return true; } double SsRangeData::sum(double *vals, int nvals) { rng_data *rda; int i; double tmp; if(FindData(vals, nvals, &rda)) { if(rda->bSum) return rda->dSum; for(i = 0, tmp = 0.0; i < nvals; i++) tmp += vals[i]; rda->dSum = tmp; rda->bSum = true; return rda->dSum; } for(i = 0, tmp = 0.0; i < nvals; i++) tmp += vals[i]; return tmp; } double SsRangeData::mean(double *vals, int nvals) { rng_data *rda; if(FindData(vals, nvals, &rda)) { if(rda->bMean) return rda->dMean; rda->dMean = d_amean(nvals, vals); rda->bMean = true; return rda->dMean; } return d_amean(nvals, vals); } double SsRangeData::quartile1(double *vals, int nvals) { rng_data *rda; if(FindData(vals, nvals, &rda)) { if(rda->bQuart1) return rda->dQuart1; do_quartiles(rda); return rda->dQuart1; } return HUGE_VAL; } double SsRangeData::quartile2(double *vals, int nvals) { rng_data *rda; if(FindData(vals, nvals, &rda)) { if(rda->bQuart2) return rda->dQuart2; do_quartiles(rda); return rda->dQuart2; } return HUGE_VAL; } double SsRangeData::quartile3(double *vals, int nvals) { rng_data *rda; if(FindData(vals, nvals, &rda)) { if(rda->bQuart3) return rda->dQuart3; do_quartiles(rda); return rda->dQuart3; } return HUGE_VAL; } static SsRangeData RangeData; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // The symrec class //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ symrec::symrec(unsigned int h_n, unsigned int h2_n, int typ, symrec *nxt) { h_name = h_n; h2_name = h2_n; type = typ; next = nxt; row = col = -1; name = text = 0L; var = 0.0; isSSval = isValid = false; a_data = 0L; a_count = 0; fnctptr = (double (*)(...))nop; } symrec::~symrec() { if(name) free(name); name = 0L; if(text) free(text); text = 0L; } double symrec::GetValue() { anyResult ares; 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)){ return var = ares.value; } isSSval = false; row = col = -1; } if(!isValid) NoInit(); return var; } void symrec::GetValue(void *re) { anyResult ares; YYSTYPE *res = (YYSTYPE*)re; int i; if(!res) return; if(isSSval && !bNoSS) { if(row < 0 && col < 0) InitSS(); res->a_data = 0L; res->a_count = 0; //GetResult( , , ,true) inhibits reentrance into parser ! if(curr_data->GetResult(&ares, row, col, parse_level > MAX_PARSE)){ isValid = true; if(text) free(text); text = 0L; switch(ares.type) { case ET_VALUE: res->type = NUM; res->val = ares.value; res->text = 0L; break; case ET_BOOL: res->type = BOOLVAL; res->val = ares.value; res->text = 0L; break; case ET_DATE: res->type = DATE1; res->val = ares.value; res->text = 0L; break; case ET_TIME: res->type = TIME1; res->val = ares.value; res->text = 0L; break; case ET_DATETIME: res->type = DATETIME1; res->val = ares.value; res->text = 0L; break; case ET_TEXT: 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; } var = res->val; return; } isSSval = false; row = col = -1; } if(!isValid) NoInit(); if(a_data && a_count) { res->text = 0L; res->a_count = a_count; res->a_data = a_data; res->val = 0.0; res->type = ARR; } else if(text && text[0]) { res->text = text; res->a_data = 0L; res->a_count = 0; res->val = 0.0; res->type = STR; } else { res->type = NUM; res->val = var; res->a_data = 0L; res->a_count = 0; res->text = 0L; } } double symrec::SetValue(double v) { if(isSSval && !bNoWrite) { if(row < 0 && col < 0) InitSS(); if(curr_data->SetValue(row, col, v)){ if(curr_data) curr_data->Command(CMD_UPDATE, 0L, 0L); RangeData.cellModified(row, col); return var = v; } isSSval = false; row = col = -1; } isValid = true; a_data = 0L; a_count = 0; return var = v; } void symrec::SetValue(void* d, void* s) { YYSTYPE *dest = (YYSTYPE*)d; YYSTYPE *src = (YYSTYPE*)s; if(isSSval && curr_data && !bNoWrite) { if(row < 0 && col < 0) InitSS(); if(last_err_desc) curr_data->SetText(row, col, last_err_desc); else if(src->type == STR) curr_data->SetText(row, col, src->text); else if(src->type == ARR || src->type == RANGEARR || (src->a_data)) curr_data->SetText(row, col, "#ARRAY"); else if(src->type == VAR && src->tptr->type == TXT) curr_data->SetText(row, col, src->tptr->text); else { if(curr_data->SetValue(row, col, src->val)) switch(src->type) { case BOOLVAL: curr_data->etRows[row][col]->type = ET_BOOL; break; } } curr_data->Command(CMD_UPDATE, 0L, 0L); RangeData.cellModified(row, col); } isValid = true; var = src->val; if(src->a_data && src->a_count) { a_data = src->a_data; a_count = src->a_count; } else if(src->text && src->text[0] && src->text != text) { if(text) free(text); text = 0L; text =(char*)memdup(src->text, (int)strlen(src->text)+1, 0); } if(d) GetValue(d); return; } void symrec::SetName(char *nam) { if(name || !nam || !nam[0]) return; name = (char*)memdup(nam, (int)strlen(nam)+1, 0); isValid = false; if((name && curr_data) && (isalpha(name[0]) || name[0] == '$') && isdigit(name[strlen(name)-1])) isSSval=true; } void symrec::InitSS() { AccRange *ar; if(row<0 && col<0 &&(ar = new AccRange(name))) { ar->GetFirst(&col, &row); delete(ar); } } void symrec::NoInit() { char message[200]; #ifdef USE_WIN_SECURE sprintf_s(message, 80, "Accessing variable '%s'\nwithout initialization!\n", name); #else sprintf(message, "Accessing variable '%s'\nwithout initialization!\n", name); #endif yywarn(message, true); } void LockData(bool lockExec, bool lockWrite) { RangeData.Clear(); bNoWrite = lockWrite; bNoExec = lockExec; bNoSS = false; } static void yyerror(char *s) { //called by yyparse on error if(curr_data) curr_data->Command(CMD_ERROR, last_error = s, 0L); else printf("%s\n", s); } static void yyargserr(char *s) { //call from function on argument type mismatch yyerror(s); last_err_desc = "#ARGS"; } static void yyargcnterr(char *s) { //call from function on argument number mismatch static char arg_cnt_err[80]; int cb; cb = rlp_strcpy(arg_cnt_err, 80, "Wrong number of arguments\nin call to "); cb += rlp_strcpy(arg_cnt_err+cb, 80-cb, s); rlp_strcpy(arg_cnt_err+cb, 80-cb, "."); yyargserr(arg_cnt_err); } static void yybadargerr(char *s) { //call from function on argument number mismatch static char bad_arg_err[80]; int cb; cb = rlp_strcpy(bad_arg_err, 80, "Bad arguments in call to function\n"); cb += rlp_strcpy(bad_arg_err+cb, 80-cb, s); rlp_strcpy(bad_arg_err+cb, 80-cb, "."); yyargserr(bad_arg_err); } static char txt_tokenerr[80]; static void yytokenerr(int c) { #ifdef USE_WIN_SECURE sprintf_s(txt_tokenerr, 80, "Illegal character\nor token '%c'\n", (char)c); #else sprintf(txt_tokenerr, "Illegal character\nor token '%c'\n", (char)c); #endif yyerror(txt_tokenerr); } static void make_time(YYSTYPE *dst, double h, double m, double s) { if(!dst || h < 0.0 || 24.0 < h || m < 0.0 || 60.0 < m || s < 0.0 || 60.0 < s) { yyerror("parse error"); return; } dst->val = s/60.0 + m; dst->val = dst->val/60.0 + h; dst->val /= 24.0; dst->type = TIME1; } static char yywarn_text[200]; char *yywarn(char *txt, bool bNew) { if(bNew) { if(txt && txt[0]) { rlp_strcpy(yywarn_text, 200, txt); return yywarn_text; } else { yywarn_text[0] = 0; return 0L; } } else if(yywarn_text[0]) return yywarn_text; 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) { line_res.type = ET_TEXT; line_res.value = 0.0; rlp_strcpy(res_txt, 1000, last_err_desc); } else if(res->type == NUM){ line_res.type = ET_VALUE; line_res.value = res->val; } else if(res->type == BOOLVAL){ line_res.type = ET_BOOL; line_res.value = res->val; } else if(res->type == DATE1){ line_res.type = ET_DATE; line_res.value = res->val; } else if(res->type == TIME1){ line_res.type = ET_TIME; line_res.value = res->val; } else if(res->type == DATETIME1){ line_res.type = ET_DATETIME; line_res.value = res->val; } else if(res->type == STR) { line_res.type = ET_TEXT; line_res.value = 0.0; if(res->text) rlp_strcpy(res_txt, 1000, res->text); } else if((res->type == ARR || res->type == RANGEARR || (res->a_data)) && res->a_count == 1) { line_res.type = ET_VALUE; line_res.value = res->a_data[0]; } else if(res->type == ARR && !(res->a_data) && !(res->a_count)) { line_res.type = ET_VALUE; line_res.value = res->val; } else if(res->type == ARR || res->type == RANGEARR || (res->a_data)) { line_res.type = ET_TEXT; line_res.value = 0.0; line_res.a_data = res->a_data; line_res.a_count = res->a_count; 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; line_res.value = 0.0; if(res->tptr->text) rlp_strcpy(res_txt, 1000, res->tptr->text); } else { line_res.type = ET_VALUE; line_res.value = res->val; } } static char *add_strings(char *st1, char *st2) { char *newstr, *ret; int cb; if(st1 && st2) { if(newstr = (char*)malloc(cb = (int)(strlen(st1) +strlen(st2) +4))) { #ifdef USE_WIN_SECURE sprintf_s(newstr, cb, "%s%s", st1, st2); #else sprintf(newstr, "%s%s", st1, st2); #endif ret = PushString(newstr); free(newstr); return ret; } else return 0L; } if(st1) return st1; if(st2) return st2; return 0L; } static char *string_value(YYSTYPE *exp) { char *st1, tmp[50]; if(exp->type == STR){ st1 = exp->text; } else if(exp->tptr && exp->tptr->type == TXT) { st1 = exp->tptr->text; } else { #ifdef USE_WIN_SECURE sprintf_s(tmp, 50, "%g", exp->val); #else sprintf(tmp,"%g", exp->val); #endif st1 = tmp; } return PushString(st1); } // store syntactical information static void push_syntax() { syntax_info *next; if(!(next = (syntax_info*)calloc(1, sizeof(syntax_info)))) return; if(syntax_level)memcpy(next, syntax_level, sizeof(syntax_info)); next->next=syntax_level; syntax_level = next; } static void pop_syntax() { syntax_info *si; if(si = syntax_level) { syntax_level = si->next; free(si); } } static int eval(YYSTYPE *dst, YYSTYPE *sr) { char *s_buffer; int s_buff_pos, s_yychar, s_yynerrs, length, parse_res; anyResult *ar; if(bNoExec) return 0; if(!sr || !sr->text || !sr->text[0]) return 1; s_buffer = buffer; s_buff_pos = buff_pos; s_yychar = yychar; s_yynerrs = yynerrs; if(!(length = (int)strlen(sr->text)))return 1; parse_level++; if(sr->text[length-1] == ';') buffer = sr->text; else { buffer = (char*)malloc(length+2); rlp_strcpy(buffer, length+1, sr->text); buffer[length++] = ';'; buffer[length] = 0; } if(buffer && buffer[0]){ buff_pos = 0; while(!(parse_res = yyparse()) && buff_pos < length); if(buffer != sr->text) free(buffer); ar = &line_res; buffer = s_buffer; buff_pos = s_buff_pos; yychar = s_yychar; yynerrs = s_yynerrs; } else return 1; dst->a_data = ar->a_data; dst->a_count = ar->a_count; if(parse_res == 2) return 2; else if(parse_res == 3 && sr->type == IBLOCK) return 3; else if(parse_res == 1) return 1; switch(ar->type) { case ET_BOOL: dst->type = BOOLVAL; dst->val = ar->value; dst->text = 0L; break; case ET_VALUE: dst->type = NUM; dst->val = ar->value; dst->text = 0L; break; case ET_TEXT: dst->type = STR; dst->val = 0.0; dst->text = PushString(ar->text); break; default: dst->type = NUM; dst->val = 0.0; dst->text = 0L; break; } parse_level--; return 0; } // more functions static double sign(double v) { if(v > 0.0) return 1.0; if(v < 0.0) return -1.0; return 0.0; } static long idum=0; static double rand1(YYSTYPE *dst, YYSTYPE *src) { if(!dst) return 0.0; dst->type = NUM; return(dst->val = ran2(&idum)); } static double srand(double v) { idum = (long)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); } static double _strlen(YYSTYPE *sr, YYSTYPE *dst, char *dum) { if(dum) yyerror("parse error"); if(!sr || !sr->text) return 0.0; return (double)strlen(sr->text); } #undef min static double min(YYSTYPE *sr) { int i; if(!sr || !sr->a_count) return 0.0; if(sr->a_data && sr->a_data){ for(i = 1, sr->val = sr->a_data[0]; i < sr->a_count; i++) if(sr->a_data[i] < sr->val) sr->val = sr->a_data[i]; } return sr->val; } #undef max static double max(YYSTYPE *sr) { int i; if(!sr || !sr->a_count) return 0.0; if(sr->a_data){ for(i = 1, sr->val = sr->a_data[0]; i < sr->a_count; i++) if(sr->a_data[i] > sr->val) sr->val = sr->a_data[i]; } return sr->val; } static double count(YYSTYPE *sr) { if(!sr) return 0.0; if(sr->a_data) sr->val = (double)sr->a_count; else sr->val = 0.0; return sr->val; } static double sum(YYSTYPE *sr) { int i; if(!sr) return 0.0; if(sr->type == RANGEARR && sr->a_data) { sr->val = RangeData.sum(sr->a_data, sr->a_count); } else if(sr->a_data){ for(i = 0, sr->val = 0.0; i < sr->a_count; i++) sr->val += sr->a_data[i]; } else sr->val = 0.0; return sr->val; } static double mean(YYSTYPE *sr) { if(!sr) return 0.0; if(sr->type == RANGEARR && sr->a_data) { sr->val = RangeData.mean(sr->a_data, sr->a_count); } else if(sr->a_data && sr->a_count){ sr->val = d_amean(sr->a_count, sr->a_data ); } else sr->val = 0.0; return sr->val; } static double kurt(YYSTYPE *sr) { if(!sr) return 0.0; if(sr->a_data && sr->a_count > 3){ sr->val = d_kurt(sr->a_count, sr->a_data ); } else sr->val = 0.0; return sr->val; } static double skew(YYSTYPE *sr) { if(!sr) return 0.0; if(sr->a_data && sr->a_count > 2){ sr->val = d_skew(sr->a_count, sr->a_data ); } else sr->val = 0.0; return sr->val; } static double gmean(YYSTYPE *sr) { int i; if(!sr) return 0.0; if(sr->a_data && sr->a_count){ for(i = 0; i < sr->a_count; i++) if(sr->a_data[i] <= 0.0) { last_err_desc = "#VALUE"; return sr->val = 0.0; } sr->val = d_gmean(sr->a_count, sr->a_data ); } else sr->val = 0.0; return sr->val; } static double hmean(YYSTYPE *sr) { int i; if(!sr) return 0.0; if(sr->a_data && sr->a_count){ for(i = 0; i < sr->a_count; i++) if(sr->a_data[i] <= 0.0) { last_err_desc = "#VALUE"; return sr->val = 0.0; } sr->val = d_hmean(sr->a_count, sr->a_data ); } else sr->val = 0.0; return sr->val; } static double quartile1(YYSTYPE *sr) { if(!sr) return 0.0; if(sr->type == RANGEARR && sr->a_data) { sr->val = RangeData.quartile1(sr->a_data, sr->a_count); } else if(sr->a_data && sr->a_count){ d_quartile(sr->a_count, sr->a_data, &sr->val, 0L, 0L); } else sr->val = 0.0; return sr->val; } static double quartile2(YYSTYPE *sr) { if(!sr) return 0.0; if(sr->type == RANGEARR && sr->a_data) { sr->val = RangeData.quartile2(sr->a_data, sr->a_count); } else if(sr->a_data && sr->a_count){ d_quartile(sr->a_count, sr->a_data, 0L, &sr->val, 0L); } else sr->val = 0.0; return sr->val; } static double quartile3(YYSTYPE *sr) { if(!sr) return 0.0; if(sr->type == RANGEARR && sr->a_data) { sr->val = RangeData.quartile3(sr->a_data, sr->a_count); } else if(sr->a_data && sr->a_count){ d_quartile(sr->a_count, sr->a_data, 0L, 0L, &sr->val); } else sr->val = 0.0; return sr->val; } static double variance(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count){ sr->val = d_variance(sr->a_count, sr->a_data); } return sr->val; } static double stdev(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count){ sr->val = sqrt(d_variance(sr->a_count, sr->a_data)); } return sr->val; } static double sterr(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count){ sr->val = sqrt(d_variance(sr->a_count, sr->a_data))/sqrt((double)sr->a_count); } return sr->val; } static double beta(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = betaf(sr->a_data[0], sr->a_data[1]); } else yyargcnterr("beta(u, v)"); return sr->val; } static double _gammp(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = gammp(sr->a_data[0], sr->a_data[1]); } else yyargcnterr("gammp(a, x)"); return sr->val; } static double _gammq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = gammq(sr->a_data[0], sr->a_data[1]); } else yyargcnterr("gammq(a, x)"); return sr->val; } static double _betai(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 3){ if(sr->a_data[2] < 0.0 || sr->a_data[2] > 1.0) { last_err_desc = "#VALUE"; return sr->val = 0.0; } sr->val = betai(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("betai(a, b, x)"); return sr->val; } static double _bincof(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = bincof(sr->a_data[0], sr->a_data[1]); } else yyargcnterr("bincof(n, k)"); return sr->val; } static double binomdist(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 3){ sr->val = binomdistf(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("binomdist(s, n, p)"); return sr->val; } static double binomfreq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 3){ sr->val = bincof(sr->a_data[1], sr->a_data[0]); sr->val *= pow(sr->a_data[2], sr->a_data[0]); sr->val *= pow(1.0 - sr->a_data[2], sr->a_data[1] - sr->a_data[0]); } else yyargcnterr("binomfreq(s, n, p)"); return sr->val; } static double normdist(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 3){ sr->val = norm_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("normdist(x, mean, SD)"); return sr->val; } static double norminv(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 3) { sr->val = distinv(norm_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], sr->a_data[1]); } else yyargcnterr("norminv(p, mean, SD)"); return sr->val; } static double normfreq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 3){ sr->val = norm_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("normfreq(x, mean, SD)"); return sr->val; } static double expdist(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = exp_dist(sr->a_data[0], sr->a_data[1], 0.0); } else yyargcnterr("expdist(x, l)"); return sr->val; } static double expinv(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2) { sr->val = exp_inv(sr->a_data[0], sr->a_data[1], 0.0); } else yyargcnterr("expinv(p, l)"); return sr->val; } static double expfreq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = exp_freq(sr->a_data[0], sr->a_data[1], 0.0); } else yyargcnterr("expfreq(x, l)"); return sr->val; } static double lognormdist(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 3){ sr->val = lognorm_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("lognormdist(x, mean, SD)"); return sr->val; } static double lognormfreq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 3){ sr->val = lognorm_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("lognormfreq(x, mean, SD)"); return sr->val; } static double lognorminv(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 3) { sr->val = distinv(lognorm_dist, sr->a_data[1], sr->a_data[2], sr->a_data[0], exp(sr->a_data[1])); } else yyargcnterr("lognorminv(p, mean, SD)"); return sr->val; } static double chidist(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = chi_dist(sr->a_data[0], sr->a_data[1], 1.0); } else yyargcnterr("chidist(x, df)"); return sr->val; } static double chifreq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = chi_freq(sr->a_data[0], sr->a_data[1]); } else yyargcnterr("chifreq(x, df)"); return sr->val; } static double chiinv(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2) { sr->val = distinv(chi_dist,sr->a_data[1], 1.0, sr->a_data[0], 2.0); } else yyargcnterr("chiinv(p, df)"); return sr->val; } static double tdist(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = t_dist(sr->a_data[0], sr->a_data[1], 1.0); } else yyargcnterr("tdist(x, df)"); return sr->val; } static double tfreq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = t_freq(sr->a_data[0], sr->a_data[1]); } else yyargcnterr("tfreq(x, df)"); return sr->val; } static double tinv(YYSTYPE *sr) { double dtmp; if(!sr) return 0.0; sr->val = 0.0; dtmp = sr->a_data[1] > 1.0E+10 ? 1.0E+10 : sr->a_data[1]; if(sr->a_data && sr->a_count == 2) { sr->val = fabs(distinv(t_dist,dtmp, 1.0, sr->a_data[0], 2.0)); } else yyargcnterr("tinv(p, df)"); return sr->val; } static double poisdist(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = pois_dist(sr->a_data[0], sr->a_data[1], 1.0); } else yyargcnterr("poisdist(x, mean)"); return sr->val; } static double poisfreq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = exp(log(sr->a_data[1])*sr->a_data[0] - sr->a_data[1] - gammln(1.0 + sr->a_data[0])); } else yyargcnterr("poisfreq(x, mean)"); return sr->val; } static double fdist(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 3){ sr->val = f_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("fdist(x, df1, df2)"); return sr->val; } static double ffreq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 3){ sr->val = f_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("ffreq(x, df1, df2)"); return sr->val; } static double finv(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0; if(sr->a_data && sr->a_count == 3){ sr->val = distinv(f_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], 2.0); } else yyargcnterr("finv(p, df1, df2)"); return sr->val; } static double weibdist(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = weib_dist(sr->a_data[0], sr->a_data[1], 1.0); } if(sr->a_data && sr->a_count == 3){ sr->val = weib_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("weibdist(x, shape[, scale=1])"); return sr->val; } static double weibfreq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = weib_freq(sr->a_data[0], sr->a_data[1], 1.0); } if(sr->a_data && sr->a_count == 3){ sr->val = weib_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("weibfreq(x, shape[, scale=1])"); return sr->val; } static double weibinv(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0; if(sr->a_data && sr->a_count == 2){ sr->val = distinv(weib_dist,sr->a_data[1], 1.0, sr->a_data[0], 1.0); } else if(sr->a_data && sr->a_count == 3){ sr->val = distinv(weib_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0],sr->a_data[2]); } else yyargcnterr("weibinv(p, shape[, scale=1])"); 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; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = cauch_dist(sr->a_data[0], sr->a_data[1], 1.0); } else if(sr->a_data && sr->a_count == 3){ sr->val = cauch_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("cauchydist(x, location[, scale=1])"); return sr->val; } static double cauchyfreq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = cauch_freq(sr->a_data[0], sr->a_data[1], 1.0); } else if(sr->a_data && sr->a_count == 3){ sr->val = cauch_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("cauchyfreq(x, location[, scale=1])"); return sr->val; } static double cauchyinv(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0; if(sr->a_data && sr->a_count == 2){ sr->val = distinv(cauch_dist,sr->a_data[1], 1.0, sr->a_data[0], sr->a_data[1]); } else if(sr->a_data && sr->a_count == 3){ sr->val = distinv(cauch_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], sr->a_data[1]); } else yyargcnterr("cauchyinv(p, location[, scale=1])"); return sr->val; } static double logisdist(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = logis_dist(sr->a_data[0], sr->a_data[1], 1.0); } else if(sr->a_data && sr->a_count == 3){ sr->val = logis_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("logisdist(x, location[, scale=1])"); return sr->val; } static double logisfreq(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0.0; if(sr->a_data && sr->a_count == 2){ sr->val = logis_freq(sr->a_data[0], sr->a_data[1], 1.0); } else if(sr->a_data && sr->a_count == 3){ sr->val = logis_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]); } else yyargcnterr("logisfreq(x, location[, scale=1])"); return sr->val; } static double logisinv(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0; if(sr->a_data && sr->a_count == 2){ sr->val = distinv(logis_dist,sr->a_data[1], 1.0, sr->a_data[0], sr->a_data[1]); } else if(sr->a_data && sr->a_count == 3){ sr->val = distinv(logis_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], sr->a_data[1]); } else yyargcnterr("logisinv(p, location[, scale=1])"); return sr->val; } static void pearson(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst) { char *dest; double *arr; if(!sr1 || !sr2) return; if(dst && !bNoWrite) dest = dst->text; else dest = 0L; if(dst && dst->a_data && dst->a_count > 3) arr = dst->a_data; else arr = 0L; lval->val = 0.0; lval->type = NUM; if(sr1->text && sr2->text)range_array2(sr1, sr2); if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){ lval->val = d_pearson(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr); } else yybadargerr("pearson(range1; range2 [;\"dest\"])"); if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count); } static void spearman(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst) { char *dest; double *arr; if(!sr1 || !sr2) return; if(dst && !bNoWrite) dest = dst->text; else dest = 0L; if(dst && dst->a_data && dst->a_count > 5) arr = dst->a_data; else arr = 0L; lval->val = 0.0; lval->type = NUM; if(sr1->text && sr2->text)range_array2(sr1, sr2); if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){ lval->val = d_spearman(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr); } else yybadargerr("spearman(range1; range2 [;\"dest\"])"); if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count); } static void kendall(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst) { char *dest; double *arr; if(!sr1 || !sr2) return; if(dst && !bNoWrite) dest = dst->text; else dest = 0L; if(dst && dst->a_data && dst->a_count > 5) arr = dst->a_data; else arr = 0L; lval->val = 0.0; lval->type = NUM; if(sr1->text && sr2->text)range_array2(sr1, sr2); if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){ lval->val = d_kendall(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr); } else yybadargerr("kendall(range1; range2 [;\"dest\"])"); if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count); } static void regression(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst) { char *dest; double *arr; if(!sr1 || !sr2) return; if(dst && !bNoWrite) dest = dst->text; else dest = 0L; if(dst && dst->a_data && dst->a_count > 9) arr = dst->a_data; else arr = 0L; lval->val = 0.0; lval->type = NUM; if(sr1->text && sr2->text)range_array2(sr1, sr2); if(!dest && !arr) yyargserr("No destination range in call to function\nregression(range1; range2; \"dest\")."); if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){ lval->val = d_regression(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr); } else yybadargerr("regression(range1; range2; \"dest\")"); if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count); } static void _covar(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2) { if(!sr1 || !sr2) return; lval->val = 0.0; if(sr1->text && sr2->text)range_array2(sr1, sr2); if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){ lval->val = d_covar(sr1->a_data, sr2->a_data, sr1->a_count, 0L, curr_data); } else yybadargerr("covar(range1; range2)"); return; } static void ttest(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst) { char *dest; double *arr; if(!sr1 || !sr2) return; if(dst && !bNoWrite) dest = dst->text; else dest = 0L; if(dst && dst->a_data && dst->a_count > 9) arr = dst->a_data; else arr = 0L; lval->val = 0.0; lval->type = NUM; if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr2->a_count > 1){ lval->val = d_ttest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data, arr); } else yybadargerr("ttest(array1; array2[;\"dest\"])"); if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count); } static void ttest2(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst) { char *dest; double *arr; if(!sr1 || !sr2) return; if(dst && !bNoWrite) dest = dst->text; else dest = 0L; if(dst && dst->a_data && dst->a_count > 6) arr = dst->a_data; else arr = 0L; lval->val = 0.0; lval->type = NUM; if(sr1->text && sr2->text)range_array2(sr1, sr2); if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr2->a_count == sr1->a_count){ lval->val = sr2->val = d_ttest2(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, arr); } else yybadargerr("ttest2(range1; range2[;\"dest\"])"); if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count); } static void utest(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst) { char *dest; double *arr; if(!sr1 || !sr2) return; if(dst && !bNoWrite) dest = dst->text; else dest = 0L; if(dst && dst->a_data && dst->a_count > 9) arr = dst->a_data; else arr = 0L; lval->val = 0.0; lval->type = NUM; if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr2->a_count > 1){ lval->val = d_utest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data, arr); } else yybadargerr("utest2(array1; array2[;\"dest\"])"); if(dst && dst->type == RANGEARR) RangeData.rmData(dst->a_data, dst->a_count); } static void ftest(YYSTYPE *lval, YYSTYPE *sr1, YYSTYPE *sr2, YYSTYPE *dst) { char *dest; double *arr; if(!sr1 || !sr2) return; if(dst && !bNoWrite) dest = dst->text; else dest = 0L; if(dst && dst->a_data && dst->a_count > 9) arr = dst->a_data; else arr = 0L; lval->val = 0.0; lval->type = NUM; if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count > 1){ lval->val = d_ftest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data, arr); } else yybadargerr("ftest(range1; range2[;\"dest\"])"); } static double p_tukey(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0; if(sr->a_data && sr->a_count == 4){ sr->val = ptukey(sr->a_data[0], sr->a_data[3], sr->a_data[1], sr->a_data[2], 1, 0); } else if(sr->a_data && sr->a_count == 3){ sr->val = ptukey(sr->a_data[0], 1.0, sr->a_data[1], sr->a_data[2], 1, 0); } else yyargcnterr("ptukey(q, nm, df[, nr = 1])"); return sr->val; } static double q_tukey(YYSTYPE *sr) { if(!sr) return 0.0; sr->val = 0; if(sr->a_data && sr->a_count == 4){ sr->val = qtukey(sr->a_data[0], sr->a_data[3], sr->a_data[1], sr->a_data[2], 1, 0); } else if(sr->a_data && sr->a_count == 3){ sr->val = qtukey(sr->a_data[0], 1.0, sr->a_data[1], sr->a_data[2], 1, 0); } else yyargcnterr("qtukey(p, nm, df[, nr = 1])"); return sr->val; } static double fill(YYSTYPE *sr, char *dest) { AccRange *ar; int i, r, c; if(!sr || !sr->a_data || !sr->a_count || !dest || !dest[0] || bNoWrite) return 0.0; if(ar = new AccRange(dest)) { for(i=0, ar->GetFirst(&c, &r); ar->GetNext(&c, &r) && i < sr->a_count; i++) { curr_data->SetValue(r, c, sr->a_data[i]); } delete ar; } return sr->val = i; } static void datestr(YYSTYPE *dst, YYSTYPE *src, char *fmt) { dst->text = PushString(value_date(src->val, fmt)); } static double dateval(YYSTYPE *sr, YYSTYPE *dst, char *fmt) { if(!sr || !sr->text) return 0.0; if(fmt && fmt[0] && date_value(sr->text, fmt, &dst->val)) return dst->val; if(date_value(sr->text, 0L, &dst->val)) return dst->val; else return dst->val = 0.0; } static double leapyear(double year) { int y = (int)year; return (double)((y % 4 == 0 && y % 100 != 0) || y % 400 == 0); } static void today(YYSTYPE *dst, YYSTYPE *src) { if(src) yyerror("parse error"); if(!dst) return; dst->val = floor(now_today()); dst->type = DATE1; } static void now(YYSTYPE *dst, YYSTYPE *src) { if(src) yyerror("parse error"); if(!dst) return; dst->val = now_today(); dst->val -= floor(dst->val); dst->type = TIME1; } static double year(double dv) { int res; split_date(dv, &res, 0L, 0L, 0L, 0L, 0L, 0L, 0L); return (double)res; } static double month(double dv) { int res; split_date(dv, 0L, &res, 0L, 0L, 0L, 0L, 0L, 0L); return (double)res; } static double dom(double dv) { int res; split_date(dv, 0L, 0L, &res, 0L, 0L, 0L, 0L, 0L); return (double)res; } static double dow(double dv) { int res; split_date(dv, 0L, 0L, 0L, &res, 0L, 0L, 0L, 0L); return (double)res; } static double doy(double dv) { int res; split_date(dv, 0L, 0L, 0L, 0L, &res, 0L, 0L, 0L); return (double)res; } static double hours(double dv) { int res; split_date(dv, 0L, 0L, 0L, 0L, 0L, &res, 0L, 0L); return (double)res; } static double minutes(double dv) { int res; split_date(dv, 0L, 0L, 0L, 0L, 0L, 0L, &res, 0L); return (double)res; } static double seconds(double dv) { double res; split_date(dv, 0L, 0L, 0L, 0L, 0L, 0L, 0L, &res); if(res < 0.0005) res = 0.0; return res; } static void fdate(YYSTYPE *dst, YYSTYPE *src) { if(!dst || !src || src->type == ARR || src->type == RANGEARR || src->type == STR) { yyerror("parse error"); return; } dst->type = DATE1; dst->val = src->val; } static void fdatetime(YYSTYPE *dst, YYSTYPE *src) { if(!dst || !src || src->type == ARR || src->type == RANGEARR || src->type == STR) { yyerror("parse error"); return; } dst->type = DATETIME1; dst->val = src->val; } static void ftime(YYSTYPE *dst, YYSTYPE *src) { if(!dst || !src || src->type == ARR || src->type == RANGEARR || src->type == STR) { yyerror("parse error"); return; } dst->type = TIME1; dst->val = src->val; } static void invert(YYSTYPE *dst, YYSTYPE *src) { int i; if(!dst || !src) return; switch(src->a_count) { case 0: dst->a_data = PushArray((double*)malloc(sizeof(double))); dst->a_count = 1; dst->a_data[0] = dst->val = src->val; break; case 1: dst->a_data = PushArray((double*)malloc(sizeof(double))); dst->a_count = 1; dst->a_data[0] = dst->val = src->a_data[0]; break; default: dst->a_data = PushArray((double*)memdup(src->a_data, src->a_count * sizeof(double), 0)); dst->a_count = src->a_count; for(i = 0; i < src->a_count; i++) dst->a_data[i] = src->a_data[src->a_count-1-i]; } } static void asort(YYSTYPE *dst, YYSTYPE *src) { if(!dst || !src) return; dst->type = ARR; switch(src->a_count) { case 0: dst->a_data = PushArray((double*)malloc(sizeof(double))); dst->a_count = 1; dst->a_data[0] = dst->val = src->val; break; case 1: dst->a_data = PushArray((double*)malloc(sizeof(double))); dst->a_count = 1; dst->a_data[0] = dst->val = src->a_data[0]; break; default: dst->a_data = PushArray((double*)memdup(src->a_data, src->a_count * sizeof(double), 0)); dst->a_count = src->a_count; SortArray(dst->a_count, dst->a_data); } } static void _randarr(YYSTYPE *dst, YYSTYPE *src) { if(!dst || !src) return; dst->type = ARR; switch(src->a_count) { case 0: dst->a_data = PushArray((double*)malloc(sizeof(double))); dst->a_count = 1; dst->a_data[0] = dst->val = src->val; break; case 1: dst->a_data = PushArray((double*)malloc(sizeof(double))); dst->a_count = 1; dst->a_data[0] = dst->val = src->a_data[0]; break; default: dst->a_data = randarr(src->a_data, src->a_count, &idum); dst->a_count = src->a_count; } } static void _resample(YYSTYPE *dst, YYSTYPE *src) { if(!dst || !src) return; dst->type = ARR; switch(src->a_count) { case 0: dst->a_data = PushArray((double*)malloc(sizeof(double))); dst->a_count = 1; dst->a_data[0] = dst->val = src->val; break; case 1: dst->a_data = PushArray((double*)malloc(sizeof(double))); dst->a_count = 1; dst->a_data[0] = dst->val = src->a_data[0]; break; default: dst->a_data = resample(src->a_data, src->a_count, &idum); dst->a_count = src->a_count; } } static void mkarr(YYSTYPE *res, YYSTYPE *sr1, YYSTYPE *sr2, char*fmt) { AccRange *rD; int i, n, r, c; anyResult ares; if(fmt || !sr2 || !sr1 || !sr1->text) yyargcnterr("mkarr(range, MD)"); if(!(rD = new AccRange(sr1->text)) || !(n = rD->CountItems())) { yybadargerr("mkarr(range, MD)"); } res->a_data = PushArray((double*)calloc(n, sizeof(double))); for(i = 0, rD->GetFirst(&c, &r); i < n; i++) { rD->GetNext(&c, &r); if(curr_data->GetResult(&ares, r, c,false) && ares.type == ET_VALUE) res->a_data[i] = ares.value; else res->a_data[i] = sr2->val; res->a_count = i; } if(rD) delete rD; } static void asort2(YYSTYPE *res, YYSTYPE *sr1, YYSTYPE *sr2, char *fmt) { int n; res->val = 0.0; res->type = NUM; if(!sr1 || !sr2 || !sr1->a_data || !sr2->a_data) return; n = sr1->a_count > sr2->a_count ? sr2->a_count : sr1->a_count; res->val = (double)n; if(n >1) SortArray2(n, sr1->a_data, sr2->a_data); return; } static double _crank(YYSTYPE *src) { double tmp = -1.0; if(!src) return tmp; tmp = 0.0; if(src->a_data && src->a_count > 1.0)crank(src->a_count, src->a_data, &tmp); if(src->type == RANGEARR) RangeData.rmData(src->a_data, src->a_count); return tmp; } static void subarr(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2, YYSTYPE *src3) { int i, pos2; if(!src1->a_data) yybadargerr("subarr(array; pos1[; pos2])"); else { if(src3) pos2 = (int)(src3->val); else pos2 = src1->a_count; dst->type = ARR; dst->a_data = PushArray((double*)malloc(src1->a_count*sizeof(double))); for(i = (int)(src2->val), dst->a_count = 0; i <= pos2 && i < src1->a_count; i++) { dst->a_data[dst->a_count++] = src1->a_data[i]; } } } static void ltrim(YYSTYPE *dst, YYSTYPE *src) { if(!src || !dst || !src->text) return; dst->text = PushString(str_ltrim(src->text)); dst->type = STR; dst->val = 0.0; } static void rtrim(YYSTYPE *dst, YYSTYPE *src) { if(!src || !dst || !src->text) return; dst->text = PushString(str_rtrim(src->text)); dst->type = STR; dst->val = 0.0; } static void trim(YYSTYPE *dst, YYSTYPE *src) { if(!src || !dst || !src->text) return; dst->text = PushString(str_trim(src->text)); dst->type = STR; dst->val = 0.0; } static double rank(YYSTYPE *sr) { if(sr->a_count < 2 || !sr->a_data) return 0.0; return d_rank(sr->a_count-1, sr->a_data+1, sr->a_data[0]); } static double classes(double start, double step, YYSTYPE *src, YYSTYPE *dest) { return d_classes(curr_data, start, step, src->a_data, src->a_count, dest->text); } static void _strpos(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2) { dst->type = NUM; dst->val = (double)strpos(src1->text, src2->text); } static void strrepl(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2, YYSTYPE *src3) { if(src3) { dst->type = STR; dst->text = PushString(strreplace(src1->text, src2->text, src3->text)); } else yyargcnterr("strrepl(search; replace; haystack)"); } static void _substr(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2, YYSTYPE *src3) { if(src3) { dst->type = STR; dst->text = PushString(substr(src1->text, (int)(src2->val), (int)(src3->val))); } else yyargcnterr("substr(text; pos1; pos2)"); } static double asc(YYSTYPE *sr, YYSTYPE *dst, char *dum) { if(dum) yyerror("parse error"); if(!sr || !sr->text) return 0.0; return (double)((unsigned char)(sr->text[0])); } static void chr(YYSTYPE *dst, YYSTYPE *src) { char tpl[] = "?\0"; if(!dst || !src) return; tpl[0] = (src->val >=32.0 && src->val <= 255.0) ? (char)(src->val) : '?'; dst->type = STR; dst->text = PushString(tpl); } static void to_upper(YYSTYPE *dst, YYSTYPE *src) { int i; if(!dst || !src) return; dst->type = STR; if(src->text && src->text[0]) { dst->text = PushString(src->text); for(i = 0; src->text[i]; i++) dst->text[i] = toupper(src->text[i]); } else dst->text = 0L; } static void to_lower(YYSTYPE *dst, YYSTYPE *src) { int i; if(!dst || !src) return; dst->type = STR; if(src->text && src->text[0]) { dst->text = PushString(src->text); for(i = 0; src->text[i]; i++) dst->text[i] = tolower(src->text[i]); } else dst->text = 0L; } static void uc_first(YYSTYPE *dst, YYSTYPE *src) { if(!dst || !src) return; dst->type = STR; if(src->text && src->text[0]) { dst->text = PushString(src->text); dst->text[0] = toupper(src->text[0]); } else dst->text = 0L; } static void uc_word(YYSTYPE *dst, YYSTYPE *src) { int i; if(!dst || !src) return; dst->type = STR; if(src->text && src->text[0]) { dst->text = PushString(src->text); dst->text[0] = toupper(src->text[0]); for(i = 1; src->text[i]; i++) { if(isalpha(src->text[i]) && src->text[i-1] < 'A') dst->text[i] = toupper(src->text[i]); } } else dst->text = 0L; } static void exec_block(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2, bool namespc) { char *cmd = 0L; int cmd_pos = 0, cmd_size, r, c; AccRange *ar = 0L; anyResult res, *eres; YYSTYPE evsrc, evdst; if(bNoExec) return; if(!src1 || !src1->text || !src1->text[0]) return; if((cmd =(char*)malloc((cmd_size = 1000) * sizeof(char))) && (ar = new AccRange(src1->text))) { if(src2 && src2->text[0] && src2->text[0]) { add_to_buff(&cmd, &cmd_pos, &cmd_size, src2->text, 0); while(cmd_pos && cmd[cmd_pos-1] < 33) cmd_pos--; if(cmd_pos && cmd[cmd_pos-1] != ';') cmd[cmd_pos++] = ';'; } cmd[cmd_pos] = 0; ar->GetFirst(&c, &r); ar->GetNext(&c, &r); do { curr_data->GetResult(&res, r, c, false); switch(res.type) { case ET_VALUE: //numerical value if(res.value == -HUGE_VAL) add_to_buff(&cmd, &cmd_pos, &cmd_size, "-inf", 4); else if(res.value == HUGE_VAL) add_to_buff(&cmd, &cmd_pos, &cmd_size, "inf", 3); else add_dbl_to_buff(&cmd, &cmd_pos, &cmd_size, res.value, false); break; case ET_TEXT: //text cell if(res.text && res.text[0]) { if(res.text[0] == res.text[1] && res.text[0] == '/') ar->NextRow(&r); else add_to_buff(&cmd, &cmd_pos, &cmd_size, res.text, 0); } break; } }while(ar->GetNext(&c, &r)); if(namespc) { eres = do_formula(curr_data, cmd); } else { memset(&evsrc, 0, sizeof(YYSTYPE)); memset(&evdst, 0, sizeof(YYSTYPE)); evsrc.text = cmd; eval(&evdst, &evsrc); eres = &line_res; } switch(eres->type) { case ET_BOOL: dst->type = BOOLVAL; dst->val = eres->value; dst->text = 0L; break; case ET_VALUE: dst->type = NUM; dst->val = eres->value; dst->text = 0L; break; case ET_TEXT: dst->type = STR; dst->val = 0.0; dst->text = PushString(eres->text); break; default: dst->type = NUM; dst->val = 0.0; dst->text = 0L; break; } } if(cmd) free(cmd); if(ar) delete ar; } static void exec(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2) { exec_block(dst, src1, src2, true); } static void call(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2) { exec_block(dst, src1, src2, false); } // Store strings in a list static char **str_list = 0L; static int n_str = 0; static char *PushString(char *text) { if(text && text[0]) { if(str_list = (char**)realloc(str_list, sizeof(char*)*(n_str+1))) str_list[n_str] = (char*)memdup(text, (int)strlen(text)+1, 0); return str_list[n_str++]; } return 0L; } //Store arrays in a list static double **arr_list = 0L; static int n_arr = 0; static double *PushArray(double *arr) { if(arr) { if(arr_list = (double**)realloc(arr_list, sizeof(double*)*(n_arr+1))){ arr_list[n_arr] = arr; return arr_list[n_arr++]; } } return 0L; } static double *ReallocArray(double *arr, int size) { int i; if(arr && size) { for(i = 0; i < n_arr; i++) if(arr_list[i] == arr) { arr_list[i] = (double*)realloc(arr, size); return arr_list[i]; } arr = (double*)realloc(arr, size); return PushArray(arr); } return 0L; } //The symbol table: a chain of `struct symrec' static symrec *sym_table, *sym_tab_first; //Rearrange function table with previously used functions in front void ArrangeFunctions() { symrec *ptr, *ptr1, *ptr2, *next; for(ptr = sym_table, ptr1 = ptr2 = 0L; (ptr); ) { next = ptr->next; if(ptr->name) { ptr->next = ptr1; ptr1 = ptr; } else { ptr->next = ptr2; ptr2 = ptr; } ptr = next; } for(sym_table = 0L, ptr = ptr2; (ptr); ){ next = ptr->next; ptr->next = sym_table; sym_table = ptr; ptr = next; } for(ptr = ptr1; (ptr); ){ next = ptr->next; ptr->next = sym_table; sym_table = ptr; ptr = next; } sym_tab_first = sym_table; bRecent = false; } // Put arithmetic functions and predifened variables in table #define INIT_SYM(TYP,NAM,FNC) {TYP,NAM,(double(*)(double))&FNC} void InitArithFuncs(DataObj *d) { struct fdef { int f_type; char *name; double (*fnct)(double); }; fdef fncts[] = { 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), INIT_SYM(AFNCT, "cauchyfreq", cauchyfreq), INIT_SYM(AFNCT, "cauchyinv", cauchyinv), INIT_SYM(AFNCT, "logisdist", logisdist), INIT_SYM(AFNCT, "logisfreq", logisfreq), INIT_SYM(AFNCT, "logisinv", logisinv), INIT_SYM(YYFNC2, "call", call), INIT_SYM(AFNCT, "ptukey", p_tukey), INIT_SYM(AFNCT, "qtukey", q_tukey), INIT_SYM(YYFNC, "toupper", to_upper), INIT_SYM(YYFNC, "tolower", to_lower), INIT_SYM(YYFNC, "ucfirst", uc_first), INIT_SYM(YYFNC, "ucword", uc_word), INIT_SYM(SFNCT, "asc", asc), INIT_SYM(YYFNC, "chr", chr), INIT_SYM(YYFNC3, "strrepl",strrepl), INIT_SYM(YYFNC3, "substr", _substr), INIT_SYM(YYFNC2, "strpos",_strpos), INIT_SYM(FUNC4, "classes", classes), INIT_SYM(AFNCT, "rank", rank), INIT_SYM(YYFNC, "ltrim", ltrim), INIT_SYM(YYFNC, "rtrim", rtrim), INIT_SYM(YYFNC, "trim", trim), INIT_SYM(YYFNC, "asort", asort), INIT_SYM(AFNCT, "crank", _crank), INIT_SYM(SRFUNC, "datestr", datestr), INIT_SYM(SFNCT, "dateval", dateval), INIT_SYM(BFNCT, "leapyear", leapyear), INIT_SYM(YYFNC, "today", today), INIT_SYM(YYFNC, "now", now), INIT_SYM(FNCT, "year", year), INIT_SYM(FNCT, "month", month), INIT_SYM(FNCT, "dom", dom), INIT_SYM(FNCT, "dow", dow), INIT_SYM(FNCT, "doy", doy), INIT_SYM(FNCT, "hours", hours), INIT_SYM(FNCT, "minutes", minutes), INIT_SYM(FNCT, "seconds", seconds), INIT_SYM(YYFNC, "date", fdate), INIT_SYM(YYFNC, "datetime", fdatetime), INIT_SYM(YYFNC, "time", ftime), INIT_SYM(FUNC1, "fill", fill), INIT_SYM(YYFNC3, "pearson", pearson), INIT_SYM(YYFNC3, "spearman", spearman), INIT_SYM(YYFNC3, "kendall", kendall), INIT_SYM(YYFNC3, "correl", pearson), INIT_SYM(YYFNC3, "regression", regression), INIT_SYM(YYFNC2, "covar", _covar), INIT_SYM(YYFNC2, "exec", exec), INIT_SYM(YYFNC3, "utest", utest), INIT_SYM(YYFNC3, "ttest2", ttest2), INIT_SYM(YYFNC3, "ttest", ttest), INIT_SYM(YYFNC3, "ftest", ftest), INIT_SYM(AFNCT, "variance", variance), INIT_SYM(AFNCT, "stdev", stdev), INIT_SYM(AFNCT, "sterr", sterr), INIT_SYM(AFNCT, "min", min), INIT_SYM(AFNCT, "max", max), INIT_SYM(AFNCT, "count", count), INIT_SYM(AFNCT, "sum", sum), INIT_SYM(AFNCT, "mean", mean), INIT_SYM(AFNCT, "kurt", kurt), INIT_SYM(AFNCT, "skew", skew), INIT_SYM(AFNCT, "median", quartile2), INIT_SYM(AFNCT, "quartile1", quartile1), INIT_SYM(AFNCT, "quartile2",quartile2), INIT_SYM(AFNCT, "quartile3", quartile3), INIT_SYM(AFNCT, "gmean", gmean), INIT_SYM(AFNCT, "hmean", hmean), INIT_SYM(AFNCT, "tdist", tdist), INIT_SYM(AFNCT, "tfreq", tfreq), INIT_SYM(AFNCT, "tinv", tinv), INIT_SYM(YYFNC, "invert", invert), INIT_SYM(AFNCT, "poisdist", poisdist), INIT_SYM(AFNCT, "poisfreq", poisfreq), INIT_SYM(AFNCT, "expdist", expdist), INIT_SYM(AFNCT, "expfreq", expfreq), INIT_SYM(AFNCT, "expinv", expinv), INIT_SYM(AFNCT, "fdist", fdist), INIT_SYM(AFNCT, "ffreq", ffreq), INIT_SYM(YYFNC3, "subarr", subarr), INIT_SYM(AFNCT, "finv", finv), INIT_SYM(AFNCT, "gammp", _gammp), INIT_SYM(AFNCT, "gammq", _gammq), INIT_SYM(AFNCT, "beta", beta), INIT_SYM(AFNCT, "betai", _betai), INIT_SYM(AFNCT, "bincof", _bincof), INIT_SYM(AFNCT, "binomdist",binomdist), INIT_SYM(AFNCT, "binomfreq",binomfreq), INIT_SYM(AFNCT, "normdist", normdist), INIT_SYM(AFNCT, "average", mean), INIT_SYM(AFNCT, "norminv", norminv), INIT_SYM(AFNCT, "normfreq", normfreq), INIT_SYM(AFNCT, "lognormdist", lognormdist), INIT_SYM(AFNCT, "lognormfreq", lognormfreq), INIT_SYM(AFNCT, "lognorminv",lognorminv), INIT_SYM(AFNCT, "chidist", chidist), INIT_SYM(AFNCT, "chifreq", chifreq), INIT_SYM(YYFNC2, "asort2", asort2), INIT_SYM(AFNCT, "chiinv", chiinv), INIT_SYM(SFNCT, "strlen", _strlen), INIT_SYM(YYFNC, "eval", eval), INIT_SYM(FNCT, "erf", errf), INIT_SYM(FNCT, "erfc", errfc), INIT_SYM(FNCT, "sign", sign), INIT_SYM(FNCT, "gammaln", gammln), INIT_SYM(FNCT, "factorial", factorial), INIT_SYM(YYFNC, "rand", rand1), INIT_SYM(FNCT, "srand", srand), INIT_SYM(FNCT, "floor", floor), INIT_SYM(FNCT, "abs", fabs), INIT_SYM(FNCT, "asin", asin), INIT_SYM(FNCT, "acos", acos), INIT_SYM(FNCT, "atan", atan), INIT_SYM(FNCT, "sinh", sinh), INIT_SYM(FNCT, "cosh", cosh), INIT_SYM(FNCT, "tanh", tanh), INIT_SYM(FNCT, "sin", sin), INIT_SYM(FNCT, "cos", cos), INIT_SYM(FNCT, "tan", tan), INIT_SYM(FNCT, "log10", log10), INIT_SYM(FNCT, "ln", log), INIT_SYM(FNCT, "log", log), INIT_SYM(FNCT, "exp", exp), INIT_SYM(FNCT, "sqrt", sqrt), INIT_SYM(0, 0L, nop)}; int i; symrec *ptr, *next; if(d) curr_data = d; if(sym_table) { for (ptr = sym_table; ptr != (symrec *) 0;){ if(ptr) { next = ptr->next; delete (ptr); } ptr = next; } sym_table = sym_tab_first = (symrec *) 0; } for (i = 0; fncts[i].name; i++) { ptr = putsym (HashValue((unsigned char*) fncts[i].name), Hash2((unsigned char*) fncts[i].name), fncts[i].f_type); ptr->fnctptr = (double (*)(...))fncts[i].fnct; } ptr = putsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv"), VAR); ptr->SetValue(1.0); sym_tab_first = sym_table; } #undef INIT_SYM static void init_table (void) { str_list = 0L; n_str = 0; arr_list = 0L; n_arr = 0; push_syntax(); } static void clear_table() { int i; if(str_list) { for(i = 0; i < n_str; i++) if(str_list[i]) free(str_list[i]); free(str_list); str_list = 0L; n_str = 0; } if(arr_list) { for(i = 0; i < n_arr; i++) if(arr_list[i]) free(arr_list[i]); free(arr_list); arr_list = 0L; n_arr = 0; } pop_syntax(); } static symrec * putsym (unsigned int h_name, unsigned int h2_name, int sym_type) { sym_table = new symrec(h_name, h2_name, sym_type, sym_table); return sym_table; } static symrec * getsym (unsigned int h_name, unsigned int h2_name, char *sym_name) { symrec *ptr; if(!h_name) return 0; for (ptr = sym_table; ptr != (symrec *) 0; ptr = (symrec *)ptr->next) { if (ptr->h_name == h_name && ptr->h2_name == h2_name){ if(sym_name && !ptr->name) { ptr->SetName(sym_name); bRecent = true; } return ptr; } //predefined variables rarely end on a digit else if(ptr == sym_tab_first) { if(sym_name && isdigit(sym_name[strlen(sym_name)-1]) && strlen(sym_name) < 5) return 0; } } return 0; } static int push(YYSTYPE *res, YYSTYPE *val) { double *tmparr; if(res->type == RANGEARR || res->text) { if((tmparr = res->a_data) && (res->a_data = PushArray((double*)malloc((res->a_count+1)*sizeof(double))))){ memcpy(res->a_data, tmparr, res->a_count * sizeof(double)); res->type = ARR; res->text = 0L; } } if(val->a_data) { if(!(res->a_data)) { if(!(val->a_data=ReallocArray(val->a_data, (val->a_count+2)*sizeof(double))))return 0; val->a_data[val->a_count++] = res->val; res->a_data = val->a_data; res->a_count = val->a_count; val->a_data = 0L; val->a_count = 0; val->val = res->val; return 1; } else { if(!(res->a_data=ReallocArray(res->a_data, (val->a_count+res->a_count)*sizeof(double))))return 0; memcpy(&res->a_data[res->a_count], val->a_data, val->a_count*sizeof(double)); res->a_count += val->a_count; val->a_data = 0L; val->a_count = 0; return 1; } } if(!(res->a_data )){ if(!(res->a_data = PushArray((double*)malloc(2*sizeof(double)))))return 0; res->a_data[0] = res->val; res->a_data[1] = val->val; res->a_count = 2; return 1; } else { if(!(res->a_data = ReallocArray(res->a_data, (res->a_count+2)*sizeof(double))))return 0; res->a_data[res->a_count] = val->val; res->a_count++; return 1; } return 0; } static int range_array(YYSTYPE *res, char *range) { RangeData.GetData(range, &res->a_data, &res->a_count, &res->text); res->val = 0.0; res->type = RANGEARR; return 1; } static int range_array2(YYSTYPE *res1, YYSTYPE *res2) { AccRange *r1, *r2; int row1, col1, row2, col2; anyResult ares1, ares2; char *range1, *range2; range1 = res1->text; range2 = res2->text; if(!range1 || !range1[0] || !range2 || !range2[0] || !(r1 = new AccRange(range1)) || !(r2 = new AccRange(range2))) return 0; if(!r1->GetFirst(&col1, &row1) || !(res1->a_data = PushArray((double*)malloc(r1->CountItems() * sizeof(double))))) { delete(r1); delete(r2); return 0; } if(!r2->GetFirst(&col2, &row2) || !(res2->a_data = PushArray((double*)malloc(r2->CountItems() * sizeof(double))))) { delete(r1); delete(r2); return 0; } parse_level++; for(res1->a_count = res2->a_count = 0; r1->GetNext(&col1, &row1) && r2->GetNext(&col2, &row2); ) { if(curr_data->GetResult(&ares1, row1, col1, parse_level > MAX_PARSE) && curr_data->GetResult(&ares2, row2, col2, parse_level > MAX_PARSE) && (ares1.type==ET_VALUE || ares1.type==ET_TIME || ares1.type==ET_DATE || ares1.type==ET_DATETIME || ares1.type==ET_BOOL) && (ares2.type==ET_VALUE || ares2.type==ET_TIME || ares2.type==ET_DATE || ares2.type==ET_DATETIME || ares2.type==ET_BOOL)){ res1->a_data[res1->a_count++] = ares1.value; res2->a_data[res2->a_count++] = ares2.value; } } parse_level--; res1->type = res2->type = ARR; delete(r1); delete(r2); return 1; } static YYSTYPE *proc_clause(YYSTYPE *res) { int i, n, o_pos; char *o_cmd; double *n_data; if(!(syntax_level) || !syntax_level->cl1 || syntax_level->cl2 <= syntax_level->cl1) return res; if(!res->text) return res; if(!res->a_data && (res->a_data = PushArray((double*)malloc(sizeof(double))))) { res->a_data[0] = res->type == VAR && res->tptr ? res->tptr->GetValue() : res->val; res->a_count = 1; } else if(!res->a_data) return res; if(!(n_data = PushArray((double*)malloc(res->a_count * sizeof(double))))) return res; o_pos = buff_pos; o_cmd = buffer; for(i = n = 0; i < res->a_count; i++) { buffer = res->text; buff_pos = 0; if(!syntax_level) break; syntax_level->clval = res->a_data[i]; yyparse(); if((line_res.type == ET_VALUE || line_res.type == ET_BOOL) && line_res.value != 0.0) n_data[n++] = res->a_data[i]; } res->a_data = n_data; res->a_count = n; res->text=0L; syntax_level->cl1 = syntax_level->cl2 = 0; buffer = o_cmd; buff_pos = o_pos; return res; } static void exec_clause(YYSTYPE *res) { int i, j; char *cmd; if((!res->a_data || res->a_count <2) && res->text && res->text[0]) range_array(res, res->text); if(!res->a_data) { if(res->a_data = PushArray((double*)malloc(2*sizeof(double)))) { res->a_data[0] = res->val; res->a_count = 1; InfoBox("fixed data"); } } if(!(syntax_level) || !syntax_level->cl1 || syntax_level->cl2 <= syntax_level->cl1) return; if(!(cmd = (char*)malloc(syntax_level->cl2 - syntax_level->cl1 +2)))return; while(buffer[syntax_level->cl1] <= ' ' && syntax_level->cl1 < syntax_level->cl2) syntax_level->cl1++; for(j = 0, i = syntax_level->cl1; i< syntax_level->cl2; i++) { cmd[j++] = buffer[i]; } cmd[j++] = ';'; cmd[j++] = 0; res->text = PushString(cmd); free(cmd); } struct parse_info { char *buffer; int buff_pos; DataObj *curr_data; symrec *sym_table; YYSTYPE yylval; struct parse_info *next; char **str_list; double **arr_list; char *last_err_desc; int n_str, n_arr, yychar, yynerrs; }; static parse_info *parse_stack = 0L; static void push_parser() { parse_info *ptr; if(!sym_table) InitArithFuncs(0L); else if(!parse_level && bRecent) ArrangeFunctions(); ptr = (parse_info *) malloc(sizeof(parse_info)); ptr->buffer = buffer; ptr->buff_pos = buff_pos; ptr->curr_data = curr_data; ptr->last_err_desc = last_err_desc; ptr->sym_table = sym_table; sym_table = sym_tab_first; memcpy(&ptr->yylval, &yylval, sizeof(YYSTYPE)); ptr->next = parse_stack; ptr->str_list = str_list; str_list = 0L; ptr->n_str = n_str; n_str = 0; ptr->arr_list = arr_list; arr_list = 0L; ptr->n_arr = n_arr; n_arr = 0; ptr->yychar = yychar; ptr->yynerrs = yynerrs; parse_stack = ptr; last_err_desc = 0L; parse_level++; //reenter ? push_syntax(); syntax_level->last_tok = 0; } static void pop_parser() { parse_info *ptr; symrec *n; if(ptr = parse_stack) { while(sym_table && sym_table != sym_tab_first) { n = sym_table->next; delete(sym_table); sym_table = n; } if(sym_table) sym_table = ptr->sym_table; parse_stack = ptr->next; buffer = ptr->buffer; buff_pos = ptr->buff_pos; curr_data = ptr->curr_data; last_err_desc = ptr->last_err_desc; memcpy(&yylval, &ptr->yylval, sizeof(YYSTYPE)); str_list = ptr->str_list; n_str = ptr->n_str; arr_list = ptr->arr_list; n_arr = ptr->n_arr; yychar = ptr->yychar; yynerrs = ptr->yynerrs; free(ptr); parse_level--; } pop_syntax(); } static int is_ttoken(unsigned int h_nam, unsigned int h2_nam) { switch(h_nam) { case 69: if(h2_nam == 101) return E; break; case 393: if(h2_nam == 47081) return PI; break; case 28381: if((h2_nam & 0x7fffffff) == 0x7c2706ed) { if(syntax_level) syntax_level->cl1 = buff_pos; return CLAUSE; } break; case 20: if(h2_nam == 5220) return CLVAL; break; case 362: if(h2_nam == 42878) return (syntax_level->last_tok = IF); break; case 28421: if(h2_nam == 82147317) return (syntax_level->last_tok = WHILE); break; case 1518: if(h2_nam == 20654586) return (syntax_level->last_tok = FOR); break; case 370: if(h2_nam == 46206) return INARR; break; case 1457: if(h2_nam == 18357885) return DIM; break; case 108774: if(h2_nam == 0x27d5d1fe) return (syntax_level->last_tok = RETURN); break; case 23583: if(h2_nam == 0x954f67ff) return BREAK; break; case 6033: if((h2_nam & 0x7fffffff) == 0x6371377d) return (syntax_level->last_tok = ELSE); break; case 7097: if((h2_nam & 0x7fffffff) == 0x550a2d65) return BTRUE; break; case 23697: if((h2_nam & 0x7fffffff) == 0x155f977d) return BFALSE; break; } return 0; } static char *copy_block() { char first[50], last[50], *res, *src; int i, j, level, mode; src = buffer + buff_pos-1; switch(*src){ case '{': first[0] = '{'; last[0] = '}'; break; case '(': first[0] = '('; last[0] = ')'; break; default: first[0] = '\0'; last[0] = ';'; break; } if(!(res = (char*)malloc(strlen(src)+2))) return 0L; for(i = 1, level = mode = j = 0; src[i]; i++) { res[j++] = src[i]; if(mode && level) { //embeded string if(src[i] == last[level]) { mode = 0; level--; } res[j++] = src[i]; } else { if(src[i] == last[level]) { if(level) level--; else { if(res[j-2] == ';'){ res[j-1] = 0; } else { res[j-1] = ';'; res[j] = 0; } buff_pos += j; return res; } } else switch(src[i]) { case '"': level++; first[level] = last[level] = '"'; break; case '\'': level++; first[level] = last[level] = '\''; break; case '{': level++; first[level] = '{'; last[level] = '}'; break; case '(': level++; first[level] = '('; last[level] = ')'; break; } } } if(res[j-1] == ';') j--; res[j] = ';'; res[j+1] = 0; buff_pos += j; return res; } static symrec *curr_sym; static int for_loop(char *block1, char *block2) { char *last_buffer, *bb1, *bb2, *bb3; int i, a_count, last_buff_pos, cb1, bres; double *a_data; YYSTYPE yyres, yysrc; symrec *var; if(!block1 || !block1[0] || bNoExec) return 0; bb1 = bb2 = bb3 = 0L; parse_level++; cb1 = (int)strlen(block1); bres = 0; last_buffer = buffer; last_buff_pos = buff_pos; buffer = block1; buff_pos = 0; //test for syntax 1 bb1 = copy_block(); 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]) bres = eval(&yyres, &yysrc); for(i = 0; !bres && i < yy_maxiter; i++) { yysrc.text = bb2; if(bb2[0]) { 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; bres = eval(&yyres, &yysrc); } yysrc.text = bb3; bres = eval(&yyres, &yysrc); } else break; } if(i) last_error = 0L; } //test for syntax 2 else if(!bb2) { buff_pos = 0; if (VAR == yylex() && (var = curr_sym) && INARR == yylex() && buffer[buff_pos]){ yysrc.text = buffer + buff_pos; bres = eval(&yyres, &yysrc); a_count = yyres.a_count; a_data = yyres.a_data; for(i = 0; !bres && i < a_count && i < yy_maxiter; i++) { var->SetValue(a_data[i]); if(block2 && block2[0]) { yysrc.text = block2; bres = eval(&yyres, &yysrc); } } last_error = 0; } else yyerror("parse error"); } else yyerror("parse error"); if(bb1) free(bb1); if(bb2) free(bb2); if(bb3) free(bb3); buffer = last_buffer; buff_pos = last_buff_pos; parse_level--; return bres; } static int yylex() { int i, c, tok; unsigned int h_nam, h2_nam; char tmp_txt[80], *block; symrec *s; memset(&yylval, 0, sizeof(YYSTYPE)); while((c = buffer[buff_pos++]) == ' ' || c == '\t'); //get first nonwhite char if(!c) return 0; //test for implicit block statement if(syntax_level && (syntax_level->last_tok == PBLOCK || syntax_level->last_tok == ELSE || syntax_level->last_tok == RETURN) && c != '{'){ buff_pos--; if(block = copy_block()) { yylval.text = PushString(block); free(block); } syntax_level->last_tok = 0; return yylval.type = IBLOCK; } //test for block statement if(c == '{') { if(block = copy_block()) { yylval.text = PushString(block); free(block); } syntax_level->last_tok = 0; return yylval.type = BLOCK; } //test for '..' operator if(c == '.' && buffer[buff_pos] == '.') { buff_pos++; return yylval.type = SER; } //test for number if(c > 31 &&(c == '.' || isdigit(c))) { for(buff_pos--, i = 0; i < 79 && ((c = buffer[buff_pos]) == '.' || isdigit(c)); buff_pos++) { tmp_txt[i++] = (char)c; if(i && buffer[buff_pos+1] == 'e' && (buffer[buff_pos+2] == '-' || buffer[buff_pos+2] == '+')){ tmp_txt[i++] = buffer[++buff_pos]; tmp_txt[i++] = buffer[++buff_pos]; } if(i && buffer[buff_pos+1] == '.' && buffer[buff_pos+2] == '.') { //operator '..' buff_pos++; break; } } tmp_txt[i] = 0; #ifdef USE_WIN_SECURE sscanf_s(tmp_txt, "%lf", &yylval.val); #else sscanf(tmp_txt, "%lf", &yylval.val); #endif return yylval.type = NUM; } //test for name or stringtoken if(c > 31 && (isalpha(c) || c=='$' || c =='_')) { for(buff_pos--, i = 0; i < 79 && ((c = buffer[buff_pos]) && c > 31 && (isalnum(c) || c == '$' || c == '_')); buff_pos++) { tmp_txt[i++] = (char)c; } while(buffer[buff_pos] == ' ' || buffer[buff_pos] == '\t') buff_pos++; if(buffer[buff_pos] == ':' && !(syntax_level && syntax_level->last_tok == '?')){ tmp_txt[i++] = buffer[buff_pos++]; for(; i < 79 && ((c = buffer[buff_pos]) && c > 31 && (isalnum(c) || c == '$')); buff_pos++) { tmp_txt[i++] = (char)c; } tmp_txt[i] = 0; RangeData.GetData(tmp_txt, &yylval.a_data, &yylval.a_count, &yylval.text); yylval.val = 0.0; return yylval.type = (yylval.a_data && yylval.a_count) ? RANGEARR : STR; } tmp_txt[i] = 0; h_nam = HashValue((unsigned char*)tmp_txt); h2_nam = Hash2((unsigned char*)tmp_txt); if(h_nam == 1550 && h2_nam == 18852086) { //'inf' = huge value yylval.val = HUGE_VAL; return yylval.type = NUM; } if(tok = is_ttoken(h_nam, h2_nam)) return tok; if(!(s = getsym(h_nam, h2_nam, tmp_txt))){ s = putsym(h_nam, h2_nam, VAR); s->SetName(tmp_txt); } curr_sym = yylval.tptr = s; return s->type; } //test for string if(c == '"' || c == '\'') { for(i= 0; i < 79 && ((tok = buffer[buff_pos]) && (tok != c)); buff_pos++) { tmp_txt[i++] = (char)tok; } if(buffer[buff_pos] == c)buff_pos++; tmp_txt[i] = 0; yylval.text = PushString(tmp_txt); return yylval.type = STR; } tok = 0; switch(c) { case '=': if(buffer[buff_pos] == '=') tok = EQ; break; case '!': if(buffer[buff_pos] == '=') tok = NE; break; case '>': if(buffer[buff_pos] == '=') tok = GE; else return GT; break; case '<': if(buffer[buff_pos] == '=') tok = LE; else if(buffer[buff_pos] == '>') tok = NE; else return LT; break; case '&': if(buffer[buff_pos] == '&') tok = AND; break; case '|': if(buffer[buff_pos] == '|') tok = OR; break; case ')': if(syntax_level) { if(syntax_level->cl1 && syntax_level->next) { syntax_level->next->cl1 = syntax_level->cl1; syntax_level->next->cl2 = buff_pos-1; } } pop_syntax(); break; case '(': if(syntax_level->last_tok == WHILE || syntax_level->last_tok == FOR || syntax_level->last_tok == IF){ if(block = copy_block()) { yylval.text = PushString(block); free(block); } return yylval.type = syntax_level->last_tok = PBLOCK; } push_syntax(); if(syntax_level) syntax_level->last_tok = c; break; case '?': if(syntax_level) syntax_level->last_tok = c; break; case ':': if(syntax_level) { if(syntax_level->last_tok == '?') return COLC; } break; case ';': if(buff_pos <2)return yylex(); if(syntax_level) { if(syntax_level->last_tok == '(') return PSEP; else syntax_level->last_tok = 0; } break; case ',': if(syntax_level && syntax_level->last_tok == '(') return LSEP; break; case '*': if(buffer[buff_pos] == '=') tok = MULEQ; break; case '/': if(buffer[buff_pos] == '=') tok = DIVEQ; break; case '+': if(buffer[buff_pos] == '+') tok = INC; else if(buffer[buff_pos] == '=') tok = ADDEQ; break; case '-': if(buffer[buff_pos] == '-') tok = DEC; else if(buffer[buff_pos] == '=') tok = SUBEQ; break; } if(tok) { buff_pos++; return tok; } //Any other character is a token by itself if(c < 0 || c > 127)yytokenerr(c); return c; } static unsigned int hn_x = HashValue((unsigned char *)"x"); static unsigned int hn_y = HashValue((unsigned char *)"y"); static unsigned int hn_z = HashValue((unsigned char *)"z"); static unsigned int h2_x = Hash2((unsigned char *)"x"); static unsigned int h2_y = Hash2((unsigned char *)"y"); static unsigned int h2_z = Hash2((unsigned char *)"z"); bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOINT **pts, long *npts, char *param) { double x, y; symrec *sx, *sy; lfPOINT *new_points; long npoints = 0; int length, parse_res, res_mode = 0; if(x1 < x2) step = fabs(step); else if(x1 == x2) return false; else step = -fabs(step); if(!(new_points = (lfPOINT*)calloc((iround(fabs(x2-x1)/fabs(step))+2), sizeof(lfPOINT)))) return false; if(d) curr_data = d; push_parser(); init_table(); if(param) { length = (int)strlen(param); if(!(buffer = (char*)malloc(length+2))){ pop_parser(); return false; } rlp_strcpy(buffer, length+1, param); buffer[length++] = ';'; buffer[length] = 0; buff_pos = 0; while(!(parse_res = yyparse()) && buff_pos < length); free(buffer); buffer = 0L; } length = (int)strlen(expr); buffer = expr; sx = putsym(hn_x, h2_x, VAR); for(x = x1; step > 0.0 ? x <= x2 : x >= x2; x += step) { if(sx){ sx->SetValue(x); buff_pos = 0; while(!(parse_res = yyparse()) && buff_pos < length); switch (res_mode) { case 1: y = sy->GetValue(); break; case 2: y = line_res.value; break; default: if(sy = getsym(hn_y, h2_y)) { y = sy->GetValue(); res_mode = 1; } else { y = line_res.value; res_mode = 2; } break; } new_points[npoints].fx = (getsym(hn_x, h2_x))->GetValue(); new_points[npoints++].fy = y; } } *pts = new_points; *npts = npoints; clear_table(); pop_parser(); if(d) { d->Command(CMD_CLEAR_ERROR, 0L, 0L); d->Command(CMD_REDRAW, 0L, 0L); } return true; } bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double z2, double zstep, char *expr, char *param) { int length, parse_res, nr, nc, r, c, res_mode=0; symrec *sx, *sz, *sy; double x, y, z; if(!d || x2 <= x1 || z2 <= z1 || xstep <= 0.0 || zstep <= 0.0) return false; push_parser(); init_table(); if(param) { length = (int)strlen(param); if(!(buffer = (char*)malloc(length+2))){ pop_parser(); return false; } rlp_strcpy(buffer, length+1, param); buffer[length++] = ';'; buffer[length] = 0; buff_pos = 0; while(!(parse_res = yyparse()) && buff_pos < length); free(buffer); buffer = 0L; } length = (int)strlen(expr); buffer = expr; sx = putsym(hn_x, h2_x, VAR); sz = putsym(hn_z, h2_z, VAR); nr = iround((z2-z1)/zstep)+1; nc = iround((x2-x1)/xstep)+1; d->Init(nr, nc); for(r = 0, x = x1; r < nr; r++, x += xstep) { for(c = 0, z = z1; c < nc; c++, z+= zstep) { sx->SetValue(x); sz->SetValue(z); buff_pos = 0; while(!(parse_res = yyparse()) && buff_pos < length); switch (res_mode) { case 1: y = sy->GetValue(); break; case 2: y = line_res.value; break; default: if(sy = getsym(hn_y, h2_y)) { y = sy->GetValue(); res_mode = 1; } else { y = line_res.value; res_mode = 2; } break; } d->SetValue(r, c, y); } } clear_table(); pop_parser(); return true; } anyResult *do_formula(DataObj *d, char *expr) { int length, parse_res; static anyResult ret, *pret = 0L; if(d) curr_data = d; ret.type = ET_ERROR; ret.text = 0L; ret.a_data = 0L; ret.a_count = 0; if(!expr || !expr[0]) { if(!sym_table) InitArithFuncs(0L); last_error = 0L; return &ret; } push_parser(); //make code reentrant init_table(); length = (int)strlen(expr); if(!(buffer = (char*)malloc(length+2))){ pop_parser(); return &ret; } rlp_strcpy(buffer, length+1, expr); if(buffer[length-1] != ';') buffer[length++] = ';'; buffer[length] = 0; buff_pos = 0; while(!(parse_res= yyparse()) && buff_pos < length); ret.type = ET_ERROR; ret.text = 0L; if(parse_res == 1 && curr_data) { if(last_error && (!(strcmp(last_error, "parse error")))) curr_data->Command(CMD_ERROR, 0L, 0L); if(last_err_desc) pret = &line_res; else pret = &ret; } else pret = &line_res; last_error = last_err_desc = 0L; free(buffer); buffer = 0L; clear_table(); pop_parser(); return pret; } bool MoveFormula(DataObj *d, char *of, char *nf, int nfsize, int dx, int dy, int r0, int c0) { int length, length2, tok, pos, i; char *res, desc1[2], desc2[2]; if(d) curr_data = d; 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))){ pop_parser(); return false; } rlp_strcpy(buffer, length+1, of); buffer[length++] = ';'; buffer[length] = 0; buff_pos = pos = 0; if(!(res = (char *)calloc(length2 = (length*2+10), sizeof(char))))return false; length2--; do { tok = yylex (); if(tok && tok < 256) { if(res[pos-1] == ' ') pos--; res[pos++] = (char)tok; } else switch(tok) { case NUM: #ifdef USE_WIN_SECURE pos += sprintf_s(res+pos, 20, "%g", yylval.val); #else pos += sprintf(res+pos, "%g", yylval.val); #endif break; case FNCT: case FUNC1: case AFNCT: case SFNCT: case SRFUNC: case BFNCT: case YYFNC: case FUNC4: case YYFNC2: case YYFNC3: pos += rlp_strcpy(res+pos, length2-pos, curr_sym->name); break; case COLC: res[pos++] = ':'; break; case PSEP: res[pos++] = ';'; break; case LSEP: res[pos++] = ','; break; case CLVAL: res[pos++] = '$'; res[pos++] = '$'; break; case CLAUSE: pos += rlp_strcpy(res+pos, length2-pos, " where "); break; case DIM: pos += rlp_strcpy(res+pos, length2-pos, "dim "); break; case VAR: curr_sym->InitSS(); if(curr_sym->col >= 0 && curr_sym->row >= 0) { desc1[0] = desc1[1] = desc2[0] = desc2[1] = 0; for(i=(int)strlen(curr_sym->name)-1; i>0 && isdigit(curr_sym->name[i]); i--); if(curr_sym->name[0] == '$') desc1[0] = '$'; if(curr_sym->name[i] == '$') desc2[0] = '$'; #ifdef USE_WIN_SECURE pos += sprintf_s(res+pos, length2-pos, "%s%s%s%d", desc1, #else pos += sprintf(res+pos, "%s%s%s%d", desc1, #endif Int2ColLabel(desc1[0] || curr_sym->col < c0 ? curr_sym->col : curr_sym->col+dx >=0 ? curr_sym->col+dx > c0 ? curr_sym->col+dx : c0 : 0, false), desc2, desc2[0] || curr_sym->row < r0 ? curr_sym->row+1 : curr_sym->row + dy >= 0 ? curr_sym->row+dy > r0 ? curr_sym->row+1+dy : r0 : 1); } else pos += rlp_strcpy(res+pos, length2-pos, curr_sym->name); break; case STR: pos += rlp_strcpy(res+pos, length2-pos, "\""); pos += rlp_strcpy(res+pos, length2-pos, yylval.text); pos += rlp_strcpy(res+pos, length2-pos, "\""); break; case SER: res[pos++] = '.'; res[pos++] = '.'; break; case INC: res[pos++] = '+'; res[pos++] = '+'; break; case DEC: res[pos++] = '-'; res[pos++] = '-'; break; case PI: res[pos++] = 'p'; res[pos++] = 'i'; break; case E: res[pos++] = 'e'; break; case BTRUE: pos += rlp_strcpy(res+pos, length2-pos, "true"); break; case BFALSE: pos += rlp_strcpy(res+pos, length2-pos, "false"); break; case AND: pos += rlp_strcpy(res+pos, length2-pos, " && "); break; case OR: pos += rlp_strcpy(res+pos, length2-pos, " || "); break; case EQ: pos += rlp_strcpy(res+pos, length2-pos, " == "); break; case NE: pos += rlp_strcpy(res+pos, length2-pos, " != "); break; case GT: res[pos++] = '>'; break; case GE: res[pos++] = '>'; res[pos++] = '='; break; case LT: res[pos++] = '<'; break; case LE: res[pos++] = '<'; res[pos++] = '='; break; case IF: res[pos++] = 'i'; res[pos++] = 'f'; break; case ADDEQ: res[pos++] = '+'; res[pos++] = '='; break; case SUBEQ: res[pos++] = '-'; res[pos++] = '='; break; case MULEQ: res[pos++] = '*'; res[pos++] = '='; break; case DIVEQ: res[pos++] = '/'; res[pos++] = '='; break; case WHILE: pos += rlp_strcpy(res+pos, length2-pos, "while"); break; case FOR: pos += rlp_strcpy(res+pos, length2-pos, "for"); break; case INARR: pos += rlp_strcpy(res+pos, length2-pos, "in"); break; case ELSE: pos += rlp_strcpy(res+pos, length2-pos, "else"); break; case RETURN: pos += rlp_strcpy(res+pos, length2-pos, " return"); break; case BREAK: pos += rlp_strcpy(res+pos, length2-pos, " break"); break; case RANGEARR: 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); } while(res[pos]) { pos++; if(res[pos] == ';') res[pos] = ':'; } break; case BLOCK: res[pos++] = '{'; MoveFormula(d, yylval.text, res+pos, nfsize-pos-2, dx, dy, r0, c0); pos += (int)strlen(res+pos); res[pos++] = '}'; break; case IBLOCK: MoveFormula(d, yylval.text, res+pos, nfsize-pos-2, dx, dy, r0, c0); pos += (int)strlen(res+pos); res[pos++] = ';'; break; case PBLOCK: res[pos++] = '('; MoveFormula(d, yylval.text, res+pos, nfsize-pos-2, dx, dy, r0, c0); pos += (int)strlen(res+pos); res[pos++] = ')'; break; } res[pos] = 0; }while(buff_pos < length); while((res[pos-1] == ';' || res[pos-1] == ' ') && pos > 0) { res[pos-1] = 0; pos--;} rlp_strcpy(nf, nfsize, res); free(res); free(buffer); buffer = 0L; clear_table(); pop_parser(); return true; } static char *txt_formula; //function to fit static double **parval; //pointers to parameter values static void fcurve(double x, double z, double **a, double *y, double dyda[], int ma) { int i, length, parse_res; double tmp, y1, y2; symrec *symx, *symz, *sy=0L; if(!(symx = getsym(hn_x, h2_x))) symx = putsym(hn_x, h2_x, VAR); if(!(symz = getsym(hn_z, h2_z))) symz = putsym(hn_z, h2_z, VAR); //swap parameters to requested set if(a != parval) for(i = 0; i < ma; i++) { tmp = *parval[i]; *parval[i] = *a[i]; *a[i] = tmp; } //calc result symx->SetValue(x); symz->SetValue(z); 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(); else *y = line_res.value; if(*y == HUGE_VAL || *y == -HUGE_VAL) { for(i = 0, *y = 0.0; i < ma; dyda[i++] = 0.0); return; } //partial derivatives for each parameter by numerical differentiation for(i = 0; i < ma; i++) { if(*parval[i] != 0.0) { tmp = *parval[i]; *parval[i] = tmp*.995; buff_pos = 0; while(!(parse_res = yyparse()) && buff_pos < length); y1 = sy ? sy->GetValue() : line_res.value; *parval[i] = tmp*1.005; buff_pos = 0; while(!(parse_res = yyparse()) && buff_pos < length); y2 = sy ? sy->GetValue() : line_res.value; *parval[i] = tmp; dyda[i] = (y2-y1)*100.0/tmp; } else dyda[i] = 0.0; } //swap parameters back to original if(a != parval) for(i = 0; i < ma; i++) { tmp = *parval[i]; *parval[i] = *a[i]; *a[i] = tmp; } bNoSS = false; } int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr, double conv, int maxiter, double *chi_2) { int length, i, j, k, l, ndata, nparam, r1, r2, r3, c1, c2, c3; int *lista, itst, itst1, parse_res; symrec *tab1, *tab2, *csr, **parsym; AccRange *arx, *ary, *arz; double *x, *y, *z, currx, curry, currz, alamda, chisq, ochisq; double **covar, **alpha; char tmp_txt[500]; if(d) curr_data = d; if(chi_2) *chi_2 = 0.0; txt_formula = expr; if(!curr_data || !par || !expr || !rx || !ry) return 0; //process ranges and create arrays arx = ary = arz = 0L; x = y = z = 0L; parval = 0L; parsym = 0L; if(!(arx = new AccRange(rx)))return 0; i = arx->CountItems()+1; if(!(ary = new AccRange(ry))){ delete arx; return 0; } if(rz && !(arz = new AccRange(rz))){ delete ary; delete arx; return 0; } if(!(x = (double*)malloc(i * sizeof(double)))){ if(arz) delete arz; delete ary; delete arx; return 0; } if(!(y = (double*)malloc(i * sizeof(double)))){ if(arz) delete arz; free(x); delete arx; delete ary; return 0; } if(rz && !(z = (double*)malloc(i * sizeof(double)))){ if(arz) delete arz; free(y); free(x); delete arx; delete ary; return 0; } arx->GetFirst(&c1, &r1); ary->GetFirst(&c2, &r2); if(rz) arz->GetFirst(&c3, &r3); for(ndata = j = 0; j < i; j++) { if(rz) { if(arx->GetNext(&c1, &r1) && ary->GetNext(&c2, & r2) && arz->GetNext(&c3, &r3) && curr_data->GetValue(r1, c1, &currx) && curr_data->GetValue(r2, c2, &curry) && curr_data->GetValue(r3, c3, &currz)) { x[ndata] = currx; y[ndata] = curry; z[ndata] = currz; ndata++; } } else { if(arx->GetNext(&c1, &r1) && ary->GetNext(&c2, & r2) && curr_data->GetValue(r1, c1, &currx) && curr_data->GetValue(r2, c2, &curry)) { x[ndata] = currx; y[ndata] = curry; ndata++; } } } //common initialization for parser tasks push_parser(); //make code reentrant init_table(); length = (int)strlen(*par); //process parameters if(!(buffer = (char*)malloc(length+2))){ clear_table(); pop_parser(); if(arz) delete arz; free(y); free(x); delete arx; delete ary; return 0; } rlp_strcpy(buffer, length, *par); buffer[length++] = ';'; buffer[length] = 0; buff_pos = 0; tab1 = sym_table; while(!(parse_res = yyparse()) && buff_pos < length); tab2 = sym_table; free(buffer); buffer =0L; for(nparam = 0, csr=tab2; csr != tab1; nparam++, csr = csr->next); parsym = (symrec**)malloc((nparam+1)*sizeof(symrec*)); parval = (double**)malloc((nparam+1)*sizeof(double*)); for(i = 0, csr=tab2; csr != tab1 && i < nparam; i++, csr = csr->next){ parsym[i] = csr; parval[i] = &csr->var; } //do iteratations to optimize fit lista = (int*)malloc(sizeof(int)*nparam); for(i = 0; i< nparam; i++) lista[i] = i; covar = dmatrix(1, nparam, 1, nparam); alpha = dmatrix(1, nparam, 1, nparam); alamda = -1.0; itst = 0; mrqmin(x, y, z, ndata, parval, nparam, lista, nparam, covar, alpha, &chisq, fcurve, &alamda); if(!Check_MRQerror()) { for(itst = itst1 = 0, ochisq = chisq; itst < maxiter && chisq > conv && ochisq >= chisq && itst1 < 9; itst++) { ochisq = chisq; mrqmin(x, y, z, ndata, parval, nparam, lista, nparam, covar, alpha, &chisq, fcurve, &alamda); if(ochisq == chisq) itst1++; else itst1 = 0; } alamda = 0.0; mrqmin(x, y, z, ndata, parval, nparam, lista, nparam, covar, alpha, &chisq, fcurve, &alamda); Check_MRQerror(); } bNoSS = true; for(i = nparam-1, j = k = l = 0; i >= 0; l = 0, i--) { if(k > 20) { if(tmp_txt[j-1] == ' ') j--; if(tmp_txt[j-1] == ';') j--; #ifdef USE_WIN_SECURE l = sprintf_s(tmp_txt+j, 500-j, "\n"); #else l = sprintf(tmp_txt+j, "\n"); #endif j += l; k = 0; } #ifdef USE_WIN_SECURE l += sprintf_s(tmp_txt+j, 500-j, "%s%s=%g;", j && k ? " " : "", parsym[i]->name, parsym[i]->GetValue()); #else l += sprintf(tmp_txt+j, "%s%s=%g;", j && k ? " " : "", parsym[i]->name, parsym[i]->GetValue()); #endif j += l; k += l; } free(*par); *par = (char*)memdup(tmp_txt, (int)strlen(tmp_txt)+1, 0); if(chi_2) *chi_2 = chisq; //write back spreadsheet data if necessary buffer = *par; length = (int)strlen(buffer); while(!(parse_res = yyparse()) && buff_pos < length); buffer = 0L; free_dmatrix(alpha, 1, nparam, 1, nparam); free_dmatrix(covar, 1, nparam, 1, nparam); if(arz) delete arz; if(z) free(z); free(y); free(x); delete arx; delete ary; if(parval) free(parval); if(parsym) free(parsym); clear_table(); pop_parser(); if(d){ d->Command(CMD_CLEAR_ERROR, 0L, 0L); d->Command(CMD_REDRAW, 0L, 0L); } bNoSS = false; return itst < maxiter ? itst+1 : maxiter; } rlplot/WinSpec.cpp0000755000076400007640000026354311005357256012746 0ustar c71960c71960//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. // // 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 #include #include //file open flags #include //I/O flags #include //for read/write #include "rlplot.h" #include "WinSpec.h" #include "rlplot.rc" #include "TheDialog.h" #include "menu.h" extern int dlgtxtheight; HINSTANCE hInstance; HWND MainWnd = 0L; HACCEL accel; extern tag_Units Units[]; extern GraphObj *CurrGO; //Selected Graphic Objects extern Graph *CurrGraph; extern char *WWWbrowser; extern char *LoadFile; extern Default defs; extern char TmpTxt[]; extern UndoObj Undo; const char name[] = "RLPLOT1"; static unsigned int cf_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; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // I/O File name dialogs //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Get a new file name to store data in char *SaveDataAsName(char *oldname) { static char szFile[500], szFileTitle[256]; static char szFilter[] = "RLPlot workbook (*.rlw)\0*.rlw\0data files (*.csv)\0*.csv\0tab separated (*.tsv)\0" "*.tsv\0XML (*.xml)\0*.xml\0"; OPENFILENAME ofn; int i, j, cb; char *ext; szFile[0] = '\0'; if(oldname)rlp_strcpy(szFile, 500, oldname); memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = GetFocus(); ofn.lpstrFilter = szFilter; ofn.nFilterIndex = 1; ofn.lpstrFile = szFile; ofn.nMaxFile = sizeof(szFile); ofn.lpstrFileTitle = szFileTitle; ofn.nMaxFileTitle = sizeof(szFileTitle); ofn.lpstrInitialDir = defs.currPath; ofn.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY; ofn.lpstrTitle = "Save Data As"; if(GetSaveFileName(&ofn)){ if(!(cb = (int)strlen(szFile)) || !szFile[0])return 0L; if(cb < 4 || szFile[cb-4] != '.'){ for(i = j = 0; (j>>1) < (int)(ofn.nFilterIndex-1); i++) { if(szFilter[i] == '\0') j++; } ext = szFilter+i; for(i = 0; ext[i] && ext[i] != '*'; i++); rlp_strcpy(szFile+cb, 5, ext+i+1); } defs.FileHistory(szFile); return szFile; } else return 0L; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Get a new file name to store graph char *SaveGraphAsName(char *oldname) { static char szFile[500], szFileTitle[256]; static char szFilter[] = "RLPlot Graph (*.rlp)\0*.rlp\0"; OPENFILENAME ofn; int i, j, cb; char *ext; szFile[0] = '\0'; if(oldname)rlp_strcpy(szFile, 500, oldname); memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = GetFocus(); ofn.lpstrFilter = szFilter; ofn.nFilterIndex = 1; ofn.lpstrFile = szFile; ofn.nMaxFile = sizeof(szFile); ofn.lpstrFileTitle = szFileTitle; ofn.nMaxFileTitle = sizeof(szFileTitle); ofn.lpstrInitialDir = defs.currPath; ofn.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY; ofn.lpstrTitle = "Save Graph As"; if(GetSaveFileName(&ofn)){ if(!(cb = (int)strlen(szFile)) || !szFile[0])return 0L; if(cb < 4 || szFile[cb-4] != '.'){ for(i = j = 0; (j>>1) < (int)(ofn.nFilterIndex-1); i++) { if(szFilter[i] == '\0') j++; } ext = szFilter+i; for(i = 0; ext[i] && ext[i] != '*'; i++); rlp_strcpy(szFile+cb, 5, ext+i+1); } defs.FileHistory(szFile); defs.FileHistory(szFile); return szFile; } else return NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Get file name to read graph char *OpenGraphName(char *oldname) { static char szFile[500], szFileTitle[256]; static char szFilter[] = "RLPlot Graph (*.rlp)\0*.rlp\0"; OPENFILENAME ofn; szFile[0] = '\0'; if(oldname)rlp_strcpy(szFile, 500, oldname); memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = GetFocus(); ofn.lpstrFilter = szFilter; ofn.nFilterIndex = 1; ofn.lpstrFile = szFile; ofn.nMaxFile = sizeof(szFile); ofn.lpstrFileTitle = szFileTitle; ofn.nMaxFileTitle = sizeof(szFileTitle); ofn.lpstrInitialDir = defs.currPath; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; ofn.lpstrTitle = "Open Graph"; if(GetOpenFileName(&ofn)){ defs.FileHistory(szFile); return szFile; } else return NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Get a file name to load data char *OpenDataName(char *oldname) { static char szFile[500], szFileTitle[256]; static char szFilter[] = "RLPlot workbook (*rlw)\0*.rlw\0data files (*.csv)\0*.csv\0" "tab separated file (*.tsv)\0*.tsv\0" "RLPlot Graph (*.rlp)\0*.rlp\0all files (*.*)\0*.*\0"; OPENFILENAME ofn; szFile[0] = '\0'; if(oldname)rlp_strcpy(szFile, 500, oldname); memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = GetFocus(); ofn.lpstrFilter = szFilter; ofn.nFilterIndex = 1; ofn.lpstrFile = szFile; ofn.nMaxFile = sizeof(szFile); ofn.lpstrFileTitle = szFileTitle; ofn.nMaxFileTitle = sizeof(szFileTitle); ofn.lpstrInitialDir = defs.currPath; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; ofn.lpstrTitle = "Open Data File"; if(GetOpenFileName(&ofn)){ defs.FileHistory(szFile); return szFile; } else return NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Get a file name to export graph void OpenExportName(GraphObj *g, char *oldname) { static char szFile[500], szFileTitle[256]; static char szFilter[] = "Scalable Vector Graphics (*.svg)\0*.svg\0" "Encapsulated Post Script (*.eps)\0*.eps\0" "Enhanced MetaFile(*.emf)\0*.emf\0Windows MetaFile(*.wmf)\0*.wmf\0" "Tag Image File Format (*.tif)\0*.tif\0"; OPENFILENAME ofn; WinCopyWMF *wmf; int i; szFile[0] = '\0'; if(!g) return; if(oldname)rlp_strcpy(szFile, 500, oldname); memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = GetFocus(); ofn.lpstrFilter = szFilter; ofn.nFilterIndex = 1; ofn.lpstrFile = szFile; ofn.nMaxFile = sizeof(szFile); ofn.lpstrFileTitle = szFileTitle; ofn.nMaxFileTitle = sizeof(szFileTitle); ofn.lpstrInitialDir = defs.currPath; ofn.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY; ofn.lpstrTitle = "Export Graph"; if(g && GetSaveFileName(&ofn)){ i = (int)strlen(szFile); g->Command(CMD_BUSY, 0L, 0L); if(0==_stricmp(".svg", szFile+i-4)) { DoExportSvg(g, szFile, 0L); } else if(0==_stricmp(".emf", szFile+i-4)) { wmf = new WinCopyWMF(g, 0L, szFile); if(wmf && wmf->StartPage()) { g->DoPlot(wmf); wmf->EndPage(); delete wmf; } else if(wmf) delete wmf; g->Command(CMD_REDRAW, 0L, 0L); } else if(0==_stricmp(".wmf", szFile+i-4)) { wmf = new WinCopyWMF(g, szFile, 0L); if(wmf && wmf->StartPage()) { g->DoPlot(wmf); wmf->EndPage(); delete wmf; } else if(wmf) delete wmf; g->Command(CMD_REDRAW, 0L, 0L); } else if(0==_stricmp(".eps", szFile+i-4)) { DoExportEps(g, szFile, 0L); } else if(0==_stricmp(".tif", szFile+i-4)) { DoExportTif(g, szFile, 0L); } else if(0==_stricmp(".tiff", szFile+i-5)) { DoExportTif(g, szFile, 0L); } else ErrorBox("Unknown file extension or format"); g->Command(CMD_MOUSECURSOR, 0L, 0L); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Common alert boxes //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void InfoBox(char *Msg) { MessageBox(0, Msg, "Info", MB_OK | MB_ICONINFORMATION); } void ErrorBox(char *Msg) { MessageBox(0, Msg, "ERROR", MB_OK | MB_ICONSTOP); } bool YesNoBox(char *Msg) { if(IDYES == MessageBox(0, Msg, "RLPlot", MB_YESNO | MB_ICONQUESTION)) return true; return false; } int YesNoCancelBox(char *Msg) { int res; res = MessageBox(0, Msg, "RLPlot", MB_YESNOCANCEL | MB_ICONQUESTION); switch(res) { case IDYES: return 1; case IDNO: return 0; default: return 2; } return 0; } void Qt_Box() { MessageBox(0, "No Qt installed\nunder Windows", "Error", MB_OK | MB_ICONQUESTION); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Display blinking text cursor //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ static anyOutput *oTxtCur = 0L, *oCopyMark = 0L; RECT rTxtCur, rCopyMark; static bool bTxtCur = false, bTxtCurIsVis = false, bSuspend = false; static DWORD cTxtCur = 0x0L; static HWND hwndTxtCur = 0L; static int iTxtCurCount = 0; static POINT ptTxtCurLine[2]; static BitMapWin *bmCopyMark = 0L; void HideTextCursor() { if(oTxtCur) { bTxtCur = false; oTxtCur->UpdateRect(&rTxtCur, false); } oTxtCur = 0L; } void HideTextCursorObj(anyOutput *out) { if(oTxtCur && oTxtCur == out) HideTextCursor(); } void ShowTextCursor(anyOutput *out, RECT *disp, DWORD color) { HWND wnd = GetFocus(); if(!out || (out->OC_type & 0xff) != OC_BITMAP) return; cTxtCur = color; HideTextCursor(); oTxtCur = out; bSuspend = false; iTxtCurCount = -2; memcpy(&rTxtCur, disp, sizeof(RECT)); ptTxtCurLine[0].x = rTxtCur.left; ptTxtCurLine[0].y = rTxtCur.top; ptTxtCurLine[1].x = rTxtCur.right; ptTxtCurLine[1].y = rTxtCur.bottom; rTxtCur.bottom++; rTxtCur.right++; oTxtCur->ShowLine(ptTxtCurLine, 2, cTxtCur); bTxtCurIsVis = bTxtCur = true; } void HideCopyMark() { BitMapWin *CurrCopyMark; if(bmCopyMark && oCopyMark) { CurrCopyMark = bmCopyMark; bmCopyMark = 0L; oCopyMark->UpdateRect(&rCopyMark, false); delete CurrCopyMark; } bmCopyMark = 0L; oCopyMark = 0L; } 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; rCopyMark.left = mrk[0].left; rCopyMark.right = mrk[0].right; rCopyMark.top = mrk[0].top; rCopyMark.bottom = mrk[0].bottom; for(i = 1; i < nRec; i++) { UpdateMinMaxRect(&rCopyMark, mrk[i].left, mrk[i].top); UpdateMinMaxRect(&rCopyMark, mrk[i].right, mrk[i].bottom); } bmCopyMark = new BitMapWin(rCopyMark.right - rCopyMark.left, rCopyMark.bottom - rCopyMark.top, out->hres, out->vres); } void InvalidateOutput(anyOutput *o) { if(!o || (o->OC_type & 0xff) != OC_BITMAP) return; if(o == oCopyMark) { oCopyMark = 0L; if(bmCopyMark) delete bmCopyMark; bmCopyMark = 0L; } if(o == oTxtCur) { oTxtCur = 0L; bTxtCur = false; } } void SuspendAnimation(anyOutput *o, bool bSusp) { if(!o || (o->OC_type & 0xff) != OC_BITMAP) return; if(!bSusp) bSuspend = false; else { if(o == oCopyMark) bSuspend = bSusp; if(o == oTxtCur) bSuspend = bSusp; } } static LineDEF liCopyMark1 = {0.0f, 1.0f, 0x00ffffffL, 0L}; static LineDEF liCopyMark2 = {0.0f, 6.0f, 0x0L, 0xf0f0f0f0L}; LRESULT FAR PASCAL TimerWndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam) { static POINT line[5]; static int cp_mark = 0; switch(message) { case WM_TIMER: if(bSuspend) return 0; 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); line[0].x = line[1].x = line[4].x = 0; line[0].y = line[3].y = line[4].y = 0; line[1].y = line[2].y = rCopyMark.bottom-rCopyMark.top-1; line[2].x = line[3].x = rCopyMark.right-rCopyMark.left-1; bmCopyMark->oPolyline(line, 5); bmCopyMark->SetLine(&liCopyMark2); bmCopyMark->RLP.finc = 1.0; bmCopyMark->RLP.fp = (cp_mark & 0x7); bmCopyMark->oPolyline(line, 5); oCopyMark->ShowBitmap(rCopyMark.left, rCopyMark.top, bmCopyMark); cp_mark++; if(bTxtCurIsVis && oTxtCur && ptTxtCurLine[0].y != ptTxtCurLine[1].y && oTxtCur == oCopyMark && OverlapRect(&rCopyMark, &rTxtCur)){ oTxtCur->ShowLine(ptTxtCurLine, 2, cTxtCur); } } if(!oTxtCur || (ptTxtCurLine[0].x == ptTxtCurLine[1].x && ptTxtCurLine[0].y == ptTxtCurLine[1].y)) return 0; iTxtCurCount++; if(iTxtCurCount<0) oTxtCur->ShowLine(ptTxtCurLine, 2, cTxtCur); if(iTxtCurCount < 4) return 0; iTxtCurCount = 0; if(bTxtCur && oTxtCur) { if(!bTxtCurIsVis) { oTxtCur->ShowLine(ptTxtCurLine, 2, cTxtCur); bTxtCurIsVis = true; } else { oTxtCur->UpdateRect(&rTxtCur, false); bTxtCurIsVis = false; } } return 0; case WM_QUERYOPEN: case WM_SIZE: return 0; case WM_DESTROY: KillTimer(hwnd, 1); break; } return DefWindowProc(hwnd, message, wParam, lParam); } void InitTextCursor(bool init) { WNDCLASS wndclass; if (init) { wndclass.style = CS_BYTEALIGNWINDOW | CS_DBLCLKS; wndclass.lpfnWndProc = TimerWndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = 0L; wndclass.hCursor = 0L; wndclass.hbrBackground = NULL; wndclass.lpszMenuName = 0L; wndclass.lpszClassName = "RLP_TIMER"; RegisterClass(&wndclass); if((hwndTxtCur = CreateWindow("RLP_TIMER", 0L, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL, hInstance, NULL))){ SetTimer(hwndTxtCur, 1, 150, 0L); } } else if(hwndTxtCur) { DestroyWindow(hwndTxtCur); hwndTxtCur = 0L; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Process paste command: check for clipboard contents //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void TestClipboard(GraphObj *g) { HANDLE hmem = 0; unsigned char *ptr; if(!g) return; OpenClipboard(MainWnd); if(g->Id == GO_SPREADDATA) { if((hmem = GetClipboardData(cf_rlpxml)) && (ptr = (unsigned char*) GlobalLock(hmem))) g->Command(CMD_PASTE_XML, ptr, 0L); else if((hmem = GetClipboardData(CF_TEXT)) && (ptr = (unsigned char*) GlobalLock(hmem))) ProcMemData(g, ptr, true); else if((hmem = GetClipboardData(cf_rlpobj)) && (ptr = (unsigned char*) GlobalLock(hmem))) OpenGraph(g, 0L, ptr, true); } else if(g->Id == GO_PAGE || g->Id == GO_GRAPH) { if((hmem = GetClipboardData(cf_rlpobj)) && (ptr = (unsigned char*) GlobalLock(hmem))) OpenGraph(g, 0L, ptr, true); } else TestClipboard(g->parent); if(hmem) GlobalUnlock(hmem); CloseClipboard(); } void EmptyClip() { HideCopyMark(); OpenClipboard(MainWnd); EmptyClipboard(); CloseClipboard(); } void CopyText(char *txt, int len) { HGLOBAL hmem; unsigned char* buf; if(!txt || !txt[0]) return; if(!len) len = (int)strlen(txt); OpenClipboard(MainWnd); EmptyClipboard(); if(hmem = GlobalAlloc(GMEM_MOVEABLE, len+2)) { if(buf = (unsigned char *)GlobalLock(hmem)) { memcpy(buf, txt, len); buf[len] = 0; GlobalUnlock(hmem); SetClipboardData(CF_TEXT, hmem); } } CloseClipboard(); } unsigned char* PasteText() { HANDLE hmem = 0; unsigned char *ptr, *ret=0L; OpenClipboard(MainWnd); if((hmem = GetClipboardData(CF_TEXT)) && (ptr = (unsigned char*) GlobalLock(hmem))){ ret = (unsigned char*) _strdup((char*)ptr); } if(hmem) GlobalUnlock(hmem); CloseClipboard(); return ret; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Get display (desktop) size //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void GetDesktopSize(int *width, int *height) { RECT rc; GetClientRect(GetDesktopWindow(), &rc); *width = rc.right - rc.left; *height = rc.bottom - rc.top; if(*width < 800 || *height < 600){ *width = 800; *height = 600; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Get long reference to pointer (win64-compatibility) //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ static void **ptrs = 0L; static size_t s_ptrs = 0; static size_t n_ptrs = 1; long lptrref(void* ptr) { size_t i; if((n_ptrs +1) > s_ptrs){ ptrs = (void **)realloc(ptrs, (s_ptrs += 1000) * sizeof(void*)); } if(!ptrs) return 0L; for(i = 1; i < n_ptrs; i++){ if(ptrs[i]== ptr) return (long)i; if(ptr && !ptrs[i]){ ptrs[i] = ptr; return (long)i; } } //new pointer ptrs[n_ptrs++] = ptr; return (long)(n_ptrs-1); } void *reflptr(long ref) { if(ref > 0 && ref < (long)n_ptrs && ptrs) return ptrs[ref]; return 0L; } void noreflptr(long ref) { if(ref > 0 && ref < (long)n_ptrs && ptrs) ptrs[ref]=0L; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Common code for any Windows output class //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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, 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); //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); else if((td->Align & TXA_VTOP) == TXA_VTOP) iy -= o->un2iy(td->fSize*.6); } else if(td->Style & TXS_SUPER) { if((td->Align & TXA_VCENTER) == TXA_VCENTER) iy += o->un2iy(td->fSize*0.4); else if((td->Align & TXA_VBOTTOM) == TXA_VBOTTOM) iy += o->un2iy(td->fSize*0.6); else if((td->Align & TXA_VTOP) == TXA_VTOP) iy -= o->un2iy(td->fSize*.0); } else { if((td->Align & TXA_VBOTTOM) == TXA_VBOTTOM) iy += td->iSize; else if((td->Align & TXA_VCENTER) == TXA_VCENTER) iy += (td->iSize>>1); } } else { if(td->Style & TXS_SUB) { if((td->Align & TXA_VCENTER) == TXA_VCENTER) iy += o->un2iy(td->fSize*0.4); else if((td->Align & TXA_VBOTTOM) == TXA_VBOTTOM) iy += o->un2iy(td->fSize*0.2); else if((td->Align & TXA_VTOP) == TXA_VTOP) iy += o->un2iy(td->fSize*.6); } else if(td->Style & TXS_SUPER) { if((td->Align & TXA_VCENTER) == TXA_VCENTER) iy -= o->un2iy(td->fSize*0.4); else if((td->Align & TXA_VBOTTOM) == TXA_VBOTTOM) iy -= o->un2iy(td->fSize*0.6); else if((td->Align & TXA_VTOP) == TXA_VTOP) iy += o->un2iy(td->fSize*.0); } else { if((td->Align & TXA_VBOTTOM) == TXA_VBOTTOM) iy -= td->iSize; else if((td->Align & TXA_VCENTER) == TXA_VCENTER) iy -= (td->iSize>>1); } } dtflags = DT_NOCLIP | DT_NOPREFIX; o->oGetTextExtentW(txt, cb, &w, &h); if((td->Align & TXA_HCENTER) == TXA_HCENTER) { dtrc.left = x+ix-(w>>1); dtflags |= DT_CENTER; } else if((td->Align & TXA_HRIGHT) == TXA_HRIGHT) { dtrc.left = x+ix-w; dtflags |= DT_RIGHT; } else { dtrc.left = x+ix; dtflags |= DT_LEFT; } 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 &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); xf.eM12 = (float)sin(td->RotBL *0.01745329252); xf.eM22 = (float)-cos(td->RotBL *0.01745329252); xf.eM21 = xf.eM12; } else { xf.eM11 = xf.eM22 = (float)cos(td->RotBL *0.01745329252); xf.eM12 = (float)-sin(td->RotBL *0.01745329252); xf.eM21 = -xf.eM12; } xf.eDx = (float)x; xf.eDy = (float)y; SetWorldTransform(*dc, &xf); dtrc.left -= x; dtrc.right -= x; dtrc.top = iy; dtrc.bottom = dtrc.top + h; DrawTextW(*dc, txt, cb, &dtrc, dtflags); ModifyWorldTransform(*dc, &xf, MWT_IDENTITY); SetGraphicsMode(*dc, GM_COMPATIBLE); return true; } else { DrawTextW(*dc, txt, cb, &dtrc, DT_CENTER | DT_NOCLIP | DT_NOPREFIX); return true; } return false; } bool com_oTextOut(int x, int y, char *atxt, int cb, HFONT *hFont, HDC *dc, TextDEF *td, anyOutput *o) { unsigned char *utxt = (unsigned char*)atxt; w_char *uc; int i; bool bRet; if(!*hFont || !atxt || !atxt[0]) return false; if(cb < 1) cb = (int)strlen(atxt); if(!(uc=(WCHAR *)calloc(cb+1, sizeof(WCHAR)))) return false; if(td->Font==FONT_GREEK) { for(i = 0; utxt[i]; i++) { if((utxt[i] >= 'A' && utxt[i] <= 'Z')) uc[i] = utxt[i] - 'A' + 0x391; else if((utxt[i] >= 'a' && utxt[i] <= 'z')) uc[i] = utxt[i] - 'a' + 0x3B1; else uc[i] = utxt[i]; } } else for(i = 0; utxt[i]; i++) uc[i] = utxt[i]; bRet = com_oTextOutW(x, y, uc, cb, hFont, dc, td, o); free(uc); return bRet; } bool com_SetTextSpec(TextDEF *set, anyOutput *o, HFONT *hFont, TextDEF *TxtSet, HDC *dc) { bool IsModified, RetVal; LOGFONT FontRec; HFONT newFont; 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 || TxtSet->Font != set->Font || TxtSet->fSize != set->fSize) IsModified = true; else IsModified = false; RetVal = o->anyOutput::SetTextSpec(set); if (IsModified && RetVal) { // create font if((TxtSet->Style & TXS_SUPER) || (TxtSet->Style & TXS_SUB)) FontRec.lfHeight = o->un2iy(set->fSize*0.71); else FontRec.lfHeight = TxtSet->iSize; if(FontRec.lfHeight <2) FontRec.lfHeight = 2; FontRec.lfWidth = 0; FontRec.lfEscapement = 0; //text angle FontRec.lfOrientation = 0; //base line angle FontRec.lfWeight = (TxtSet->Style & TXS_BOLD) ? FW_BOLD : FW_NORMAL; FontRec.lfItalic = (TxtSet->Style & TXS_ITALIC) ? TRUE : FALSE; FontRec.lfUnderline = (TxtSet->Style & TXS_UNDERLINE) ? TRUE : FALSE; FontRec.lfStrikeOut = 0; FontRec.lfOutPrecision = OUT_DEFAULT_PRECIS; FontRec.lfClipPrecision = CLIP_DEFAULT_PRECIS; FontRec.lfQuality = PROOF_QUALITY; switch(TxtSet->Font){ case FONT_HELVETICA: default: FontRec.lfCharSet = ANSI_CHARSET; FontRec.lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS; rlp_strcpy(FontRec.lfFaceName, 32, "Arial"); break; case FONT_GREEK: case FONT_TIMES: FontRec.lfCharSet = ANSI_CHARSET; FontRec.lfPitchAndFamily = VARIABLE_PITCH | FF_ROMAN; rlp_strcpy(FontRec.lfFaceName, 32, "Times New Roman"); break; case FONT_COURIER: FontRec.lfCharSet = ANSI_CHARSET; FontRec.lfPitchAndFamily = FIXED_PITCH | FF_MODERN; rlp_strcpy(FontRec.lfFaceName, 32, "Courier New"); break; } newFont = CreateFontIndirect(&FontRec); SelectObject(*dc, newFont); if(*hFont)DeleteObject(*hFont); *hFont = newFont; if(!(*hFont)) return false; } return RetVal; } bool com_oGetTextExtentW(w_char *text, int cb, int *width, int *height, HDC dc, TextDEF *TxtSet) { SIZE TextExtent; double si, csi, d; if(!text || !TxtSet) return false; if(!GetTextExtentPoint32W(dc, text, cb ? cb : (int)wcslen(text), &TextExtent))return false; if(fabs(TxtSet->RotBL) >0.01) { si = fabs(sin(TxtSet->RotBL * 0.01745329252)); csi = fabs(cos(TxtSet->RotBL * 0.01745329252)); d = si > csi ? 1.0/si : 1.0/csi; d = (TextExtent.cx * ((7.0 + d)/8.0)); TextExtent.cx = iround(d); } *width = TextExtent.cx; *height = TextExtent.cy; return true; } bool com_oGetTextExtent(char *text, int cb, int *width, int *height, HDC dc, TextDEF *TxtSet) { int i; unsigned char *utext; w_char *uc; bool bRet; if(!text || !TxtSet) return false; if(!cb) cb = (int)strlen(text); if(!(uc = (w_char *) malloc((cb+1)*sizeof(w_char))))return false; for(i = 0, utext = (unsigned char*)text ; i <= cb; i++) uc[i] = utext[i]; bRet = com_oGetTextExtentW(uc, cb, width, height, dc, TxtSet); free(uc); return bRet; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Output to windows bitmap //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BitMapWin::BitMapWin(GraphObj *g, HWND hw):anyOutput() { HDC dc; HWND hwndDesk; memDC = 0L; hgo = 0L; go = g; dc = GetDC(hwndDesk = GetDesktopWindow()); hres = (double)GetDeviceCaps(dc, LOGPIXELSX); vres = (double)GetDeviceCaps(dc, LOGPIXELSY); if(hw) GetClientRect(hw, &DeskRect); else GetClientRect(hwndDesk, &DeskRect); Box1.Xmin = DeskRect.left; Box1.Xmax = DeskRect.right; Box1.Ymin = DeskRect.top; Box1.Ymax = DeskRect.bottom; scr = CreateCompatibleBitmap(dc, DeskRect.right, DeskRect.bottom); memDC = CreateCompatibleDC(NULL); SelectObject(memDC, scr); ReleaseDC(hwndDesk, dc); hPen = CreatePen(PS_SOLID, 1, dLineCol = 0x00ffffffL); hBrush = CreateSolidBrush(dFillCol =dBgCol = 0x00ffffffL); dPattern = 0L; minLW = 1; if(memDC) { oldPen = (HPEN)SelectObject(memDC, hPen); oldBrush = (HBRUSH)SelectObject(memDC, hBrush); } else { oldBrush = 0L; oldPen = 0L; } hFont = 0L; OC_type = OC_BITMAP; } BitMapWin::BitMapWin(int w, int h, double hr, double vr) { HDC dc; HWND hwndDesk; memDC = 0L; hgo = 0L; go = 0L; hres = hr; vres = vr; minLW = 1; units = defs.cUnits; DeskRect.right = w; DeskRect.bottom = h; DeskRect.left = DeskRect.top = 0; VPorg.fx = VPorg.fy = 0.0; dc = GetDC(hwndDesk = GetDesktopWindow()); scr = CreateCompatibleBitmap(dc, DeskRect.right, DeskRect.bottom); memDC = CreateCompatibleDC(NULL); ReleaseDC(hwndDesk, dc); SelectObject(memDC, scr); hPen = CreatePen(PS_SOLID, 1, dLineCol = 0x00ffffffL); hBrush = CreateSolidBrush(dFillCol =dBgCol = 0x00ffffffL); dPattern = 0L; if(memDC) { SelectObject(memDC, hPen); SelectObject(memDC, hBrush); } hFont = 0L; OC_type = OC_BITMAP; } BitMapWin::BitMapWin(GraphObj *g):anyOutput() { HDC dc; HWND hwndDesk; memDC = 0L; hgo = 0L; go = g; dc = GetDC(hwndDesk = GetDesktopWindow()); hres = vres = 300.0; units = defs.cUnits; 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; VPorg.fy = -co2fiy(go->GetSize(SIZE_GRECT_TOP)); VPorg.fx = -co2fix(go->GetSize(SIZE_GRECT_LEFT)); scr = CreateCompatibleBitmap(dc, DeskRect.right, DeskRect.bottom); memDC = CreateCompatibleDC(NULL); SelectObject(memDC, scr); ReleaseDC(hwndDesk, dc); hPen = CreatePen(PS_SOLID, 1, dLineCol = 0x00ffffffL); hBrush = CreateSolidBrush(dFillCol =dBgCol = 0x00ffffffL); dPattern = 0L; if(memDC) { SelectObject(memDC, hPen); SelectObject(memDC, hBrush); } hFont = 0L; 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); if(hBrush) DeleteObject(hBrush); hgo = 0L; hFont = 0L; scr = 0L; memDC = 0L; hPen = 0L; hBrush = 0L; } bool BitMapWin::SetLine(LineDEF *lDef) { int iw; HPEN newPen; if(!hPen || lDef->width != LineWidth || lDef->width != LineWidth || lDef->pattern != dPattern || lDef->color != dLineCol) { LineWidth = lDef->width; iw = iround(un2fix(lDef->width)); dPattern = lDef->pattern; RLP.finc = 256.0/un2fix(lDef->patlength*8.0); RLP.fp = 0.0; if(iLine == iw && dLineCol == lDef->color && hPen) return true; iLine = iw; dLineCol = lDef->color; newPen = CreatePen(PS_SOLID, iw > 0 ? iw : 1, dLineCol); SelectObject(memDC, newPen); if(hPen) DeleteObject(hPen); hPen = newPen; } return true; } bool BitMapWin::SetFill(FillDEF *fill) { HBRUSH newBrush; if(!fill) return false; if((fill->type & 0xff) != FILL_NONE) { if(!hgo) hgo = new HatchOut(this); if(hgo) hgo->SetFill(fill); } else { if(hgo) delete hgo; hgo = 0L; } if(dFillCol != fill->color) { newBrush = CreateSolidBrush(dFillCol = fill->color); SelectObject(memDC, newBrush); if(hBrush) DeleteObject(hBrush); hBrush = newBrush; } dFillCol = fill->color; dFillCol2 = fill->color2; return true; } bool BitMapWin::SetTextSpec(TextDEF *set) { return com_SetTextSpec(set, this, &hFont, &TxtSet, &memDC); } bool BitMapWin::Erase(DWORD Color) { HPEN hBGpen, hOldPen; HBRUSH hBGbrush, hOldBrush; hBGpen = CreatePen(PS_SOLID, 1, Color); hBGbrush = CreateSolidBrush(Color); if(hBGpen && memDC) { if(hBGbrush) { hOldBrush = (HBRUSH)SelectObject(memDC, hBGbrush); hOldPen = (HPEN)SelectObject(memDC, hBGpen); Rectangle(memDC, 0, 0, DeskRect.right, DeskRect.bottom); SelectObject(memDC, hOldBrush); SelectObject(memDC, hOldPen); DeleteObject(hBGbrush); DeleteObject(hBGpen); return true; } if(hBGpen) DeleteObject(hBGpen); } return false; } bool BitMapWin::CopyBitmap(int x, int y, anyOutput* sr, int sx, int sy, int sw, int sh, bool invert) { BitMapWin *src = (BitMapWin*)sr; return(0 != BitBlt(memDC, x, y, sw, sh, src->memDC, sx, sy, invert ? DSTINVERT : SRCCOPY)); } bool BitMapWin::oGetTextExtent(char *text, int cb, int *width, int *height) { return com_oGetTextExtent(text, cb, width, height, memDC, &TxtSet); } bool BitMapWin::oGetTextExtentW(w_char *text, int cb, int *width, int *height) { return com_oGetTextExtentW(text, cb, width, height, memDC, &TxtSet); } bool BitMapWin::oGetPix(int x, int y, DWORD *col) { DWORD pix; if(x >= DeskRect.left && x < DeskRect.right && y >= DeskRect.top && y < DeskRect.bottom) { pix = GetPixel(memDC, x, y); *col = pix; return true; } else return false; } bool BitMapWin::oDrawIcon(int type, int x, int y) { HICON icon = 0L; switch(type) { case ICO_INFO: icon = LoadIcon(0L, IDI_ASTERISK); break; case ICO_ERROR: icon = LoadIcon(0L, IDI_HAND); break; case ICO_RLPLOT: icon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_EVAL)); break; } if(icon){ DrawIcon(memDC, x, y, icon); return true; } return false; } bool BitMapWin::oCircle(int x1, int y1, int x2, int y2, char *nam) { BOOL RetVal; FillDEF tr_fill = {FILL_NONE, 0x0, 1.0, 0L, 0x0}; LineDEF tr_line = {0.0, 1.0, 0x0, 0x0}; bool bTrans = false; HPEN newPen; 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; 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 (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 *nam) { POINT pts[5]; 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) { 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; } bool BitMapWin::oTextOut(int x, int y, char *txt, int cb) { return com_oTextOut(x, y, txt, cb, &hFont, &memDC, &TxtSet, this); } bool BitMapWin::oTextOutW(int x, int y, w_char *txt, int cb) { return com_oTextOutW(x, y, txt, cb, &hFont, &memDC, &TxtSet, this); } 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; 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); 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; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Output to windows window //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ OutputWin::OutputWin(GraphObj *g, HWND hw):BitMapWin(g, hw) { hdc = 0L; minLW = 1; if(g) { if(!hw) CreateNewWindow(g); else hWnd = hw; if(!MainWnd) MainWnd = hWnd; } else { //its a dialog window hWnd = hw; yAxis.flags = AXIS_INVERT; //drawing origin upper left corner } } OutputWin::~OutputWin() { HideTextCursorObj(this); SendMessage(hWnd, WM_CLOSE, 0, 0L); //Note: HGDI objects are deleted by the BitMapWin destructor } bool OutputWin::ActualSize(RECT *rc) { if(GetClientRect(hWnd, rc)&& (rc->right-rc->left) > 40 && (rc->bottom - rc->top) > 40) return true; return false; } void OutputWin::Caption(char *txt, bool bModified) { 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 0x01, 0x80, 0x1b, 0xf0, 0x3f, 0xf8, 0x3f, 0xfa, 0x1f, 0xff, 0x1f, 0xff, 0x6f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x3f, 0xfc, 0x1f, 0xfc, 0x0f, 0xf8, 0x07, 0xf8, 0x07, 0xf8}; const static unsigned char hand_mask[] = { //hand cursor mask 0xff, 0xff, 0xfe, 0x7f, 0xe6, 0x4f, 0xe6, 0x4f, 0xf2, 0x4d, 0xf2, 0x49, 0x78, 0x09, 0x98, 0x01, 0x88, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xe0, 0x07, 0xf0, 0x07, 0xf8, 0x0f, 0xfc, 0x0f, 0xfc, 0x0f}; const static unsigned char zoom_bits[] = { //zoom cursor bitmap 0x00, 0x00, 0x00, 0x00, 0x01, 0xa0, 0x06, 0x30, 0x08, 0x08, 0x10, 0x84, 0x10, 0x84, 0x20, 0x02, 0x26, 0x32, 0x20, 0x02, 0x10, 0x84, 0x10, 0x84, 0x08, 0x08, 0x06, 0x30, 0x01, 0xa0, 0x00, 0x00}; const static unsigned char zoom_mask[] = { //zoom cursor mask 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; const static unsigned char paste_bits[] = { //paste cursor bitmap 0x20, 0x00, 0x20, 0x00, 0xf8, 0x00, 0x20, 0x00, 0x23, 0xfe, 0x07, 0xff, 0x07, 0xff, 0x07, 0xff, 0x07, 0xff, 0x07, 0xff, 0x07, 0xff, 0x07, 0xff, 0x07, 0xff, 0x07, 0xff, 0x03, 0xfe, 0x00, 0x00}; const static unsigned char paste_mask[] = { //paste cursor mask 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x05, 0xfd, 0x05, 0xfd, 0xf9, 0xfc, 0x01, 0xfc, 0x01, 0xfc, 0x01, 0xfc, 0x01, 0xfc, 0x01, 0xfc, 0x01, 0xff, 0xff, 0xff, 0xff}; const static unsigned char drawpen_bits[] = { //draw cursor bitmap 0xc0, 0x00, 0xf0, 0x00, 0x7c, 0x00, 0x7f, 0x00, 0x3f, 0x80, 0x3f, 0xc0, 0x1f, 0xe0, 0x1f, 0xf0, 0x0f, 0xf8, 0x07, 0xfc, 0x03, 0xfe, 0x01, 0xff, 0x00, 0xff, 0x00, 0x7e, 0x00, 0x3c, 0x00, 0x18}; const static unsigned char drawpen_mask[] = { //draw cursor mask 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xe0, 0xff, 0xe2, 0x7f, 0xf1, 0x3f, 0xf0, 0x9f, 0xf8, 0x4f, 0xfc, 0x27, 0xfe, 0x13, 0xff, 0x0b, 0xff, 0x87, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff}; const static unsigned char drect_bits[] = { //draw rectangle bitmap 0x20, 0x00, 0x20, 0x00, 0xf8, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1f, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0x00, 0x00}; const static unsigned char drect_mask[] = { //draw rectangle mask 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x01, 0xf0, 0x01, 0xf0, 0x01, 0xf0, 0x01, 0xf0, 0x01, 0xf0, 0x01, 0xf0, 0x01, 0xff, 0xff, 0xff, 0xff}; const static unsigned char drrect_bits[] = { //draw rounded rectangle bitmap 0x20, 0x00, 0x20, 0x00, 0xf8, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x07, 0xfc, 0x0f, 0xfe, 0x1f, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0x0f, 0xfe, 0x07, 0xfc, 0x00, 0x00}; const static unsigned char drrect_mask[] = { //draw rounded rectangle mask 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x03, 0xf0, 0x01, 0xf0, 0x01, 0xf0, 0x01, 0xf0, 0x01, 0xf0, 0x01, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xff}; const static unsigned char delly_bits[] = { //draw ellipse bitmap 0x20, 0x00, 0x20, 0x00, 0xf8, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x07, 0xfc, 0x0f, 0xfe, 0x1f, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0x0f, 0xfe, 0x07, 0xfc, 0x01, 0xf0, 0x00, 0x00}; const static unsigned char delly_mask[] = { //draw ellipse mask 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0f, 0xf8, 0x03, 0xf0, 0x01, 0xf0, 0x01, 0xf0, 0x01, 0xf8, 0x03, 0xfe, 0x0f, 0xff, 0xff, 0xff, 0xff}; //display 16x16 cursor data: developers utility /* void disp_bm(unsigned char *tb) { char txt[512]; unsigned char currbyte; int i, j, pos; for(i = pos = 0; i < 32; i++) { currbyte = tb[i]; for (j = 0; j < 8; j++) { if(currbyte & 0x80) pos += sprintf(txt+pos, "1"); else pos += sprintf(txt+pos, "0"); currbyte <<= 1; } if(i & 1) pos += sprintf(txt+pos, "\n"); } InfoBox(txt); } */ void OutputWin::MouseCursor(int cid, bool force) { HCURSOR hc, hoc = 0L; if(cid == cCursor && !force) return; if(cid == MC_LAST) cid = cCursor; switch(cid) { case MC_ARROW: hoc = SetCursor(LoadCursor(NULL, IDC_ARROW)); break; case MC_TXTFRM: case MC_CROSS: hoc = SetCursor(LoadCursor(NULL, IDC_CROSS)); break; case MC_WAIT: hoc = SetCursor(LoadCursor(NULL, IDC_WAIT)); break; case MC_TEXT: hoc = SetCursor(LoadCursor(NULL, IDC_IBEAM)); break; case MC_NORTH: hoc = SetCursor(LoadCursor(NULL, IDC_SIZENS)); break; case MC_NE: hoc = SetCursor(LoadCursor(NULL, IDC_SIZENESW));break; case MC_COLWIDTH: case MC_EAST: hoc = SetCursor(LoadCursor(NULL, IDC_SIZEWE)); break; case MC_SE: hoc = SetCursor(LoadCursor(NULL, IDC_SIZENWSE));break; case MC_SALL: hoc = SetCursor(LoadCursor(NULL, IDC_SIZEALL)); break; case MC_MOVE: hc = CreateCursor(hInstance, 7, 7, 16, 16, hand_mask, hand_bits); hoc = SetCursor(hc); break; case MC_ZOOM: hc = CreateCursor(hInstance, 7, 7, 16, 16, zoom_mask, zoom_bits); hoc = SetCursor(hc); break; case MC_PASTE: hc = CreateCursor(hInstance, 2, 2, 16, 16, paste_mask, paste_bits); hoc = SetCursor(hc); break; case MC_DRAWPEN: hc = CreateCursor(hInstance, 0, 0, 16, 16, drawpen_mask, drawpen_bits); hoc = SetCursor(hc); break; case MC_DRAWREC: hc = CreateCursor(hInstance, 2, 2, 16, 16, drect_mask, drect_bits); hoc = SetCursor(hc); break; case MC_DRAWRREC: hc = CreateCursor(hInstance, 2, 2, 16, 16, drrect_mask, drrect_bits); hoc = SetCursor(hc); break; case MC_DRAWELLY: hc = CreateCursor(hInstance, 2, 2, 16, 16, delly_mask, delly_bits); hoc = SetCursor(hc); break; default: return; } if(hoc) DestroyCursor(hoc); cCursor = cid; } bool OutputWin::SetScroll(bool isVert, int iMin, int iMax, int iPSize, int iPos) { SCROLLINFO si; if(iPos < iMin) return false; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_ALL; si.nMin = iMin; si.nMax = iMax; si.nPage = iPSize < iMax ? iPSize : iMax; si.nPos = iPos; si.nTrackPos = 0; SetScrollInfo(hWnd, isVert ? SB_VERT : SB_HORZ, &si, TRUE); return true; } bool OutputWin::Erase(DWORD Color) { bool bRet; RECT ClientRect; if(bRet = BitMapWin::Erase(Color)) { GetClientRect(hWnd, &ClientRect); InvalidateRect(hWnd, &ClientRect, FALSE); } return bRet; } bool OutputWin::StartPage() { MrkMode = MRK_NONE; MrkRect = 0L; hdc = memDC; if(hgo && hdc) hgo->StartPage(); return true; } bool OutputWin::EndPage() { RECT ClientRect; hdc = NULL; GetClientRect(hWnd, &ClientRect); return UpdateRect(&ClientRect, false); } bool OutputWin::UpdateRect(RECT *rc, bool invert) { HDC dc; BOOL RetVal = FALSE; if(dc = GetDC(hWnd)) { RetVal = BitBlt(dc, rc->left, rc->top, rc->right - rc->left, rc->bottom - rc->top, memDC, rc->left, rc->top, invert ? DSTINVERT : SRCCOPY); ReleaseDC(hWnd, dc); } return (RetVal != 0); } bool OutputWin::UpdateRect(HDC dc, RECT rc) { if(BitBlt(dc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, memDC, rc.left, rc.top, SRCCOPY))return true; return false; } void OutputWin::ShowBitmap(int x, int y, anyOutput* src) { int w, h; HDC dc; BitMapWin *sr; if(!src) return; sr = (BitMapWin *) src; w = sr->DeskRect.right - sr->DeskRect.left; h = sr->DeskRect.bottom - sr->DeskRect.top; if(dc = GetDC(hWnd)) { BitBlt(dc, x, y, w, h, sr->memDC, 0, 0, SRCCOPY); ReleaseDC(hWnd, dc); } } void OutputWin::ShowLine(POINT * pts, int cp, DWORD color) { HDC dc; HPEN hP, oP; if((hP = CreatePen(PS_SOLID, 0, color))&& (dc = GetDC(hWnd))) { oP = (HPEN)SelectObject(dc, hP); Polyline(dc, pts, cp); SelectObject(dc, oP); DeleteObject(hP); ReleaseDC(hWnd, dc); } } void OutputWin::ShowEllipse(POINT p1, POINT p2, DWORD color) { HDC dc; HPEN hP, oP; if((hP = CreatePen(PS_SOLID, 0, color)) && (dc = GetDC(hWnd))) { oP = (HPEN)SelectObject(dc, hP); Arc(dc, p1.x, p1.y, p2.x, p2.y, 0, 0, 0, 0); SelectObject(dc, oP); DeleteObject(hP); ReleaseDC(hWnd, dc); } } bool OutputWin::SetMenu(int type) { HMENU hMenu = 0L, hPopup = 0L; switch(type) { case MENU_NONE: break; case MENU_SPREAD: hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(MENU_2)); break; case MENU_GRAPH: /* hMenu = CreateMenu(); hPopup = CreatePopupMenu(); AppendMenu(hPopup, MF_STRING, CM_OPEN, "&Open"); AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hPopup, "&File"); // AppendMenu(hMenu, MF_POPUP, (unsigned int)hPopup, "&File"); //*/ hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(MENU_1)); break; case MENU_PAGE: hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(MENU_3)); } ::SetMenu(hWnd, hMenu); return true; } void OutputWin::CheckMenu(int mid, bool check) { HMENU hMenu = GetMenu(hWnd); if(mid < CM_T_STANDARD) switch(mid){ //tool mode identifier case TM_STANDARD: mid = CM_T_STANDARD; break; case TM_DRAW: mid = CM_T_DRAW; break; case TM_POLYLINE: mid = CM_T_POLYLINE; break; case TM_POLYGON: mid = CM_T_POLYGON; break; case TM_RECTANGLE: mid = CM_T_RECTANGLE; break; case TM_ROUNDREC: mid = CM_T_ROUNDREC; break; case TM_ELLIPSE: mid = CM_T_ELLIPSE; break; case TM_ARROW: mid = CM_T_ARROW; break; case TM_TEXT: mid = CM_T_TEXT; break; default: return; } if(hMenu) CheckMenuItem(hMenu, mid, check ? MF_CHECKED : MF_UNCHECKED); } void OutputWin::FileHistory() { HMENU hSubMenu; char **history[] = {&defs.File1, &defs.File2, &defs.File3, &defs.File4, &defs.File5, &defs.File6}; int i, j, k; if(!hasHistMenu || !defs.File1) return; if(!(hSubMenu = GetSubMenu(GetMenu(hWnd), 0))) return; if(!HistMenuSize) AppendMenu(hSubMenu, MF_SEPARATOR, 0L, 0L); for(i = 0; i < 6 && *history[i]; i++) { k = (int)strlen(*history[i]); for (j = 0; j < k && defs.currPath[j] == (*history[i])[j]; j++); if((*history[i])[j] == '\\' || (*history[i])[j] == '/') j++; if(i < HistMenuSize) { ModifyMenu(hSubMenu, CM_FILE1+i, MF_BYCOMMAND | MF_STRING, CM_FILE1+i, *history[i]+j); } else { AppendMenu(hSubMenu, MF_STRING, CM_FILE1+i, *history[i]+j); } } HistMenuSize = i; } void OutputWin::CreateNewWindow(void *g) { RECT ClientRect; hWnd = CreateWindow(name, "RLPlot", WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); #if _MSC_VER >= 1400 SetWindowLongPtr(hWnd, 0, lptrref(g)); // g is the parent graphic obj SetWindowLongPtr(hWnd, GWL_USERDATA, lptrref(this)); #else SetWindowLong(hWnd, 0, lptrref(g)); // g is the parent graphic obj SetWindowLong(hWnd, GWL_USERDATA, lptrref(this)); #endif if(BitMapWin::Erase(0x00cbcbcb)) { GetClientRect(hWnd, &ClientRect); InvalidateRect(hWnd, &ClientRect, FALSE); } UpdateWindow(hWnd); ShowWindow(hWnd, SW_SHOW); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Copy to Clipboard //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Create Windows Meta File for clipboard WinCopyWMF::WinCopyWMF(GraphObj *g, char *file_wmf, char *file_emf) { HDC dc; HWND hwndDesk; DeskRect.left = DeskRect.top = 0; DeskRect.right = DeskRect.bottom = 0x4fffffffL; 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()); minLW = 1; hres = (double)GetDeviceCaps(dc, LOGPIXELSX); vres = (double)GetDeviceCaps(dc, LOGPIXELSY); ReleaseDC(hwndDesk, dc); wmf_file = file_wmf; emf_file = file_emf; } WinCopyWMF::~WinCopyWMF() { if(hgo) delete hgo; if(hFont) DeleteObject(hFont); if(hBrush) DeleteObject(hBrush); if(hPen) DeleteObject(hPen); } bool WinCopyWMF::SetLine(LineDEF *lDef) { int iw; HPEN newPen; if(!hPen || lDef->width != LineWidth || lDef->width != LineWidth || lDef->pattern != dPattern || lDef->color != dLineCol) { LineWidth = lDef->width; iw = iround(un2fix(lDef->width)); dPattern = lDef->pattern; RLP.finc = 256.0/un2fix(lDef->patlength*8.0); RLP.fp = 0.0; if(iLine == iw && dLineCol == lDef->color && hPen) return true; iLine = iw; dLineCol = lDef->color; newPen = CreatePen(PS_SOLID, iw > 0 ? iw : 1, dLineCol); SelectObject(hdc, newPen); if(hPen) DeleteObject(hPen); hPen = newPen; } return true; } bool WinCopyWMF::SetFill(FillDEF *fill) { HBRUSH newBrush; if(!fill) return false; if((fill->type & 0xff) != FILL_NONE) { if(!hgo) hgo = new HatchOut(this); if(hgo) hgo->SetFill(fill); } else { if(hgo) delete hgo; hgo = NULL; } if(dFillCol != fill->color) { newBrush = CreateSolidBrush(dFillCol = fill->color); SelectObject(hdc, newBrush); if(hBrush) DeleteObject(hBrush); hBrush = newBrush; } dFillCol = fill->color; dFillCol2 = fill->color2; return true; } bool WinCopyWMF::SetTextSpec(TextDEF *set) { return com_SetTextSpec(set, this, &hFont, &TxtSet, &hdc); } bool WinCopyWMF::oGetTextExtent(char *text, int cb, int *width, int *height) { return com_oGetTextExtent(text, cb, width, height, hdc, &TxtSet); } bool WinCopyWMF::oGetTextExtentW(w_char *text, int cb, int *width, int *height) { return com_oGetTextExtentW(text, cb, width, height, hdc, &TxtSet); } bool WinCopyWMF::StartPage() { int w, h; RECT rect; double res; if(!go) return false; res = Units[defs.cUnits].convert; w = iround(hres*res*(go->GetSize(SIZE_GRECT_RIGHT) - go->GetSize(SIZE_GRECT_LEFT))); h = iround(vres*res*(go->GetSize(SIZE_GRECT_BOTTOM) - go->GetSize(SIZE_GRECT_TOP))); rect.left = rect.top = 0; rect.bottom = h+560; rect.right = w+720; if(!(hdc = CreateEnhMetaFile(0L, emf_file, &rect, "RLPlot")))return false; if(SetMapMode(hdc, MM_HIMETRIC)) { hres = vres = 2540.0; OC_type = OC_HIMETRIC; bott_y = un2iy(go->GetSize(SIZE_GRECT_TOP) - go->GetSize(SIZE_GRECT_BOTTOM)); VPorg.fy = bott_y; } else return false; if(hPen)SelectObject(hdc, hPen); if(hBrush) SelectObject(hdc, hBrush); VPorg.fx = -co2fix(go->GetSize(SIZE_GRECT_LEFT)); return true; } bool WinCopyWMF::EndPage() { int iFile; HENHMETAFILE hmf; unsigned int cb; unsigned char *buff; HDC dc; hmf = CloseEnhMetaFile(hdc); if(emf_file); // nothing more to do else if(wmf_file) { dc = GetDC(MainWnd); cb = GetWinMetaFileBits(hmf, 0, 0L, MM_HIMETRIC, dc); if(cb && (buff = (unsigned char*)malloc(cb+1))){ #ifdef USE_WIN_SECURE if(_sopen_s(&iFile, wmf_file, O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 0x40, S_IWRITE) || iFile < 0){ ErrorBox("Open failed for metafile"); free(buff); return false; } #else if(-1 ==(iFile = open(wmf_file, O_RDWR | O_BINARY | O_CREAT | O_TRUNC, S_IWRITE | S_IREAD))){ ErrorBox("Open failed for metafile"); free(buff); return false; } #endif if(cb = GetWinMetaFileBits(hmf, cb, buff, MM_HIMETRIC, dc)){ #ifdef USE_WIN_SECURE _write(iFile, buff, cb); _close(iFile); #else write(iFile, buff, cb); close(iFile); #endif } free(buff); } ReleaseDC(MainWnd, dc); } else SetClipboardData(CF_ENHMETAFILE, hmf); DeleteEnhMetaFile(hmf); return true; } bool WinCopyWMF::oCircle(int ix1, int iy1, int ix2, int iy2, char* nam) { int x1=ix1, x2=ix2, y1, y2; BOOL RetVal; y1 = bott_y - iy1; y2 = bott_y - iy2; if(x2 > x1) x2 = ix2 + 25; else x1 = ix1 + 25; if(y1 > y2) y2 -= 25; else y1 -=25; RetVal = Ellipse(hdc, x1, y1, x2, y2); if(RetVal && hgo) return hgo->oCircle(x1, y1, x2, y2); return RetVal != 0; } bool WinCopyWMF::oPolyline(POINT * pts, int cp, char *nam) { int i; if(cp < 1) return false; for (i = 0; i < cp; i++) pts[i].y = bott_y - pts[i].y; if (dPattern) { for (i = 1; i < cp; i++) PatLine(pts[i-1], pts[i]); return true; } return (0 != Polyline(hdc, pts, cp)); } bool WinCopyWMF::oRectangle(int ix1, int iy1, int ix2, int iy2, char *name) { int x1=ix1, x2=ix2, y1, y2; BOOL RetVal; y1 = bott_y - iy1; y2 = bott_y - iy2; if(x2 > x1) x2 = ix2 + 25; else x1 = ix1 + 25; if(y1 > y2) y2 -= 25; else y1 -=25; RetVal = Rectangle(hdc, x1, y1, x2, y2); if(RetVal && hgo) return hgo->oRectangle(ix1, iy1, ix2, iy2, 0L); return RetVal != 0; } bool WinCopyWMF::oSolidLine(POINT *p) { p[0].y = bott_y - p[0].y; p[1].y = bott_y - p[1].y; if(Polyline(hdc, p, 2)) return true; return false; } bool WinCopyWMF::oTextOut(int x, int y, char *txt, int cb) { y = bott_y - y; return com_oTextOut(x, y, txt, cb, &hFont, &hdc, &TxtSet, this); } bool WinCopyWMF::oTextOutW(int x, int y, w_char *txt, int cb) { y = bott_y - y; return com_oTextOutW(x, y, txt, cb, &hFont, &hdc, &TxtSet, this); } bool WinCopyWMF::oPolygon(POINT *pts, int cp, char *nam) { int i; BOOL RetVal; for (i = 0; i < cp; i++) pts[i].y = bott_y - pts[i].y; RetVal = Polygon(hdc, pts, cp); if(RetVal && hgo) { for (i = 0; i < cp; i++) pts[i].y = - pts[i].y + bott_y ; return hgo->oPolygon(pts, cp); } return (RetVal != 0); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Print //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PrintWin::PrintWin() { int i, j; double pw, ph; PrintDriver = PrintDevice = PrintPort = 0L; hPen = 0L; hBrush = 0L; hFont = 0L; hDC = 0L; hgo = 0L; units = defs.cUnits; i = j = 0; minLW = 1; GetProfileString("windows", "device", "", TmpTxt, 4096); while(TmpTxt[i] && TmpTxt[i] != ',') i++; TmpTxt[i] = 0; if (i >2) { PrintDevice = _strdup(TmpTxt); i++; j = i; while(TmpTxt[i] && TmpTxt[i] != ',') i++; if(i-j > 2) { TmpTxt[i] = 0; PrintDriver = _strdup(TmpTxt+j); i++; j = i; while(TmpTxt[i] && TmpTxt[i] != ',') i++; if(i-j > 2) { TmpTxt[i] = 0; PrintPort = _strdup(TmpTxt+j); //Get default paper setup if(hDC = CreateDC(PrintDriver, PrintDevice, PrintPort, 0L)) { pw = GetDeviceCaps(hDC, PHYSICALWIDTH); pw /= (double)GetDeviceCaps(hDC, LOGPIXELSX); ph = GetDeviceCaps(hDC, PHYSICALHEIGHT); ph /= (double)GetDeviceCaps(hDC, LOGPIXELSY); switch (defs.cUnits){ case 1: pw *= 2.54; ph *= 2.54; break; case 2: break; default: pw *= 25.4; ph *= 25.4; break; } FindPaper(pw, ph, 0.01); DeleteDC(hDC); } hDC = 0L; } } } } PrintWin::~PrintWin() { if(PrintDriver) free(PrintDriver); if(PrintDevice) free(PrintDevice); if(PrintPort) free(PrintPort); if(hPen) DeleteObject(hPen); if(hBrush) DeleteObject(hBrush); if(hFont) DeleteObject(hFont); } bool PrintWin::SetLine(LineDEF *lDef) { int iw; HPEN newPen; if(!hPen || lDef->width != LineWidth || lDef->width != LineWidth || lDef->pattern != dPattern || lDef->color != dLineCol) { LineWidth = lDef->width; iw = iround(un2ix(lDef->width)); dPattern = lDef->pattern; RLP.finc = 256.0/un2fix(lDef->patlength*8.0); RLP.fp = 0.0; if(iLine == iw && dLineCol == lDef->color && hPen) return true; iLine = iw; dLineCol = lDef->color; newPen = CreatePen(PS_SOLID, iw > 0 ? iw : 1, dLineCol); SelectObject(hDC, newPen); if(hPen) DeleteObject(hPen); hPen = newPen; } return true; } bool PrintWin::SetFill(FillDEF *fill) { HBRUSH newBrush; if(!fill) return false; if((fill->type & 0xff) != FILL_NONE) { if(!hgo) hgo = new HatchOut(this); if(hgo) hgo->SetFill(fill); } else { if(hgo) delete hgo; hgo = NULL; } newBrush = CreateSolidBrush(fill->color); SelectObject(hDC, newBrush); if(hBrush) DeleteObject(hBrush); hBrush = newBrush; dFillCol = fill->color; dFillCol2 = fill->color2; return true; } bool PrintWin::SetTextSpec(TextDEF *set) { return com_SetTextSpec(set, this, &hFont, &TxtSet, &hDC); } bool PrintWin::oGetTextExtent(char *text, int cb, int *width, int *height) { return com_oGetTextExtent(text, cb, width, height, hDC, &TxtSet); } bool PrintWin::oGetTextExtentW(w_char *text, int cb, int *width, int *height) { return com_oGetTextExtentW(text, cb, width, height, hDC, &TxtSet); } bool PrintWin::StartPage() { DOCINFO DocInfo; bool bRet = false; if(hDC = CreateDC(PrintDriver, PrintDevice, PrintPort, 0L)) { hPen = CreatePen(PS_SOLID, 1, dLineCol = 0x00ffffffL); hBrush = CreateSolidBrush(dFillCol =dBgCol = 0x00ffffffL); dPattern = 0L; SelectObject(hDC, hPen); SelectObject(hDC, hBrush); memset(&DocInfo, 0, sizeof(DOCINFO)); DocInfo.lpszDocName = "RLPlot graph"; DocInfo.cbSize = sizeof(DOCINFO); DeskRect.left = DeskRect.top = 0; DeskRect.right = GetDeviceCaps(hDC, HORZRES); DeskRect.bottom = GetDeviceCaps(hDC, VERTRES); hres = (double)GetDeviceCaps(hDC, LOGPIXELSX); vres = (double)GetDeviceCaps(hDC, LOGPIXELSY); if(StartDoc(hDC, &DocInfo) >= 0) { if(::StartPage(hDC)>0) bRet = true; } } return bRet; } bool PrintWin::EndPage() { if(hDC) { ::EndPage(hDC); EndDoc(hDC); DeleteDC(hDC); } hDC = 0L; return true; } bool PrintWin::Eject() { if(hDC) { ::EndPage(hDC); ::StartPage(hDC); return true; } return false; } bool PrintWin::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; RetVal = Ellipse(hDC, x1, y1, x2, y2); if(RetVal && hgo) return hgo->oCircle(x1, y1, x2, y2); else if(RetVal) return true; return false; } bool PrintWin::oPolyline(POINT * pts, int cp, char *nam) { int i; if(cp < 1) return FALSE; if (dPattern) { for (i = 1; i < cp; i++) PatLine(pts[i-1], pts[i]); return true; } else { if(Polyline(hDC, pts, cp))return true; else return false; } } bool PrintWin::oRectangle(int x1, int y1, int x2, int y2, char *nam) { POINT pts[5]; 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 PrintWin::oSolidLine(POINT *p) { if(Polyline(hDC, p, 2)) return true; return false; } bool PrintWin::oTextOut(int x, int y, char *txt, int cb) { return com_oTextOut(x, y, txt, cb, &hFont, &hDC, &TxtSet, this); } bool PrintWin::oTextOutW(int x, int y, w_char *txt, int cb) { return com_oTextOutW(x, y, txt, cb, &hFont, &hDC, &TxtSet, this); } bool PrintWin::oPolygon(POINT *pts, int cp, char *nam) { BOOL RetVal; RetVal = Polygon(hDC, pts, cp); if(RetVal && hgo) return hgo->oPolygon(pts, cp); else if (RetVal) return true; return false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Find a suitable www browser void FindBrowser() { char text[600]; long size = 599; HKEY hdl; int i; //find the default browser if(ERROR_SUCCESS == RegQueryValue(HKEY_CLASSES_ROOT, "http\\shell\\open\\command", text, &size) && size > 7) { if(text[0] == '"') { for(i = size-2; i >3; i--) { if(text[i+1] == '"') { text[i+1] = 0; break; } else text[i+1] = 0; } WWWbrowser = _strdup(text+1); } else { for(i = size-1; i >5; i--) { if(0 == _stricmp(text+i-3, ".exe")) break; else text[i] = 0; } WWWbrowser = _strdup(text); } } //find user default data directory if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, "Environment", NULL, KEY_READ, &hdl)) { text[0] = 0; size=599; RegQueryValueEx(hdl, "HOMEDRIVE", 0, 0, (unsigned char*)text, (unsigned long*)&size); size= 599; RegQueryValueEx(hdl, "HOMEPATH", 0, 0, (unsigned char*)(text+strlen(text)), (unsigned long*)&size); defs.currPath = _strdup(text); } //find user application data directory if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", NULL, KEY_READ, &hdl)) { text[0] = 0; size=599; RegQueryValueEx(hdl, "AppData", 0, 0, (unsigned char*)text, (unsigned long*)&size); #ifdef USE_WIN_SECURE strcat_s(text, 600, "\\RLPlot"); #else strcat(text, "\\RLPlot"); #endif defs.IniFile = _strdup(text); } //find country specific information // its not a perfect place to do it, but a good one GetProfileString("intl", "sDecimal", ".", text, 2); if(text[0]) defs.DecPoint[0] = text[0]; GetProfileString("intl", "sList", ".", text, 2); if(text[0]) defs.ColSep[0] = text[0]; if(GetProfileInt("intl", "iMeasure", 0)) defs.dUnits = defs.cUnits = 2; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Windos entry point //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { WNDCLASS wndclass; MSG msg; DefsRW *drw; HWND hwnd; HDC dc; //OS dependent initialization dlgtxtheight = 16; if(lpCmdLine && lpCmdLine[0] && FileExist(lpCmdLine)) LoadFile = _strdup(lpCmdLine); else if(lpCmdLine) { //probably Unicode #ifdef USE_WIN_SECURE sprintf_s(TmpTxt, TMP_TXT_SIZE, "%s", lpCmdLine); #else sprintf(TmpTxt, "%s", lpCmdLine); #endif rmquot(TmpTxt); if(TmpTxt[0]) LoadFile= _strdup(TmpTxt); } ShellCmd = GetCommandLine(); hInstance = hInst; wndclass.style = CS_BYTEALIGNWINDOW | CS_DBLCLKS; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = sizeof(GraphObj*); wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_EVAL)); wndclass.hCursor = 0L; wndclass.hbrBackground = NULL; wndclass.lpszMenuName = 0L; wndclass.lpszClassName = name; RegisterClass(&wndclass); dc = GetDC(hwnd = GetDesktopWindow()); if(0 == SetGraphicsMode(dc, GM_ADVANCED)){ ErrorBox("RLPlot detected an\nold version of Windows which\nis no longer supported!\n"); return 1; } SetGraphicsMode(dc, GM_COMPATIBLE); ReleaseDC(hwnd, dc); ShowBanner(true); InitTextCursor(true); Printer = new PrintWin(); accel = LoadAccelerators(hInstance, MAKEINTRESOURCE(ACCELERATORS_1)); while(GetMessage(&msg, NULL, 0, 0)){ TranslateMessage(&msg); TranslateAccelerator(msg.hwnd, accel, &msg); DispatchMessage(&msg); } if(defs.IniFile) { if(drw = new DefsRW()){ drw->FileIO(FILE_WRITE); delete drw; } } if(WWWbrowser) free(WWWbrowser); if(LoadFile) free(LoadFile); SpreadMain(false); if(Printer) delete Printer; InitTextCursor(false); UnregisterClass(name, hInstance); return (int)msg.wParam; } void CopyData(GraphObj *g, unsigned int cf) { HGLOBAL hmem; long cb; unsigned char *dt = 0L; unsigned char *buf; if(!g || g->Id != GO_SPREADDATA) return; switch(cf) { case CF_TEXT: if(!g->Command(CMD_COPY_TSV, &dt, 0L))return; break; case CF_SYLK: if(!g->Command(CMD_COPY_SYLK, &dt, 0L))return; break; default: if(cf == cf_rlpxml && g->Command(CMD_COPY_XML, &dt, 0L)) break; else return; } cb = (long)strlen((char*)dt); if(hmem = GlobalAlloc(GMEM_MOVEABLE, cb+2)) { if(buf = (unsigned char *)GlobalLock(hmem)) { memcpy(buf, dt, cb+1); GlobalUnlock(hmem); SetClipboardData(cf, hmem); } } } void CopyGraph(GraphObj *g, unsigned int cf, anyOutput *o) { HGLOBAL hmem; char *dt, *buf; long cb; if(!(dt = GraphToMem(g, &cb)))return; if(o) ShowCopyMark(o, &g->rDims, 1); if(hmem = GlobalAlloc(GMEM_MOVEABLE, cb+1)) { if(buf = (char *)GlobalLock(hmem)) { memcpy(buf, dt, cb); buf[cb] = 0; GlobalUnlock(hmem); SetClipboardData(cf, hmem); } } free(dt); } void ScrollEvent(bool bVert, HWND hwnd, UINT type, GraphObj *g, OutputWin *w) { SCROLLINFO si; int LineStep, cmd, pos; if(hwnd && g && w) { cmd = bVert ? CMD_SETVPOS : CMD_SETHPOS; si.fMask = SIF_ALL; si.cbSize = sizeof(SCROLLINFO); if(!(GetScrollInfo(hwnd, bVert ? SB_VERT : SB_HORZ, &si)))return; LineStep = (g->Id == GO_GRAPH || g->Id == GO_PAGE) ? 16 : 1; switch(type){ case SB_LINEUP: pos = si.nPos - LineStep; break; case SB_LINEDOWN: pos = si.nPos + LineStep; break; case SB_PAGEUP: if(g->Id == GO_SPREADDATA) { g->Command(CMD_PAGEUP, 0L, w); return; } pos = (si.nPos - (int)si.nPage) >= si.nMin ? (si.nPos - si.nPage) : si.nMin; break; case SB_PAGEDOWN: if(g->Id == GO_SPREADDATA) { g->Command(CMD_PAGEDOWN, 0L, w); return; } pos = (si.nPos + (int)si.nPage*2) < si.nMax ? (si.nPos + si.nPage) : (si.nMax - si.nPage+1); break; case SB_THUMBTRACK: case SB_THUMBPOSITION: pos = si.nTrackPos; break; default: return; } g->Command(cmd, (void*)(& pos), w); } } long OpenFileFromHistory(OutputWin *w, GraphObj *g, int id) { char *name = 0L; switch (id) { case 0: name = defs.File1; break; case 1: name = defs.File2; break; case 2: name = defs.File3; break; case 3: name = defs.File4; break; case 4: name = defs.File5; break; case 5: name = defs.File6; break; default: return 0; } if(name && name[0] && FileExist(name)) { g->Command(CMD_DROPFILE, name, w); defs.FileHistory(name); w->FileHistory(); } else { ErrorBox("The selected file \ndoes not exist!\n"); } return 0; } static GraphObj *copy_obj; long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam) { static WinCopyWMF *CopyWMF = NULL; static BitMapWin *CopyBMP = NULL; static bool CtrlDown = false, bAltKey = false; static w_char uc_char; PAINTSTRUCT ps; OutputWin *w; GraphObj *g; MouseEvent mev; HDC dc; int cc; RECT rec; g = (GraphObj *) reflptr(GetWindowLong(hwnd, 0)); w = (OutputWin *) reflptr(GetWindowLong(hwnd, GWL_USERDATA)); if(g && w) switch(message) { case WM_SETFOCUS: if(g->Id == GO_GRAPH) CurrGraph = (Graph*)g; else CurrGraph = 0L; break; case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: HideTextCursor(); case WM_MOUSEMOVE: case WM_RBUTTONUP: case WM_LBUTTONUP: mev.x = LOWORD(lParam); mev.y = HIWORD(lParam); mev.StateFlags = 0; if(wParam & MK_LBUTTON) mev.StateFlags |= 1; if(wParam & MK_MBUTTON) mev.StateFlags |= 2; if(wParam & MK_RBUTTON) mev.StateFlags |= 4; if(wParam & MK_SHIFT) mev.StateFlags |= 8; if(wParam & MK_CONTROL) mev.StateFlags |= 16; if(message == WM_LBUTTONUP) mev.Action = MOUSE_LBUP; else if(message == WM_RBUTTONUP) mev.Action = MOUSE_RBUP; else if(message == WM_LBUTTONDBLCLK) mev.Action = MOUSE_LBDOUBLECLICK; else if(message == WM_LBUTTONDOWN) mev.Action = MOUSE_LBDOWN; else if(message == WM_MOUSEMOVE)mev.Action = MOUSE_MOVE; g->Command(CMD_MOUSE_EVENT, (void *)&mev, w); break; case 0x020A: //WM_MOUSEWHEEL ScrollEvent(true, hwnd, (int)wParam > 0 ? SB_LINEUP : SB_LINEDOWN, g, w); return 0; case WM_KEYDOWN: cc = (wParam & 0xff); if(g && w && (GetKeyState(VK_LCONTROL) || GetKeyState(VK_RCONTROL))){ if(cc == 0xbb || cc == 0x6b ) g->Command(CMD_ZOOM, &"+", w); else if(cc == 0xbd || cc == 0x6d ) g->Command(CMD_ZOOM, &"-", w); else break; return 0; } break; case WM_CHAR: cc = (wParam & 0xff); if(bAltKey && uc_char) { if(uc_char >=255) { g->Command(CMD_ADDCHARW, (void *)(& uc_char), w); uc_char = 0; bAltKey = false; return 0; } else cc = (int)uc_char; uc_char = 0; bAltKey = false; } g->Command(CMD_ADDCHAR, (void *)(& cc), w); return 0; case WM_SYSKEYDOWN: if(wParam == VK_MENU) { bAltKey = true; uc_char = 0; } break; case WM_SYSKEYUP: if(wParam == VK_MENU) bAltKey = false; if(bAltKey) { cc = (wParam & 0xff); if( cc >= 0x60 && cc <= 0x69) { uc_char *= 10; uc_char += (cc-0x60); return 0; } else { uc_char = 0; bAltKey = false; return 0; } } break; case WM_VSCROLL: case WM_HSCROLL: ScrollEvent(message == WM_VSCROLL, hwnd, wParam & 0xffff, g, w); return 0; } switch(message) { case WM_CREATE: break; case WM_SIZE: if(g && w) g->Command(CMD_SETSCROLL, 0L, w); break; case WM_INITMENUPOPUP: case WM_NCMOUSEMOVE: SetCursor(LoadCursor(NULL, IDC_ARROW)); break; case WM_SETCURSOR: if(w) w->MouseCursor(MC_LAST, true); return TRUE; case WM_SETFOCUS: if(g && w) if(!g->Command(message == WM_SETFOCUS ? CMD_SETFOCUS : CMD_KILLFOCUS, NULL, w)) SetCursor(LoadCursor(NULL, IDC_ARROW)); return 0; case WM_DESTROYCLIPBOARD: if(g && w) g->Command(CMD_HIDEMARK, 0L, w); HideCopyMark(); return 0; case WM_RENDERALLFORMATS: // we do not support leaving data on the clipboard after exit OpenClipboard(hwnd); EmptyClipboard(); CloseClipboard(); return 0; case WM_RENDERFORMAT: if(g && w) switch(wParam){ case CF_ENHMETAFILE: CopyWMF = new WinCopyWMF(copy_obj, 0L, 0L); if(CopyWMF && CopyWMF->StartPage()) { copy_obj->DoPlot(CopyWMF); CopyWMF->EndPage(); delete CopyWMF; CopyWMF = NULL; } if(copy_obj->Id == GO_GRAPH || copy_obj->Id == GO_PAGE) copy_obj->DoPlot(0L); break; case CF_BITMAP: if((CopyBMP = new BitMapWin(copy_obj)) && CopyBMP->StartPage()) { copy_obj->DoPlot(CopyBMP); CopyBMP->EndPage(); SetClipboardData(CF_BITMAP, CopyBMP->scr); CopyBMP->scr = 0L; CopyBMP->go = 0L; delete CopyBMP; CopyBMP = NULL; } if(copy_obj->Id == GO_GRAPH || copy_obj->Id == GO_PAGE) copy_obj->DoPlot(0L); break; case CF_SYLK: case CF_TEXT: if(g->Id == GO_SPREADDATA) CopyData(g, wParam); break; default: // if(wParam == cf_rlpgraph) CopyGraph(copy_obj, wParam, w); if(wParam == cf_rlpxml) CopyData(g, wParam); break; } if(w->Erase(defs.Color(COL_BG))) g->DoPlot(w); return 0; case WM_COMMAND: wParam &= 0xffff; if(g && w) switch(wParam) { case CM_EXIT: if(g->Command(CMD_CAN_CLOSE, 0L, 0L)) { SetWindowLong(hwnd, 0, 0L); SetWindowLong(hwnd, GWL_USERDATA, 0L); w->go = 0L; 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); else if(g->Id == GO_PAGE || g->Id == GO_GRAPH){ if(CurrGO && CurrGO->Id == GO_TEXTFRAME && CurrGO->Command(CMD_PASTE, 0L, w)); else TestClipboard(g); } g->Command(CMD_MOUSECURSOR, 0L, w); return 0; case CM_COPY: case CM_CUT: case CM_COPYGRAPH: EmptyClip(); if(CurrGO && g->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) { OpenClipboard(hwnd); CopyGraph(CurrGO, cf_rlpobj, w); copy_obj = CurrGO; CloseClipboard(); return 0; } else if(CurrGO->Id == GO_TEXTFRAME) { if(CurrGO->Command(CMD_COPY, 0L, w)) return 0; } } OpenClipboard(hwnd); if(g->Id == GO_SPREADDATA && g->Command(wParam == CM_CUT ? CMD_CUT : CMD_QUERY_COPY, 0L, w)) { SetClipboardData(CF_TEXT, NULL); SetClipboardData(CF_SYLK, NULL); SetClipboardData(cf_rlpxml, NULL); } else if(g->Id == GO_PAGE) { if(!g->hasTransp()) SetClipboardData(CF_ENHMETAFILE, NULL); SetClipboardData(CF_BITMAP, NULL); if(CurrGraph) { CopyGraph(CurrGraph, cf_rlpobj, w); copy_obj = CurrGraph; } } else if (wParam == CM_CUT)return 0; else if(CurrGraph && CurrGraph->Id == GO_GRAPH){ 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){ if(!g->hasTransp()) SetClipboardData(CF_ENHMETAFILE, NULL); SetClipboardData(CF_BITMAP, NULL); CopyGraph(g, cf_rlpobj, w); copy_obj = g; } CloseClipboard(); return 0; case CM_UPDATE: g->Command(CMD_UPDATE, 0L, w); return 0; case CM_OPEN: g->Command(CMD_OPEN, 0L, w); return 0; case CM_FILE1: case CM_FILE2: case CM_FILE3: case CM_FILE4: case CM_FILE5: case CM_FILE6: return OpenFileFromHistory(w, g, wParam - CM_FILE1); case CM_FILLRANGE: g->Command(CMD_FILLRANGE, (void *)NULL, w); return 0; case CM_ABOUT: RLPlotInfo(); return 0; case CM_ZOOM25: g->Command(CMD_ZOOM, &"25", w); return 0; case CM_ZOOM50: g->Command(CMD_ZOOM, &"50", w); return 0; case CM_ZOOM100: g->Command(CMD_ZOOM, &"100", w); return 0; case CM_ZOOM200: g->Command(CMD_ZOOM, &"200", w); return 0; case CM_ZOOM400: g->Command(CMD_ZOOM, &"400", w); return 0; case CM_ZOOMIN: g->Command(CMD_ZOOM, &"+", w); return 0; case CM_ZOOMOUT: g->Command(CMD_ZOOM, &"-", w); return 0; case CM_ZOOMFIT: g->Command(CMD_ZOOM, &"fit", w); return 0; case CM_ADDPLOT: g->Command(CMD_ADDPLOT, 0L, w); return 0; case CM_LEGEND: g->Command(CMD_LEGEND, 0L, w); return 0; case CM_LAYERS: g->Command(CMD_LAYERS, 0L, w); return 0; case CM_NEWGRAPH: g->Command(CMD_NEWGRAPH, 0L, w); return 0; case CM_NEWPAGE: g->Command(CMD_NEWPAGE, 0L, w); return 0; case CM_DELGRAPH: g->Command(CMD_DELGRAPH, 0L, w); return 0; case CM_SAVE: g->Command(CMD_SAVE, 0L, w); return 0; case CM_SAVEAS: g->Command(CMD_SAVEAS, 0L, w); return 0; case CM_REDRAW: if(w->Erase(defs.Color(COL_BG))) g->DoPlot(w); return 0; case CM_DELOBJ: if(CurrGO && CurrGO->parent && CurrGO->parent-> Command(CMD_DELOBJ, (void*)CurrGO, w)) { CurrGO = 0L; if(w->Erase(defs.Color(COL_BG))) g->DoPlot(w); } else if(!CurrGO) InfoBox("No object selected!"); return 0; case CM_EXPORT: OpenExportName(g, 0L); g->DoPlot(w); return 0; case CM_PRINT: if(g->Id == GO_SPREADDATA){ g->Command(CMD_PRINT, 0L, Printer); return 0; } if(Printer && Printer->StartPage()) { SetCursor(LoadCursor(0L, IDC_WAIT)); 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)); } return 0; case CM_ADDROWCOL: g->Command(CMD_ADDROWCOL, (void *)NULL, w); return 0; case CM_DEFAULTS: g->Command(CMD_CONFIG, 0L, w); return 0; case CM_ADDAXIS: g->Command(CMD_ADDAXIS, 0L, w); return 0; case CM_T_STANDARD: cc = TM_STANDARD; g->Command(CMD_TOOLMODE, (void*)(& cc), w); return 0; case CM_T_DRAW: cc = TM_DRAW; g->Command(CMD_TOOLMODE, (void*)(& cc), w); return 0; case CM_T_POLYLINE: cc = TM_POLYLINE; g->Command(CMD_TOOLMODE, (void*)(& cc), w); return 0; case CM_T_POLYGON: cc = TM_POLYGON; g->Command(CMD_TOOLMODE, (void*)(& cc), w); return 0; case CM_T_RECTANGLE: cc = TM_RECTANGLE; g->Command(CMD_TOOLMODE, (void*)(& cc), w); return 0; case CM_T_ROUNDREC: cc = TM_ROUNDREC; g->Command(CMD_TOOLMODE, (void*)(& cc), w); return 0; case CM_T_ELLIPSE: cc = TM_ELLIPSE; g->Command(CMD_TOOLMODE, (void*)(& cc), w); return 0; case CM_T_ARROW: cc = TM_ARROW; g->Command(CMD_TOOLMODE, (void*)(& cc), w); return 0; case CM_T_TEXT: cc = TM_TEXT; g->Command(CMD_TOOLMODE, (void*)(& cc), w); return 0; case CM_DELKEY: case CM_LEFTARRKEY: case CM_RIGHTARRKEY: case CM_UPARRKEY: case CM_DOWNARRKEY: case CM_POS_FIRST: case CM_POS_LAST: case CM_SHLEFT: case CM_SHRIGHT: case CM_SHUP: case CM_SHDOWN: case CM_TAB: case CM_SHTAB: case CM_SHPGUP: case CM_SHPGDOWN: switch(wParam) { case CM_DELKEY: cc = CMD_DELETE; break; case CM_LEFTARRKEY: cc = CMD_CURRLEFT; break; case CM_RIGHTARRKEY: cc = CMD_CURRIGHT; break; case CM_UPARRKEY: cc = CMD_CURRUP; break; case CM_DOWNARRKEY: cc = CMD_CURRDOWN; break; case CM_POS_FIRST: cc = CMD_POS_FIRST; break; case CM_POS_LAST: cc = CMD_POS_LAST; break; case CM_SHLEFT: cc = CMD_SHIFTLEFT; break; case CM_SHRIGHT: cc = CMD_SHIFTRIGHT; break; case CM_SHUP: cc = CMD_SHIFTUP; break; case CM_SHDOWN: cc = CMD_SHIFTDOWN; break; case CM_TAB: cc = CMD_TAB; break; case CM_SHTAB: cc = CMD_SHTAB; break; case CM_SHPGUP: cc = CMD_SHPGUP; break; case CM_SHPGDOWN: cc = CMD_SHPGDOWN; break; } g->Command(cc, (void *)NULL, w); return 0; case CM_PGUP: case CM_PGDOWN: g->Command(wParam == CM_PGUP ? CMD_PAGEUP : CMD_PAGEDOWN, 0L, w); return 0; case CM_UNDO: g->Command(CMD_UNDO, 0L, w); return 0; case CM_INSROW: g->Command(CMD_INSROW, 0L, w); return 0; case CM_INSCOL: g->Command(CMD_INSCOL, 0L, w); return 0; case CM_DELROW: g->Command(CMD_DELROW, 0L, w); return 0; case CM_DELCOL: g->Command(CMD_DELCOL, 0L, w); return 0; case CM_SMPLSTAT: if(g->data) rep_samplestats(g, g->data); return 0; case CM_REPCMEANS: if(g->data) rep_compmeans(g, g->data); return 0; 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; case CM_REPKRUSKAL: if(g->data) rep_kruskal(g, g->data); return 0; case CM_REPTWANOV: if(g->data) rep_twanova(g, g->data); return 0; case CM_REPFRIEDM: if(g->data) rep_fmanova(g, g->data); return 0; case CM_REPREGR: if(g->data) rep_regression(g, g->data); return 0; case CM_ROBUSTLINE: if(g->data) rep_robustline(g, g->data); return 0; case CM_CORRELM: if(g->data) rep_correl(g, g->data, 0); return 0; case CM_CORRELT: if(g->data) rep_correl(g, g->data, 1); return 0; case CM_REPTWOWAY: if(g->data) rep_twowaytable(g, g->data); return 0; default: #ifdef USE_WIN_SECURE sprintf_s(TmpTxt, TMP_TXT_SIZE, "Command 0x%x (%d)\nreceived", wParam & 0xffff, wParam & 0xffff); #else sprintf(TmpTxt, "Command 0x%x (%d)\nreceived", wParam & 0xffff, wParam & 0xffff); #endif MessageBox(hwnd, TmpTxt, "Info", MB_OK | MB_ICONINFORMATION); } return 0; case WM_CLOSE: if(g && g->Command(CMD_CAN_CLOSE, 0L, 0L)) { SetWindowLong(hwnd, 0, 0L); SetWindowLong(hwnd, GWL_USERDATA, 0L); w->go = 0L; if(g->parent) g->parent->Command(CMD_DELOBJ, g, w); else DestroyWindow(hwnd); } else if(!g) DestroyWindow(hwnd); return 0; case WM_DESTROY: if(hwnd == MainWnd)PostQuitMessage(0); break; case WM_PAINT: dc = BeginPaint(hwnd, &ps); if(w && dc) w->UpdateRect(dc, ps.rcPaint); EndPaint(hwnd, &ps); break; } return (long)DefWindowProc(hwnd, message, wParam, lParam); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Dialog window: Windows specific //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ const char dlgname[] = "RLDLGWIN"; LRESULT FAR PASCAL DlgWndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam) { OutputWin *w; tag_DlgObj *d; PAINTSTRUCT ps; HDC dc; MouseEvent mev; int i, cc; d = (tag_DlgObj *) reflptr(GetWindowLong(hwnd, 0)); w = (OutputWin *) reflptr(GetWindowLong(hwnd, GWL_USERDATA)); switch(message) { case WM_CREATE: break; case WM_KILLFOCUS: HideTextCursorObj(w); if(d) d->Command(CMD_ENDDIALOG, NULL, w); return 0; case WM_TIMER: if(d) d->Command(CMD_ENDDIALOG, d, w); return 0; case WM_DESTROY: case WM_CLOSE: if(d) { d->Command(CMD_UNLOCK, 0L, w); d->Command(CMD_ENDDIALOG, 0L, w); SetWindowLong(hwnd, 0, NULL); noreflptr(GetWindowLong(hwnd, 0)); } if(w) { w->hWnd = 0L; SetWindowLong(hwnd, GWL_USERDATA, NULL); noreflptr(GetWindowLong(hwnd, GWL_USERDATA)); delete w; } break; case WM_CHAR: if(0x09 == (cc = wParam & 0xff)) break; //ignore Tab if(cc == 0x03) return d->Command(CMD_COPY, 0L, w); //^c copy if(cc == 0x16) return d->Command(CMD_PASTE, 0L, w); //^v paste if(d && w) d->Command(CMD_ADDCHAR, (void *)(& cc), w); break; case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: HideTextCursor(); case WM_RBUTTONUP: case WM_LBUTTONUP: case WM_MOUSEMOVE: mev.x = LOWORD(lParam); mev.y = HIWORD(lParam); mev.StateFlags = 0; if(wParam & MK_LBUTTON) mev.StateFlags |= 1; if(wParam & MK_MBUTTON) mev.StateFlags |= 2; if(wParam & MK_RBUTTON) mev.StateFlags |= 4; if(wParam & MK_SHIFT) mev.StateFlags |= 8; if(wParam & MK_CONTROL) mev.StateFlags |= 16; if(message == WM_MOUSEMOVE) mev.Action = MOUSE_MOVE; else if(message == WM_LBUTTONDOWN) mev.Action = MOUSE_LBDOWN; else if(message == WM_LBUTTONUP) mev.Action = MOUSE_LBUP; else if(message == WM_RBUTTONUP) mev.Action = MOUSE_RBUP; else if(message == WM_LBUTTONDBLCLK) mev.Action = MOUSE_LBDOUBLECLICK; if(d && w) d->Command(CMD_MOUSE_EVENT, (void *)&mev, w); break; case WM_COMMAND: wParam &= 0xffff; i = 0; switch(wParam) { case CM_DELKEY: i = CMD_DELETE; break; case CM_LEFTARRKEY: i = CMD_CURRLEFT; break; case CM_RIGHTARRKEY: i = CMD_CURRIGHT; break; case CM_UPARRKEY: i = CMD_CURRUP; break; case CM_DOWNARRKEY: i = CMD_CURRDOWN; break; case CM_TAB: i = CMD_TAB; break; case CM_SHTAB: i = CMD_SHTAB; break; case CM_POS_FIRST: i = CMD_POS_FIRST; break; case CM_POS_LAST: i = CMD_POS_LAST; break; case CM_SHLEFT: i = CMD_SHIFTLEFT; break; case CM_SHRIGHT: i = CMD_SHIFTRIGHT; break; case CM_UNDO: i = CMD_UNDO; break; } if(i && d && w) d->Command(i, 0L, w); return 0; case WM_PAINT: dc = BeginPaint(hwnd, &ps); if(w && dc){ w->HideMark(); w->UpdateRect(dc, ps.rcPaint); } EndPaint(hwnd, &ps); break; } return DefWindowProc(hwnd, message, wParam, lParam); } void *CreateDlgWnd(char *title, int x, int y, int width, int height, tag_DlgObj *d, DWORD flags) { WNDCLASS wndclass; OutputWin *w; HWND hDlg, hFoc; RECT rec, BoxRec, DeskRect; DWORD ws; wndclass.style = CS_BYTEALIGNWINDOW | CS_DBLCLKS; wndclass.lpfnWndProc = DlgWndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = sizeof(tag_DlgObj *); wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_EVAL)); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = NULL; wndclass.lpszMenuName = NULL; wndclass.lpszClassName = dlgname; RegisterClass(&wndclass); hFoc = GetFocus(); if(hFoc) { GetWindowRect(hFoc, &rec); x += rec.left; y += rec.top; } ws = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS; if(!(flags & 0x2)) ws |= WS_CAPTION; hDlg = CreateWindow(dlgname, title, ws, x, y, width, height, GetFocus(), NULL, hInstance, NULL); w = new OutputWin(0L, hDlg); w->units = defs.cUnits; if(hDlg && w && w->Erase(0x00e0e0e0L)) { ((DlgRoot*)d)->hDialog = hDlg; SetWindowLong(hDlg, GWL_USERDATA, lptrref(w)); SetWindowLong(hDlg, 0, lptrref(d)); if(flags & 0x01) { //center on screen GetWindowRect(hDlg, &BoxRec); GetClientRect(GetDesktopWindow(), &DeskRect); SetWindowPos(hDlg, HWND_TOPMOST, (DeskRect.right -DeskRect.left)/2 - (BoxRec.right - BoxRec.left)/2, (DeskRect.bottom -DeskRect.top)/2 - (BoxRec.bottom- BoxRec.top)/2, BoxRec.right - BoxRec.left, BoxRec.bottom - BoxRec.top, 0); } if(flags & 0x08) SetTimer(hDlg, 1, 100, 0L); UpdateWindow(hDlg); d->DoPlot(w); ShowWindow(hDlg, SW_SHOW); } else { if(w) delete (w); return 0L; } return hDlg; } void LoopDlgWnd() //keep message processing running { MSG msg; GetMessage(&msg, NULL, 0, 0); TranslateMessage(&msg); TranslateAccelerator(msg.hwnd, accel, &msg); DispatchMessage(&msg); } void CloseDlgWnd(void *hDlg) { HideCopyMark(); if(hDlg) SendMessage((HWND)hDlg, WM_CLOSE, 0, 0); } void ShowDlgWnd(void *hDlg) { ShowWindow((HWND)hDlg, SW_SHOW); SetFocus((HWND)hDlg); } void ResizeDlgWnd(void *hDlg, int w, int h) { HWND hwnd = (HWND)hDlg; RECT rc; GetWindowRect(hwnd, &rc); SetWindowPos(hwnd, HWND_TOPMOST, rc.left, rc.top, w, h, 0); ShowDlgWnd(hDlg); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // OS independent interface to Windows specific classes //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ anyOutput *NewDispClass(GraphObj *g) { return new OutputWin(g, 0L); } bool DelDispClass(anyOutput *w) { if (w) delete (OutputWin*) w; return true; } anyOutput *NewBitmapClass(int w, int h, double hr, double vr) { return new BitMapWin(w, h, hr, vr); } bool DelBitmapClass(anyOutput *w) { if (w) delete (BitMapWin*) w; return true; } rlplot/exprlp.cpp0000755000076400007640000001531310741722222012671 0ustar c71960c71960//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 #include #include #include #include //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] [options] []\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; } rlplot/rlp_math.cpp0000755000076400007640000024426310764512227013204 0ustar c71960c71960//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 #include #include #include #include #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) 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 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) */ /* 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; } rlplot/rlplot.10000755000076400007640000000513510741722223012253 0ustar c71960c71960.\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH RLPLOT 1 .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME rlplot \- generate publication quality graphs .br exprlp \- convert rlplot files to vector based graphic files .SH SYNOPSIS .B rlplot .I .br .B exprlp .RI [options] [options] [] .SH DESCRIPTION This manual page documents briefly the .B rlplot and .B exprlp commands. .PP .B rlplot is a GUI based program for displaying scientific data in standard formats. Output is generated on the X display where further changes can be made to the graph using point and click methods. Images can be exported as scalable vector graphics (SVG) as well as EPS, WMF and TIFF formats. .PP .B exprlp reads RLPlot files and exports various vector based graphic file formats including scaleable vector graphics (SVG), Encapsulated PostScript (EPS), and Windows Metafile (WMF). .SH OPTIONS .B rlplot does not have any command line options but the following options are available for .B exprlp . .TP .B \- use stdin/stdout as input or output file; requires that file format is set by -e | -s | -w option .TP .B \-h help .TP .B \-d delete input file after read .TP .B \-e output Encapsulated PostScript, *.eps .TP .B \-s output Scalable Vector Graphics, *.svg .TP .B \-S like -s, start output with "Content-Type: image/svg+xml" .TP .B \-v print RLPlot version .TP .B \-w output Windows Meta File, *.wmf .TP .B \-q quiet mode: suppress output to the console .SH EXAMPLES .B exprlp foo.rlp foo.svg ;exports Scalable Vector Graphics .TP .B exprlp \-q foo.rlp foo.eps ;exports Encapsulated PostScript, no messages .TP .B exprlp foo.rlp foo.wmf ;exports Windows Meta File .TP .B exprlp \-sq foo.rlp \- ;exports SVG to the console, no messages .TP .B exprlp exprlp \-eq \- \- ;converts inputfile from stdin to EPS on stdout .TP switch character is either '\-' or '\//' .SH AUTHOR .B rlplot and .B exprlp were written by Reinhard Lackner and are released under the GNU general public license. .sp This manual page was written by James Stone . rlplot/no_gui.cpp0000755000076400007640000001621010741722223012635 0ustar c71960c71960//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; } rlplot/RLPlot.xpm0000755000076400007640000001412310741722217012557 0ustar c71960c71960/* XPM */ static char *rlplot-icon[] = { /* width height ncolors chars_per_pixel */ "32 32 169 2", /* colors */ "AA c #FFFFFFFFFFFF", "BA c #FFFFF7F79494", "CA c #FFFFF7F78484", "DA c #FFFFF7F77373", "EA c #FFFFF7F75252", "FA c #FFFFF7F74242", "GA c #FFFFF7F73939", "HA c #FFFFEFEF8C8C", "IA c #FFFFEFEF4A4A", "JA c #FFFFEFEF2929", "KA c #F7F7E7E77B7B", "LA c #F7F7C6C6ADAD", "MA c #F7F7B5B59C9C", "NA c #F7F7ADAD9494", "OA c #EFEFF7F7F7F7", "PA c #EFEFF7F7EFEF", "AB c #EFEFEFEFEFEF", "BB c #EFEFEFEFDEDE", "CB c #EFEFE7E7A5A5", "DB c #EFEFDEDE7373", "EB c #EFEFDEDE3939", "FB c #EFEFDEDE2929", "GB c #EFEFD6D64242", "HB c #EFEFA5A58C8C", "IB c #EFEF94947B7B", "JB c #EFEF84847373", "KB c #EFEF84846363", "LB c #EFEF7B7B7373", "MB c #E7E7E7E7CECE", "NB c #E7E7E7E79494", "OB c #E7E7DEDE6B6B", "PB c #E7E7DEDE5252", "AC c #E7E7CECE5252", "BC c #E7E77B7B6363", "CC c #E7E773735A5A", "DC c #E7E76B6B5252", "EC c #E7E75A5A4A4A", "FC c #DEDEE7E7F7F7", "GC c #DEDEE7E7EFEF", "HC c #DEDEDEDEDEDE", "IC c #DEDEDEDEBDBD", "JC c #DEDECECE4A4A", "KC c #DEDE4A4A3939", "LC c #D6D6EFEFCECE", "MC c #D6D6DEDEEFEF", "NC c #D6D6DEDECECE", "OC c #CECEDEDEDEDE", "PC c #CECED6D6CECE", "AD c #CECECECEB5B5", "BD c #CECECECE5A5A", "CD c #C6C6E7E7C6C6", "DD c #C6C6DEDEEFEF", "ED c #C6C6D6D67373", "FD c #C6C6CECE4A4A", "GD c #BDBDDEDEB5B5", "HD c #BDBDCECEE7E7", "ID c #BDBDCECECECE", "JD c #BDBDC6C6D6D6", "KD c #BDBD39394242", "LD c #B5B5DEDEADAD", "MD c #B5B5BDBDCECE", "ND c #B5B5BDBD4242", "OD c #B5B5B5B59C9C", "PD c #ADADD6D6ADAD", "AE c #ADADCECEDEDE", "BE c #ADADBDBDB5B5", "CE c #ADADB5B54242", "DE c #ADAD4A4A5252", "EE c #A5A5BDBDDEDE", "FE c #A5A5BDBDCECE", "GE c #A5A5ADADB5B5", "HE c #A5A5ADAD4242", "IE c #A5A563637B7B", "JE c #9C9CD6D6A5A5", "KE c #9C9CBDBDD6D6", "LE c #9C9CBDBDBDBD", "ME c #9C9CADADCECE", "NE c #9C9CADADA5A5", "OE c #9C9C52525252", "PE c #9C9C4A4A5252", "AF c #9494CECE9C9C", "BF c #9494B5B5CECE", "CF c #9494ADAD5A5A", "DF c #9494ADAD3939", "EF c #8C8CCECE9494", "FF c #8C8CCECE8C8C", "GF c #8C8CB5B5B5B5", "HF c #8C8CADADD6D6", "IF c #8C8CADADCECE", "JF c #8C8CADADB5B5", "KF c #8C8CADADA5A5", "LF c #8C8C9C9CB5B5", "MF c #8C8C9C9CADAD", "NF c #8C8C8C8CA5A5", "OF c #8C8C52526363", "PF c #8C8C42425252", "AG c #8484B5B5CECE", "BG c #7B7BCECE9494", "CG c #7B7BC6C68484", "DG c #7B7BC6C67B7B", "EG c #7B7BADADC6C6", "FG c #7B7BADADADAD", "GG c #7B7B9C9CC6C6", "HG c #7B7B9C9CB5B5", "IG c #7B7B9C9CADAD", "JG c #7B7B84849C9C", "KG c #7B7B42425252", "LG c #737384848C8C", "MG c #737373738484", "NG c #737339395252", "OG c #6B6BC6C68484", "PG c #6B6BBDBD7B7B", "AH c #6B6BA5A5CECE", "BH c #6B6B9C9CBDBD", "CH c #6B6B9C9CA5A5", "DH c #6B6B94949C9C", "EH c #6B6B8C8CA5A5", "FH c #6B6B8C8C9C9C", "GH c #6B6B6B6B7B7B", "HH c #6B6B42425252", "IH c #6363BDBD6B6B", "JH c #6363B5B58C8C", "KH c #6363A5A58C8C", "LH c #63639C9CC6C6", "MH c #5A5AB5B56363", "NH c #5A5A9C9CBDBD", "OH c #5A5A8C8C9C9C", "PH c #5A5A7B7B8C8C", "AI c #5A5A6B6B8484", "BI c #5A5A63637B7B", "CI c #5252BDBD7373", "DI c #5252ADAD8484", "EI c #5252A5A57B7B", "FI c #4A4AB5B55A5A", "GI c #4A4A8C8CBDBD", "HI c #4A4A8C8CADAD", "II c #4A4A7B7B9C9C", "JI c #4A4A7B7B8484", "KI c #4A4A6B6B7B7B", "LI c #42429C9C7373", "MI c #42428C8C7B7B", "NI c #42425A5A7373", "OI c #42424A4A6B6B", "PI c #3939ADAD6B6B", "AJ c #3939ADAD5A5A", "BJ c #39399C9C6B6B", "CJ c #39398484BDBD", "DJ c #39397B7BADAD", "EJ c #39397B7B8C8C", "FJ c #393973737B7B", "GJ c #313163637B7B", "HJ c #31315A5A7B7B", "IJ c #292984846B6B", "JJ c #29296B6B7B7B", "KJ c #21217B7BB5B5", "LJ c #21217373A5A5", "MJ c #212173739C9C", "NJ c #21216B6B8C8C", "OJ c #212152527373", "PJ c #181884846363", "AK c #18186B6B7B7B", "BK c #18185A5A7373", "CK c #10106B6B9C9C", "DK c #10105A5A8484", "EK c #08087B7B6363", "FK c #08085A5A7B7B", "GK c #00006B6B9C9C", "HK c #000063637B7B", "IK c #00005A5A8C8C", /* pixels */ "CJAHAHAHAHHILHLHBHLHLJNHNHNHGINHGINHGINHGINHGINHGINHGINHGINHGIKJ", "AHAAAAAAAGHDABBBGCBFBFHCPCOCEEHDJDEEJDEEHDJDEEHDJDEEJDEEHDEEJDNH", "AHAAAGAAABABABKEOCHCHCPCFEFEABAEHDFCDDJDDDMCJDHDFCHDHDGCDDJDDDLH", "EGAEDDABOAABOCEGHCHCPCHCBHJDJDEEJDEEJDEEJDAEJDEEAEJDEEJDEEJDEELH", "AHAAAAAAMCJDGCABHCHCBFOCPCJDEEJDEEJDEEAEEEEEAEJDEEFEFEFEEEEEJDGI", "AHAAAAPAAGGCABBBMCEGJDNCPCPCEEEEEEEEEEEEEEJDEEEEFEDIPIGFFEFEEENH", "EGOAKEAAABPAABKEHCHCHCHCMEBFABJDAEMCOCEEMCMCFEOCDDLEKHIDIDEEDDLH", "LHAEMCAAABABAEIFHCHCHCPCBHOCKEKEEEFEEEFEEEFEEEKEBFGEDIKFMEFEEEGI", "AHAAAAABGCJDABGCBBOCHGHCPCMDEEFEKEEEFEKEFEKEEEMEBFJFDIGEIFBFFEGI", "AHAAAAPAAHGCABBBMCJFMDOCPCJDMEKEKEMEKEKEKEKEMEIFGEFGEIIGJFGEMEGI", "AHAAAEAAABABGCNBDBOCNCNCMDEEMCEEEEMCJDKEDDDDLFCIDIEIPICIDIDIJDNH", "AHKEDDAAPAABOCKFPBICNCPCHGFEMEMEMEMEHFMEMEIFJFJELCCDCGBBCDLIIGHI", "EGAAAAABABJDMBNCPBADGENCMDMDMEHFIFHFMEHFIFMECHJEPCLDBGGDGDLIIGDJ", "AHAAAAAAAHEDKAOBEBBDCEODICMDIFIFMEIFIFIFIFIFCHEFLDPDOGGDPDMIFHHI", "AHAAOCABMBEABABAFABABAGBNELEHDKEHFDDEEIFJDEEFGCGLDPDPGPDPDAJMFHI", "AHDDEGABBBEABACAFABACBGBFHGEIFGGIFGGIFIFGGIFDHCGJEMHFIAFAFBJDHII", "AHAAAAABMBEAHAEAEADACABDODBEHGIFGGIFHGGGIFHGCHJHAFAFEFAFFFFJDHMJ", "AHAAAAAABEIADADAKACADAGBODNEGGHGIEIENFGGHGGGOHDGFFFFFFFFFFAJOHHI", "AHAAABABPCGAKADADAKADAFDODMFHIHIAIPFIIIIHIHIEJCIFFDGFFDGDGJJFJCK", "AHAAAHHCMBGAEAEAEAFAFAJCLGFKPEPEPEKDPEPEOIIKHKLIDGDGPGDGIHEKIKGK", "EGFCDDAANCJAIAIAIAIAIANDBKOJJBLALALBLAMANGFKHKFIMHPGMHFILIEKFKGK", "LHAAAABBNCFBJAJAJAEBGBDFBKOJBCNADCDCIBHBNGBKAKFIMHMHMHMHMHEKHKGK", "AHAAAAABADEBJCEBGBACACHEBKNIBCJBJBHBJBJBHHOJJJPIIHPGIHIHIHPJDKGK", "AHAAOCJDNCEBOBACOBOBOBHEEJNIKCLBKBBCKBCCKGHJJJMHDGIHPGDGIHEKEJCK", "AHAAKEABMBEBDBDBOBOBOBHENIAIKCDCDCDCDCECKGKIGJCIDGFFLGDGDGPJNJMJ", "CJAAOAABBBIADBHADBHAKAHEAIBIDCDCBCCCDCCCPFKIJIPGBGCFDGFFDGIJIIMJ", "AHAAAAABMBIABADBBAHAHAHEAIGHKCJBBCKBKBBCKGPHJIPGFFGFFFFFFFIJJILJ", "AHAAAAABMDFDFDBDFDNDBDHEFHJGDEDEDEDEOEDEOFPHMGBJBJAJBJBJBJMIOHDJ", "EGAAAAJDHGNFFHMGFHJGMGEHJGNFNFMGMGMGMGMGLGJGCHEHFHPHMGOHPHFHIGDJ", "LHAAOCIFIFIFLFLFMFMFJFLFIFJFHGIGMFIGNFMFMFLFIFLFHGIGFGIGIGHGJFCJ", "EGDDKEKEMEBFBFBFBFMEBFBFFEKEMEMEMEGEBFMEBFBFBFKEMEBFMEBFBFKEKEGI", "KJLHGINHGINHNHNHNHGINHNHGINHGINHNHGIGINHGINHNHGINHNHGIGINHNHGICJ"}; rlplot/RLPLOT.ICO0000755000076400007640000001027610741722217012232 0ustar c71960c71960 ¨( @ ¸†9¿’R¿’R¿’R¿’R¿’R¿’R¾’R¾’R¾’R¾’R¿’R¿’R¿’R¿’R¿’R¾’R¾’R¾’R¾’R¿’R¿’R¿’R¿’R¿’R¾’R¾’Q¾’Q¾’R¿’R¿’R¶‚3̧oìßÔÖ¸ŸÖ¸ŸÕ¸ŸÓ·žÐ¶ÎµÍµÍµÎµÏµÒ¶žÒ¶žÏ´žÌ²žÊ±È¯È¯Ê±Í³ÐµžÒ¶žÑµœÏ´šÍ´™Í´˜Í´˜Î´™Ðµ›Ó·¼ŒJ̧oþþþèØÊϬŒÊªŒÀ§Œµ¤‹°¢‰®¡ˆ®¡ˆ°¢‰µ£Š½¥Œ¾¤Œ¶žŒ«—Š¥’ˆ£ˆ£‘ˆ¦“‰­˜‰¹ ‰¿¤‰º¢„³ ®ž|¬z­{°ž|·¢€Â§†µ†@̧oþþþúûûàÑÀ½ž|©˜z™v‘ŒrŠpŠq’Œr˜Žv£’z§‘{š‡z‹zvƒtsrr‚sr„utŽ|užŠw¨’v n–Še‡`…^†^‘ˆa›f­—q­8̧oþþþúûûðõöÇôIÏÍMÌËKÊÈKÈÇKÉÇKÉÉ]¨‘‚kŒzuRM¶SOµQN³PM²QM³PM³eZ†‹yf†_lŸ:lŸ=kž<j;j;iž:y‹B‰_¦z0Ë¥lþþþúúúïôôÐåèRðýŒîúŒîúŒîúŒîúŒîúF·³…v[~lnO]âg‚èg‚èg‚èg‚èazçUKŽnXƒ}N{¿jŽÈŽÈŽÈŽÈˆÅ„j‹/”N u(ºˆ;ýüûúúúîôôÏäçIêú}äõ}äõ}äõ}äõ}äõD´®oOzfcGTàZsåZsåZsåZsåUläTGˆ}iL€xDu¼d†Ä„†Ä„†Ä„†Ä„Â|i‡(yBžr"̧oüûúØ¿—íôôÏäçBæöpÜïpÜïpÜïpÜïpÜïB±¨iCyaY?JÞQjäSkäRkäMdãI^âSE{cB}s9pº\ÀzÀzÀzÀz{¾rg„!s4œņoþþþåÖ¾ØÍ³Ïäç:àòaÑçaÑçaÑçaÑçaÑç@¯¢|d6v\MGTáfèfèfèeè]tæQB{x^4{n-j·Tv¼ov¼ov¼ov¼or»heŠm#šļoþþþúúúíôôÅ̽2ÛïOÍä9ÜïMÏåSÉáSÉá?¬œ{_'tX@Ziäz–ìz–ìz–ìz–ìrëP@uwZ'yj d´Mn¸en¸en¸en¸ek·_d~ˆh™iʤjþþþúúúíôôÊØÒ)Úî1ëû*ñÿ.îý@×ëCÏå=ª–y\tW3huç’«ðYdäWaã•술îP?pwYyh_²EgµZgµZgµZgµZe´Ud| …d ˜ḩoõïåèÛÅíôôÏäç)ðþDñÿDñÿDñÿDñÿDñÿ@¼´y\ xV!w„é¬ÄôŸ¶òsè¬ÄôŸ¶òTAk~Z {gZ¯<l¸`qºhk·_`²N^±Hczƒa—f̧oýüûÌ©räâØÏäç4òÿXòÿXòÿXòÿXòÿXòÿGÎÙŠu[VJš\UTO£C>¸VQWPjLGŠ_€gfµM{¾u{¾u{¾uy½rr»gby^–ḑoþþþúúúíôôÇÑÇ>òÿióÿióÿióÿióÿióÿIÏÙ•°µ¤™}©‚I¤JqXbQŠqJ™xJ¥I©H’‚>t»a„€„€„€„€Àxh‡$y<r ̧oþþþúúúíôôÁŰGóÿyôÿyôÿyôÿyôÿyôÿIÐÙ˜³¶±¯¤Àž~ž~k¦zg§ ˆŒºš~ž|¾{Ÿ—gz¿jȌȌȌȌ‡Åƒl‘;™f£|6̧oýýüúúúîôôÐåçOôÿˆöÿYôÿRôÿzöÿˆöÿJÑÚ™¶¸³²§Å¢‚ɤ‚Ç£‚Ä¡‚Ä¡‚È£‚ɤ¡€¡šiÃq–Í—–Í—–Í—–Í—Êm‘<ši£}8̧oè×¾Òµ†ïôõÔçéWõÿ–÷ÿ‡÷ÿAôÿ’÷ÿ–÷ÿMÔÝ‘Žg¸´§È¦†Ì§…ͧ…̧…̧…ͧ…̧…Ĥ‚£kˆÆz Ò£r»Ufµ>˜Î–˜Î˜m’=›l¤~9̧oþþþèÛÇñôôÝêìXõÿ˜÷ÿ˜÷ÿKôÿ˜÷ÿ˜÷ÿSÙ⤯µ—áÐÀÔ´—Ó²”åÒÀÛÁ¨Îª‰àË·ØÈ´¤Ÿnʃª×¯¡Ó£€Âjª×¯¡Ó£m“?§©‹¬ŽO̧oþþþûûûö÷÷À£lsÒÆtæíjßç1æñ^ËÉX¯”ŒÓ×½ËÊȾ±Ï¬ŽÐ­ŽÐ­ŽÐ­ŽÐ­ŽÐ­ŽÏ­ŽÈªŠ¥¢q—ÎŒ¶Ý½¬Ø°†År¶Ý½¬Ø°o•@•q¦=̧oþþþûûú÷ø÷ðñðÙÒÁÕäåÂÚÜWáê±Íϳ»¬ÅÑÐËÐÎÎÁ´Ñ¯’ѯ’ѯ’ѯ’ѯ’ѯ’ѯ’Ê­Ž©¤uŸÒ”ÁâȶݺŒÈxÁâȶݺq˜C¢™w¨‚?̧oÜÜîäÔ÷ø÷ôôôíïïØÖʧ²TæïºÕÖÈÕÔÏÔÒ»jν¬Ò±–Ò±–Ò±–Ò±–Ò±–Ò±–Ò±–ί“¯©{§ÖœÌèÒÀâÓÌ~ÌèÒÀâÃvH¬ €®…B̧oýüûâϲ÷ø÷ôôóïðïèëê¡æé’ãæ¿ÜÝÒØÖÓÖÓÎɽ×Å­ìÞÓÚ¿¨Ù¼¥ìÞÓâ̺Դšè×ÊæÙ˾¯‡³T‚µ]{²Ug­8~²Y}²Y¥bÌdz¾š]̧oþþþûûúöõòȤlìéâëìëåçæÞãáê€ÏǵÖ×ÕÑÒÏÒŹննննննննѵšÉ±•¿­©¨€¤Q«£…·©‹Ã¯“ͳ˜º‹Ḩoþþþûûú÷ø÷êãÖàѺììëèèçãäâÝÛÖÆ¬ƒ××ÕÑÒÏÒÆºÖ¹¡Ö¹¡Ö¹¡Ö¹¡Ö¹¡Ö¹¡Ö¹¡Ö¹¡Ö¹ Ô¸ŸÍµš¶®Š…©W¸«Å±–жո ½ĶoÜÄžñéÞ÷ø÷ôôóððïÜ͵̰„ãäâÞßÝÚÛÙÖÖÓ¾¢tÓǺؼ¤Ø¼¤Ø¼¤Ø¼¤Ø¼¤Ø¼¤Ø¼¤Ø¼¤Ø¼¤Ö»£Ñ¹Ÿ¸±Ž†ªX¹­’Ç´šÓº¡Ø¼¤¾ŽM̧oú÷󨾕÷ø÷ôôóððïììëÖÃ¥ßÜÓÞßÝÚÛÙ××ÕÉ»£ÕÁ¤îâÙÞǵÜűîâÙåÓÄØ¾¨ëÝÒìßÕØ¾¨âÏ¿äÝн»›‰°aÈͺÒɶԼ¥êÛÏÇ ȩoþþþûûú÷÷öή}íëçììëèèæãäâÅ©zÔ̾××ÕÑÒÏÔÉ¿ÚÀ«ÚÀ«ÚÀ«ÚÀ«ÚÀ«ÚÀ«ÚÀ«ÚÀ«ÚÀ«Ø¿©Ó½¦ƒ¯Vk«;µ³Íº¢Ö¾§ÚÀ«¿P̧oþþþûûú÷ø÷ëåÚàÒ»ììëèèæãäâÜÛÕ̹›××ÕÑÒÏÔÊÀÚ®Ú®Ú®Ú®Ú®Ú®Ú®Ú®Ú®Ú­ØÁ«Ó¿©Î¼¥Ð½¦ÕÀªÚÁ­Ú®¿‘Ŗoá̬êÝÉ÷ø÷ôôóððïáÖÄË®€ããáÞßÝÚÛÙÖÕÓ¼kÓȼÛıÛıÛıÛıÛıÛıÛıÛıÛıÛıÛİÛïٮٯÛïÛİÛı¿’Şoüûúؽ”÷ø÷ôôóððïììëׯªÛÓÄÞßÝÚÛÙ××ÕËÀ¬×ŪðæÝâνà̺ðæÝèØÊÜÆ²íâ×ïãÙÜÆ²æÖÈðæÝâνà̺ðæÝèÙÌÜÆ²íàÕÈ¢ḩoþþþûûú÷ø÷Ñ´‡ã×ÃììëèèæãäâÌ·”Ë·˜××ÕÑÒÏÕÌÂÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´ÝÇ´À”U¶‚0̧oʦmÉ¥lÆ f¶„6Å hßfÁd¿›b®w »—^¹–]»“W¾P¾P¾P¾P¾P¾P¾P¾P¾P¾P¾P¾P¾P¾P¾P¾P¾P²z&rlplot/PropertyDlg.cpp0000755000076400007640000142454210756052134013647 0ustar c71960c71960//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 #include #include #include #include #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<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<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 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;iSetColor(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<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<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 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 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; } rlplot/Version.h0000755000076400007640000000151411006641345012450 0ustar c71960c71960//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 // #define SZ_VERSION "1.5" rlplot/QT3_Spec.h0000755000076400007640000002027310771207761012417 0ustar c71960c71960//QT_Spec.h, 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 // #include "rlplot.h" #include "menu.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "TheDialog.h" #define RLP_PORT 4321 //enable clipboard server #ifdef RLP_PORT #include #include #include #include #include #include #include #endif bool ProcMenuEvent(int id, QWidget *parent, anyOutput *OutputClass, GraphObj *BaseObj); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class TxtCurBlink:public QObject { Q_OBJECT public: TxtCurBlink(); void Show(); // void showCopyMark(); protected: void timerEvent(QTimerEvent *); private: bool isVis; int count; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // use sockets for to exchange clipboard data // undefine RLP_PORT to limit clipboard to a single instance 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(); char *GetTXT() {return text_plain; }; bool ok() {return true;}; #ifdef RLP_PORT int Socket() {return sock;}; #endif private: char *text_xml, *text_rlp, *text_plain; #ifdef RLP_PORT pthread_t thread; pthread_attr_t thread_attr; int sock; #endif }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class RLPmenu:public QMenuBar { Q_OBJECT public: RLPmenu(QWidget *par, anyOutput *o, GraphObj *g); public slots: void doMenuItem(int id); private: anyOutput *OutputClass; QWidget *parent; GraphObj *BaseObj; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // The Qt widget class implementet for RLPlot class RLPwidget:public QWidget { Q_OBJECT public: QScrollBar *HScroll, *VScroll; QPixmap *mempic; QMenuBar *menu_bar; RLPwidget(QWidget *par=0, const char *name=0, anyOutput *o = 0, GraphObj *g = 0); ~RLPwidget(); void openHistoryFile(int idx); public slots: void hScrollEvent(int pos); void vScrollEvent(int pos); void cmNOP(){;}; void cmCopy(){ProcMenuEvent(CM_COPY, this, OutputClass, BaseObj);}; void cmCut(){ProcMenuEvent(CM_CUT, this, OutputClass, BaseObj);}; void cmZoomIn(){ProcMenuEvent(CM_ZOOMIN, this, OutputClass, BaseObj);}; void cmZoomOut(){ProcMenuEvent(CM_ZOOMOUT, this, OutputClass, BaseObj);}; 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 *); void resizeEvent(QResizeEvent *); void closeEvent(QCloseEvent *); void mouseDoubleClickEvent(QMouseEvent *e); void mousePressEvent(QMouseEvent *e); void mouseReleaseEvent(QMouseEvent *e); void mouseMoveEvent(QMouseEvent *e); void keyPressEvent(QKeyEvent *e); void focusInEvent(QFocusEvent *e); private: QWidget *parent; anyOutput *OutputClass; GraphObj *BaseObj; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class DlgWidget:public QWidget { Q_OBJECT public: QPixmap *mempic; anyOutput *OutputClass; DlgWidget(QWidget *par=0, const char *name=0, tag_DlgObj *d = 0, DWORD flags = 0L); ~DlgWidget(); protected: void paintEvent(QPaintEvent *); void mouseDoubleClickEvent(QMouseEvent *e); void mousePressEvent(QMouseEvent *e); void mouseReleaseEvent(QMouseEvent *e); void mouseMoveEvent(QMouseEvent *e); void keyPressEvent(QKeyEvent *e); void focusInEvent(QFocusEvent *e); void focusOutEvent(QFocusEvent *e); void closeEvent(QCloseEvent *e); void timerEvent(QTimerEvent *); private: QWidget *parent; tag_DlgObj *dlg; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class BitMapQT:public anyOutput { public: QWidget *widget; QWidget *dlgwidget; HatchOut *hgo; QPixmap *mempic; QImage *image; QPen qPen; QPainter qPainter; QFont qFont; void *ShowObj; //eph_obj* void *ShowAnimated; //copy mark BitMapQT(GraphObj *g, QWidget *wi, int vr = 98, int hr = 98); BitMapQT(int w, int h, double hr, double vr); ~BitMapQT(); bool SetLine(LineDEF *lDef); bool SetFill(FillDEF *fill); bool SetTextSpec(TextDEF *set); virtual bool Erase(DWORD Color); virtual bool StartPage() {return true;}; bool CopyBitmap(int x, int y, anyOutput* src, int sx, int sy, int sw, int sh, bool invert); bool oGetTextExtent(char *text, int cb, int *width, int *height); bool oGetTextExtentW(w_char *text, int cb, int *width, int *height); bool oGetPix(int x, int y, DWORD *col); bool oDrawIcon(int type, int x, int y); bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L); bool oPolyline(POINT * pts, int cp, char *nam = 0L); bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L); bool oSolidLine(POINT *p); bool oTextOut(int x, int y, char *txt, int cb); bool oTextOutW(int x, int y, w_char *txt, int cb); bool oPolygon(POINT *pts, int cp, char *nam = 0L); }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class OutputQT:public BitMapQT { public: QScrollBar *HScroll, *VScroll; RLPmenu *menu; OutputQT(GraphObj *g); OutputQT(DlgWidget *wi); ~OutputQT(); bool ActualSize(RECT *rc); void Focus(){if(widget){widget->show(); widget->raise();}}; 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(); void CreateNewWindow(GraphObj *g); private: GraphObj *BaseObj; }; class PrintQT:public anyOutput{ public: HatchOut *hgo; QPrinter *printer; PrintQT(GraphObj *g, char *file); ~PrintQT(); bool ActualSize(RECT *rc); bool SetLine(LineDEF *lDef); bool SetFill(FillDEF *fill); bool SetTextSpec(TextDEF *set); bool StartPage(); bool EndPage(); bool Eject(); bool oGetTextExtent(char *text, int cb, int *width, int *height); bool oGetTextExtentW(w_char *text, int cb, int *width, int *height); bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L); bool oPolyline(POINT * pts, int cp, char *nam = 0L); bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L); bool oSolidLine(POINT *p); bool oTextOut(int x, int y, char *txt, int cb); bool oTextOutW(int x, int y, w_char *txt, int cb); bool oPolygon(POINT *pts, int cp, char *nam = 0L); private: QPen qPen; QFont qFont; QPainter qPainter; QWMatrix dxf; char *fileName; GraphObj *go; bool bPrinting; }; rlplot/PlotObs.cpp0000755000076400007640000055254710770264250012764 0ustar c71960c71960//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 #include #include #include 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=\"Chi2 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 2 ="); 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; }