/** 
 *  Yudit Unicode Editor Source File
 *
 *  GNU Copyright (C) 1997-2006  Gaspar Sinai <gaspar@yudit.org>  
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License, version 2,
 *  dated June 1991. See file COPYYING for details.
 *
 *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "swidget/SButton.h"

#define SS_MGN 2

SButtonListener::SButtonListener(void)
{
}

SButtonListener::~SButtonListener()
{
}
void
SButtonListener::enterWindow (void* source)
{
}

void
SButtonListener::leaveWindow (void* source)
{
}

/**
 * create a button.
 * @param autoacc indicates that the letter preceeded by '&'
 * should contain the accelerator.
 */
SButton::SButton (const SString& string) : label (string) , back("white")
{
  pressed = false;
  inside = false;
  listener = 0;
  button = 0;
  applyAccelerator();
  recalcSize();
  clip (true);
}

SButton::SButton (SIcon* icon, const SString& accel) :
  label ("", icon), back ("white")
{
  pressed = false;
  inside = false;
  listener = 0;
  button = 0;
  addAccelerator (accel);
  recalcSize();
  clip (true);
}

/**
 * create a button.
 * @param autoacc indicates that the letter preceeded by '&'
 * should contain the accelerator.
 */
SButton::SButton (const SString& string, SIcon* _icon) 
  : label (string, _icon), back ("white")
{
  pressed = false;
  inside = false;
  button = 0;
  listener = 0;
  applyAccelerator();
  recalcSize();
  clip (true);
}

/**
 * get the &char from text and apply accel on it.
 */
void
SButton::applyAccelerator()
{
  processLabelText();
}

void 
SButton::processLabelText ()
{
  label.textView.textData.move(STextIndex(0,0));
  /* accelerate &key */
  STextIndex inx = label.textView.textData.find ("&");
  if (inx!=STextIndex(0,0))
  {
    STextIndex at = label.textView.textData.getTextIndex ();
    label.textView.textData.remove (inx);
    SString orig = label.textView.textData.getText (inx, at);
    if (addAccelerator (orig))
    {
      label.textView.textData.underline (inx);
    }
  }
  label.textView.textData.fireEvent();
}

bool
SButton::addAccelerator(const SString& orig)
{
  SString upper = orig;
  SString lower = orig;
  upper.upper ();
  lower.lower ();

  int id0 = getButtonID (upper);
  if (id0 < 0)
  {
    fprintf (stderr, "SButton::applyAccelerator no id for '%*.*s'.\n",
        SSARGS (upper));
    return false;
  }
  int id1 = getButtonID (lower);
  if (id1 < 0)
  {
    fprintf (stderr, "SButton::applyAccelerator no id for '%*.*s'.\n",
        SSARGS (lower));
    return false;
  }
  /* ctrl */
  addAccelerator ((SWindowListener::SKey)id0, true, false, false);
  addAccelerator ((SWindowListener::SKey)id1, true, false, false);

  /* alt */
  addAccelerator ((SWindowListener::SKey)id0, false, false, true);
  addAccelerator ((SWindowListener::SKey)id1, false, false, true);

  /* alt-ctrl */
  addAccelerator ((SWindowListener::SKey)id0, true, false, true);
  addAccelerator ((SWindowListener::SKey)id1, true, false, true);

  return true;
}

SButton::~SButton ()
{
}

void
SButton::redraw(SWindow* w, int x, int y,
     unsigned int width ,unsigned int height)
{
  clip(true);
  label.redraw (w, x, y, width, height);
  clip(false);
  border.redraw (w, x, y, width, height);
  clip(true);
}

/**
 * The pointer entered the button.
 */
void
SButton::enterWindow (SWindow* w)
{
  if (listener) listener->enterWindow (this);
}

/**
 * The pointer left the button.
 */
void
SButton::leaveWindow (SWindow* w)
{
  if (listener) listener->leaveWindow (this);
}

void
SButton::resize (const SDimension& _size)
{
  SPanel::resize (_size);
  border.resize (_size);

  SDimension ds = getSize() - (border.getBorderSize() * 2);

  SLocation dl = SLocation (
     border.getBorderSize().width,
     border.getBorderSize().height);
  label.move (dl);
  label.resize (ds);
}

void
SButton::move (const SLocation& loc)
{
  SPanel::move (loc);
}

void
SButton::recalcSize()
{
  SDimension db = border.getBorderSize();
  SDimension dl = label.getPreferredSize();
  preferredSize = (db *2 ) + dl;
  label.move (SLocation (db.width, db.height));
}

void
SButton::setFontSize (double fontSize)
{
  label.setFontSize (fontSize);
  recalcSize();
}

void
SButton::setFont (const SString& font, double fontSize)
{
  label.setFont(font, fontSize);
  recalcSize();
}

void
SButton::setForeground (const SColor& fg)
{
  label.setForeground (fg, fg);
}

void
SButton::setForeground (const SColor& lrfg, const SColor& rlfg)
{
  label.setForeground (lrfg, rlfg);
}

void
SButton::setBackground (const SColor& bg)
{
  back = bg;
  SPanel::setBackground(bg);
  border.setBackground (bg);
  label.setBackground (bg);
  window->redraw (true, 0, 0, getSize().width, getSize().height);
}

void
SButton::setButtonBackground (const SColor& bg)
{
  back = bg;
  SPanel::setBackground(bg);
  label.setBackground (bg);
  window->redraw (true, 0, 0, getSize().width, getSize().height);
}

/**
 * Turn clipping at the border on and off.
 * @param on is true if we turn on clipping.
 */
void
SButton::clip (bool on)
{
  if (!on)
  {
    window->removeClippingArea ();
    return;
  }
  window->setClippingArea (
       (int) border.getBorderSize().width ,
       (int) border.getBorderSize().height,
       size.width - 2 * border.getBorderSize().width,
       size.height - 2 * border.getBorderSize().height);
}


/**
 * called when the accelerator key combination is pressed 
 */
void
SButton::acceleratorPressed (const SAccelerator& a)
{
  if (!pressed)
  {
    pressed = true;
    inside = true;
    button = -1;
    changed ();
  }
}

void
SButton::acceleratorReleased (const SAccelerator& a)
{
  if (pressed)
  {
    pressed = false;
    inside = false;
    button = -1;
    changed ();
    if (listener)
    {
      listener->buttonPressed(this, &a);
    }
  }
}

void
SButton::buttonPressed (SWindow * w, int _button, int x, int y)
{
  if (!pressed)
  {
    pressed = true;
    inside = true;
    button = _button;
    changed ();
  }
}

void
SButton::buttonReleased (SWindow * w, int _button, int x, int y)
{
  if (button != _button)
  {
    return;
  }
  bool ins;
  if (x >= 0 && y >= 0 && x < (int) getSize().width 
     && y < (int) getSize().height)
  {
    ins = true;
  } 
  else
  {
    ins = false;
  }
  if (ins != inside)
  {
    inside = ins;
    changed ();
  }
  bool callb = false;
  /* call callback if pressed and inside */
  if (pressed && inside)
  {
    callb = true;
  }
  pressed = false;
  inside = false;
  changed ();
  if (callb && listener)
  {
    listener->buttonPressed(this, 0);
  }
}

void
SButton::buttonDragged (SWindow * w, int button, int x, int y)
{
  bool ins;
  if (x >= 0 && y >= 0 
      && x < (int) getSize().width && y < (int) getSize().height)
  {
    ins = true;
  } 
  else
  {
    ins = false;
  }
  if (ins != inside)
  {
    inside = ins;
    changed ();
  }
}

void
SButton::changed ()
{
  if (pressed && inside)
  {
    SPanel::setBackground(back.darker());
    label.setBackground (back.darker());
  }
  else
  {
    SPanel::setBackground(back);
    label.setBackground (back);
  }

  window->redraw (true, 0, 0, getSize().width, getSize().height);
  // commented out because of double buffer   
  // window->clear (0, 0, getSize().width, getSize().height);
  // label.redraw (window, 0, 0, 
  // getSize().width, getSize().height);
}

void
SButton::setButtonListener (SButtonListener* l)
{
  listener = l;
}

void
SButton::addAccelerator (SWindowListener::SKey k, bool ctrl, 
          bool shift, bool meta)
{
  window->addAccelerator (SAccelerator ((int)k, 
         (int)ctrl, (int) shift, (int) meta), this);
}

void
SButton::setIcon (SIcon* icon)
{
  label.setIcon (icon);
  window->redraw (true, 0, 0, getSize().width, getSize().height);
  // commented out for the above
  // window->clear (0, 0, getSize().width, getSize().height);
  // label.redraw (window, 0, 0, 
  //     getSize().width, getSize().height);
}
void
SButton::setText (const SString& text)
{
  label.setText (text);
  processLabelText ();
  recalcSize();
  window->redraw (true, 0, 0, getSize().width, getSize().height);
  // commented out for the above
  // window->clear (0, 0, getSize().width, getSize().height);
  // label.redraw (window, 0, 0, 
  //     getSize().width, getSize().height);
}

void
SButton::setAlignment (SAlignment _alignment)
{
  label.setAlignment (_alignment);
  window->redraw (true, 0, 0, getSize().width, getSize().height);
}
