#include <cdk_int.h>

/*
 * $Author: tom $
 * $Date: 2005/03/08 21:48:30 $
 * $Revision: 1.17 $
 */

#define limitFocusIndex(screen, value) \
 	(((value) >= (screen)->objectCount || (value) < 0) \
	 ? 0 \
	 : (value))

static int getFocusIndex (CDKSCREEN *screen)
{
   int result = limitFocusIndex (screen, screen->objectFocus);

   return result;
}

static void setFocusIndex (CDKSCREEN *screen, int value)
{
   screen->objectFocus = limitFocusIndex (screen, value);
}

static void unsetFocus (CDKOBJS *obj)
{
   curs_set (0);
   if (obj != 0)
   {
      HasFocusObj (obj) = FALSE;
      UnfocusObj (obj);
   }
}

static void setFocus (CDKOBJS *obj)
{
   if (obj != 0)
   {
      HasFocusObj (obj) = TRUE;
      FocusObj (obj);
   }
   curs_set (1);
}

static CDKOBJS *switchFocus (CDKOBJS *newobj, CDKOBJS *oldobj)
{
   if (oldobj != newobj)
   {
      unsetFocus (oldobj);
      setFocus (newobj);
   }
   return newobj;
}

static CDKOBJS *handleMenu (CDKSCREEN *screen, CDKOBJS *menu, CDKOBJS *oldobj)
{
   bool done = FALSE;
   CDKOBJS *newobj;

   switchFocus (menu, oldobj);
   while (!done)
   {
      int key = getcCDKObject (menu);

      switch (key)
      {
      case KEY_TAB:
	 {
	    done = TRUE;
	    break;
	 }
      case KEY_ESC:
	 {
	    /* cleanup the menu */
	    injectCDKMenu ((CDKMENU *) menu, key);
	    done = TRUE;
	    break;
	 }
      default:
	 {
	    int m = injectCDKMenu ((CDKMENU *) menu, key);
	    done = (m >= 0);
	    break;
	 }
      }
   }
   if ((newobj = getCDKFocusCurrent (screen)) == 0)
      newobj = setCDKFocusNext (screen);

   return switchFocus (newobj, menu);
}

/*
 * Save data in widgets on a screen
 */
static void saveDataCDKScreen (CDKSCREEN *screen)
{
   int i;

   for (i = 0; i < screen->objectCount; ++i)
      SaveDataObj (screen->object[i]);
}

/*
 * Refresh data in widgets on a screen
 */
static void refreshDataCDKScreen (CDKSCREEN *screen)
{
   int i;

   for (i = 0; i < screen->objectCount; ++i)
      RefreshDataObj (screen->object[i]);
}


/*
 * ======================================================================
 * Public Interface
 */

void resetCDKScreen (CDKSCREEN *screen)
{
   refreshDataCDKScreen (screen);
}

void exitOKCDKScreen (CDKSCREEN *screen)
{
   screen->exitStatus = CDKSCREEN_EXITOK;
}

void exitCancelCDKScreen (CDKSCREEN *screen)
{
   screen->exitStatus = CDKSCREEN_EXITCANCEL;
}

void exitOKCDKScreenOf (CDKOBJS *obj)
{
   exitOKCDKScreen (obj->screen);
}

void exitCancelCDKScreenOf (CDKOBJS *obj)
{
   exitCancelCDKScreen (obj->screen);
}

void resetCDKScreenOf (CDKOBJS *obj)
{
   resetCDKScreen (obj->screen);
}

/*
 * Returns the object on which the focus lies.
 */
CDKOBJS *getCDKFocusCurrent (CDKSCREEN *screen)
{
   CDKOBJS *result = 0;
   int n = screen->objectFocus;

   if (n >= 0 && n < screen->objectCount)
      result = screen->object[n];
   return result;
}

/*
 * Set focus to the next object, returning it.
 */
CDKOBJS *setCDKFocusNext (CDKSCREEN *screen)
{
   CDKOBJS *result = 0;
   CDKOBJS *curobj;
   int n = getFocusIndex (screen);
   int first = n;

   for (;;)
   {
      if (++n >= screen->objectCount)
	 n = 0;
      curobj = screen->object[n];
      if (curobj != 0 && AcceptsFocusObj (curobj))
      {
	 result = curobj;
	 break;
      }
      else
      {
	 if (n == first)
	 {
	    break;
	 }
      }
   }

   setFocusIndex (screen, (result != 0) ? n : -1);
   return result;
}

/*
 * Set focus to the previous object, returning it.
 */
CDKOBJS *setCDKFocusPrevious (CDKSCREEN *screen)
{
   CDKOBJS *result = 0;
   CDKOBJS *curobj;
   int n = getFocusIndex (screen);
   int first = n;

   for (;;)
   {
      if (--n < 0)
	 n = screen->objectCount - 1;
      curobj = screen->object[n];
      if (curobj != 0 && AcceptsFocusObj (curobj))
      {
	 result = curobj;
	 break;
      }
      else if (n == first)
      {
	 break;
      }
   }

   setFocusIndex (screen, (result != 0) ? n : -1);
   return result;
}

/*
 * Traverse the widgets on a screen
 */
int traverseCDKScreen (CDKSCREEN *screen)
{
   CDKOBJS *curobj;

   setFocusIndex (screen, screen->objectCount - 1);
   curobj = switchFocus (setCDKFocusNext (screen), 0);
   if (curobj == 0)
      return 0;

   refreshDataCDKScreen (screen);

   screen->exitStatus = CDKSCREEN_NOEXIT;

   while ((curobj != 0) && (screen->exitStatus == CDKSCREEN_NOEXIT))
   {
      int key;
      key = getcCDKObject (curobj);

      switch (key)
      {
      case KEY_BTAB:
	 {
	    curobj = switchFocus (setCDKFocusPrevious (screen), curobj);
	    break;
	 }
      case KEY_TAB:
	 {
	    curobj = switchFocus (setCDKFocusNext (screen), curobj);
	    break;
	 }
      case KEY_F(10):
	 {
	    /* save data and exit */
	    exitOKCDKScreen (screen);
	    break;
	 }
      case CTRL('X'):
	 {
	    exitCancelCDKScreen (screen);
	    break;
	 }
      case CTRL('R'):
	 {
	    /* reset data to defaults */
	    resetCDKScreen (screen);
	    setFocus (curobj);
	    break;
	 }
      case CDK_REFRESH:
	 {
	    /* redraw screen */
	    refreshCDKScreen (screen);
	    setFocus (curobj);
	    break;
	 }
      case KEY_ESC:
	 {
	    /* find and enable drop down menu */
	    int j;

	    for (j = 0; j < screen->objectCount; ++j)
	       if (ObjTypeOf (screen->object[j]) == vMENU)
	       {
		  curobj = handleMenu (screen, screen->object[j], curobj);
		  break;
	       }
	    break;
	 }
      default:
	 {
	    InjectObj (curobj, key);
	    break;
	 }
      }
   }

   if (screen->exitStatus == CDKSCREEN_EXITOK)
   {
      saveDataCDKScreen (screen);
      return 1;
   }
   else
      return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1