[BACK]Return to slider.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / othersrc / dist / cdk

File: [cvs.NetBSD.org] / othersrc / dist / cdk / slider.c (download)

Revision 1.3, Tue Jan 9 18:41:54 2001 UTC (13 years, 11 months ago) by garbled
Branch: MAIN
CVS Tags: HEAD
Changes since 1.2: +2 -3 lines

Fix a problem in these widgets where they uncondititonally set the
exitType to either vEARLY_EXIT, or vESCAPE_HIT when returning from a bound
function.  This had the unfortunate effect that when you hit F2 to refresh
the screen in sushi, it would exit out immediately after refreshing the
screen.

This modification allows the programmer to still create an exit-causing
bound function, by simply setting the exitType in the function, as was likely
intended by the author.  Many thanks to Charles Hannum for helping me figure
this out.

This should fix problems noted by itojun on tech-userlevel with the function
keys.

#include <cdk.h>

/*
 * $Author: garbled $
 * $Date: 2001/01/09 18:41:54 $
 * $Revision: 1.3 $
 */

/*
 * Declare file local prototypes.
 */
static void drawCDKSliderField (CDKSLIDER *slider);

DeclareCDKObjects(my_funcs,Slider);

/*
 * This function creates a slider widget.
 */
CDKSLIDER *newCDKSlider (CDKSCREEN *cdkscreen, int xplace, int yplace, char *title, char *label, chtype filler, int fieldWidth, int start, int low, int high, int inc, int fastInc, boolean Box, boolean shadow)
{
   /* Declare local variables. */
   CDKSLIDER *slider	= newCDKObject(CDKSLIDER, &my_funcs);
   chtype *holder	= 0;
   int parentWidth	= getmaxx(cdkscreen->window);
   int parentHeight	= getmaxy(cdkscreen->window);
   int boxHeight	= 3;
   int boxWidth		= 0;
   int maxWidth		= INT_MIN;
   int horizontalAdjust = 0;
   int xpos		= xplace;
   int ypos		= yplace;
   int highValueLen	= intlen (high);
   char **temp		= 0;
   int x, len, junk, junk2;

   /* Set some basic values of the slider field. */
   slider->label	= 0;
   slider->labelLen	= 0;
   slider->labelWin	= 0;
   slider->titleLines	= 0;

  /*
   * If the fieldWidth is a negative value, the fieldWidth will
   * be COLS-fieldWidth, otherwise, the fieldWidth will be the
   * given width.
   */
   fieldWidth = setWidgetDimension (parentWidth, fieldWidth, 0);

   /* Translate the label char *pointer to a chtype pointer. */
   boxWidth = fieldWidth + highValueLen + 2;
   if (label != 0)
   {
      slider->label	= char2Chtype (label, &slider->labelLen, &junk);
      boxWidth		+= slider->labelLen;
   }

   /* Translate the char * items to chtype * */
   if (title != 0)
   {
      temp = CDKsplitString (title, '\n');
      slider->titleLines = CDKcountStrings (temp);

      /* We need to determine the widest title line. */
      for (x=0; x < slider->titleLines; x++)
      {
	 holder = char2Chtype (temp[x], &len, &junk2);
	 maxWidth = MAXIMUM (maxWidth, len);
	 freeChtype (holder);
      }

      /*
       * If one of the title lines is wider than the field and the label,
       * the box width will expand to accomodate.
       */
       if (maxWidth > boxWidth)
       {
	  horizontalAdjust = (int)((maxWidth - boxWidth) / 2) + 1;
	  boxWidth = maxWidth + 2;
       }

      /* For each line in the title, convert from char * to chtype * */
      for (x=0; x < slider->titleLines; x++)
      {
	 slider->title[x]	= char2Chtype (temp[x], &slider->titleLen[x], &slider->titlePos[x]);
	 slider->titlePos[x]	= justifyString (boxWidth - 2, slider->titleLen[x], slider->titlePos[x]);
      }

      CDKfreeStrings(temp);
   }
   else
   {
      /* No title? Set the required variables. */
      slider->titleLines = 0;
   }
   boxHeight += slider->titleLines;

  /*
   * Make sure we didn't extend beyond the dimensions of the window.
   */
   boxWidth = MINIMUM (boxWidth, parentWidth);
   boxHeight = MINIMUM (boxHeight, parentHeight);
   fieldWidth = (fieldWidth > (boxWidth-slider->labelLen-highValueLen-2) ? (boxWidth-slider->labelLen-highValueLen-2) : fieldWidth);

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

   /* Make the slider window. */
   slider->win = newwin (boxHeight + !!shadow, boxWidth + !!shadow, ypos, xpos);

   /* Is the main window null??? */
   if (slider->win == 0)
   {
      freeChtype (slider->label);
      free (slider);

      /* Return a null pointer. */
      return (0);
   }
   keypad (slider->win, TRUE);
   leaveok (slider->win, TRUE);

   if (slider->titleLines > 0)
   {
      /* Make the title window. */
      slider->titleWin = subwin (slider->win,
				slider->titleLines, boxWidth - 2,
				ypos + 1, xpos + 1);
   }

   /* Create the slider label window. */
   if (slider->label != 0)
   {
      slider->labelWin = subwin (slider->win, 1,
				slider->labelLen,
				ypos + slider->titleLines + 1,
				xpos + horizontalAdjust + 1);
   }

   /* Create the slider field window. */
   slider->fieldWin = subwin (slider->win, 1, fieldWidth + highValueLen,
				ypos + slider->titleLines + 1,
				xpos + slider->labelLen + horizontalAdjust + 1);

   /* Create the slider field. */
   ScreenOf(slider)		= cdkscreen;
   slider->parent		= cdkscreen->window;
   slider->boxWidth		= boxWidth;
   slider->boxHeight		= boxHeight;
   slider->fieldWidth		= fieldWidth;
   slider->filler		= filler;
   slider->low			= low;
   slider->high			= high;
   slider->current		= start;
   slider->inc			= inc;
   slider->fastinc		= fastInc;
   slider->exitType		= vNEVER_ACTIVATED;
   ObjOf(slider)->box		= Box;
   slider->shadow		= shadow;
   slider->preProcessFunction	= 0;
   slider->preProcessData	= 0;
   slider->postProcessFunction	= 0;
   slider->postProcessData	= 0;
   slider->ULChar		= ACS_ULCORNER;
   slider->URChar		= ACS_URCORNER;
   slider->LLChar		= ACS_LLCORNER;
   slider->LRChar		= ACS_LRCORNER;
   slider->HChar		= ACS_HLINE;
   slider->VChar		= ACS_VLINE;
   slider->BoxAttrib		= A_NORMAL;

   /* Determine the step value. */
   slider->step = (float)((float)slider->fieldWidth/(float)(high-low));

   /* Set the start value. */
   if (start < low)
   {
      slider->current = low;
   }

   /* Clean the key bindings. */
   cleanCDKObjectBindings (vSLIDER, slider);

   /* Register this baby. */
   registerCDKObject (cdkscreen, vSLIDER, slider);

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

/*
 * This allows the person to use the slider field.
 */
int activateCDKSlider (CDKSLIDER *slider, chtype *actions)
{
   /* Declare local variables. */
   int ret;

   /* Draw the slider widget. */
   drawCDKSlider (slider, ObjOf(slider)->box);

   /* Check if actions is null. */
   if (actions == 0)
   {
      chtype input = 0;
      for (;;)
      {
	 /* Get the input. */
	 wrefresh (slider->win);
	 input = wgetch (slider->win);

	 /* Inject the character into the widget. */
	 ret = injectCDKSlider (slider, input);
	 if (slider->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 = injectCDKSlider (slider, actions[x]);
	 if (slider->exitType != vEARLY_EXIT)
	 {
	    return ret;
	 }
      }
   }

   /* Set the exit type and return. */
   slider->exitType = vEARLY_EXIT;
   return -1;
}

/*
 * This function injects a single character into the widget.
 */
int injectCDKSlider (CDKSLIDER *slider, chtype input)
{
   /* Declare some local variables. */
   int ppReturn = 1;

   /* Set the exit type. */
   slider->exitType = vEARLY_EXIT;

   /* Draw the field. */
   drawCDKSliderField (slider);

   /* Check if there is a pre-process function to be called. */
   if (slider->preProcessFunction != 0)
   {
      /* Call the pre-process function. */
      ppReturn = ((PROCESSFN)(slider->preProcessFunction)) (vSLIDER, slider, slider->preProcessData, input);
   }

   /* Should we continue? */
   if (ppReturn != 0)
   {
      /* Check for a key binding. */
      if (checkCDKObjectBind(vSLIDER, slider, input) != 0)
      {
	 return -1;
      }
      else
      {
	 switch (input)
	 {
	    case KEY_LEFT : case 'd' : case '-' : case KEY_DOWN :
		 if (slider->current > slider->low)
		 {
		    slider->current -= slider->inc;
		 }
		 else
		 {
		    Beep();
		 }
		 break;

	    case KEY_RIGHT : case 'u' : case '+' : case KEY_UP :
		 if (slider->current < slider->high)
		 {
		    slider->current += slider->inc;
		 }
		 else
		 {
		    Beep();
		 }
		 break;

	    case KEY_PPAGE : case 'U' : case CONTROL('B') :
		 if ((slider->current + slider->fastinc) <= slider->high)
		 {
		    slider->current += slider->fastinc;
		 }
		 else
		 {
		    Beep();
		 }
		 break;

	       case KEY_NPAGE : case 'D' : case CONTROL('F') :
		 if ((slider->current - slider->fastinc) >= slider->low)
		 {
		    slider->current -= slider->fastinc;
		 }
		 else
		 {
		    Beep();
		 }
		 break;

	    case KEY_HOME : case 'g' : case '0' :
		 slider->current = slider->low;
		 break;

	    case KEY_END : case 'G' : case '$' :
		 slider->current = slider->high;
		 break;

	    case KEY_ESC :
		 slider->exitType = vESCAPE_HIT;
		 return -1;

	    case KEY_RETURN : case KEY_TAB : case KEY_ENTER : case KEY_CR :
		 slider->exitType = vNORMAL;
		 return (slider->current);

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

	    default :
		 Beep();
		 break;
	 }
      }

      /* Should we call a post-process? */
      if (slider->postProcessFunction != 0)
      {
	 ((PROCESSFN)(slider->postProcessFunction)) (vSLIDER, slider, slider->postProcessData, input);
      }
   }

   /* Draw the field window. */
   drawCDKSliderField (slider);

   /* Set the exit type and return. */
   slider->exitType = vEARLY_EXIT;
   return -1;
}

/*
 * This moves the slider field to the given location.
 */
static void _moveCDKSlider (CDKOBJS *object, int xplace, int yplace, boolean relative, boolean refresh_flag)
{
   CDKSLIDER *slider = (CDKSLIDER *)object;

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

   /* Adjust the window if we need to. */
   alignxy (WindowOf(slider), &xplace, &yplace, slider->boxWidth, slider->boxHeight);

   /* Move the window to the new location. */
   moveCursesWindow(slider->win, xplace, yplace);

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

/*
 * This function draws the slider widget.
 */
static void _drawCDKSlider (CDKOBJS *object, boolean Box)
{
   CDKSLIDER *slider = (CDKSLIDER *)object;
   int x;

   /* Box the widget if asked. */
   if (Box)
   {
      attrbox (slider->win,
		slider->ULChar, slider->URChar,
		slider->LLChar, slider->LRChar,
		slider->HChar,	slider->VChar,
		slider->BoxAttrib,
		slider->shadow);
   }

   if (slider->titleLines > 0)
   {
      /* Draw in the title if there is one. */
      for (x=0; x < slider->titleLines; x++)
      {
	 writeChtype (slider->titleWin,
			slider->titlePos[x], x,
			slider->title[x],
			HORIZONTAL, 0,
			slider->titleLen[x]);
      }
   }

   /* Draw the label. */
   if (slider->label != 0)
   {
      writeChtype (slider->labelWin, 0, 0,
			slider->label,
			HORIZONTAL, 0,
			slider->labelLen);
      wnoutrefresh (slider->labelWin);
   }

   /* Draw the field window. */
   drawCDKSliderField (slider);
}

/*
 * This draws the slider widget.
 */
static void drawCDKSliderField (CDKSLIDER *slider)
{
   /* Declare the local variables. */
   int fillerCharacters, len;
   char temp[256];

   /* Determine how many filler characters need to be drawn. */
   fillerCharacters = (int)((slider->current-slider->low) * slider->step);

   /* Empty the field. */
   werase (slider->fieldWin);

   /* Add the character to the window. */
   mvwhline (slider->fieldWin, 0, 0, slider->filler, fillerCharacters);

   /* Draw the value in the field. */
   sprintf (temp, "%d", slider->current);
   len = (int)strlen(temp);
   writeCharAttrib (slider->fieldWin,
			slider->fieldWidth, 0, temp,
			A_NORMAL,
			HORIZONTAL, 0,
			len);

   /* Refresh the field window. */
   wnoutrefresh (slider->fieldWin);
   wnoutrefresh (slider->win);
}

/*
 * These functions set the drawing characters of the widget.
 */
void setCDKSliderULChar (CDKSLIDER *slider, chtype character)
{
   slider->ULChar = character;
}
void setCDKSliderURChar (CDKSLIDER *slider, chtype character)
{
   slider->URChar = character;
}
void setCDKSliderLLChar (CDKSLIDER *slider, chtype character)
{
   slider->LLChar = character;
}
void setCDKSliderLRChar (CDKSLIDER *slider, chtype character)
{
   slider->LRChar = character;
}
void setCDKSliderVerticalChar (CDKSLIDER *slider, chtype character)
{
   slider->VChar = character;
}
void setCDKSliderHorizontalChar (CDKSLIDER *slider, chtype character)
{
   slider->HChar = character;
}
void setCDKSliderBoxAttribute (CDKSLIDER *slider, chtype character)
{
   slider->BoxAttrib = character;
}

/*
 * This sets the background color of the widget.
 */
void setCDKSliderBackgroundColor (CDKSLIDER *slider, char *color)
{
   chtype *holder = 0;
   int junk1, junk2;

   /* Make sure the color isn't null. */
   if (color == 0)
   {
      return;
   }

   /* Convert the value of the environment variable to a chtype. */
   holder = char2Chtype (color, &junk1, &junk2);

   /* Set the widgets background color. */
   wbkgd (slider->win, holder[0]);
   wbkgd (slider->fieldWin, holder[0]);
   if (slider->label != 0)
   {
      wbkgd (slider->labelWin, holder[0]);
   }

   /* Clean up. */
   freeChtype (holder);
}

/*
 * This function destroys the slider widget.
 */
void destroyCDKSlider (CDKSLIDER *slider)
{
   int x;

   /* Erase the object. */
   eraseCDKSlider (slider);

   /* Clean up the char pointers. */
   freeChtype (slider->label);
   for (x=0; x < slider->titleLines; x++)
   {
      freeChtype (slider->title[x]);
   }

   /* Clean up the windows. */
   deleteCursesWindow (slider->win);

   /* Unregister this object. */
   unregisterCDKObject (vSLIDER, slider);

   /* Finish cleaning up. */
   free (slider);
}

/*
 * This function erases the slider widget from the screen.
 */
static void _eraseCDKSlider (CDKOBJS *object)
{
   CDKSLIDER *slider = (CDKSLIDER *)object;

   eraseCursesWindow (slider->win);
}

/*
 * This function sets the low/high/current values of the slider widget.
 */
void setCDKSlider (CDKSLIDER *slider, int low, int high, int value, boolean Box)
{
   setCDKSliderLowHigh (slider, low, high);
   setCDKSliderValue (slider, value);
   setCDKSliderBox (slider, Box);
}

/*
 * This function sets the low/high/current value of the widget.
 */
void setCDKSliderValue (CDKSLIDER *slider, int value)
{
   slider->current = value;
}
int getCDKSliderValue (CDKSLIDER *slider)
{
   return slider->current;
}

/*
 * This function sets the low/high values of the widget.
 */
void setCDKSliderLowHigh (CDKSLIDER *slider, int low, int high)
{
   /* Make sure the values aren't out of bounds. */
   if (low <= high)
   {
      slider->low	= low;
      slider->high	= high;
   }
   else if (low > high)
   {
      slider->low	= high;
      slider->high	= low;
   }

   /* Make sure the user hasn't done something silly. */
   if (slider->current < low)
   {
      slider->current = low;
   }
   if (slider->current > high)
   {
      slider->current = high;
   }

   /* Determine the step value. */
   slider->step = (float)((float)slider->fieldWidth / (float)(high-low));
}
int getCDKSliderLowValue (CDKSLIDER *slider)
{
   return slider->low;
}
int getCDKSliderHighValue (CDKSLIDER *slider)
{
   return slider->high;
}

/*
 * This sets the box attribute of the slider widget.
 */
void setCDKSliderBox (CDKSLIDER *slider, boolean Box)
{
   ObjOf(slider)->box = Box;
}
boolean getCDKSliderBox (CDKSLIDER *slider)
{
   return ObjOf(slider)->box;
}

/*
 * This function sets the pre-process function.
 */
void setCDKSliderPreProcess (CDKSLIDER *slider, PROCESSFN callback, void *data)
{
   slider->preProcessFunction = callback;
   slider->preProcessData = data;
}

/*
 * This function sets the post-process function.
 */
void setCDKSliderPostProcess (CDKSLIDER *slider, PROCESSFN callback, void *data)
{
   slider->postProcessFunction = callback;
   slider->postProcessData = data;
}