/* choosebutton.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2001-2015 Ralf Hoffmann.
 * You can contact me at: ralf@boomerangsworld.de
 *   or http://www.boomerangsworld.de/worker
 *
 * 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 St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "choosebutton.h"
#include "awindow.h"
#include "guielement.h"
#include "drawablecont.hh"

const char *ChooseButton::type="ChooseButton";

ChooseButton::~ChooseButton()
{
  destroy();
  if(label!=NULL) _freesafe(label);
}

ChooseButton::ChooseButton(AGUIX *taguix,int tx,int ty,int width,int height,bool tstate,
                           const char *tlabel,int tlabelpos,int tdata):GUIElement(taguix)
{
  _x=tx;
  _y=ty;
  if ( width > 0 ) _w = width;
  if ( height > 0 ) _h = height;
  this->data=tdata;
  this->state=tstate;
  this->instate=tstate;
  this->label=dupstring(tlabel);
  this->labelpos=tlabelpos;
  cross=false;
  font=NULL;

  calcLabelGeometry();
  calcRealPos(tx,ty);
  laststate=tstate;
  lwin = 0;
  setCanHandleFocus();
  setAcceptFocus( true );

  labelcolor = _aguix->getFaces().getColor( "default-fg" );
}

ChooseButton::ChooseButton(AGUIX *taguix,int tx,int ty,bool tstate,
                           const char *tlabel,int tlabelpos,int tdata):GUIElement(taguix)
{
  int th;

  th = taguix->getCharHeight() + 6;

  _x=tx;
  _y=ty;
  _w = th;
  _h = th;
  this->data=tdata;
  this->state=tstate;
  this->instate=tstate;
  this->label=dupstring(tlabel);
  this->labelpos=tlabelpos;
  cross=false;
  font=NULL;

  calcLabelGeometry();
  calcRealPos(tx,ty);
  laststate=tstate;
  lwin = 0;
  setCanHandleFocus();
  setAcceptFocus( true );

  labelcolor = _aguix->getFaces().getColor( "default-fg" );
}

const char *ChooseButton::getLabel() const
{
  return label;
}

void ChooseButton::setLabel(const char *new_text)
{
  if(label!=NULL) _freesafe(label);
  label=dupstring(new_text);
  updateWin();
  lredraw();
}

void ChooseButton::setLabelColor(int color)
{
    if ( color < _aguix->getNumberOfColorsForType( AGUIXColor::USER_COLOR ) && color >= 0 ) {
        this->labelcolor = color;
        lredraw();
    }
}

int ChooseButton::getLabelColor() const
{
  return labelcolor;
}

void ChooseButton::setLabelPos(int pos)
{
  this->labelpos=pos;
  updateWin();
  lredraw();
}

int ChooseButton::getLabelPos() const
{
  return labelpos;
}

int ChooseButton::getData() const
{
  return data;
}

void ChooseButton::setData(int tdata)
{
  this->data=tdata;
}

void ChooseButton::redraw()
{
  cbredraw();
  lredraw();
}

void ChooseButton::cbredraw()
{
  if ( isCreated() == false ) return;
  if ( win == 0 ) return;

  prepareBG();
  
  _aguix->ClearWin(win);

  _aguix->drawBorder( win, false, 0, 0, _w, _h, 0 );

  int dx1,dy1;
  if(state==true) {
    _aguix->setFG( _aguix->getFaceCol_default_fg() );
    dy1=_h/2;
    dx1=_w/4;
    int dy2=_h*3/4;
    int dx2=_w/2;
    _aguix->DrawLine(win,dx1,dy1,dx2,dy2);
    dy1=_h/4;
    dx1=_w*3/4;
    _aguix->DrawLine(win,dx2,dy2,dx1,dy1);
  }
  
  if ( ( getAcceptFocus() == true ) && ( getHasFocus() == true ) ) {
    if ( strlen( label ) < 1 ) {
      _aguix->setDottedFG( _aguix->getFaceCol_default_fg() );
      _aguix->DrawDottedRectangle( win, 1, 1, _w - 2, _h - 2 );
    }
  }

  _aguix->Flush();
}

void ChooseButton::lredraw()
{
  if ( isCreated() == false ) return;
  if ( lwin == 0 ) return;
  _aguix->SetWindowBG(lwin,_parent->getBG());
  _aguix->ClearWin(lwin);

  DrawableCont dc( _aguix, lwin );
  _aguix->DrawText( dc, font, label, 0, 0, labelcolor );

  if ( ( getAcceptFocus() == true ) && ( getHasFocus() == true ) ) {
    if ( strlen( label ) > 0 ) {
      _aguix->setDottedFG( _aguix->getFaceCol_default_fg() );
      _aguix->DrawDottedRectangle( lwin, 0, 0, getLabelWidth(), getLabelHeight() );
    }
  }

  _aguix->Flush();
}

void ChooseButton::flush()
{
}

void ChooseButton::setState(bool tstate)
{
  this->state=tstate;
  cbredraw();
}

bool ChooseButton::getState() const
{
  return state;
}

bool ChooseButton::isInside(int px,int py) const
{
  if((px>0)&&(px<=_w)) {
    if((py>0)&&(py<=_h)) return true;
  }
  return false;
}

bool ChooseButton::handleMessage(XEvent *E,Message *msg)
{
    //bool returnvalue;

  if ( isCreated() == false ) return false;

  GUIElement::handleMessage( E, msg );

  //returnvalue=false;
  if((msg->type==ButtonPress)||(msg->type==ButtonRelease)) {
    if ( msg->window == win || msg->window == lwin ) {
      takeFocus();
      if(msg->type==ButtonPress) {
	AGMessage *agmsg = AGUIX_allocAGMessage();
	agmsg->type=AG_CHOOSEPRESSED;
	agmsg->choose.button=this;
	laststate=state;
	if(state==false) {
	  setState(true);
	  instate=true;
	} else {
	  setState(false);
	  instate=false;
	}
	cross=true;
	agmsg->choose.state=state;
        msgAndCB( std::unique_ptr<AGMessage>( agmsg ) );
	//returnvalue=true;
      } else {
        if(state==instate) {
          AGMessage *agmsg = AGUIX_allocAGMessage();
          agmsg->type=AG_CHOOSERELEASED;
          agmsg->choose.button=this;
          agmsg->choose.state=state;
          msgAndCB( std::unique_ptr<AGMessage>( agmsg ) );
          agmsg = AGUIX_allocAGMessage();
          agmsg->type=AG_CHOOSECLICKED;
          agmsg->choose.button=this;
          agmsg->choose.state=state;
          msgAndCB( std::unique_ptr<AGMessage>( agmsg ) );
          laststate=state;
        }
        cross=false;
      }
    }
  } else if(msg->type==EnterNotify) {
    if ( msg->window == win || msg->window == lwin ) {
      if(cross==true) {
	if(instate!=state) {
	  setState(instate);
	}
      }
    }
  } else if(msg->type==LeaveNotify) {
    if ( msg->window == win || msg->window == lwin ) {
      if(cross==true) {
	setState(laststate);
      }
    }
  } else if ( msg->type == KeyPress ) {
    if ( msg->key == XK_space ) {
      if ( ( getAcceptFocus() == true ) && ( getHasFocus() == true ) ) {
	if ( isVisible() == true ) {
	  if ( _parent->isTopParent( msg->window ) == true ) {
	    setState( ( state == true ) ? false : true );
	    AGMessage *agmsg;
	    agmsg = AGUIX_allocAGMessage();
	    agmsg->type=AG_CHOOSECLICKED;
	    agmsg->choose.button=this;
	    agmsg->choose.state=state;
            msgAndCB( std::unique_ptr<AGMessage>( agmsg ) );
	    laststate=state;
	    cross=false;
	  }
	}
      }
    }
  }
  if(msg->type==Expose) {
    if(msg->window==win) cbredraw();
    else if(msg->window==lwin) lredraw();
  }
//  return returnvalue;
  return false; // see cyclebutton.cc
}

void ChooseButton::resize(int tw,int th)
{
  if ( ( tw < 1 ) || ( th < 1 ) ) return;
  _w=tw;
  _h=th;
  updateWin();
  if ( isCreated() == true ) _parent->resizeSubWin( win, tw, th );
}

void ChooseButton::move(int nx,int ny)
{
  _x=nx;
  _y=ny;
  calcRealPos(_x,_y);
  updateWin();
  if ( isCreated() == true ) _parent->moveSubWin( win, _x, _y );
}

int ChooseButton::getLabelWidth() const
{
  if(label!=NULL) {
    int l;
    l= _aguix->getTextWidth( label, font );
    l += 2;
    return l;
  } else return 0;
}

int ChooseButton::getLabelHeight() const
{
  if(font==NULL) return ( _aguix->getCharHeight() + 2 );
  else return ( font->getCharHeight() + 2 );
}

void ChooseButton::calcLabelGeometry()
{
  double f1;
  lw=getLabelWidth();
  lh=getLabelHeight();
  switch(labelpos) {
    case LABEL_LEFT:
      lx=_x-5-lw;
      f1=_y+_h/2-lh/2;
      ly=(int)f1;
      break;
    case LABEL_RIGHT:
      lx=_x+_w+5;
      f1=_y+_h/2-lh/2;
      ly=(int)f1;
      break;
    case LABEL_TOP:
      ly=_y-5-lh;
      f1=_x+_w/2-lw/2;
      lx=(int)f1;
      break;
    case LABEL_BOTTOM:
      ly=_y+_h+5;
      f1=_x+_w/2-lw/2;
      lx=(int)f1;
      break;
  }
  if(lw<1) lw=1;
}

void ChooseButton::updateWin()
{
  calcLabelGeometry();
  if ( isCreated() == true ) {
    _parent->moveSubWin(lwin,lx,ly);
    _parent->resizeSubWin(lwin,lw,lh);
  }
}

int ChooseButton::setFont( const char *fontname )
{
  font=_aguix->getFont(fontname);
  if(font==NULL) return -1;
  updateWin();
  return 0;
}

const char *ChooseButton::getType() const
{
  return type;
}

bool ChooseButton::isType(const char *qtype) const
{
  if(strcmp(type,qtype)==0) return true;
  return false;
}

bool ChooseButton::isParent(Window child) const
{
  if ( isCreated() == true ) {
    if(child==win) return true;
    if(child==lwin) return true;
  }
  return false;
}

int ChooseButton::getX() const
{
  return ((_x<lx)?_x:lx);
}

int ChooseButton::getY() const
{
  return ((_y<ly)?_y:ly);
}

int ChooseButton::getWidth() const
{
  if((labelpos==LABEL_TOP)||(labelpos==LABEL_BOTTOM)) {
    return ((_w>lw)?_w:lw);
  }
  return lw+_w+5;
}

int ChooseButton::getHeight() const
{
  if((labelpos==LABEL_LEFT)||(labelpos==LABEL_RIGHT)) {
    return ((_h>lh)?_h:lh);
  }
  return lh+_h+5;
}

void ChooseButton::calcRealPos(int tx,int ty)
{
  switch(labelpos) {
    case LABEL_TOP:
    case LABEL_BOTTOM:
      if(lw<_w) {
        _x=tx;
      } else {
        double b=tx+lw/2-_w/2;
        _x=(int)b;
      }
      break;
    case LABEL_RIGHT:
      _x=tx;
      break;
    default: // LABEL_LEFT
      _x=tx+5+lw;
  }
  switch(labelpos) {
    case LABEL_TOP:
      _y=ty+5+lh;
      break;
    case LABEL_BOTTOM:
      _y=ty;
      break;
    default: // LABEL_LEFT & LABEL_RIGHT
      if(lh<_h) {
        _y=ty;
      } else {
        double b=ty+lh/2-_h/2;
        _y=(int)b;
      }
  }
}

void ChooseButton::toBack()
{
  if ( isCreated() == false ) return;
  GUIElement::toBack();
  _aguix->WindowtoBack( lwin );
}

void ChooseButton::toFront()
{
  if ( isCreated() == false ) return;
  GUIElement::toFront();
  _aguix->WindowtoFront( lwin );
}

void ChooseButton::hide()
{
  if ( isCreated() == false ) return;
  GUIElement::hide();
  _parent->hide( lwin );
}

void ChooseButton::show()
{
  if ( isCreated() == false ) return;
  GUIElement::show();
  _parent->show( lwin );
}

void ChooseButton::doCreateStuff()
{
  GUIElement::doCreateStuff();
  calcLabelGeometry();
  if ( lwin == 0 ) {
    lwin = _parent->getSubWindow( 0, lx, ly, lw, lh );
  }
}

void ChooseButton::doDestroyStuff()
{
  if ( lwin != 0 ) {
    _parent->removeSubWin( lwin );
    lwin = 0;
  }
  GUIElement::doDestroyStuff();
}

void ChooseButton::prepareBG( bool force )
{
  if ( isCreated() == false ) return;
  if ( win == 0 ) return;

  _aguix->SetWindowBG( win, _aguix->getFaces().getAGUIXColor( "button-bg" ) );
  _aguix->SetWindowBG( lwin, _parent->getBG() );
}
