//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 <qnamespace.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#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;
}



