//ODbuttons.cpp, Copyright (c) 2001-2008 R.Lackner
//Property dialogs for graphic objects
//
//    This file is part of RLPlot.
//
//    RLPlot is free software; you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation; either version 2 of the License, or
//    (at your option) any later version.
//
//    RLPlot is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with RLPlot; if not, write to the Free Software
//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// Tis module contains the different graphic buttons for dialogs
#include "rlplot.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "TheDialog.h"

extern int ODtickstyle;
extern int AxisTempl3D;
extern Default defs;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// utility draw base rectangle for OD-button
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static void OD_BaseRect(anyOutput *o, int cmd, RECT *rec)
{
	LineDEF Line = {0.0, 1.0, 0x0L, 0x0L};
	FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
	POINT pts[5];

	Line.color = cmd == OD_DRAWSELECTED ? 0x00000000L : 0x00e8e8e8L;
	Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00e8e8e8L;
	o->SetLine(&Line);
	pts[0].x = pts[3].x = pts[4].x = rec->left;
	pts[0].y = pts[1].y = pts[4].y = rec->top;
	pts[1].x = pts[2].x = rec->right-1;
	pts[2].y = pts[3].y = rec->bottom-1;
	o->oPolyline(pts, 5);				Line.color = 0x00000000L;
	o->SetLine(&Line);				o->SetFill(&Fill);
	o->oRectangle(rec->left+3, rec->top+3, rec->right-3, rec->bottom-3);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Common code to modify drawing order in any dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Exceute drawing order buttons as owner drwn buttons
void OD_DrawOrder(int cmd, void *par, RECT *rec, anyOutput *o,
		void *data, int id)
{
	LineDEF Line = {.0f, 1.0f, 0x0L, 0x0L};
	FillDEF Fill = {FILL_NONE, 0x0080ffffL, 1.0, 0L};
	POINT pts[5];
	RECT hrc;
	int i, j, x, y;

	Fill.color = 0x0080ffffL;
	switch(cmd) {
	case OD_MBTRACK:
		if(!data) return;
		x = ((MouseEvent*)data)->x;		y = ((MouseEvent*)data)->y;
		memcpy(&hrc, rec, sizeof(RECT));
		IncrementMinMaxRect(&hrc, -6);
		if(IsInRect(&hrc, x, y)) Fill.color = 0x00e0ffffL;
	case OD_DRAWNORMAL:
	case OD_DRAWSELECTED:
		pts[0].x = rec->left+10;	pts[0].y = rec->bottom-3;
		pts[1].x = rec->right-9;	pts[1].y = rec->bottom-3;
		pts[2].x = rec->right-3;	pts[2].y = rec->bottom-9;
		pts[3].x = rec->left+16;	pts[3].y = rec->bottom-9;
		pts[4].x = pts[0].x;		pts[4].y = pts[0].y;
		o->SetLine(&Line);			o->SetFill(&Fill);
		for(i = 0; i < 5; i++){
			o->oPolygon(pts, 5);
			for(j = 0; j < 5; j++) {
				pts[j].y -=4;
				}
			}
		pts[0].x = pts[1].x = pts[3].x = rec->left+4;
		pts[2].x = rec->left+1;		pts[4].x = rec->left+7;
		switch (id) {
		case 600:
			pts[0].y = pts[3].y = rec->top+6;			pts[1].y = rec->bottom-3;
			pts[2].y = pts[4].y = rec->top+9;
			break;
		case 601:
			pts[0].y = pts[3].y = rec->top+12;			pts[1].y = rec->bottom-9;
			pts[2].y = pts[4].y = rec->top+15;
			break;
		case 602:
			pts[0].y = pts[3].y = rec->bottom-9;		pts[1].y = rec->top+12;
			pts[2].y = pts[4].y = rec->bottom-12;
			break;
		case 603:
			pts[0].y = pts[3].y = rec->bottom-3;		pts[1].y = rec->top+6;
			pts[2].y = pts[4].y = rec->bottom-6;
			break;
			}
		Fill.color = 0x0fL;								o->SetFill(&Fill);
		o->oPolyline(pts, 2);							o->oPolygon(pts+2, 3);
		o->UpdateRect(rec, false);
		break;
		}
}

int ExecDrawOrderButt(GraphObj *parent, GraphObj *obj, int id)
{
	switch(id){
	case 600:
		parent->Command(CMD_MOVE_TOP, obj, 0L);
		return -1;
	case 601:
		parent->Command(CMD_MOVE_UP, obj, 0L);
		return -1;
	case 602:
		parent->Command(CMD_MOVE_DOWN, obj, 0L);
		return -1;
	case 603:
		parent->Command(CMD_MOVE_BOTTOM, obj, 0L);
		return -1;
		}
	return id;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Execute polygon style as owner drawn buttons
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void OD_PolygonStyleTempl(int cmd, void *par, RECT *rec, anyOutput *o,
		void *data, int id)
{
	FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
	POINT *pts;
	int ix= (rec->left + rec->right)>>1, iy = (rec->top +rec->bottom)>>1, np;
	long cp;
	POINT tmppts[] = {{rec->left+15, iy}, {rec->left+15, iy-5}, {ix-5, rec->top+14},
		{ix, rec->top+15}, {ix+10, rec->top+17}, {rec->right-7, rec->bottom-22},
		{rec->right-15, rec->bottom-15}, {rec->right-23, rec->bottom-8},
		{rec->left+15, iy+5}, {rec->left+15, iy}};
	

	if(!(pts=(POINT*)malloc(2*sizeof(POINT)*(rec->right-rec->left)))) return;
	switch(cmd) {
	case OD_DRAWNORMAL:
	case OD_DRAWSELECTED:
		OD_BaseRect(o, cmd, rec);
		if(cmd == OD_DRAWSELECTED){
			Fill.color = 0x0000ffffL;		o->SetFill(&Fill);
			}

		np = 0;
		switch(id) {
		case 201:
			pts[np].x = rec->left+15;		pts[np++].y = iy;
			pts[np].x = ix;				pts[np++].y = rec->top+15;
			pts[np].x = rec->right-15;		pts[np++].y = rec->bottom-15;
			break;
		case 202:
			pts[np].x = rec->left+15;		pts[np++].y = iy;
			pts[np].x = ix;				pts[np++].y = iy;
			pts[np].x = ix;				pts[np++].y = rec->top+15;
			pts[np].x = rec->right-15;		pts[np++].y = rec->top+15;
			pts[np].x = rec->right-15;		pts[np++].y = rec->bottom-15;
			pts[np].x = rec->left+15;		pts[np++].y = rec->bottom-15;
			break;
		case 203:
			pts[np].x = rec->left+15;		pts[np++].y = iy;
			pts[np].x = rec->left+15;		pts[np++].y = rec->top+15;
			pts[np].x = ix;				pts[np++].y = rec->top+15;
			pts[np].x = ix;				pts[np++].y = rec->bottom-15;
			pts[np].x = rec->right-15;		pts[np++].y = rec->bottom-15;
			pts[np].x = rec->right-15;		pts[np++].y = iy;
			break;
		case 213:
			cp = 0;
			DrawBezier(&cp, pts, tmppts[0], tmppts[1], tmppts[2], tmppts[3], 0);
			DrawBezier(&cp, pts, tmppts[3], tmppts[4], tmppts[5], tmppts[6], 0);
			DrawBezier(&cp, pts, tmppts[6], tmppts[7], tmppts[8], tmppts[9], 0);
			np = (int)cp;
			break;
			}
		if(np) o->oPolygon(pts, np);
		switch(id) {
		case 201:	case 202:	case 203:	case 213:
			Fill.color = (cmd == OD_DRAWSELECTED) ? 0x000000ffL : 0x00ffffffL;
			o->SetFill(&Fill);
			o->oCircle(ix-2, rec->top+13, ix+3, rec->top+18);
			o->oCircle(rec->left+13, iy-2, rec->left+18, iy+3);
			o->oCircle(rec->right-14, rec->bottom-14, rec->right-17, rec->bottom-17);
			break;
			}
		o->UpdateRect(rec, false);
		free(pts);
		break;
		}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Execute line style as owner drawn buttons
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void OD_LineStyleTempl(int cmd, void *par, RECT *rec, anyOutput *o,
		void *data, int id)
{
	LineDEF Line = {0.0, 1.0, 0x0L, 0x0L};
	FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
	POINT *pts;
	int i, ix, iy, np;

	if(!(pts=(POINT*)malloc(2*sizeof(POINT)*(rec->right-rec->left)))) return;
	switch(cmd) {
	case OD_DRAWNORMAL:
	case OD_DRAWSELECTED:
		Line.color = cmd == OD_DRAWSELECTED ? 0x00000000L : 0x00e8e8e8L;
		Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00e8e8e8L;
		ix = (rec->left + rec->right)/2;
		iy = (rec->top +rec->bottom)/2;
		o->SetLine(&Line);
		pts[0].x = pts[3].x = pts[4].x = rec->left;
		pts[0].y = pts[1].y = pts[4].y = rec->top;
		pts[1].x = pts[2].x = rec->right-1;
		pts[2].y = pts[3].y = rec->bottom-1;
		o->oPolyline(pts, 5);				Line.color = 0x00000000L;
		o->SetLine(&Line);					o->SetFill(&Fill);
		o->oRectangle(rec->left+3, rec->top+3, rec->right-3, rec->bottom-3);
		if(cmd == OD_DRAWSELECTED){
			Fill.color = 0x000000ffL;		o->SetFill(&Fill);
			}
		np = 0;
		switch(id) {
		case 201:
			pts[np].x = rec->left+15;		pts[np++].y = rec->bottom-15;
			pts[np].x = rec->right-15;		pts[np++].y = rec->top+15;
			break;
		case 206:
			pts[np].x = rec->left+15;		pts[np++].y = rec->bottom-10;
		case 202:
			pts[np].x = rec->left+15;		pts[np++].y = rec->bottom-15;
			pts[np].x = ix;					pts[np++].y = pts[np-1].y;
			pts[np].x = ix;					pts[np++].y = iy;
			pts[np].x = rec->right-15;		pts[np++].y = iy;
			pts[np].x = pts[np-1].x;		pts[np++].y = rec->top+15;
			if(id == 206){
				pts[np].x = rec->right-8;	pts[np++].y = rec->top+15;
				}
			break;
		case 207:
			pts[np].x = rec->left+8;		pts[np++].y = rec->bottom-15;
		case 203:
			pts[np].x = rec->left+15;		pts[np++].y = rec->bottom-15;
			pts[np].x = pts[np-1].x;		pts[np++].y = iy;
			pts[np].x = ix;					pts[np++].y = iy;
			pts[np].x = ix;					pts[np++].y = rec->top+15;
			pts[np].x = rec->right-15;		pts[np++].y = pts[np-1].y;
			if(id == 207){
				pts[np].x = rec->right-15;	pts[np++].y = rec->top+7;
				}
			break;
		case 208:
			pts[np].x = rec->left+8;		pts[np++].y = rec->bottom-15;
		case 204:
			pts[np].x = rec->left+15;		pts[np++].y = rec->bottom-15;
			pts[np].x = (pts[np-1].x + ix)>>1;	pts[np++].y = pts[np-1].y;
			pts[np].x = pts[np-1].x;		pts[np++].y = iy;
			pts[np].x = (rec->right-15 + ix)>>1;	pts[np++].y = iy;
			pts[np].x = pts[np-1].x;		pts[np++].y = rec->top+15;
			pts[np].x = rec->right-15;		pts[np++].y = pts[np-1].y;
			if(id == 208) pts[np-1].x += 6;
			break;
		case 209:
			pts[np].x = rec->left+15;		pts[np++].y = rec->bottom-10;
		case 205:
			pts[np].x = rec->left+15;		pts[np++].y = rec->bottom-15;
			pts[np].x = pts[0].x;			pts[np++].y = (pts[np-1].y +iy)>>1;
			pts[np].x = ix;					pts[np++].y = pts[np-1].y;
			pts[np].x = ix;					pts[np++].y = (iy + rec->top+15)>>1;
			pts[np].x = rec->right-15;		pts[np++].y = pts[np-1].y;
			pts[np].x = pts[np-1].x;		pts[np++].y = rec->top+15;
			if(id == 209) pts[np-1].y -= 7;
			break;
		case 210:
			pts[0].x = rec->left +9;	pts[0].y = iy+4;	pts[1].x = pts[0].x+1;
			for(i = 0; i < (rec->right - rec->left - 18); i++) {
				pts[1].y = 4 + iy + iround(pow(20.0, 1.0+((double)-i)/30.0) * -sin(((double)i)/4.0));
				o->oSolidLine(pts);
				pts[0].x++;		pts[1].x++;		pts[0].y = pts[1].y;	
				}
			o->oCircle(rec->left+7, iy+4, rec->left+12, iy +9);
			o->oCircle(rec->left+12, iy-10, rec->left+17, iy -5);
			o->oCircle(rec->right-19, iy+5, rec->right-24, iy +10);
			o->oCircle(rec->right-9, iy, rec->right-14, iy+5);
			break;
		case 211:
			pts[0].y = rec->top +9;	pts[0].x = ix;	pts[1].y = pts[0].y+1;
			for(i = 0; i < (rec->bottom - rec->top - 18); i++) {
				pts[1].x = ix + iround(pow(20.0, 1.0+((double)-i)/50.0) * -sin(((double)i)/4.0));
				o->oSolidLine(pts);
				pts[0].y++;		pts[1].y++;		pts[0].x = pts[1].x;	
				}
			o->oCircle(ix-3, rec->top + 9, ix+2, rec->top + 14);
			o->oCircle(rec->left+11, iy-10, rec->left+16, iy -5);
			o->oCircle(ix+3, rec->top + 27, ix+8, rec->top + 32);
			o->oCircle(ix-5, iy+12, ix, iy + 17);
			break;
		case 212:
			for(i = 2; i < (rec->bottom - rec->top - 18); i++) {
				pts[1].x = ix + iround(pow(20.0, 1.0+((double)-i)/50.0) * -sin(((double)i)/4.0));
				pts[1].y = iy + iround(pow(20.0, 1.0+((double)-i)/50.0) * -cos(((double)i)/4.0));
				if(i>2)o->oSolidLine(pts);
				pts[0].y = pts[1].y;		pts[0].x = pts[1].x;	
				}
			o->oCircle(ix-5, iy-4, ix, iy+1);			o->oCircle(ix-10, iy-17, ix-5, iy-12);
#ifdef _WINDOWS
			o->oCircle(ix-12, iy+9, ix-7, iy+4);		o->oCircle(ix+9, iy+7, ix+4, iy+2);
#else
			o->oCircle(ix-12, iy+9, ix-7, iy+4);		o->oCircle(ix+8, iy+6, ix+4, iy+2);
#endif
			break;
			}
		if(np) o->oPolyline(pts, np);
		switch(id) {
		case 201:	case 202:	case 203:	case 204:	case 205:
		case 206:	case 207:	case 208:	case 209:
			o->oCircle(ix-2, iy-2, ix+3, iy+3);
#ifdef _WINDOWS
			o->oCircle(rec->left+13, rec->bottom-13, rec->left+18, rec->bottom-18);
			o->oCircle(rec->right-13, rec->top+13, rec->right-18, rec->top+18);
#else
			o->oCircle(rec->left+13, rec->bottom-14, rec->left+18, rec->bottom-18);
			o->oCircle(rec->right-14, rec->top+13, rec->right-18, rec->top+18);
#endif
			break;
		case 210:	case 211:	case 212:
			break;
			}
		o->UpdateRect(rec, false);
		free(pts);
		break;
		}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Execute bubble style as owner drawn buttons
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void OD_BubbleTempl(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id)
{
	FillDEF Fill = {FILL_NONE, 0x00c0ffffL, 1.0, 0L};
	POINT pts[3];
	int ix, iy;

	switch(cmd) {
	case OD_DRAWNORMAL:
	case OD_DRAWSELECTED:
		ix = (rec->left + rec->right)/2;
		iy = (rec->top +rec->bottom)/2;
		pts[0].x = ix-10;	pts[2].x = ix+10;	pts[1].x = ix;
		OD_BaseRect(o, cmd, rec);
		if(cmd == OD_DRAWSELECTED) o->SetFill(&Fill);
		switch(id) {
		case 109:	case 201:
			o->oCircle(ix-10, iy-10, ix+10, iy+10);
			break;
		case 110:	case 202:
			o->oRectangle(ix-10, iy-10, ix+10, iy+10);
			break;
		case 111:	case 203:
			pts[0].y = pts[2].y = iy + 9;		pts[1].y = iy - 11;
			o->oPolygon(pts, 3);
			break;
		case 112:	case 204:
			pts[0].y = pts[2].y = iy - 9;		pts[1].y = iy + 11;
			o->oPolygon(pts, 3);
			break;
			}
		o->UpdateRect(rec, false);
		}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Execute error bar style as owner drawn buttons for the error bar dialog
// and in the scatterplot dialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void OD_ErrBarTempl(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id)
{
	POINT pts[6];
	int ix, iy;

	switch(cmd) {
	case OD_DRAWNORMAL:
	case OD_DRAWSELECTED:
		ix = (rec->left + rec->right)/2;
		iy = (rec->top +rec->bottom)/2;
		OD_BaseRect(o, cmd, rec);
		switch(id) {
		case 500:
			pts[2].x = pts[3].x = ix;
			pts[0].x = pts[4].x = ix-5;			pts[1].x = pts[5].x = ix+5;
			pts[0].y = pts[1].y = pts[2].y = rec->top +8;
			pts[3].y = pts[4].y = pts[5].y = rec->bottom -8;
			o->oSolidLine(pts);		o->oSolidLine(pts+2);		o->oSolidLine(pts+4);
			break;
		case 501:
		case 502:
			pts[2].x = pts[3].x = ix;	pts[0].x = ix-5;	pts[1].x = ix+5;
			pts[0].y = pts[1].y = pts[2].y = (id == 502 ? rec->bottom -8 : rec->top +8);
			pts[3].y = iy;
			o->oSolidLine(pts);			o->oSolidLine(pts+2);
			break;
		case 503:
			pts[2].y = pts[3].y = iy;
			pts[0].y = pts[4].y = iy-5;			pts[1].y = pts[5].y = iy+5;
			pts[0].x = pts[1].x = pts[2].x = rec->left +8;
			pts[3].x = pts[4].x = pts[5].x = rec->right -8;
			o->oSolidLine(pts);		o->oSolidLine(pts+2);		o->oSolidLine(pts+4);
			break;
		case 504:
		case 505:
			pts[2].y = pts[3].y = iy;	pts[0].y = iy-5;	pts[1].y = iy+5;
			pts[0].x = pts[1].x = pts[2].x = (id == 505 ? rec->right -8 : rec->left +8);
			pts[3].x = ix;
			o->oSolidLine(pts);			o->oSolidLine(pts+2);
			break;
			}
		o->oCircle(ix-4, iy-4, ix+4, iy+4);
		o->UpdateRect(rec, false);
		break;
		}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Execute whisker style as owner drawn buttons 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void OD_WhiskerTempl(int cmd, void *par, RECT *rec, anyOutput *o,
		void *data, int id)
{
	POINT pts[6];
	int ix, iy;

	switch(cmd) {
	case OD_DRAWNORMAL:
	case OD_DRAWSELECTED:
		ix = (rec->left + rec->right)/2;
		iy = (rec->top +rec->bottom)/2;
		OD_BaseRect(o, cmd, rec);
		switch(id) {
		case 500:
			pts[2].x = pts[3].x = ix;
			pts[0].x = pts[4].x = ix-5;			pts[1].x = pts[5].x = ix+5;
			pts[0].y = pts[1].y = pts[2].y = rec->top +8;
			pts[3].y = pts[4].y = pts[5].y = rec->bottom -8;
			o->oSolidLine(pts);		o->oSolidLine(pts+2);		o->oSolidLine(pts+4);
			break;
		case 501:
			pts[0].x = pts[1].x = ix;			pts[0].y =  rec->bottom -8;
			pts[1].y =  rec->top +8;			o->oSolidLine(pts);
			break;
		case 502:
			pts[0].x = ix-5;	pts[1].x = pts[2].x = ix;	pts[3].x = ix +5;
			pts[0].y = pts[1].y = rec->bottom-8;	pts[2].y = pts[3].y = rec->top+8;
			o->oPolyline(pts, 4);
			break;
		case 503:
			pts[0].x = ix+5;	pts[1].x = pts[2].x = ix;	pts[3].x = ix -5;
			pts[0].y = pts[1].y = rec->bottom-8;	pts[2].y = pts[3].y = rec->top+8;
			o->oPolyline(pts, 4);
			break;
			}
		o->UpdateRect(rec, false);
		break;
		}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Execute polar plot templates as owner drawn buttons
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void OD_PolarTempl(int cmd, void *par, RECT *rec, anyOutput *o,
		void *data, int id)
{
	LineDEF Line = {.0f, 1.0f, 0x0L, 0x0L};
	FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
	FillDEF FillR = {FILL_NONE, 0x000000ffL, 1.0, 0L};
	FillDEF FillG = {FILL_NONE, 0x0000ff00L, 1.0, 0L};
	FillDEF FillB = {FILL_NONE, 0x00ff0000L, 1.0, 0L};
	FillDEF FillY = {FILL_NONE, 0x0000ffffL, 1.0, 0L};
	TextDEF td, otd;
	POINT pts[12];
	int ix, iy;

	switch(cmd) {
	case OD_DRAWNORMAL:
	case OD_DRAWSELECTED:
		Line.color = cmd == OD_DRAWSELECTED ? 0x00000000L : 0x00e8e8e8L;
		Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00e8e8e8L;
		ix = (rec->left + rec->right)/2;
		iy = (rec->top +rec->bottom)/2;
		o->SetLine(&Line);
		pts[0].x = pts[3].x = pts[4].x = rec->left;
		pts[0].y = pts[1].y = pts[4].y = rec->top;
		pts[1].x = pts[2].x = rec->right-1;
		pts[2].y = pts[3].y = rec->bottom-1;
		o->oPolyline(pts, 5);
		Line.color = 0x00000000L;
		o->SetLine(&Line);
		o->SetFill(&Fill);
		o->oCircle(rec->left+3, rec->top+3, rec->right-3, rec->bottom-3);
		switch(id) {
		case 200:
		case 201:
		case 202:
			if(id == 201 || id == 202) {
				pts[0].x = rec->left+13;	pts[0].y = rec->top+10;
				pts[1].x = rec->left+15;	pts[1].y = rec->top+25;
				pts[2].x = rec->right-19;	pts[2].y = rec->top+33;
				pts[3].x = rec->right-11;	pts[3].y = rec->top+13;
				o->oPolyline(pts, 4);
				o->SetFill(&FillG);
				}
			else o->SetFill(&FillR);
			if(id == 200 || id == 201) {
				o->oCircle(rec->left+10, rec->top+7, rec->left+16, rec->top+13);
				o->oCircle(rec->left+12, rec->top+22, rec->left+18, rec->top+28);
				o->oCircle(rec->right-22, rec->top+30, rec->right-16, rec->top+36);
				o->oCircle(rec->right-14, rec->top+10, rec->right-8, rec->top+16);
				}
			break;
		case 203:
			pts[0].x = rec->left+7;		pts[0].y = rec->top+13;
			pts[1].x = rec->left+10;	pts[1].y = rec->top+30;
			pts[2].x = rec->right-19;	pts[2].y = rec->top+33;
			pts[3].x = rec->right-9;	pts[3].y = rec->top+11;
			pts[4].x = ix-4;			pts[4].y =iy +3;
			o->SetFill(&FillY);
			o->oPolygon(pts, 5);
			break;
		case 204:
			if(cmd == OD_DRAWNORMAL) FillG.color = 0x00e8e8e8L;
			o->SetFill(&FillG);
			o->oCircle(ix-6, rec->top+5, ix+6, iy+6);
			memcpy(&td, &o->TxtSet, sizeof(TextDEF));
			memcpy(&otd, &o->TxtSet, sizeof(TextDEF));
			td.Align = TXA_HCENTER | TXA_VTOP;
			td.Style = TXS_NORMAL;
			td.Mode = TXM_TRANSPARENT;
			td.fSize *= 0.8;	td.iSize = 0;
			td.ColTxt = 0x00ff0000L;
			o->SetTextSpec(&td);
			o->oTextOut(ix, iy+3, "y=f(x)", 0);
			o->SetTextSpec(&otd);
			}
		o->UpdateRect(rec, false);
		break;
		}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Execute templates for pie-charts as owner drawn buttons
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void OD_PieTempl(int cmd, void *par, RECT *rec, anyOutput *o,
		void *data, int id)
{
	LineDEF Line = {.0, 1.0, 0x0L, 0x0L};
	FillDEF FillR = {FILL_NONE, 0x000000ffL, 1.0, 0L};
	FillDEF FillG = {FILL_NONE, 0x0000ff00L, 1.0, 0L};
	FillDEF FillB = {FILL_NONE, 0x00ff0000L, 1.0, 0L};
	double angels1[]={90.0, 45.0, -45.0, 90.0};
	double angels2[]={180, 157.5, 112.5, 0.0};
	int ix, iy;
	double r, *ang = angels1;
	segment *seg = 0L;
	lfPOINT fc;

	switch(cmd) {
	case OD_DRAWNORMAL:
	case OD_DRAWSELECTED:
		ix = (rec->left + rec->right)/2;
		iy = (rec->top +rec->bottom)/2;
		OD_BaseRect(o, cmd, rec);
		switch(id) {
		case 401:		case 411:
			ang = angels2;
		case 400:		case 410:
			fc.fx = o->fix2un((double)ix-1);		fc.fy = o->fiy2un((double)iy);
			r = o->fix2un((double)(rec->right -rec->left))/3;
			seg = new segment(0L, 0L, &fc, 0.0, r, ang[0], ang[1]);
			if(seg) {
				if(id == 410 || id == 411) seg->SetSize(SIZE_RADIUS1, r*.7);
				seg->Command(CMD_SEG_LINE, &Line, 0L);
				seg->Command(CMD_SEG_FILL, &FillR, 0L);
				seg->DoPlot(o);
				seg->SetSize(SIZE_ANGLE1, ang[1]);
				seg->SetSize(SIZE_ANGLE2, ang[2]);
				seg->Command(CMD_SEG_FILL, &FillG, 0L);
				seg->DoPlot(o);
				seg->SetSize(SIZE_ANGLE1, ang[2]);
				seg->SetSize(SIZE_ANGLE2, ang[3]);
				seg->Command(CMD_SEG_FILL, &FillB, 0L);
				seg->DoPlot(o);
				delete seg;
				}
			break;
			}
		o->UpdateRect(rec, false);
		break;
		}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Show a simple graph how 3D axes are organized as owner drawn button
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void OD_AxisDesc3D(int cmd, void *par, RECT *rec, anyOutput *o,
		void *data, int id)
{
	POINT pts[5];

	switch(cmd) {
	case OD_DRAWNORMAL:
	case OD_DRAWSELECTED:
		pts[0].x = ((rec->left + rec->right)>>1)-15;
		pts[0].y = ((rec->bottom + rec->top)>>1)+10;
		pts[1].x = rec->left + 15;	pts[1].y = rec->bottom-20;
		o->oSolidLine(pts);
		pts[2].x = pts[1].x +2;		pts[2].y = pts[1].y -7;
		o->oSolidLine(pts + 1);
		pts[2].x = pts[1].x +6;		pts[2].y = pts[1].y -2;
		o->oSolidLine(pts + 1);
		o->oTextOut(pts[1].x -2, pts[1].y -5, "z", 1);
		pts[1].x = pts[0].x;		pts[1].y = rec->top+20;
		o->oSolidLine(pts);
		pts[2].x = pts[1].x -4;		pts[2].y = pts[1].y +6;
		o->oSolidLine(pts + 1);
		pts[2].x = pts[1].x +4;
		o->oSolidLine(pts + 1);
		o->oTextOut(pts[1].x + 4, pts[1].y - 18, "y", 1);
		pts[1].x = rec->right-15;	pts[1].y = rec->bottom -22;
		o->oSolidLine(pts);
		pts[2].x = pts[1].x -6;		pts[2].y = pts[1].y +2;
		o->oSolidLine(pts + 1);
		pts[2].x = pts[1].x -4;		pts[2].y = pts[1].y -5;
		o->oSolidLine(pts + 1);
		o->oTextOut(pts[1].x +9, pts[1].y -4, "x", 1);
		o->UpdateRect(rec, false);
		break;
		}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Execute axis breaks symbols as owner drawn button
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void OD_BreakTempl(int cmd, void *par, RECT *rec, anyOutput *o,
		void *data, int id)
{
	LineDEF Line = {0.0, 1.0, 0x0L, 0x0L};
	FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
	POINT pts[15];
	int i, ix, iy;

	switch(cmd) {
	case OD_DRAWNORMAL:
	case OD_DRAWSELECTED:
		ix = (rec->left + rec->right)>>1;
		iy = (rec->top +rec->bottom)>>1;
		OD_BaseRect(o, cmd, rec);
		pts[0].x = pts[1].x = ix;
		pts[0].y = rec->top +5;		pts[1].y = iy-3;
		o->oSolidLine(pts);
		pts[0].y = rec->bottom -7;		pts[1].y = iy+3;
		o->oSolidLine(pts);
		switch(id) {
		case 402:
			pts[0].x = ix-7;		pts[1].x = ix+7;
			pts[0].y = iy;			pts[1].y = iy-6;
			o->oSolidLine(pts);
			pts[0].y += 6;			pts[1].y += 6;
			o->oSolidLine(pts);
			break;
		case 403:
			pts[0].x = ix-7;		pts[1].x = ix+7;
			pts[0].y = iy-3;		pts[1].y = iy-3;
			o->oSolidLine(pts);
			pts[1].y += 6;			o->oSolidLine(pts);
			pts[0].y += 6;			o->oSolidLine(pts);
			break;
		case 404:
			for(i = 0; i < 15; i++) {
				pts[i].x = ix +i -7;
				pts[i].y = iy - 3 + (int)(sin((double)i*0.41887902)*2.5);
				}
			o->oPolyline(pts, 15);
			for(i = 0; i < 15; i++) pts[i].y += 6;
			o->oPolyline(pts, 15);
			break;
			}
		o->UpdateRect(rec, false);
		break;
		}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Execute plot selection templates as owner drawn button
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static void UtilBarDraw(POINT *pts, int x, int y1, int y2, anyOutput *o)
{
	pts[1].x = pts[0].x = pts[4].x = x;
	pts[0].y = y1;			pts[1].y = y2;
	pts[2].y = pts[1].y-1;		pts[2].x = pts[3].x = pts[0].x-3;	
	pts[3].y = pts[0].y-1;		pts[4].y = pts[0].y;
	o->oPolygon(pts, 5);
	pts[2].x += 5;			pts[3].x += 5;
	o->oPolygon(pts, 5);
	pts[1].x -= 3;			pts[1].y = pts[0].y-1;
	pts[2].x = pts[0].x-2;		pts[2].y = pts[0].y-2;
	o->oPolygon(pts, 5);
}

void OD_PlotTempl(int cmd, void *par, RECT *rec, anyOutput *o,
		void *data, int id)
{
	LineDEF Line = {.0, 1.0, 0x0L, 0x0L};
	LineDEF rLine = {.0, 1.0, 0x00000080L, 0x0L};
	LineDEF bLine = {.0, 1.0, 0x00e00000L, 0x0L};
	LineDEF gLine = {.0, 1.0, 0x0000e000L, 0x0L};
	FillDEF FillR = {FILL_NONE, 0x000000ffL, 1.0, 0L};
	FillDEF FillG = {FILL_NONE, 0x0000ff00L, 1.0, 0L};
	FillDEF FillB = {FILL_NONE, 0x00ff0000L, 1.0, 0L};
	FillDEF FillY = {FILL_NONE, 0x0000ffffL, 1.0, 0L};
	TextDEF td, otd;
	POINT pts[12];
	int i, j, ix, iy;
	double r;
	segment *seg = 0L;
	lfPOINT fc;

	switch(cmd) {
	case OD_DRAWNORMAL:
	case OD_DRAWSELECTED:
		ix = (rec->left + rec->right)>>1;
		iy = (rec->top +rec->bottom)>>1;
		switch(id) {
		case 560:	case 561:	case 562:	case 563:	case 564:		//3D axes
		case 565:	case 566:	case 567:
			OD_AxisTempl3D(cmd, par, rec, o, data, 410+AxisTempl3D);
			break;
		default:
			OD_BaseRect(o, cmd, rec);
			break;
			}
		if(cmd != OD_DRAWSELECTED) {
			FillR.color |= 0x00808080L;		FillG.color |= 0x00808080L;
			FillB.color |= 0x00808080L;		FillY.color |= 0x00808080L;
			}
		switch(id) {
		case 500:
		case 501:
			fc.fx = o->fix2un((double)ix-1);		fc.fy = o->fiy2un((double)iy);
			r = o->fix2un((double)(rec->right -rec->left))/3;
			seg = new segment(0L, 0L, &fc, 0.0, r, 90.0, 45.0);
			if(seg) {
				if(id == 501) seg->SetSize(SIZE_RADIUS1, r*.7f);
				seg->Command(CMD_SEG_LINE, &Line, 0L);
				seg->Command(CMD_SEG_FILL, &FillR, 0L);
				seg->DoPlot(o);
				seg->SetSize(SIZE_ANGLE1, 45.0f);
				seg->SetSize(SIZE_ANGLE2, -45.0f);
				seg->Command(CMD_SEG_FILL, &FillG, 0L);
				seg->DoPlot(o);
				seg->SetSize(SIZE_ANGLE1, -45.0f);
				seg->SetSize(SIZE_ANGLE2, 90.0f);
				seg->Command(CMD_SEG_FILL, &FillB, 0L);
				seg->DoPlot(o);
				delete seg;
				}
			break;
		case 502:
			pts[0].x = rec->right-8;	pts[0].y = rec->top+8;
			pts[1].x = ix+4;			pts[1].y = iy+2;
			pts[2].x = ix+8;			pts[2].y = rec->bottom-11;
			pts[3].x = ix;				pts[3].y = iy+7;
			pts[4].x = ix-6;			pts[4].y = iy+13;
			pts[5].x = ix-5;			pts[5].y = iy+5;
			pts[6].x = rec->left+10;	pts[6].y = iy+2;
			pts[7].x = ix-3;			pts[7].y = iy-1;
			pts[8].x = ix-3;			pts[8].y = iy-10;
			pts[9].x = ix+2;			pts[9].y = iy-4;
			pts[10].x = pts[0].x;		pts[10].y = pts[0].y;
			o->SetFill(&FillY);
			o->oPolygon(pts, 11);
			break;
		case 503:
			o->SetFill(&FillR);
			o->oRectangle(rec->left+8, rec->top+30, rec->left+12, rec->bottom-3);
			o->oRectangle(rec->left+15, rec->bottom-10, rec->left+19, rec->bottom-3);
			o->oRectangle(rec->left+22, rec->top+10, rec->left+26, rec->bottom-3);
			o->oRectangle(rec->left+29, rec->bottom-35, rec->left+33, rec->bottom-3);
			o->oRectangle(rec->left+36, rec->top+30, rec->left+40, rec->bottom-3);
			break;
		case 504:	case 507:
			o->SetFill(&FillR);
			o->oRectangle(rec->left+9, rec->top+30, rec->left+13, rec->bottom-3);
			o->oRectangle(rec->right-20, id == 507 ? rec->top + 25 : rec->top+10, rec->right-16, rec->bottom-3);
			o->SetFill(&FillG);
			o->oRectangle(rec->left+13, rec->top+25, rec->left+17, rec->bottom-3);
			o->oRectangle(rec->right-16, rec->top+15, rec->right-12, rec->bottom-3);
			o->SetFill(&FillB);
			o->oRectangle(rec->left+17, rec->top+35, rec->left+21, rec->bottom-3);
			o->oRectangle(rec->right-12, rec->top+20, rec->right-8, rec->bottom-3);
			if(id == 507) {
				o->SetLine(&Line);
				pts[0].x = pts[1].x = rec->left+11;			pts[0].y = rec->top+20;
				pts[1].y = rec->top+40;						o->oSolidLine(pts);
				pts[0].x = pts[1].x = rec->left+15;			pts[0].y = rec->top+15;
				pts[1].y = rec->top+35;						o->oSolidLine(pts);
				pts[0].x = pts[1].x = rec->left+19;			pts[0].y = rec->top+30;
				pts[1].y = rec->top+40;						o->oSolidLine(pts);
				pts[0].x = pts[1].x = rec->right-18;		pts[0].y = rec->top+15;
				pts[1].y = rec->top+35;						o->oSolidLine(pts);
				pts[0].x = pts[1].x = rec->right-14;		pts[0].y = rec->top+10;
				pts[1].y = rec->top+20;						o->oSolidLine(pts);
				pts[0].x = pts[1].x = rec->right-10;		pts[0].y = rec->top+10;
				pts[1].y = rec->top+30;						o->oSolidLine(pts);
				}
			break;
		case 505:
			o->SetFill(&FillY);
			o->oRectangle(rec->left+15, rec->bottom-10, rec->left+19, rec->bottom-3);
			o->oRectangle(rec->left+22, rec->top+15, rec->left+26, rec->bottom-3);
			o->oRectangle(rec->left+29, rec->bottom-30, rec->left+33, rec->bottom-3);
			o->oRectangle(rec->left+36, rec->bottom-12, rec->left+40, rec->bottom-3);
			o->SetLine(&bLine);
			pts[0].x = rec->left +9;	pts[0].y = rec->bottom-5;	pts[1].x = pts[0].x+1;
			for(i = 0; i < (rec->right - rec->left - 18); i++) {
				r = ((double)(i+rec->left-ix+7))/8.0;
				pts[1].y = rec->bottom - iround(exp(-r*r)*35.0+5.0);
				o->oSolidLine(pts);
				pts[0].x++;		pts[1].x++;		pts[0].y = pts[1].y;	
				}
			break;
		case 506:
			o->SetLine(&bLine);
			pts[0].x = rec->left +9;	pts[0].y = rec->bottom-5;	pts[1].x = pts[0].x+1;
			for(i = 0; i < (rec->right - rec->left - 18); i++) {
				r = ((double)(i+rec->left-ix+7))/8.0;
				pts[1].y = pts[0].y - iround(exp(-r*r)*1.0+5.0);
				pts[1].y = rec->bottom - iround(errf(r)*16.0+26.0);
				if (i) o->oSolidLine(pts);
				pts[0].x++;		pts[1].x++;		pts[0].y = pts[1].y;	
				}
			o->SetLine(&rLine);
			pts[0].x = ix-2;	pts[1].x = pts[0].x+1;
			for(i = 0; i < (rec->right - ix-5); i++) {
				r = ((double)(i-9))/4.0;
				pts[1].y = rec->bottom - iround(exp(-r*r)*17.0+7.0);
				if (i) o->oSolidLine(pts);
				pts[0].x++;		pts[1].x++;		pts[0].y = pts[1].y;	
				}
			o->SetFill(&FillG);			o->SetLine(&Line);
			o->oCircle(ix, iy, ix+5, iy+5);
			o->oCircle(ix-5, iy+8, ix, iy+13);
			o->oCircle(ix+5, iy-10, ix+10, iy-5);
			break;
		case 520:		case 521:
			if(id == 521) {
				pts[0].x = rec->left+13;	pts[0].y = rec->bottom-12;
				pts[1].x = rec->left+20;	pts[1].y = rec->top+18;
				pts[2].x = rec->right-19;	pts[2].y = rec->top+33;
				pts[3].x = rec->right-11;	pts[3].y = rec->top+13;
				o->oPolyline(pts, 4);
				o->SetFill(&FillG);
				}
			else o->SetFill(&FillR);
			o->oCircle(rec->left+10, rec->bottom-15, rec->left+16, rec->bottom-9);
			o->oCircle(rec->left+17, rec->top+15, rec->left+23, rec->top+21);
			o->oCircle(rec->right-22, rec->top+30, rec->right-16, rec->top+36);
			o->oCircle(rec->right-14, rec->top+10, rec->right-8, rec->top+16);
			break;
		case 522:
			o->SetFill(&FillR);
			o->oRectangle(rec->left+3, rec->top+8, rec->left+16, rec->top+16);
			o->SetFill(&FillG);
			o->oRectangle(rec->left+3, iy-4, rec->right-16, iy+4);
			o->SetFill(&FillB);
			o->oRectangle(rec->left+3, rec->bottom-8, rec->left+26, rec->bottom-16);
			break;
		case 523:
			o->SetFill(&FillR);
			o->oRectangle(rec->left+8, rec->top+30, rec->left+16, rec->bottom-3);
			o->SetFill(&FillG);
			o->oRectangle(ix-4, rec->top+10, ix+4, rec->bottom-3);
			o->SetFill(&FillB);
			o->oRectangle(rec->right-8, rec->top+20, rec->right-16, rec->bottom-3);
			break;
		case 524:
			o->SetFill(&FillG);
			o->oCircle(rec->left+10, rec->bottom-15, rec->left+16, rec->bottom-9);
			o->oCircle(ix-9, iy-18, ix+9, iy);
			o->oCircle(rec->right-7, rec->top+30, rec->right-17, rec->top+40);
			break;
		case 525:
			pts[0].x = pts[1].x = rec->left +12;
			pts[0].y = rec->top+20;		pts[1].y = rec->top+40;
			o->oPolyline(pts,2);
			pts[0].x = pts[1].x = rec->right-12;
			o->oPolyline(pts,2);
			pts[0].x = pts[1].x = ix;
			pts[0].y = rec->top+10;		pts[1].y = rec->top+35;
			o->oPolyline(pts,2);
			o->SetFill(&FillY);
			o->oRectangle(rec->left+8, rec->top+25, rec->left+16, rec->top+35);
			o->oRectangle(ix-4, rec->top+13, ix+4, rec->top+28);
			o->oRectangle(rec->right-8, rec->top+30, rec->right-16, rec->top+35);
			break;
		case 526:
			pts[0].x = rec->left+13;	pts[0].y = rec->bottom-12;
			pts[1].x = rec->right-11;	pts[1].y = rec->top+8;
			o->oSolidLine(pts);
			o->SetFill(&FillB);
			o->oCircle(rec->left+10, rec->bottom-21, rec->left+16, rec->bottom-15);
			o->oCircle(rec->left+17, rec->top+20, rec->left+23, rec->top+26);
			o->oCircle(rec->right-22, rec->top+25, rec->right-16, rec->top+31);
			o->oCircle(rec->right-14, rec->top+15, rec->right-8, rec->top+21);
			o->oCircle(rec->right-22, rec->top+9, rec->right-16, rec->top+15);
			break;
		case 527:
			o->oCircle(rec->left+8, rec->top+8, rec->right-8, rec->bottom-8);
			o->oCircle(rec->left+16, rec->top+16, rec->right-16, rec->bottom-16);
			pts[0].x = rec->left+6;		pts[0].y = iy;
			pts[1].x = rec->right-6;	pts[1].y = iy;
			o->oSolidLine(pts);
			pts[0].x = ix;				pts[0].y = rec->bottom-6;
			pts[1].x = ix;				pts[1].y = rec->top+6;
			o->oSolidLine(pts);			o->SetFill(&FillR);
			o->oCircle(rec->left+13, rec->top+13, rec->left+19, rec->top+19);
			o->oCircle(ix-7, iy+1, ix-1, iy+7);
			o->oCircle(rec->right-19, rec->bottom-19, rec->right-13, rec->bottom-13);
			o->oCircle(rec->right-19, rec->top+13, rec->right-13, rec->top+19);
			break;
		case 528:
			o->SetFill(&FillY);
			o->oRectangle(rec->left+8, iy-2, ix-2, iy+2);
			o->oRectangle(ix-2, iy-15, ix+2, iy+15);
			o->oRectangle(ix+2, iy-11, ix+6, iy+11);
			o->oRectangle(ix+6, iy-5, rec->right-8, iy+5);
			break;
		case 529:
			o->SetLine(&rLine);
			pts[0].x = rec->left +9;	pts[0].y = iy;	pts[1].x = pts[0].x+1;
			for(i = 0; i < (rec->right - rec->left - 18); i++) {
				pts[1].y = iy-4 + iround(pow(20.0, 1.0+((double)-i)/30.0) * -sin(((double)i)));
				o->oSolidLine(pts);
				pts[0].x++;		pts[1].x++;		pts[0].y = pts[1].y;	
				}
			memcpy(&td, &o->TxtSet, sizeof(TextDEF));
			memcpy(&otd, &o->TxtSet, sizeof(TextDEF));
			td.Align = TXA_HCENTER | TXA_VTOP;
			td.Style = TXS_NORMAL;
			td.Mode = TXM_TRANSPARENT;
			td.ColTxt = 0x00c00000L;
			o->SetTextSpec(&td);
			o->oTextOut(ix, iy+4, "y=f(x)", 0);
			o->SetTextSpec(&otd);
			break;
		case 530:
			o->SetLine(&rLine);
			pts[0].x = rec->left +9;	pts[0].y = iy+13;	pts[1].x = pts[0].x+1;
			for(i = 0; i < (rec->right - rec->left - 18); i++) {
				pts[1].y = iy+12 + iround(-log10(((double)i)/.4 + 1.0)*15.0);
				o->oSolidLine(pts);
				pts[0].x++;		pts[1].x++;		pts[0].y = pts[1].y;	
				}
			o->SetLine(&Line);			o->SetFill(&FillG);
			o->oCircle(rec->left+8, rec->bottom-15, rec->left+14, rec->bottom-9);
			o->oCircle(rec->left+11, iy-1, rec->left+17, iy+5);
			o->oCircle(rec->left+17, rec->top+12, rec->left+23, rec->top+18);
			o->oCircle(rec->right-22, rec->top+8, rec->right-16, rec->top+14);
			o->oCircle(rec->right-14, rec->top+10, rec->right-8, rec->top+16);
			memcpy(&td, &o->TxtSet, sizeof(TextDEF));
			memcpy(&otd, &o->TxtSet, sizeof(TextDEF));
			td.Align = TXA_HLEFT | TXA_VCENTER;
			td.Style = TXS_BOLD;	td.Mode = TXM_TRANSPARENT;
			td.fSize = defs.GetSize(SIZE_TEXT)*1.75;			td.iSize = 0;
			td.ColTxt = cmd == OD_DRAWSELECTED ? 0x0000f0f0L : 0x00c00000;
			o->SetTextSpec(&td);
			o->oTextOut(ix-2, iy+3, "?", 0);
			o->SetTextSpec(&otd);
			break;
		case 531:
			o->SetLine(&rLine);
			pts[0].x = rec->left +9;	pts[0].y = iy;	
			pts[1].x = ix;				pts[1].y = rec->top + 9;
			pts[2].x = rec->right -9;	pts[2].y = iy;
			o->oPolyline(pts, 3, 0L);
			o->SetLine(&gLine);
			pts[0].y -= 15;	pts[1].y = iy;	pts[2].y -=7;
			o->oPolyline(pts, 3, 0L);
			o->SetLine(&bLine);
			pts[0].y += 9;	pts[1].y += 10;	pts[2].y = pts[1].y;
			o->oPolyline(pts, 3, 0L);
			break;
		case 532:
			pts[0].x = rec->left +13;	pts[0].y = rec->top+8;	
			pts[1].x = rec->left +13;	pts[1].y = iy;
			o->oSolidLine(pts);
			pts[0].x -= 3;		pts[1].x += 3;
			pts[0].y = pts[1].y = rec->top+8;
			o->oSolidLine(pts);
			pts[0].y = pts[1].y = iy;
			o->oSolidLine(pts);
			pts[0].x = ix;	pts[0].y = iy-8;	
			pts[1].x = ix;	pts[1].y = rec->bottom-13;
			o->oSolidLine(pts);
			pts[0].x -= 3;		pts[1].x += 3;
			pts[0].y = pts[1].y = iy-8;
			o->oSolidLine(pts);
			pts[0].y = pts[1].y = rec->bottom-13;
			o->oSolidLine(pts);
			pts[0].x = rec->right -13;	pts[0].y = rec->top+10;	
			pts[1].x = rec->right -13;	pts[1].y = iy-6;
			o->oSolidLine(pts);
			pts[0].x -= 3;		pts[1].x += 3;
			pts[0].y = pts[1].y = rec->top+10;
			o->oSolidLine(pts);
			pts[0].y = pts[1].y = iy-6;
			o->oSolidLine(pts);
			pts[0].x = rec->left+13;	pts[1].x = ix;		pts[2].x = rec->right-13;
			pts[0].y = (rec->top+8+iy)>>1;
			pts[1].y = (rec->bottom-13 + iy -8)>>1;
			pts[2].y = (rec->top+10+iy-6)>>1;
			o->oPolyline(pts, 3, 0L);
			o->SetFill(&FillY);
			o->oCircle(pts[0].x-3, pts[0].y-3, pts[0].x+3, pts[0].y+3);
			o->oCircle(pts[1].x-3, pts[1].y-3, pts[1].x+3, pts[1].y+3);
			o->oCircle(pts[2].x-3, pts[2].y-3, pts[2].x+3, pts[2].y+3);
			break;
		case 540:
			o->SetFill(&FillR);
			o->oRectangle(rec->left+8, rec->bottom-8, rec->left+16, rec->bottom-3);
			o->oRectangle(ix-4, rec->bottom-18, ix+4, rec->bottom-3);
			o->oRectangle(rec->right-8, rec->bottom-12, rec->right-16, rec->bottom-3);
			o->SetFill(&FillG);
			o->oRectangle(rec->left+8, rec->bottom-13, rec->left+16, rec->bottom-8);
			o->oRectangle(ix-4, rec->bottom-28, ix+4, rec->bottom-18);
			o->oRectangle(rec->right-8, rec->bottom-22, rec->right-16, rec->bottom-12);
			o->SetFill(&FillB);
			o->oRectangle(rec->left+8, rec->bottom-18, rec->left+16, rec->bottom-13);
			o->oRectangle(ix-4, rec->bottom-38, ix+4, rec->bottom-28);
			o->oRectangle(rec->right-8, rec->bottom-27, rec->right-16, rec->bottom-22);
			break;
		case 541:
			o->SetFill(&FillR);
			pts[0].x = pts[1].x = pts[5].x = rec->left+8;
			pts[0].y = pts[4].y =pts[5].y = rec->bottom-4;
			pts[1].y = iy+5;	pts[2].x = ix;	pts[2].y = rec->bottom-5;
			pts[3].x = pts[4].x = rec->right-8;
			pts[3].y = rec->bottom-12;
			o->oPolygon(pts, 6);
			o->SetFill(&FillY);
			for(i = 1; i < 6; i++) {
				pts[i-1].x = pts[i].x;	pts[i-1].y = pts[i].y;
				}
			pts[5].x = pts[0].x;	pts[5].y = pts[0].y;
			pts[4].x = pts[1].x;	pts[4].y = pts[1].y-8;
			pts[3].y = rec->bottom-20;
			o->oPolygon(pts, 6);
			o->SetFill(&FillG);
			pts[1].y = pts[4].y;	pts[2].y = pts[3].y;
			pts[4].y -= 12;	pts[3].y -= 3;
			o->oPolygon(pts, 6);
			break;
		case 542:
			Line.color = 0x00ff0000L;
			o->SetLine(&Line);
			pts[0].x = rec->left+6;		pts[0].y = rec->bottom-6;
			pts[1].x = rec->left+10;	pts[1].y = rec->bottom-6;
			pts[2].x = rec->left+12;	pts[2].y = iy + 8;
			pts[3].x = rec->left+14;	pts[3].y = rec->bottom-6;
			pts[4].x = rec->right-24;	pts[4].y = rec->bottom-6;
			pts[5].x = rec->right-22;	pts[5].y = iy + 4;
			pts[6].x = rec->right-20;	pts[6].y = rec->bottom-6;
			pts[7].x = rec->right-16;	pts[7].y = rec->bottom-6;
			for(i = 0; i < 4; i++){
				o->oPolyline(pts, 8);
				for(j = 0; j < 8; j++) {
					pts[j].x += 4;	pts[j].y -= 4;
					}
				pts[2].y -= 4;	pts[5].y++;
				}
			break;
		case 543:
			OD_AxisTempl3D(cmd, par, rec, o, data, 411);
			o->SetFill(&FillR);
			UtilBarDraw(pts, ix-5, iy-2, rec->bottom-12, o);
			UtilBarDraw(pts, ix, iy+3, rec->bottom-11, o);
			UtilBarDraw(pts, ix+5, iy-5, rec->bottom-10, o);
			UtilBarDraw(pts, ix+10, iy-4, rec->bottom-9, o);
			o->SetFill(&FillG);
			UtilBarDraw(pts, ix-10, iy+2, rec->bottom-9, o);
			UtilBarDraw(pts, ix-5, iy+10, rec->bottom-8, o);
			UtilBarDraw(pts, ix, iy+8, rec->bottom-7, o);
			UtilBarDraw(pts, ix+5, iy, rec->bottom-6, o);
			break;
		case 544:
			OD_AxisTempl3D(cmd, par, rec, o, data, 411);
			for(i = 0; i < 6; i++){
				switch(i) {
				case 0:
					o->SetFill(&FillY);
					pts[0].x = ix-5;		pts[0].y = iy+1;
					pts[1].x = ix;			pts[1].y = iy-10;
					break;
				case 1:
					pts[0].x = pts[1].x;	pts[0].y = pts[1].y;
					pts[1].x = ix+5;			pts[1].y = iy -6;
					break;
				case 2:
					pts[0].x = pts[1].x;	pts[0].y = pts[1].y;
					pts[1].x = ix+10;		pts[1].y = iy +4;
					break;
				case 3:
					o->SetFill(&FillR);
					pts[0].x = ix-10;		pts[0].y = iy-10;
					pts[1].x = ix-5;		pts[1].y = iy+4;
					break;
				case 4:
					pts[0].x = pts[1].x;	pts[0].y = pts[1].y;
					pts[1].x = ix;			pts[1].y = iy +9;
					break;
				case 5:
					pts[0].x = pts[1].x;	pts[0].y = pts[1].y;
					pts[1].x = ix+10;		pts[1].y = iy +12;
					break;
					}
				pts[2].x = pts[1].x -3;	pts[2].y = pts[1].y + 2;
				pts[3].x = pts[0].x -3;	pts[3].y = pts[0].y + 2;
				pts[4].x = pts[0].x;	pts[4].y = pts[0].y;
				o->oPolygon(pts, 5);
				}
			break;
		case 560:
			o->SetFill(&FillY);
#ifdef _WINDOWS
			o->oCircle(rec->right-13, rec->top+7, rec->right-19, rec->top+13);
			o->oCircle(rec->right-11, iy-3, rec->right-17, iy+3);
			o->oCircle(ix, iy+3, ix+6, iy+9);
			o->oCircle(rec->left+12, iy+3, rec->left+18, iy+9);
			o->oCircle(ix, rec->bottom-6, ix+6, rec->bottom-12);
#else
			o->oCircle(rec->right-15, rec->top+7, rec->right-19, rec->top+13);
			o->oCircle(rec->right-13, iy-3, rec->right-17, iy+3);
			o->oCircle(ix, iy+3, ix+6, iy+9);
			o->oCircle(rec->left+12, iy+3, rec->left+18, iy+9);
			o->oCircle(ix, rec->bottom-8, ix+6, rec->bottom-12);
#endif
			break;
		case 561:
			o->SetFill(&FillG);
			UtilBarDraw(pts, ix+1, rec->top +12, rec->bottom-10, o);
			UtilBarDraw(pts, rec->left+16, iy+8, rec->bottom-8, o);
			UtilBarDraw(pts, rec->right-12, iy+12, rec->bottom-8, o);
			break;
		case 562:
			o->SetLine(&bLine);
			pts[0].x = rec->left+20;	pts[0].y = rec->bottom-10;
			pts[1].x = rec->right-10;	pts[1].y = rec->bottom-16;
			o->oSolidLine(pts);
			pts[0].x = pts[1].x;		pts[0].y = pts[1].y;
			pts[1].x -= 8;				pts[1].y -= 12;
			o->oSolidLine(pts);
			pts[0].x = pts[1].x;		pts[0].y = pts[1].y;
			pts[1].x -= 18;				pts[1].y += 3;
			o->oSolidLine(pts);
			pts[0].x = pts[1].x;		pts[0].y = pts[1].y;
			pts[1].x += 15;				pts[1].y += 4;
			o->oSolidLine(pts);
			break;
		case 563:
			o->SetFill(&FillG);
			o->oCircle(rec->left+12, rec->bottom-19, rec->left+18, rec->bottom-13);
			o->oCircle(ix, iy-10, ix+14, iy+4);
			o->oCircle(ix, rec->top+34, ix+10, rec->top+44);
			break;
		case 564:
			o->SetFill(&FillY);
			pts[0].x = rec->left+10;	pts[0].y = rec->bottom-14;
			pts[1].x = pts[0].x;		pts[1].y = rec->top +16;
			pts[2].x = ix-6;			pts[2].y = iy+4;
			pts[3].x = pts[2].x;		pts[3].y = rec->bottom -10;
			pts[4].x = pts[0].x;		pts[4].y = pts[0].y;
			o->oPolygon(pts, 5, 0L);
			pts[0].x = pts[2].x;		pts[0].y = pts[2].y;
			pts[1].x = pts[3].x;		pts[1].y = pts[3].y;
			pts[2].x = ix + 3;			pts[2].y = pts[1].y -2;
			pts[3].x = pts[2].x;		pts[3].y = pts[0].y +1;
			pts[4].x = pts[0].x;		pts[4].y = pts[0].y;
			o->oPolygon(pts, 5, 0L);
			pts[0].x = pts[2].x;		pts[0].y = pts[2].y;
			pts[1].x = pts[3].x;		pts[1].y = pts[3].y;
			pts[2].x = ix + 10;			pts[2].y = pts[1].y +9;
			pts[3].x = pts[2].x;		pts[3].y = pts[0].y +3;
			pts[4].x = pts[0].x;		pts[4].y = pts[0].y;
			o->oPolygon(pts, 5, 0L);
			break;
		case 565:	case 566:
			o->SetLine(&rLine);
			pts[0].x = ix-16;			pts[0].y = iy-2;
			pts[1].x = ix+4;			pts[1].y = iy+6;
			for(i = 0; i < 4; i++) {
				o->oSolidLine(pts);
				pts[0].x += 4;			pts[1].x += 4;
				pts[0].y -= 4;			pts[1].y -= 4;
				}
			pts[0].x = ix+4;			pts[0].y = iy+6;
			pts[1].x -= 2;				pts[1].y += 4;
			for(i = 0; i < 5; i++) {
				o->oSolidLine(pts);
				pts[0].x -= 5;			pts[1].x -= 5;
				pts[0].y -= 2;			pts[1].y -= 2;
				}
			memcpy(&td, &o->TxtSet, sizeof(TextDEF));
			memcpy(&otd, &o->TxtSet, sizeof(TextDEF));
			td.Align = TXA_HCENTER | TXA_VTOP;
			td.Mode = TXM_TRANSPARENT;
			if(id == 565) {
				td.Style = TXS_NORMAL;			td.ColTxt = 0x00c00000L;
				o->SetTextSpec(&td);			o->oTextOut(ix, iy+4, "f(x,z)", 0);
				}
			else {
				td.Style = TXS_BOLD;
				td.fSize = defs.GetSize(SIZE_TEXT)*1.75;			td.iSize = 0;
				td.ColTxt = cmd == OD_DRAWSELECTED ? 0x0000cb00L : 0x00cb00c0L;
				o->SetTextSpec(&td);
				o->oTextOut(ix-10, iy-6, "?", 0);
				}
			o->SetTextSpec(&otd);
			break;
		case 567:
			o->SetLine(&bLine);			if(cmd == OD_DRAWSELECTED) o->SetFill(&FillG);
			pts[0].x = ix-10;			pts[0].y = iy+4;
			pts[1].x = ix-6;			pts[1].y = iy+10;
			pts[2].x = ix-16;			pts[2].y = iy+8;
			o->oPolygon(pts, 3, 0L);
			pts[2].x = ix+2;		pts[2].y = iy-10;		o->oPolygon(pts, 3, 0L);
			pts[0].x = ix+10;		pts[0].y = iy-12;		o->oPolygon(pts, 3, 0L);
			pts[2].x = ix+2;		pts[2].y = iy+14;		o->oPolygon(pts, 3, 0L);
			pts[1].x = ix+12;		pts[1].y = iy+4;		o->oPolygon(pts, 3, 0L);
			pts[0].x = ix+16;		pts[0].y = iy+12;		o->oPolygon(pts, 3, 0L);
			break;
		case 568:
			if(cmd == OD_DRAWSELECTED) {
				FillY.color |= 0x00808080L;			FillG.color |= 0x00808080L;
				FillR.color |= 0x00808080L;			FillB.color |= 0x00808080L;
				o->SetFill(&FillY);
				pts[0].x = pts[3].x = rec->left+3;		pts[0].y = pts[1].y = rec->top+3;
				pts[1].x = pts[2].x = rec->right-3;		pts[2].y = pts[3].y = rec->bottom-3;
				o->oPolygon(pts, 4);
				}
			o->SetLine(cmd == OD_DRAWSELECTED ? &bLine : &Line);
			if(cmd == OD_DRAWSELECTED) o->SetFill(&FillG);
			pts[0].x = pts[1].x = rec->left+15;				pts[0].y = rec->top+3;
			pts[1].y = rec->top+5;		pts[2].x = rec->left+12;	pts[2].y = rec->top+12;
			pts[3].x = rec->left+7;		pts[3].y = pts[4].y = rec->top+15;
			pts[4].x = rec->left+3;		pts[5].x = rec->left+3;		pts[5].y = rec->top+3;
			o->oPolygon(pts, 6);
			pts[0].x = pts[1].x = ix;	pts[2].x = ix+6;		pts[3].x = rec->right-7;
			pts[4].x = rec->right-3;	pts[5].x = rec->right-3;	o->oPolygon(pts, 6);
			pts[0].y = rec->bottom-3;	pts[1].y = rec->bottom-9;	pts[2].y = iy+3;
			pts[3].x = rec->right-9;	pts[3].y = pts[4].y = iy-3;	pts[5].y = rec->bottom-3;
			o->oPolygon(pts, 6);
			pts[0].x = pts[1].x = rec->right-15;				pts[0].y = rec->bottom-3;
			pts[1].y = rec->bottom-5;	pts[2].x = rec->right-12;	pts[2].y = rec->bottom-10;
			pts[3].x = rec->right-7;	pts[3].y = pts[4].y = rec->bottom-15;
			pts[4].x = rec->right-3;	pts[5].x = rec->right-3;	pts[5].y = rec->bottom-3;
			if(cmd == OD_DRAWSELECTED) o->SetFill(&FillB);			o->oPolygon(pts, 6);
			pts[0].x = pts[1].x = rec->left+15;				pts[0].y = rec->bottom-3;
			pts[1].y = rec->bottom-5;	pts[2].x = rec->left+12;	pts[2].y = iy+5;
			pts[3].x = rec->left+7;		pts[3].y = pts[4].y = iy-3;	pts[4].x = rec->left+3;
			pts[5].x = rec->left+3;		if(cmd == OD_DRAWSELECTED) o->SetFill(&FillG);
			o->oPolygon(pts, 6);
			if(cmd == OD_DRAWSELECTED) o->SetFill(&FillR);	o->oCircle(ix-9, iy-9, ix+1, iy+3);
			break;
			}
		o->UpdateRect(rec, false);
		break;
		}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Execute axis templates as owner drawn buttons
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void OD_AxisTempl(int cmd, void *par, RECT *rec, anyOutput *o,
		void *data, int id)
{
	LineDEF Line = {0.0, 1.0, 0x0L, 0x0L};
	LineDEF Grid = {0.0, 1.0, 0x00c0c0c0, 0x0L};
	POINT pts[5];
	int i, ty, tx, sx;

	switch(cmd) {
	case OD_DRAWNORMAL:
	case OD_DRAWSELECTED:
		OD_BaseRect(o, cmd, rec);
		tx = ty = 0;
		switch(id) {
		case 310:
			o->oRectangle(rec->left+10, rec->top+6, rec->right-6, rec->bottom-10);
			ty = rec->bottom -10;		tx = rec->left+8;
			break;
		case 311:
			o->oRectangle(rec->left+10, rec->top+6, rec->right-6, rec->bottom-10);
			pts[0].x = rec->left+10;		pts[1].x = rec->right-6;
			pts[0].y = pts[1].y = rec->bottom-32;
			o->oSolidLine(pts);
			pts[0].y = rec->top+6;		pts[1].y = rec->bottom-10;
			pts[0].x = pts[1].x = rec->left + 32;
			o->oSolidLine(pts);
			ty = rec->bottom -31;		tx = rec->left+30;
			break;
		case 312:
			pts[0].x = rec->left+10;		pts[1].x = rec->right-6;
			pts[0].y = pts[1].y = rec->bottom-11;
			o->oSolidLine(pts);
			pts[0].y = rec->top+6;		pts[1].y = rec->bottom-10;
			pts[0].x = pts[1].x = rec->left + 10;
			o->oSolidLine(pts);
			ty = rec->bottom -10;		tx = rec->left+8;
			break;
		case 313:
			pts[0].x = rec->left+10;		pts[1].x = rec->right-6;
			pts[0].y = pts[1].y = rec->top + 9;
			o->oSolidLine(pts);
			pts[0].y = rec->top+10;			pts[1].y = rec->bottom-10;
			pts[0].x = pts[1].x = rec->left + 10;
			o->oSolidLine(pts);
			ty = rec->top+7;			tx = rec->left+8;
			break;
		case 314:
			pts[0].x = rec->left+10;		pts[1].x = rec->right-6;
			pts[0].y = pts[1].y = rec->bottom-11;
			o->oSolidLine(pts);
			pts[0].y = rec->top+6;		pts[1].y = rec->bottom-10;
			pts[0].x = pts[1].x = rec->left + 27;
			o->oSolidLine(pts);
			ty = rec->bottom -10;		tx = rec->left+25;
			break;
			}
		if(ODtickstyle & 0x300) {
			o->SetLine(&Grid);
			pts[0].y = rec->top+7;		pts[1].y = rec->bottom-11;
			if(id == 313) pts[0].y +=3;
			if(ODtickstyle & 0x100) for(i = rec->left+16; i < rec->right-6; i+=12) {
				pts[0].x = pts[1].x = i;
				o->oSolidLine(pts);
				}
			pts[0].x = rec->left+11;	pts[1].x = rec->right-7;
			if(ODtickstyle & 0x200) 
				for(i = rec->bottom- (id == 313 ? 11 : 17); i > rec->top+6; i -=12) {
				pts[0].y = pts[1].y = i;
				o->oSolidLine(pts);
				}
			o->SetLine(&Line);
			}
		if(tx != ty) {
			sx = 2;
			switch(ODtickstyle & 0x03){
			case 1:
				if(id == 313) ty += 3;
				else ty -= 3;
				tx += 3;	
				break;
			case 2:
				if(id == 313) ty += 1;
				else ty -= 2;
				tx += 1;
#ifdef _WINDOWS
				sx = 3;
#endif
				break;
			default:
				break;
				}
			pts[0].y = ty;	pts[1].y = ty+sx;
			for(i = rec->left+10; i < rec->right-6; i+=6) {
				pts[0].x = pts[1].x = i;
				o->oSolidLine(pts);
				}
			pts[0].x = tx;	pts[1].x = tx+sx;
			for(i = rec->bottom-11; i > rec->top+6; i -=6) {
				pts[0].y = pts[1].y = i;
				o->oSolidLine(pts);
				}
			}
		o->UpdateRect(rec, false);
		break;
		}

}

void OD_AxisTempl3D(int cmd, void *par, RECT *rec, anyOutput *o,
		void *data, int id)
{
	LineDEF Line = {0.0, 1.0, 0x0L, 0x0L};
	FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
	POINT pts[5];
	int x, y;

	switch(cmd) {
	case OD_DRAWNORMAL:
	case OD_DRAWSELECTED:
		OD_BaseRect(o, cmd, rec);
		Line.color = cmd == OD_DRAWSELECTED ? 0x00c0c0c0L : 0x0L;
		o->SetLine(&Line);						o->SetFill(&Fill);
		switch(id) {
		case 410:	case 411:
			pts[0].x = rec->left+20;			pts[0].y = rec->bottom-14;
			pts[1].x = rec->left+10;			pts[1].y = rec->bottom-10;
			o->oSolidLine(pts);
			pts[1].x = rec->right-10;			pts[1].y = pts[0].y + 3;
			o->oSolidLine(pts);
			pts[1].x = pts[0].x;				pts[1].y = rec->top+8;
			o->oSolidLine(pts);
			if(id == 411) {
				pts[0].x = rec->left+10;		pts[0].y = rec->top+12;
				o->oSolidLine(pts);
				pts[0].x = rec->right-10;		pts[0].y = pts[1].y + 3;
				o->oSolidLine(pts);
				pts[1].x = pts[0].x;			pts[1].y = rec->bottom-11;
				o->oSolidLine(pts);
				pts[0].x = rec->right-20;		pts[0].y = rec->bottom-7;
				o->oSolidLine(pts);
				pts[1].x = rec->left+10;		pts[1].y = rec->bottom-10;
				o->oSolidLine(pts);
				pts[0].x = rec->left+10;		pts[0].y = rec->top+12;
				o->oSolidLine(pts);
				}
			break;
		case 412:
			x = (rec->right+rec->left)>>1;		y = (rec->top+rec->bottom)>>1;
			pts[0].x = rec->left+14;			pts[0].y = y+4;
			pts[1].x = rec->right-14;			pts[1].y = y-2;
			o->oSolidLine(pts);
			pts[1].y += 6;	pts[0].y -= 6;	pts[1].x +=4;	pts[0].x -=4;
			o->oSolidLine(pts);
			pts[0].x = pts[1].x = x;	pts[0].y = y-15;	pts[1].y = y+15;
			o->oSolidLine(pts);
			}
		o->UpdateRect(rec, false);
		Line.color = 0x00000000L;		o->SetLine(&Line);
		break;
		}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 2D Plot: Execute axis templates for new axis as owner drawn buttons
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void OD_NewAxisTempl(int cmd, void *par, RECT *rec, anyOutput *o,
		void *data, int id)
{
	POINT pts[5];
	int i, ix, iy, step, d1, d2;

	switch(cmd) {
	case OD_DRAWNORMAL:
	case OD_DRAWSELECTED:
		ix = (rec->right + rec->left)>>1;
		iy = (rec->bottom + rec->top)>>1;
		OD_BaseRect(o, cmd, rec);
		d1 = d2 = 0;
		switch(id) {
		case 201:			d1 = -6;				d2 = -2;
		case 202:			d2 -= 14;
		case 203:			d1 += 6;				d2 += 3;
		case 204:
			d1 = d1 + ix -3;		d2 = d2 + ix +4;
			pts[0].x = pts[1].x = ix;
			pts[0].y = rec->top +9;	pts[1].y = rec->bottom -9;
			step = ((pts[1].y - pts[0].y)/5)+1;
			o->oSolidLine(pts);
			pts[0].x = d1;		pts[1].x = ix;
			for(i = rec->top +11; i <= rec->bottom-9; i += step) {
				pts[0].y = pts[1].y = i;
				o->oSolidLine(pts);
				o->oRectangle(d2, i-1, d2+4, i+1);
				}
			break;
		case 205:			d1 = 6;					d2 = 3;
		case 206:			d2 += 10;
		case 207:			d1 -= 6;				d2 -= 3;
		case 208:
			d1 = d1 + iy +3;		d2 = d2 + iy - 4;
			pts[0].y = pts[1].y = iy;
			pts[0].x = rec->left +9;	pts[1].x = rec->right -9;
			step = ((pts[1].x - pts[0].x)/4)+1;
			o->oSolidLine(pts);
			pts[0].y = d1;		pts[1].y = iy;
			for(i = rec->left +11; i <= rec->right-9; i += step) {
				pts[0].x = pts[1].x = i;
				o->oSolidLine(pts);
				o->oRectangle(i-1, d2, i+2, d2+2);
				}
			break;
			}
		o->UpdateRect(rec, false);
		break;
		}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 3D Plot: Execute axis templates for new axis as owner drawn buttons
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void OD_NewAxisTempl3D(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id)
{
	LineDEF Line = {0.0, 1.0, 0x0L, 0x0L};
	FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
	POINT spts[24];
	int i, ix, iy, edge;
	DWORD col1, col2;

	switch(cmd) {
	case OD_DRAWNORMAL:
	case OD_DRAWSELECTED:
		Line.color = cmd == OD_DRAWSELECTED ? 0x00000000L : 0x00e8e8e8L;
		Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00e8e8e8L;
		col1 = cmd == OD_DRAWSELECTED ? 0x008080c0L : 0x00c8c8c8L;
		col2 = cmd == OD_DRAWSELECTED ? 0x0000ff00L : 0x0000c000L;
		o->SetLine(&Line);
		ix = (rec->right + rec->left)>>1;		iy = (rec->bottom + rec->top)>>1;
		spts[0].x = spts[3].x = spts[4].x = rec->left;
		spts[0].y = spts[1].y = spts[4].y = rec->top;
		spts[1].x = spts[2].x = rec->right-1;	spts[2].y = spts[3].y = rec->bottom-1;
		o->oPolyline(spts, 5);					Line.color = 0x00000000L;
		o->SetLine(&Line);					o->SetFill(&Fill);
		o->oRectangle(rec->left+3, rec->top+3, rec->right-3, rec->bottom-3);
		spts[0].x = spts[6].x = spts[8].x = spts[13].x = spts[18].x = spts[19].x = rec->left+20;		
		spts[0].y = spts[13].y = spts[18].y = rec->bottom-14;
		spts[1].x = spts[2].x = spts[4].x = spts[5].x = spts[7].x = spts[21].x = rec->left+10;
		spts[1].y = spts[2].y = spts[4].y = rec->bottom-10;
		spts[3].x = spts[15].x = spts[16].x = spts[17].x = spts[20].x = spts[22].x = rec->right-20;				
		spts[3].y = spts[15].y = spts[16].y = spts[2].y + 3;
		spts[5].y = spts[7].y = spts[21].y = rec->top+12;
		spts[6].y = spts[8].y = spts[19].y = rec->top+8;
		spts[9].x = spts[10].x = spts[11].x = spts[12].x = spts[14].x = spts[23].x = rec->right-10;
		spts[9].y = spts[10].y = spts[23].y = spts[8].y+3;
		spts[11].y = spts[12].y = spts[14].y = spts[0].y+3;
		spts[17].y = spts[20].y = spts[22].y = spts[7].y+3;
		switch(id) {
			case 201:		edge = 4;			break;
			case 202:		edge = 16;			break;
			case 203:		edge = 10;			break;
			case 204:		edge = 18;			break;
			case 205:		edge = 2;			break;
			case 206:		edge = 14;			break;
			case 207:		edge = 12;			break;
			case 208:		edge = 0;			break;
			case 209:		edge = 20;			break;
			case 210:		edge = 22;			break;
			case 211:		edge = 8;			break;
			case 212:		edge = 6;			break;
			default:		edge = -1;			break;
			}
		Line.color = col1;				o->SetLine(&Line);
		if(true)for(i = 0; i < 24; i+= 2) {
			if(i == edge){
				Line.color = col2;		o->SetLine(&Line);
				o->oSolidLine(spts+i);
				Line.color = col1;		o->SetLine(&Line);
				}
			else o->oSolidLine(spts+i);
			}
		o->UpdateRect(rec, false);
		break;
		}
}
