#include "Fl_Synoptic.h"
Fl_Synoptic::Fl_Synoptic(int x,int y,int w,int h,flsMouse_cb *mouseCb,const void* pClient):Fl_Box(x,y,w,h,0)
{
m_Img=NULL;
m_MouseCb=mouseCb;
m_pClient=pClient;
fl_register_images();
m_currGroup=NULL;
}
Fl_Synoptic::~Fl_Synoptic()
{
if (m_Img) delete m_Img;
struct item* currItem;
while (itemList.moveLast()){
currItem=((item*)(itemList.getCurrentPayload()));
if (currItem->image) delete (currItem->image);
if (currItem->text) delete (currItem->text);
delete currItem;
}
struct group* currGroup;
while (groupList.moveLast()){
currGroup=((group*)(groupList.getCurrentPayload()));
delete currGroup;
}
}
Fl_Shared_Image *Fl_Synoptic::rotate_image(Fl_Shared_Image *img,int mode)
{
int w_rot,h_rot,d;
double dxx,dyy,dxy,dyx,sx,sy;
int rh=(int)(0.707*img->h()+0.5);
int rw=(int)(0.707*img->w()+0.5);
switch (mode){
case 1:
dxx=0.707; dxy=-0.707; dyx=0.707 ; dyy=0.707 ;
sx=rh; sy=0;
w_rot=rw+rh;
h_rot=w_rot;
break;
case 3:
dxx=-0.707; dxy=-0.707; dyx=0.707 ; dyy=-0.707 ;
sx=rh+rw-1; sy=rh;
w_rot=rw+rh;
h_rot=w_rot;
break;
case 5:
dxx=-0.707; dxy=0.707; dyx=-0.707 ; dyy=-0.707 ;
sx=rw; sy=rw+rh-1;
w_rot=rw+rh;
h_rot=w_rot;
break;
case 7:
dxx=0.707; dxy=0.707; dyx=-0.707 ; dyy=+0.707 ;
sx=0; sy=rw-1;
w_rot=rw+rh;
h_rot=w_rot;
break;
case 0:
w_rot=img->w();
h_rot=img->h();
break;
case 4:
dxx=-1 ; dxy=0 ; dyx=0 ; dyy=-1 ;
w_rot=img->w();
h_rot=img->h();
sx=w_rot-1; sy=h_rot-1;
break;
case 2:
dxx=0 ; dxy=-1 ; dyx=1 ; dyy=0 ;
w_rot=img->h();
h_rot=img->w();
sx=w_rot-1;
sy=0;
break;
case 6:
dxx=0 ; dxy=1 ; dyx=-1 ; dyy=0 ;
w_rot=img->h();
h_rot=img->w();
sx=0;
sy=h_rot-1;
break;
}
Fl_Shared_Image *rot = (Fl_Shared_Image*)img->copy(w_rot,h_rot);
if (mode==0) return rot;
d=img->d();
int cx,cy,o,rx,ry;
const uchar* imgp=(const uchar*)img->data()[0];
uchar* rotp=(uchar *)rot->data()[0];
memset(rotp,0,(w_rot*h_rot*d));
for (cx=0;cx<img->w();cx++){
for (cy=0;cy<img->h();cy++){
rx=(int)(sx+cx*dxx+cy*dxy);
ry=(int)(sy+cx*dyx+cy*dyy);
for (o=0;o<d;o++)
*(rotp+(rx+ry*w_rot)*d+o)=*(imgp+(cx+cy*img->w())*d+o);
}
}
if ((mode==2)||(mode==4)||(mode==6)) return rot;
uchar* pp;
bool unt;
for (cx=1;cx<w_rot-1;cx++){
for (cy=1;cy<h_rot-1;cy++){
unt=true;
pp=rotp+(cx+cy*w_rot)*d;
for (o=0;o<d;o++) if (*(pp+o)!=0) unt=false;
if (unt) {
for (o=0;o<d;o++){
if ((*(pp+o+d)!=0)&&(*(pp+o-d)!=0))
*(pp+o)=(uchar)(((double)*(pp+o-d)+(double)*(pp+o+d))/2);
}
}
}
}
return rot;
}
void Fl_Synoptic::controlGroup(int ID)
{
if (m_currGroup){
m_currGroup->last=ID;
if (m_currGroup->first==0)
m_currGroup->first=ID;
}
}
int Fl_Synoptic::handle(int event)
{
if ((event==FL_PUSH)&&(m_MouseCb)){
int it=getItem(Fl::event_x()-x(),Fl::event_y()-y());
if (it!=0) m_MouseCb(it,m_pClient);
}
}
void Fl_Synoptic::draw()
{
fl_draw_box(FL_BORDER_BOX,x(),y(),w(),h(),m_bgColor);
if (m_Img) m_Img->draw(x()+1,y()+1,w()-2,h()-2,m_xOffset,m_yOffset);
fl_push_clip(x()+1,y()+1,w()-2,h()-2);
itemList.moveFirst();
struct item* currItem;
if ( itemList.getCount()!=0 ) do{
currItem=(item*)itemList.getCurrentPayload();
if ((!currItem->visible)||((currItem->fcolor==-1)&&(currItem->bcolor==-1))) continue;
switch (currItem->type)
{
case FLS_POINT:
if (currItem->fcolor!=-1) fl_color(currItem->fcolor);
if (currItem->bcolor!=-1) fl_color(currItem->bcolor);
fl_point(currItem->x1+x(),currItem->y1+y());
break;
case FLS_LINE:
if (currItem->fcolor!=-1) fl_color(currItem->fcolor);
if (currItem->bcolor!=-1) fl_color(currItem->bcolor);
fl_line_style(currItem->lineStyle,currItem->lineWidth);
fl_line(currItem->x1+x(),currItem->y1+y(),currItem->x2+x(),currItem->y2+y());
break;
case FLS_RECT:
if (currItem->fcolor!=(Fl_Color)-1){
fl_color(currItem->fcolor);
fl_rectf(currItem->x1+x()-currItem->x2/2,currItem->y1+y()-currItem->y2/2,
currItem->x2,currItem->y2);
}
if (currItem->bcolor!=(Fl_Color)-1){
fl_color(currItem->bcolor);
fl_line_style(currItem->lineStyle,currItem->lineWidth);
fl_rect(currItem->x1+x()-currItem->x2/2,currItem->y1+y()-currItem->y2/2,
currItem->x2,currItem->y2);
}
break;
case FLS_TRIANGLE:
if (currItem->fcolor!=-1){
fl_color(currItem->fcolor);
fl_polygon(currItem->x1+x(),currItem->y1+y(),
currItem->x2+x(),currItem->y2+y(),
currItem->x3+x(),currItem->y3+y());
}
if (currItem->bcolor!=-1){
fl_color(currItem->bcolor);
fl_line_style(currItem->lineStyle,currItem->lineWidth);
fl_loop(currItem->x1+x(),currItem->y1+y(),
currItem->x2+x(),currItem->y2+y(),
currItem->x3+x(),currItem->y3+y());
}
break;
case FLS_QUAD:
fl_push_matrix();
fl_rotate(90);
if (currItem->fcolor!=-1){
fl_color(currItem->fcolor);
fl_polygon(currItem->x1+x(),currItem->y1+y(),
currItem->x2+x(),currItem->y2+y(),
currItem->x3+x(),currItem->y3+y(),
currItem->x4+x(),currItem->y4+y());
}
if (currItem->bcolor!=-1){
fl_color(currItem->bcolor);
fl_line_style(currItem->lineStyle,currItem->lineWidth);
fl_loop(currItem->x1+x(),currItem->y1+y(),
currItem->x2+x(),currItem->y2+y(),
currItem->x3+x(),currItem->y3+y(),
currItem->x4+x(),currItem->y4+y());
}
fl_pop_matrix();
break;
case FLS_ELLIPSE:
if (currItem->fcolor!=-1){
fl_color(currItem->fcolor);
fl_pie(currItem->x1+x()-currItem->x2/2,currItem->y1+y()-currItem->y2/2,
currItem->x2,currItem->y2,0,360);
}
if (currItem->bcolor!=-1){
fl_color(currItem->bcolor);
fl_line_style(currItem->lineStyle,currItem->lineWidth);
fl_arc(currItem->x1+x()-currItem->x2/2,currItem->y1+y()-currItem->y2/2,
currItem->x2,currItem->y2,0,300);
}
break;
case FLS_IMAGE:
currItem->image->draw(currItem->x1+x(),currItem->y1+y());
break;
case FLS_TEXT:
if (currItem->bcolor!=-1){
fl_color(currItem->bcolor);
fl_rectf(currItem->x1+x()-currItem->x2/2,currItem->y1+y()-currItem->y2/2,
currItem->x2,currItem->y2);
}
fl_color(currItem->fcolor);
fl_font(currItem->x3,currItem->y3);
fl_draw(currItem->text,currItem->x1+x()-currItem->x2/2,currItem->y1+y()-currItem->y2/2,
currItem->x2,currItem->y2,FL_ALIGN_CENTER);
break;
}
}while (itemList.moveNext());
fl_pop_clip();
fl_line_style(0);
}
bool Fl_Synoptic::loadBackground(const char* file,int xOffset,int yOffset)
{
setBgOffset(xOffset,yOffset);
Fl_Shared_Image* si=Fl_Shared_Image::get(file);
if (si){
if (m_Img) delete m_Img;
m_Img=si->copy();
si->release();
redraw();
return true;
}
return false;
}
void Fl_Synoptic::setBgColor(Fl_Color col)
{
m_bgColor=col;
}
void Fl_Synoptic::setBgOffset(int xOffset,int yOffset)
{
m_xOffset=xOffset;
m_yOffset=yOffset;
}
int Fl_Synoptic::addItem(int type,Fl_Color fcolor,Fl_Color bcolor,int lineWidth,int lineStyle,
bool visible,int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4)
{
struct item *newItem=new item();
newItem->visible=visible;
newItem->type=type;
newItem->fcolor=fcolor;
newItem->bcolor=bcolor;
newItem->lineWidth=lineWidth;
newItem->lineStyle=lineStyle;
newItem->image=NULL;
newItem->text=NULL;
newItem->x1=x1;
newItem->y1=y1;
newItem->x2=x2;
newItem->y2=y2;
newItem->x3=x3;
newItem->y3=y3;
newItem->x4=x4;
newItem->y4=y4;
itemList.addNewLast(newItem);
controlGroup(itemList.getCount());
if (visible) redraw();
return itemList.getCount();
}
int Fl_Synoptic::addImage(const char* file,int x,int y,bool visible,int rotate,int width,int height)
{
Fl_Shared_Image* si1=Fl_Shared_Image::get(file);
if (!si1) return 0;
if ((rotate<0)||(rotate>7)) rotate=0;
Fl_Shared_Image *si2=rotate_image(si1,rotate);
struct item *newItem=new item();
newItem->visible=visible;
newItem->type=FLS_IMAGE;
newItem->fcolor=(Fl_Color)0;
newItem->bcolor=(Fl_Color)0;
if ((width!=0)||(height!=0)) newItem->image=si2->copy(width,height);
else newItem->image=si2->copy();
newItem->x1=x;
newItem->y1=y;
itemList.addNewLast(newItem);
si1->release();
si2->release();
controlGroup(itemList.getCount());
if (visible) redraw();
return itemList.getCount();
}
int Fl_Synoptic::addImageCopy(int ID,int x,int y,bool visible)
{
if (!itemList.moveTo(ID)) return 0;
struct item *it=(item*)(itemList.getCurrentPayload());
if (it->type!=FLS_IMAGE) return 0;
struct item *newItem=new item();
newItem->visible=visible;
newItem->type=FLS_IMAGE;
newItem->fcolor=(Fl_Color)0;
newItem->bcolor=(Fl_Color)0;
newItem->image=it->image;
newItem->x1=x;
newItem->y1=y;
itemList.addNewLast(newItem);
controlGroup(itemList.getCount());
if (visible) redraw();
return itemList.getCount();
}
int Fl_Synoptic::addText(const char* text,int x,int y,int face,int size,Fl_Color color,Fl_Color lcolor,int lw,int lh,bool visible)
{
struct item *newItem=new item();
newItem->text = new char[strlen(text)];
strcpy(newItem->text,text);
newItem->visible=visible;
newItem->type=FLS_TEXT;
newItem->fcolor=color;
newItem->bcolor=lcolor;
newItem->x1=x;
newItem->y1=y;
if ((lw==-1)||(lh==-1)){
int tw,th;
fl_font(face,size);
fl_measure(text,tw,th);
if (lw==-1) lw=tw;
if (lh==-1) lh=th;
}
newItem->x2=lw;
newItem->y2=lh;
newItem->x3=face;
newItem->y3=size;
itemList.addNewLast(newItem);
controlGroup(itemList.getCount());
if (visible) redraw();
return itemList.getCount();
}
bool Fl_Synoptic::delItem(int ID)
{
if (!itemList.moveTo(ID)) return false;
struct item *it=(item*)(itemList.getCurrentPayload());
bool visible=it->visible;
if (it->image) delete (it->image);
if (it->text) delete (it->text);
delete (it);
itemList.delCurrent();
if (visible) redraw();
return true;
}
bool Fl_Synoptic::moveItem(int ID,int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4)
{
if (!itemList.moveTo(ID)) return false;
struct item *it=(item*)(itemList.getCurrentPayload());
if (x1!=-1) it->x1=x1;
if (y1!=-1) it->y1=y1;
if (x2!=-1) it->x2=x2;
if (y2!=-1) it->y2=y2;
if (x3!=-1) it->x3=x3;
if (y3!=-1) it->y3=y3;
if (x4!=-1) it->x4=x4;
if (y4!=-1) it->y4=y4;
if (it->visible) redraw();
return true;
}
bool Fl_Synoptic::getItemVisible(int ID)
{
if (!itemList.moveTo(ID)) return false;
return ((item*)(itemList.getCurrentPayload()))->visible;
}
bool Fl_Synoptic::setItemVisible(int ID,bool visible)
{
if (!itemList.moveTo(ID)) return false;
struct item *it=(item*)(itemList.getCurrentPayload());
if (it->visible!=visible){
it->visible=visible;
redraw();
}
return true;
}
bool Fl_Synoptic::setItemFillColor(int ID,Fl_Color fcolor)
{
if (!itemList.moveTo(ID)) return false;
struct item *it=(item*)(itemList.getCurrentPayload());
it->fcolor=fcolor;
if (it->visible) redraw();
return true;
}
bool Fl_Synoptic::setItemBorderColor(int ID,Fl_Color bcolor)
{
if (!itemList.moveTo(ID)) return false;
struct item *it=(item*)(itemList.getCurrentPayload());
it->bcolor=bcolor;
if (it->visible) redraw();
return true;
}
bool Fl_Synoptic::setItemLineWidth(int ID,int lineWidth)
{
if (!itemList.moveTo(ID)) return false;
struct item *it=(item*)(itemList.getCurrentPayload());
it->lineWidth=lineWidth;
if (it->visible) redraw();
return true;
}
bool Fl_Synoptic::setItemLineStyle(int ID,int lineStyle)
{
if (!itemList.moveTo(ID)) return false;
struct item *it=(item*)(itemList.getCurrentPayload());
it->lineStyle=lineStyle;
if (it->visible) redraw();
return true;
}
int Fl_Synoptic::getItem(int Px,int Py)
{
if (itemList.getCount()==0) return 0;
struct item *it;
int Xmin,Xmax,Ymin,Ymax;
itemList.moveLast();
do{
it=(item*)(itemList.getCurrentPayload());
if ((!it->visible)||((it->fcolor==-1)&&(it->bcolor==-1))) continue;
switch (it->type) {
case FLS_POINT:
if ((it->x1==Px)&&(it->y1==Py))
return itemList.getCurrentIndex();
else continue;
break;
case FLS_LINE:
Xmin=(it->x1<it->x2?it->x1:it->x2);
Xmax=(it->x1>it->x2?it->x1:it->x2);
Ymin=(it->y1<it->y2?it->y1:it->y2);
Ymax=(it->y1>it->y2?it->y1:it->y2);
break;
case FLS_RECT:
case FLS_ELLIPSE:
case FLS_TEXT:
Xmin=it->x1-it->x2/2;
Xmax=it->x1+it->x2/2;
Ymin=it->y1-it->y2/2;
Ymax=it->y1+it->y2/2;
break;
case FLS_TRIANGLE:
Xmin=(it->x1<it->x2?it->x1:it->x2);
Xmin=(it->x3<Xmin?it->x3:Xmin);
Xmax=(it->x1>it->x2?it->x1:it->x2);
Xmax=(it->x3>Xmax?it->x3:Xmax);
Ymin=(it->y1<it->y2?it->y1:it->y2);
Ymin=(it->y3<Ymin?it->y3:Ymin);
Ymax=(it->y1>it->y2?it->y1:it->y2);
Ymax=(it->y3>Ymax?it->y3:Ymax);
break;
case FLS_QUAD:
Xmin=(it->x1<it->x2?it->x1:it->x2);
Xmin=(it->x3<Xmin?it->x3:Xmin);
Xmin=(it->x4<Xmin?it->x4:Xmin);
Xmax=(it->x1>it->x2?it->x1:it->x2);
Xmax=(it->x3>Xmax?it->x3:Xmax);
Xmax=(it->x4>Xmax?it->x4:Xmax);
Ymin=(it->y1<it->y2?it->y1:it->y2);
Ymin=(it->y3<Ymin?it->y3:Ymin);
Ymin=(it->y4<Ymin?it->y4:Ymin);
Ymax=(it->y1>it->y2?it->y1:it->y2);
Ymax=(it->y3>Ymax?it->y3:Ymax);
Ymax=(it->y4>Ymax?it->y4:Ymax);
break;
case FLS_IMAGE:
Xmin=it->x1;
Xmax=it->x1+it->image->w();
Ymin=it->y1;
Ymax=it->y1+it->image->h();
break;
}
if ((Px>=Xmin)&&(Px<=Xmax)&&(Py>=Ymin)&&(Py<=Ymax))
return itemList.getCurrentIndex();
}while (itemList.movePrev());
return 0;
}
int Fl_Synoptic::beginGroup()
{
m_currGroup=new group();
m_currGroup->first=0;
m_currGroup->last=0;
groupList.addNewLast(m_currGroup);
return groupList.getCount();
}
int Fl_Synoptic::endGroup()
{
m_currGroup=NULL;
return groupList.getCount();
}
bool Fl_Synoptic::setGroupVisible(int ID,bool visible)
{
if (!groupList.moveTo(ID)) return false;
struct group *gp=(group*)(groupList.getCurrentPayload());
for(int i=gp->first;i<=gp->last;i++){
if (!itemList.moveTo(i)) continue;
((item*)(itemList.getCurrentPayload()))->visible=visible;
}
redraw();
return true;
}
bool Fl_Synoptic::setGroupFillColor(int ID,Fl_Color fcolor)
{
if (!groupList.moveTo(ID)) return false;
struct group *gp=(group*)(groupList.getCurrentPayload());
for(int i=gp->first;i<=gp->last;i++){
if (!itemList.moveTo(i)) continue;
((item*)(itemList.getCurrentPayload()))->fcolor=fcolor;
}
redraw();
return true;
}
bool Fl_Synoptic::setGroupBorderColor(int ID,Fl_Color bcolor)
{
if (!groupList.moveTo(ID)) return false;
struct group *gp=(group*)(groupList.getCurrentPayload());
for(int i=gp->first;i<=gp->last;i++){
if (!itemList.moveTo(i)) continue;
((item*)(itemList.getCurrentPayload()))->bcolor=bcolor;
}
redraw();
return true;
}
bool Fl_Synoptic::setGroupLineWidth(int ID,int lineWidth)
{
if (!groupList.moveTo(ID)) return false;
struct group *gp=(group*)(groupList.getCurrentPayload());
for(int i=gp->first;i<=gp->last;i++){
if (!itemList.moveTo(i)) continue;
((item*)(itemList.getCurrentPayload()))->lineWidth=lineWidth;
}
redraw();
return true;
}
bool Fl_Synoptic::setGroupLineStyle(int ID,int lineStyle)
{
if (!groupList.moveTo(ID)) return false;
struct group *gp=(group*)(groupList.getCurrentPayload());
for(int i=gp->first;i<=gp->last;i++){
if (!itemList.moveTo(i)) continue;
((item*)(itemList.getCurrentPayload()))->lineStyle=lineStyle;
}
redraw();
return true;
}
bool Fl_Synoptic::moveFront(int ID)
{
if (!itemList.moveTo(ID)) return false;
if (ID==itemList.getCount()) return false;
struct item *it=(item*)(itemList.getCurrentPayload());
itemList.delCurrent();
itemList.moveTo(ID);
itemList.addNewAfterCurrent(it);
redraw();
return true;
}
bool Fl_Synoptic::moveBack(int ID)
{
if (!itemList.moveTo(ID)) return false;
if (ID==1) return false;
struct item *it=(item*)(itemList.getCurrentPayload());
itemList.delCurrent();
itemList.moveTo(ID-1);
itemList.addNewBeforeCurrent(it);
redraw();
return true;
}