/******************************************************************************
Copyright (C) 2006 Matteo Lucarelli

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
******************************************************************************/
/*	Fl_Synoptic is a widget to realize a synoptical panel
 *	Date: 19/07/2006
 *	Author: Matteo Lucarelli
 *
 *	// to add to a fltk window (here wMain)
 * 	Fl_Synoptic* syn=new Fl_Synoptic(x,y,w,h);
 *	wMain->add(syn);
 *
 *      // to make it the resizable widget
 *	wMain->resizable(syn);
 *
 *      All coordinates are from upper left corner
 *      of the synPanel in down-right direction
 *
 *      Items are draw from the first to the last
 *      then the last is on top of the view
 *
******************************************************************/
// NEED: `fltk-config --ldflags --use-images`
// NEED: dynaList class

#if !defined(FL_SYNOPTIC_H_INCLUDED)
#define FL_SYNOPTIC_H_INCLUDED

#include <stdlib.h>
#include <string.h>
#include <FL/Fl.H>
#include <FL/Fl_Box.H>
#include <FL/fl_draw.H>
#include <FL/Fl_Shared_Image.H>
#include "dynaList.h"

// defines for items type
#define FLS_POINT	0	// p(x1,y1)
#define FLS_LINE	1	// p1(x1,y1)-p2(x2,y2)
#define FLS_RECT	2	// center(x1,y1) width=x2 height=y2
#define FLS_TRIANGLE	3	// p1(x1,y1)-p2(x2,y2)-p3(x3,y3)
#define FLS_QUAD	4	// p1(x1,y1)-p2(x2,y2)-p3(x3,y3)-p4(x4,y4)
#define FLS_ELLIPSE	5	// center(x1,y1) h-axe=x2 v-axe=y2
#define FLS_IMAGE	10	// p1(x1,y1) is the top-left.
#define FLS_TEXT	11	// center(x1,y1) width=x2 height=y2, face=x3, dim=x4

// to catch mouse DOWN define a global function:
// void MouseCb(int ID,const void* pClient)
// and pass MouseCb to the constructor
// MouseCb is called only for PUSH on a identified ID
typedef void flsMouse_cb(int ID,const void* pClient); 

class Fl_Synoptic : public Fl_Box
{
public:
	// Fl_Synptic inherited all metods from Fl_Box
	Fl_Synoptic(int x,int y,int w,int h,flsMouse_cb *mouseCb=NULL,const void* pClient=NULL);
	virtual ~Fl_Synoptic();
	
	// color uses the fltk enumeration
	void setBgColor(Fl_Color col);
	
	// offset is from upper-left corner
	// in upper (y) left (x) direction
	void setBgOffset(int x,int y);
	
	// load an image file as backgroud
	bool loadBackground(const char* file,int xOffset=0,int yOffset=0);
	
	// add a new graphic item
	// for images and text use the dedicated function
	// returned value is the item ID
	// not all the items types needs all the coordinates
	int addItem(
		int type,		// type of item (rect,point,ecc)
		Fl_Color fcolor,	// fill color, -1 means don't fill)
		Fl_Color bcolor,        // border color, -1 means no border)
		int lineWidth,          // in pixel, for border or FLS_LINE
		int lineStyle,          // fltk styles, for border or FLS_LINE
		bool visible,		// start visible or hidden
		int x1,			// x position or P1
		int y1,			// y position or P1
		int x2=-1,              // width or P2
		int y2=-1,              // height or P2
		int x3=-1,              // P3
		int y3=-1,              // P3
		int x4=-1,              // P4
		int y4=-1               // P4
	);
	
	// returned value is the item ID	
	// width and height are used to resize (both 0 means no resize)
	// rotate clockwise 0:0°,1:45°,2:90°,3:135°,4:180°,5:225°,6:270°,7:315°
	int addImage(const char* file,int x,int y,bool visible=true,int rotate=0,int width=0,int height=0);
	
	// add another instance of a yet-loaded image (ID)
	// no more RAM is required
	int addImageCopy(int ID,int x,int y,bool visible=true);
	
	// returned value is the item ID
	// text can use the fltk symbols (@-nxxx)
	// string is limited to 1024 caracters
	int addText(const char* text,int x,int y,int face=FL_COURIER,int size=10,
	            Fl_Color color=FL_BLACK,       // font color
	            Fl_Color lcolor=(Fl_Color)-1,  // label color (-1 is no label)
	            int lw=-1,int lh=-1,           // the box dim (-1 is auto)
	            bool visible=true);
	
	// WARNING: this changes all the following ID
	bool delItem(int ID);

	// -1 means don't modify
	bool moveItem(int ID,int x1,int y1=-1,int x2=-1,int y2=-1,int x3=-1,int y3=-1,int x4=-1,int y4=-1);

	bool setItemVisible(int ID,bool visible);		// true/false
	bool setItemFillColor(int ID,Fl_Color fcolor);		// (Fl_Color)-1-1 = transparent, else use fltk style
	bool setItemBorderColor(int ID,Fl_Color bcolor);	// (Fl_Color)-1-1 = transparent, else use fltk style
	bool setItemLineWidth(int ID,int lineWidth);		// 0 is the thinest (still visible)
	bool setItemLineStyle(int ID,int lineStyle);		// fltk defined styles	
	
	bool getItemVisible(int ID);
	
	// group are used to change property whith "one shot"
	// items between beginGroup and endGroup are grouped
	bool setGroupVisible(int ID,bool visible);
	bool setGroupFillColor(int ID,Fl_Color fcolor);
	bool setGroupBorderColor(int ID,Fl_Color bcolor);
	bool setGroupLineWidth(int ID,int lineWidth);
	bool setGroupLineStyle(int ID,int lineStyle);
	
	// both beginGroup and evndGroup returns the group ID
	// call this to begin a group 
	int beginGroup();
	// call this to end a group 
	int endGroup();

	// return the ID of the item in x,y - 0 means "no items"
	int getItem(int x,int y);
	
	// move the object one place to 
	// the bottom of the list (top view)
	// WARNING: this changes all the following ID
	bool moveFront(int ID);
	
	// move the object one place to the top of the list 
	// WARNING: this changes all the following ID
	bool moveBack(int ID);
	
protected:

	void controlGroup(int ID);
	
	// a small function to rotate images
	Fl_Shared_Image *rotate_image(Fl_Shared_Image *img,int mode);

	flsMouse_cb *m_MouseCb;
	const void* m_pClient;

	void draw();
	int handle(int event) ;
	
	// the background image
	//Fl_Shared_Image *m_Img;
	Fl_Image *m_Img;

	// the background offset
	int m_xOffset;
	int m_yOffset;
	
	// the background color
	Fl_Color m_bgColor;
	
	// the list item structure
	struct item{
		bool visible;
		int type;
		Fl_Color fcolor;
		Fl_Color bcolor;
		int lineWidth;
		int lineStyle;
		Fl_Image *image;
		char* text;
		int x1;
		int y1;
		int x2;
		int y2;
		int x3;
		int y3;
		int x4;
		int y4;
	};
	
	// the group item structure
	struct group{
		int first;
		int last;
	};
	
	dynaList itemList;
	dynaList groupList;
	
	struct group *m_currGroup;
};

#endif // !defined(FL_SYNOPTIC_H_INCLUDED)