/****************************************************************************/
/*  xmDrawing.h - Xm++ DM graphics header file - (05/05/1992) 02/17/1993    */
/****************************************************************************/
/*                                                                          */
/*   Copyright (c) 1992, 1993 Bernhard Strassl                              */
/*       Vienna User Interface Group                                        */
/*       Institute for Applied Computer Science and Information Systems     */
/*       University of Vienna, Austria                                      */
/*                                                                          */
/*   See file COPYRIGHT in this directory for details. If this file is      */
/*   missing please mail to xmpp@ani.univie.ac.at                           */
/****************************************************************************/

#ifndef XmDrawing_included
#define XmDrawing_included 1

#include "xmObject.h"

typedef enum gprShape { GPR_DOT, GPR_PLINE, GPR_RECT, GPR_POLYGON, GPR_CIRCLE, GPR_ELLIPSE, GPR_TEXT };
typedef enum gprColor { GPR_WHITE, GPR_BLACK, GPR_RED, GPR_GREEN, GPR_BLUE, GPR_YELLOW };
typedef enum gprFill  { GPR_NONE, GPR_SOLID, GPR_LGRAY, GPR_DGRAY };
typedef enum gprAlign { GPR_BEGINNING, GPR_CENTER, GPR_END };


#define GPR_MAX_COLORS 6
#define GPR_DEFAULT_FONT "fixed"

struct gprPoint
{
    short x;
	short y;

	gprPoint()					{ x = y = 0; }
	gprPoint(int nx, int ny)	{ x = nx; y = ny; }
	gprPoint(gprPoint& p)		{ x = p.x; y = p.y; }
};

struct gprDrawInfo;
struct gprImageInfo;

struct gprData
{
    gprShape shape;
    int linewidth;
    gprPoint linestyle;    /* x - on, y - off percent */
    gprColor lineColor;
    gprColor fillColor;
    gprFill linePattern;
    gprFill fillPattern;
    int numdesc;
    gprPoint* descr;
	char* text;
	char* fontName;
	gprAlign hTextAlign;
	gprAlign vTextAlign;
	gprDrawInfo* drawInfo;
	gprImageInfo* imageInfo;
};

#undef XmDrawing
class ostream;

class DrawPrim : public XmRootClass
{
friend class XmDrawing;
friend class CiObject;
friend class XmCiWorld;
friend class Dot;
friend class PolyLine;
friend class Line;
friend class Polygon;
friend class Rectangle;
friend class Circle;
friend class Ellipse;
friend class Text;
	gprData* data;
	XmDrawing* disp;

	DrawPrim(gprShape, int, gprColor, gprFill);
	DrawPrim(gprData*);
	virtual ~DrawPrim();

	virtual int maxpoints();
	void copyData(gprData*);
	void changeFlags(unsigned int, bool);
public:
	DrawPrim* addPoint(int, int);
	DrawPrim* setPoints(int, ...);
	DrawPrim* setPoint(int, int, int);

	DrawPrim* setOrigin(int, int);
	DrawPrim* setExtent(int, int);
	DrawPrim* setCorner(int, int);

	DrawPrim* setText(char*, char* = NULL);
	DrawPrim* setFont(char*);

	DrawPrim* lineWidth(int lw)					{ data->linewidth = lw; return(this); }
	DrawPrim* lineStyle(int on, int off = 0)	{ data->linestyle.x = on; data->linestyle.y = ((off) ? off : 100 - on); return(this); }
	DrawPrim* lineColor(gprColor c)				{ data->lineColor = c; return(this); }
	DrawPrim* fillColor(gprColor c)				{ data->fillColor = c; return(this); }
	DrawPrim* linePattern(gprFill f)			{ data->linePattern = f; return(this); }
	DrawPrim* fillPattern(gprFill f)			{ data->fillPattern = f; return(this); }
	DrawPrim* textHorzAlign(gprAlign a)			{ data->hTextAlign = a; return(this); }
	DrawPrim* textVertAlign(gprAlign a)			{ data->vTextAlign = a; return(this); }

	DrawPrim* setFlags(unsigned int f)			{ changeFlags(f, TRUE); return(this); }
	DrawPrim* clearFlags(unsigned int f)		{ changeFlags(f, FALSE); return(this); }

	bool containsPoint(gprPoint p);
	gprPoint pointAt(int i)	{ gprPoint p; p = data->descr[0]; p.x = p.y = 0; return(data->numdesc > i ? data->descr[i] : p); }

	gprPoint origin()		{ return(data->descr[0]); }
	gprPoint extent()		{ gprPoint p; p = data->descr[0]; p.x = p.y = 0; return(data->numdesc > 1 ? data->descr[1] : p); }
	gprPoint corner()		{ gprPoint p, p1; p = data->descr[0]; p1 = extent(); p.x += p1.x; p.y += p1.y; return(p); }
	gprPoint center()		{ gprPoint p, p1; p = data->descr[0]; p1 = extent(); p.x += p1.x / 2; p.y += p1.y / 2; return(p); }

	char* getText()			{ return(data->text); }
	char* getFontName()		{ return(data->fontName); }

	bool hide();
	bool show();
	bool update();

	virtual void selectedAt(int, int)	{ }

	void dumpOn(ostream&);
};

#ifndef GPR_DEFAULT_COLOR
#define GPR_DEFAULT_COLOR GPR_BLACK
#endif

#ifndef GPR_DEFAULT_FILL
#define GPR_DEFAULT_FILL GPR_NONE
#endif

class Dot : public DrawPrim
{
public:
	Dot(int, int, int = 1, gprColor = GPR_DEFAULT_COLOR, gprFill = GPR_DEFAULT_FILL);

};

class PolyLine : public DrawPrim
{
public:
	PolyLine(int = 1, gprColor = GPR_DEFAULT_COLOR, gprFill = GPR_DEFAULT_FILL);

	void setFill(gprFill);
	int maxpoints();
};

class Line : public PolyLine
{
public:
	Line(int, int, int, int, int = 1, gprColor = GPR_DEFAULT_COLOR, gprFill = GPR_DEFAULT_FILL);

	int maxpoints();
};

class Polygon : public DrawPrim
{
public:
	Polygon(int = 1, gprColor = GPR_DEFAULT_COLOR, gprFill = GPR_DEFAULT_FILL);

	int maxpoints();
};

class Rectangle : public DrawPrim
{
public:
	Rectangle(int, int, int, int, int = 1, gprColor = GPR_DEFAULT_COLOR, gprFill = GPR_DEFAULT_FILL);
};

class Circle : public DrawPrim
{
public:
	Circle(int, int, int, int = 1, gprColor = GPR_DEFAULT_COLOR, gprFill = GPR_DEFAULT_FILL);
};

class Ellipse : public DrawPrim
{
public:
	Ellipse(int, int, int, int, int = 1, gprColor = GPR_DEFAULT_COLOR, gprFill = GPR_DEFAULT_FILL);
};

class Text : public DrawPrim
{
public:
	Text(int, int, char*, char* = NULL, int = 0, int = 0, gprColor = GPR_DEFAULT_COLOR);
};


struct gprDrawInfo
{
	unsigned int flags;
	unsigned int status;
	gprPoint dimensions[2];
	gprPoint hotspots[10];
	int index;
};

struct gprImageInfo
{
//...
};

#define SELECT 0x0001
#define RESIZE_TOP_LEFT 0x0002
#define RESIZE_TOP_CENTER 0x0004
#define RESIZE_TOP_RIGHT 0x0008
#define RESIZE_CENTER_LEFT 0x0010
#define RESIZE_CENTER_RIGHT 0x020
#define RESIZE_BOTTOM_LEFT 0x040
#define RESIZE_BOTTOM_CENTER 0x080
#define RESIZE_BOTTOM_RIGHT 0x0100
#define RESIZE_ANY 0x01FE
#define MOVE 0x0200

#define SELECTED 0x01
#define PRIMARY_SELECTION 0x02

#define MARKER_SIZE 6
#define OUTLINE_WIDTH 2
#define MAX_DRAWING_PRIMS 100

#include <sys/time.h>

class XmDrawing : public XmControl
{
friend void sysAlarm(int);
friend void awHandler(Widget, XtPointer, XEvent*, Boolean*);
friend void sysMouseMove(Widget, XtPointer, XEvent*, Boolean*);
friend void DrawPrim::changeFlags(unsigned int, bool);
friend bool DrawPrim::show();
friend class XmCiWorld; //::userMove(DrawPrim*, int, int, int, int);

	DrawPrim* prims[MAX_DRAWING_PRIMS];
	gprData* drawInfo[MAX_DRAWING_PRIMS];
	gprData* dragInfo[MAX_DRAWING_PRIMS];
	int selDepend[MAX_DRAWING_PRIMS];
	int primCount, dragCount, prSelection;
	struct itimerval timer;
	bool buttonDown, primLock, wasOverriding;
	int dragTarget, desigPrim, curLinePt;
	bool* dragControl;
	unsigned int defaultFlags, desigOp;
	gprPoint curLoc;
	int moveGrid, resizeGrid;
	char* defaultFont, * curFont;
	XFontStruct* curFontInfo;
	unsigned long valmask;
	XGCValues gcvals;
	GC gc, dgc;

	void redraw(void*);
	void mouseClick(void*);
	void mouseAlarm();

	bool mouseSelect(int, int, bool, bool);
	void beginDrag();
	bool drag(XEvent*);
	void endDrag();

	bool* checkDragTarget(int, int);

	char* defaultCallback()						{ return(NULL); }
	ctrlType controlType()						{ return(Drawing); };
	bool createControl(XmControlPane*);

	bool changeGc();
	unsigned long convertColor(gprColor);
	void setLineWidth(int);
	void setLineStyle(gprPoint&);
	void setLinePattern(gprFill);
	void setFillPattern(gprFill);
	void setForeColor(gprColor);
	void setBackColor(gprColor);
	void draw(int, bool = FALSE);
	void fill(int);
	void drawText(int);
	void drawAttribs(int);

	int findPrim(DrawPrim*);
	void updatePrim(int);
	gprData* drawingDataFor(DrawPrim*, int = -1);
	void changeFlags(int, unsigned int, bool, bool = TRUE);
	void changeStatus(int, unsigned int, bool, bool = TRUE);
	bool getStatus(int ndx, unsigned int st)		{ return((drawInfo[ndx]->drawInfo)->status & st ? TRUE : FALSE); }
	bool checkSelDepend(int, int);
	void alignToGrid(int, gprData*);
public:
	XmDrawing(char*, int = 0, int = 0, int = 0, int = 0, xmStyle = XmSautovscroll);
	~XmDrawing();

	void setGrid(int n)								{ moveGrid = n; }
	int getGrid()									{ return(moveGrid); }
	void setBackground(gprColor);
	void setDefaultFont(char* fn)					{ defaultFont = fn; }
	void setDefaultFlags(unsigned int f)			{ defaultFlags = f; }
	bool getStatus(DrawPrim* p, unsigned int st)	{ return(getStatus(findPrim(p), st)); }

	DrawPrim* add(DrawPrim*);
	DrawPrim* remove(DrawPrim*);
	void toForeground(DrawPrim*);
	void toBackground(DrawPrim*);

	void select(DrawPrim* p, bool pr = TRUE, bool rp = TRUE)		{ int n; changeStatus((n = findPrim(p)), (pr ? PRIMARY_SELECTION : SELECTED), TRUE, rp); prSelection = (pr ? n : prSelection); }
	void deSelect(DrawPrim* p, bool rp = TRUE)						{ int n; changeStatus((n = findPrim(p)), SELECTED, FALSE, rp); prSelection = (n == prSelection ? -1 : prSelection); }
	bool isSelected(DrawPrim*);
	bool makeSelDepend(DrawPrim*, DrawPrim*);
	int selectedCount();
	int draggedPoint()								{ return(curLinePt); }
	DrawPrim* curDragTarget()						{ return(dragTarget >= 0 ? prims[dragTarget] : NULL); }
	void clearSelections(bool = TRUE);
	void setFlags(DrawPrim* p, unsigned int f)		{ changeFlags(findPrim(p), f, TRUE); }
	void clearFlags(DrawPrim* p, unsigned int f)	{ changeFlags(findPrim(p), f, FALSE); }
	unsigned int defaultFlagsFor(DrawPrim*);

	void updatePrim(DrawPrim* p)					{ updatePrim(findPrim(p)); }

	void refresh(bool = FALSE);
	virtual void clearAll(bool = FALSE);

	virtual bool userClick(int, int)							{ return(TRUE); }
	virtual bool userSelect(DrawPrim*, int, int)				{ return(TRUE); }
	virtual bool userMove(DrawPrim*, int, int, int, int)		{ return(TRUE); }
	virtual bool userResize(DrawPrim*, int, int)				{ return(TRUE); }
	virtual void userActivate(DrawPrim*, int, int)				{ }
	virtual bool userDragEnter(DrawPrim*, DrawPrim**, bool*)	{ return(FALSE); }

	void bell(bool = FALSE);
};

#endif

