#include <cdk_int.h>
#include "button.h"
#include <limits.h>

/*
 * $Author: tom $
 * $Date: 2004/08/30 00:11:34 $
 * $Revision: 1.29 $
 */

DeclareCDKObjects (BUTTON, Button, setCdk, Int);

/*
 * This creates a button widget.
 */
CDKBUTTON *newCDKButton (CDKSCREEN * cdkscreen, int xplace, int yplace, char
			 *text, tButtonCallback callback, boolean Box,
			 boolean shadow)
{
   /* Maintain the button information. */
   CDKBUTTON *button	= 0;
   int parentWidth      = getmaxx (cdkscreen->window);
   int parentHeight     = getmaxy (cdkscreen->window);
   int boxWidth         = 0;
   int boxHeight;
   int xpos = xplace;
   int ypos = yplace;

   if ((button = newCDKObject(CDKBUTTON, &my_funcs)) == 0)
      return (0);

   setCDKButtonBox (button, Box);
   boxHeight = 1 + 2 * BorderOf(button);

   /* Translate the char * to a chtype. */
   button->info = char2Chtype (text, &button->infoLen, &button->infoPos);
   boxWidth = MAXIMUM (boxWidth, button->infoLen) + 2 * BorderOf(button);

   /* Create the string alignments. */
   button->infoPos = justifyString (boxWidth - 2 * BorderOf(button),
				    button->infoLen, button->infoPos);

   /*
    * Make sure we didn't extend beyond the dimensions of the window.
    */
   boxWidth = (boxWidth > parentWidth ? parentWidth : boxWidth);
   boxHeight = (boxHeight > parentHeight ? parentHeight : boxHeight);

   /* Rejustify the x and y positions if we need to. */
   alignxy (cdkscreen->window, &xpos, &ypos, boxWidth, boxHeight);

   /* Create the button. */
   ScreenOf (button)            = cdkscreen;
   ObjOf (button)->fn           = &my_funcs;
   button->parent               = cdkscreen->window;
   button->win                  = newwin (boxHeight, boxWidth, ypos, xpos);
   button->shadowWin            = (WINDOW *) NULL;
   button->xpos                 = xpos;
   button->ypos                 = ypos;
   button->boxWidth             = boxWidth;
   button->boxHeight            = boxHeight;
   button->callback             = callback;
   ObjOf (button)->inputWindow  = button->win;
   ObjOf (button)->acceptsFocus = TRUE;
   initExitType(button);
   button->shadow               = shadow;

   /* Is the window NULL? */
   if (button->win == (WINDOW *) NULL)
   {
      destroyCDKObject (button);
      return (0);
   }

   keypad (button->win, TRUE);

   /* If a shadow was requested, then create the shadow window. */
   if (shadow)
      button->shadowWin = newwin (boxHeight, boxWidth, ypos + 1, xpos + 1);

   /* Register this baby. */
   registerCDKObject (cdkscreen, vBUTTON, button);

   /* Return the button pointer. */
   return (button);
}

/*
 * This was added for the builder.
 */
int activateCDKButton (CDKBUTTON * button, chtype * actions)
{
   chtype input = 0;
   int ret;

   drawCDKButton (button, ObjOf (button)->box);

   /* Check if actions is null. */
   if (actions == 0)
   {
      for (;;)
      {
	 /* Get the input. */
	 input = getcCDKObject (ObjOf(button));

	 /* Inject the character into the widget. */
	 ret = injectCDKButton(button, input);
	 if (button->exitType != vEARLY_EXIT)
	 {
	    return ret;
	 }
      }
   }
   else
   {
      int length = chlen (actions);
      int x = 0;

      /* Inject each character one at a time. */
      for (x=0; x < length; x++)
      {
	 ret = injectCDKButton(button, actions[x]);
	 if (button->exitType != vEARLY_EXIT)
	 {
	    return ret;
	 }
      }
   }

   /* Set the exit type and exit. */
   setExitType(button, 0);
   return -1;
}

/*
 * This sets multiple attributes of the widget.
 */
void setCDKButton (CDKBUTTON * button, char *mesg, boolean Box)
{
   setCDKButtonMessage (button, mesg);
   setCDKButtonBox (button, Box);
}

/*
 * This sets the information within the button.
 */
void setCDKButtonMessage (CDKBUTTON * button, char *info)
{
   /* Clean out the old message. */
   freeChtype (button->info);
   button->infoPos = 0;
   button->infoLen = 0;

   /* Copy in the new message. */

   button->info = char2Chtype (info, &button->infoLen, &button->infoPos);
   button->infoPos = justifyString (button->boxWidth - 2 * BorderOf(button),
				    button->infoLen, button->infoPos);

   /* Redraw the button widget. */
   eraseCDKButton (button);
   drawCDKButton (button, ObjOf (button)->box);
}

chtype *getCDKButtonMessage (CDKBUTTON * button)
{
   return button->info;
}

/*
 * This sets the box flag for the button widget.
 */
void setCDKButtonBox (CDKBUTTON * button, boolean Box)
{
   ObjOf (button)->box = Box;
   ObjOf (button)->borderSize = Box ? 1 : 0;
}

boolean getCDKButtonBox (CDKBUTTON * button)
{
   return ObjOf (button)->box;
}

/*
 * This sets the background attribute of the widget.
 */
static void _setBKattrButton (CDKOBJS * object, chtype attrib)
{
   if (object != 0)
   {
      CDKBUTTON *widget = (CDKBUTTON *) object;

      wbkgd (widget->win, attrib);
   }
}

static void drawCDKButtonText (CDKBUTTON * button)
{
   int boxWidth = button->boxWidth;
   int i;

   /* Draw in the message. */

   for (i = 0; i < boxWidth - 2 * BorderOf(button); i++)
   {
      chtype c;
      int pos = button->infoPos;
      int len = button->infoLen;

      if (i >= pos && (i - pos) < len)
	 c = button->info[i - pos];
      else
	 c = ' ';

      if (HasFocusObj (button))
      {
	 c = A_REVERSE | CharOf(c);
      }

      mvwaddch (button->win, BorderOf(button), i + BorderOf(button), c);
   }
}

/*
 * This draws the button widget.
 */
static void _drawCDKButton (CDKOBJS * object, boolean Box GCC_UNUSED)
{
   CDKBUTTON *button = (CDKBUTTON *) object;

   /* Is there a shadow? */
   if (button->shadowWin != (WINDOW *) NULL)
   {
      drawShadow (button->shadowWin);
   }

   /* Box the widget if asked. */
   if (ObjOf (button)->box)
   {
      drawObjBox (button->win, ObjOf(button));
   }
   drawCDKButtonText (button);
   refreshCDKWindow (button->win);
}

/*
 * This erases the button widget.
 */
static void _eraseCDKButton (CDKOBJS * object)
{
   if (validCDKObject (object))
   {
      CDKBUTTON *button = (CDKBUTTON *) object;

      eraseCursesWindow (button->win);
      eraseCursesWindow (button->shadowWin);
   }
}

/*
 * This moves the button field to the given location.
 */
static void _moveCDKButton (CDKOBJS *object,
			    int xplace,
			    int yplace,
			    boolean relative,
			    boolean refresh_flag)
{
   CDKBUTTON *button = (CDKBUTTON *) object;
   int currentX = getbegx (button->win);
   int currentY = getbegy (button->win);
   int xpos = xplace;
   int ypos = yplace;
   int xdiff = 0;
   int ydiff = 0;

   /*
    * If this is a relative move, then we will adjust where we want
    * to move to.
    */
   if (relative)
   {
      xpos = getbegx (button->win) + xplace;
      ypos = getbegy (button->win) + yplace;
   }

   /* Adjust the window if we need to. */
   alignxy (WindowOf (button), &xpos, &ypos, button->boxWidth,
	    button->boxHeight);

   /* Get the difference. */
   xdiff = currentX - xpos;
   ydiff = currentY - ypos;

   /* Move the window to the new location. */
   moveCursesWindow(button->win, -xdiff, -ydiff);
   moveCursesWindow(button->shadowWin, -xdiff, -ydiff);

   /* Touch the windows so they 'move'. */
   refreshCDKWindow (WindowOf (button));

   /* Redraw the window, if they asked for it. */
   if (refresh_flag)
   {
      drawCDKButton (button, ObjOf (button)->box);
   }
}

/*
 * This allows the user to use the cursor keys to adjust the
 * position of the widget.
 */
void positionCDKButton (CDKBUTTON * button)
{
   /* Declare some variables. */
   int origX = getbegx (button->win);
   int origY = getbegy (button->win);
   chtype key = (chtype) NULL;

   /* Let them move the widget around until they hit return. */
   while (key != KEY_ENTER)
   {
      key = getcCDKObject (ObjOf(button));
      if (key == KEY_UP || key == '8')
      {
	 if (getbegy (button->win) > 0)
	 {
	    moveCDKButton (button, 0, -1, TRUE, TRUE);
	 }
	 else
	 {
	    Beep ();
	 }
      }
      else if (key == KEY_DOWN || key == '2')
      {
	 if (getbegy (button->win) + getmaxy (button->win) <
	     getmaxy (WindowOf (button)) - 1)
	 {
	    moveCDKButton (button, 0, 1, TRUE, TRUE);
	 }
	 else
	 {
	    Beep ();
	 }
      }
      else if (key == KEY_LEFT || key == '4')
      {
	 if (getbegx (button->win) > 0)
	 {
	    moveCDKButton (button, -1, 0, TRUE, TRUE);
	 }
	 else
	 {
	    Beep ();
	 }
      }
      else if (key == KEY_RIGHT || key == '6')
      {
	 if (getbegx (button->win) + getmaxx (button->win) < getmaxx
	     (WindowOf (button)) - 1)
	 {
	    moveCDKButton (button, 1, 0, TRUE, TRUE);
	 }
	 else
	 {
	    Beep ();
	 }
      }
      else if (key == '7')
      {
	 if (getbegy (button->win) > 0 && getbegx (button->win) > 0)
	 {
	    moveCDKButton (button, -1, -1, TRUE, TRUE);
	 }
	 else
	 {
	    Beep ();
	 }
      }
      else if (key == '9')
      {
	 if (getbegx (button->win) + getmaxx (button->win) < getmaxx
	     (WindowOf (button)) - 1 &&
	     getbegy (button->win) > 0)
	 {
	    moveCDKButton (button, 1, -1, TRUE, TRUE);
	 }
	 else
	 {
	    Beep ();
	 }
      }
      else if (key == '1')
      {
	 if (getbegx (button->win) > 0 && getbegx (button->win) +
	     getmaxx (button->win) < getmaxx (WindowOf (button)) - 1)
	 {
	    moveCDKButton (button, -1, 1, TRUE, TRUE);
	 }
	 else
	 {
	    Beep ();
	 }
      }
      else if (key == '3')
      {
	 if (getbegx (button->win) + getmaxx (button->win) <
	     getmaxx (WindowOf (button)) - 1
	     && getbegy (button->win) + getmaxy (button->win) <
	     getmaxy (WindowOf (button)) - 1)
	 {
	    moveCDKButton (button, 1, 1, TRUE, TRUE);
	 }
	 else
	 {
	    Beep ();
	 }
      }
      else if (key == '5')
      {
	 moveCDKButton (button, CENTER, CENTER, FALSE, TRUE);
      }
      else if (key == 't')
      {
	 moveCDKButton (button, getbegx (button->win), TOP, FALSE, TRUE);
      }
      else if (key == 'b')
      {
	 moveCDKButton (button, getbegx (button->win), BOTTOM, FALSE, TRUE);
      }
      else if (key == 'l')
      {
	 moveCDKButton (button, LEFT, getbegy (button->win), FALSE, TRUE);
      }
      else if (key == 'r')
      {
	 moveCDKButton (button, RIGHT, getbegy (button->win), FALSE, TRUE);
      }
      else if (key == 'c')
      {
	 moveCDKButton (button, CENTER, getbegy (button->win), FALSE, TRUE);
      }
      else if (key == 'C')
      {
	 moveCDKButton (button, getbegx (button->win), CENTER, FALSE, TRUE);
      }
      else if (key == CDK_REFRESH)
      {
	 eraseCDKScreen (ScreenOf (button));
	 refreshCDKScreen (ScreenOf (button));
      }
      else if (key == KEY_ESC)
      {
	 moveCDKButton (button, origX, origY, FALSE, TRUE);
      }
      else if (key != KEY_ENTER)
      {
	 Beep ();
      }
   }
}

/*
 * This destroys the button object pointer.
 */
static void _destroyCDKButton (CDKOBJS * object)
{
   if (object != 0)
   {
      CDKBUTTON *button = (CDKBUTTON *) object;

      /* Free up the character pointers. */
      freeChtype (button->info);

      /* Free up the window pointers. */
      deleteCursesWindow (button->shadowWin);
      deleteCursesWindow (button->win);

      /* Unregister the object. */
      unregisterCDKObject (vBUTTON, button);
   }
}

/*
 * This injects a single character into the widget.
 */
static int _injectCDKButton (CDKOBJS * object, chtype input)
{
   CDKBUTTON *button = (CDKBUTTON *) object;
   int ret = unknownInt;
   bool complete = FALSE;

   setExitType(button, 0);

   /* Check a predefined binding. */
   if (checkCDKObjectBind (vBUTTON, button, input) != 0)
   {
      checkEarlyExit(button);
      complete = TRUE;
   }
   else
   {
      switch (input)
      {
      case KEY_ESC :
	 setExitType(button, input);
	 complete = TRUE;
	 break;

      case KEY_ENTER: case SPACE:
	 if (button->callback)
	    button->callback (button);
	 setExitType(button, KEY_ENTER);
	 ret = 0;
	 complete = TRUE;
	 break;

      case CDK_REFRESH:
	 eraseCDKScreen (ScreenOf (button));
	 refreshCDKScreen (ScreenOf (button));
	 break;

      default:
	 Beep ();
	 break;
      }
   }

   if (!complete) {
      setExitType(button, 0);
   }

   ResultOf(button).valueInt = ret;
   return (ret != unknownInt);
}

static void _focusCDKButton (CDKOBJS * object)
{
   CDKBUTTON *button = (CDKBUTTON *) object;

   drawCDKButtonText (button);
   wrefresh (button->win);
}

static void _unfocusCDKButton (CDKOBJS * object)
{
   CDKBUTTON *button = (CDKBUTTON *) object;

   drawCDKButtonText (button);
   wrefresh (button->win);
}

dummyRefreshData(Button)

dummySaveData(Button)


syntax highlighted by Code2HTML, v. 0.9.1