1 #include <cdk_int.h>
2 #include "button.h"
3 #include <limits.h>
4 
5 /*
6  * $Author: Aarian.P.Aleahmad $
7  * $Date: 2016/01/31 20:32:25 $
8  * $Revision: 1.38 $
9  */
10 
11 DeclareCDKObjects (BUTTON, Button, setCdk, Int);
12 
13 /*
14  * This creates a button widget.
15  */
newCDKButton(CDKSCREEN * cdkscreen,int xplace,int yplace,const char * text,tButtonCallback callback,boolean Box,boolean shadow)16 CDKBUTTON *newCDKButton (CDKSCREEN *cdkscreen,
17 			 int xplace,
18 			 int yplace,
19 			 const char *text,
20 			 tButtonCallback callback,
21 			 boolean Box,
22 			 boolean shadow)
23 {
24    /* *INDENT-EQLS* */
25    CDKBUTTON *button    = 0;
26    int parentWidth      = getmaxx (cdkscreen->window);
27    int parentHeight     = getmaxy (cdkscreen->window);
28    int boxWidth         = 0;
29    int boxHeight;
30    int xpos             = xplace;
31    int ypos             = yplace;
32 
33    if ((button = newCDKObject (CDKBUTTON, &my_funcs)) == 0)
34         return (0);
35 
36    setCDKButtonBox (button, Box);
37    boxHeight = 1 + 2 * BorderOf (button);
38 
39    /* Translate the char * to a chtype. */
40    button->info = char2Chtype (text, &button->infoLen, &button->infoPos);
41    boxWidth = MAXIMUM (boxWidth, button->infoLen) + 2 * BorderOf (button);
42 
43    /* Create the string alignments. */
44    button->infoPos = justifyString (boxWidth - 2 * BorderOf (button),
45 				    button->infoLen, button->infoPos);
46 
47    /*
48     * Make sure we didn't extend beyond the dimensions of the window.
49     */
50    boxWidth = (boxWidth > parentWidth ? parentWidth : boxWidth);
51    boxHeight = (boxHeight > parentHeight ? parentHeight : boxHeight);
52 
53    /* Rejustify the x and y positions if we need to. */
54    alignxy (cdkscreen->window, &xpos, &ypos, boxWidth, boxHeight);
55 
56    /* *INDENT-EQLS* Create the button. */
57    ScreenOf (button)            = cdkscreen;
58    ObjOf (button)->fn           = &my_funcs;
59    button->parent               = cdkscreen->window;
60    button->win                  = newwin (boxHeight, boxWidth, ypos, xpos);
61    button->shadowWin            = (WINDOW *)NULL;
62    button->xpos                 = xpos;
63    button->ypos                 = ypos;
64    button->boxWidth             = boxWidth;
65    button->boxHeight            = boxHeight;
66    button->callback             = callback;
67    button->callbackData         = NULL;
68    ObjOf (button)->inputWindow  = button->win;
69    ObjOf (button)->acceptsFocus = TRUE;
70    initExitType (button);
71    button->shadow               = shadow;
72    button->highlight            = A_REVERSE;
73 
74    /* Is the window NULL? */
75    if (button->win == (WINDOW *)NULL)
76    {
77       destroyCDKObject (button);
78       return (0);
79    }
80 
81    keypad (button->win, TRUE);
82 
83    /* If a shadow was requested, then create the shadow window. */
84    if (shadow)
85       button->shadowWin = newwin (boxHeight, boxWidth, ypos + 1, xpos + 1);
86 
87    /* Register this baby. */
88    registerCDKObject (cdkscreen, vBUTTON, button);
89 
90    /* Return the button pointer. */
91    return (button);
92 }
93 
94 /*
95  * This was added for the builder.
96  */
activateCDKButton(CDKBUTTON * button,chtype * actions)97 int activateCDKButton (CDKBUTTON *button, chtype *actions)
98 {
99    chtype input = 0;
100    boolean functionKey;
101    int ret;
102 
103    drawCDKButton (button, ObjOf (button)->box);
104 
105    if (actions == 0)
106    {
107       for (;;)
108       {
109 	 input = (chtype)getchCDKObject (ObjOf (button), &functionKey);
110 
111 	 /* Inject the character into the widget. */
112 	 ret = injectCDKButton (button, input);
113 	 if (button->exitType != vEARLY_EXIT)
114 	 {
115 	    return ret;
116 	 }
117       }
118    }
119    else
120    {
121       int length = chlen (actions);
122       int x = 0;
123 
124       /* Inject each character one at a time. */
125       for (x = 0; x < length; x++)
126       {
127 	 ret = injectCDKButton (button, actions[x]);
128 	 if (button->exitType != vEARLY_EXIT)
129 	 {
130 	    return ret;
131 	 }
132       }
133    }
134 
135    /* Set the exit type and exit. */
136    setExitType (button, 0);
137    return -1;
138 }
139 
140 /*
141  * This sets multiple attributes of the widget.
142  */
setCDKButton(CDKBUTTON * button,const char * mesg,boolean Box)143 void setCDKButton (CDKBUTTON *button, const char *mesg, boolean Box)
144 {
145    setCDKButtonMessage (button, mesg);
146    setCDKButtonBox (button, Box);
147 }
148 
149 /*
150  * This sets the information within the button.
151  */
setCDKButtonMessage(CDKBUTTON * button,const char * info)152 void setCDKButtonMessage (CDKBUTTON *button, const char *info)
153 {
154    /* Clean out the old message. */
155    freeChtype (button->info);
156    button->infoPos = 0;
157    button->infoLen = 0;
158 
159    /* Copy in the new message. */
160 
161    button->info = char2Chtype (info, &button->infoLen, &button->infoPos);
162    button->infoPos = justifyString (button->boxWidth - 2 * BorderOf (button),
163 				    button->infoLen, button->infoPos);
164 
165    /* Redraw the button widget. */
166    eraseCDKButton (button);
167    drawCDKButton (button, ObjOf (button)->box);
168 }
169 
getCDKButtonMessage(CDKBUTTON * button)170 chtype *getCDKButtonMessage (CDKBUTTON *button)
171 {
172    return button->info;
173 }
174 
175 /*
176  * This sets the box flag for the button widget.
177  */
setCDKButtonBox(CDKBUTTON * button,boolean Box)178 void setCDKButtonBox (CDKBUTTON *button, boolean Box)
179 {
180    ObjOf (button)->box = Box;
181    ObjOf (button)->borderSize = Box ? 1 : 0;
182 }
183 
getCDKButtonBox(CDKBUTTON * button)184 boolean getCDKButtonBox (CDKBUTTON *button)
185 {
186    return ObjOf (button)->box;
187 }
188 
189 /*
190  * This sets the background attribute of the widget.
191  */
_setBKattrButton(CDKOBJS * object,chtype attrib)192 static void _setBKattrButton (CDKOBJS *object, chtype attrib)
193 {
194    if (object != 0)
195    {
196       CDKBUTTON *widget = (CDKBUTTON *)object;
197 
198       wbkgd (widget->win, attrib);
199    }
200 }
201 
drawCDKButtonText(CDKBUTTON * button)202 static void drawCDKButtonText (CDKBUTTON *button)
203 {
204    int boxWidth = button->boxWidth;
205    int i;
206 
207    /* Draw in the message. */
208 
209    for (i = 0; i < boxWidth - 2 * BorderOf (button); i++)
210    {
211       chtype c;
212       int pos = button->infoPos;
213       int len = button->infoLen;
214 
215       if (i >= pos && (i - pos) < len)
216 	 c = button->info[i - pos];
217       else
218 	 c = ' ';
219 
220       if (HasFocusObj (button))
221       {
222 	 c = button->highlight | CharOf (c);
223       }
224 
225       (void)mvwaddch (button->win, BorderOf (button), i + BorderOf (button), c);
226    }
227 }
228 
229 /*
230  * This draws the button widget.
231  */
_drawCDKButton(CDKOBJS * object,boolean Box GCC_UNUSED)232 static void _drawCDKButton (CDKOBJS *object, boolean Box GCC_UNUSED)
233 {
234    CDKBUTTON *button = (CDKBUTTON *)object;
235 
236    /* Is there a shadow? */
237    if (button->shadowWin != (WINDOW *)NULL)
238    {
239       drawShadow (button->shadowWin);
240    }
241 
242    /* Box the widget if asked. */
243    if (ObjOf (button)->box)
244    {
245       drawObjBox (button->win, ObjOf (button));
246    }
247    drawCDKButtonText (button);
248    wrefresh (button->win);
249 }
250 
251 /*
252  * This erases the button widget.
253  */
_eraseCDKButton(CDKOBJS * object)254 static void _eraseCDKButton (CDKOBJS *object)
255 {
256    if (validCDKObject (object))
257    {
258       CDKBUTTON *button = (CDKBUTTON *)object;
259 
260       eraseCursesWindow (button->win);
261       eraseCursesWindow (button->shadowWin);
262    }
263 }
264 
265 /*
266  * This moves the button field to the given location.
267  */
_moveCDKButton(CDKOBJS * object,int xplace,int yplace,boolean relative,boolean refresh_flag)268 static void _moveCDKButton (CDKOBJS *object,
269 			    int xplace,
270 			    int yplace,
271 			    boolean relative,
272 			    boolean refresh_flag)
273 {
274    CDKBUTTON *button = (CDKBUTTON *)object;
275    int currentX = getbegx (button->win);
276    int currentY = getbegy (button->win);
277    int xpos = xplace;
278    int ypos = yplace;
279    int xdiff = 0;
280    int ydiff = 0;
281 
282    /*
283     * If this is a relative move, then we will adjust where we want
284     * to move to.
285     */
286    if (relative)
287    {
288       xpos = getbegx (button->win) + xplace;
289       ypos = getbegy (button->win) + yplace;
290    }
291 
292    /* Adjust the window if we need to. */
293    alignxy (WindowOf (button), &xpos, &ypos, button->boxWidth,
294 	    button->boxHeight);
295 
296    /* Get the difference. */
297    xdiff = currentX - xpos;
298    ydiff = currentY - ypos;
299 
300    /* Move the window to the new location. */
301    moveCursesWindow (button->win, -xdiff, -ydiff);
302    moveCursesWindow (button->shadowWin, -xdiff, -ydiff);
303 
304    /* Touch the windows so they 'move'. */
305    refreshCDKWindow (WindowOf (button));
306 
307    /* Redraw the window, if they asked for it. */
308    if (refresh_flag)
309    {
310       drawCDKButton (button, ObjOf (button)->box);
311    }
312 }
313 
314 /*
315  * This allows the user to use the cursor keys to adjust the
316  * position of the widget.
317  */
positionCDKButton(CDKBUTTON * button)318 void positionCDKButton (CDKBUTTON *button)
319 {
320    /* Declare some variables. */
321    int origX = getbegx (button->win);
322    int origY = getbegy (button->win);
323    chtype key = (chtype)0;
324    boolean functionKey;
325 
326    /* Let them move the widget around until they hit return. */
327    while (key != KEY_ENTER)
328    {
329       key = (chtype)getchCDKObject (ObjOf (button), &functionKey);
330       if (key == KEY_UP || key == '8')
331       {
332 	 if (getbegy (button->win) > 0)
333 	 {
334 	    moveCDKButton (button, 0, -1, TRUE, TRUE);
335 	 }
336 	 else
337 	 {
338 	    Beep ();
339 	 }
340       }
341       else if (key == KEY_DOWN || key == '2')
342       {
343 	 if (getbegy (button->win) + getmaxy (button->win) <
344 	     getmaxy (WindowOf (button)) - 1)
345 	 {
346 	    moveCDKButton (button, 0, 1, TRUE, TRUE);
347 	 }
348 	 else
349 	 {
350 	    Beep ();
351 	 }
352       }
353       else if (key == KEY_LEFT || key == '4')
354       {
355 	 if (getbegx (button->win) > 0)
356 	 {
357 	    moveCDKButton (button, -1, 0, TRUE, TRUE);
358 	 }
359 	 else
360 	 {
361 	    Beep ();
362 	 }
363       }
364       else if (key == KEY_RIGHT || key == '6')
365       {
366 	 if (getbegx (button->win) + getmaxx (button->win) < getmaxx
367 	     (WindowOf (button)) - 1)
368 	 {
369 	    moveCDKButton (button, 1, 0, TRUE, TRUE);
370 	 }
371 	 else
372 	 {
373 	    Beep ();
374 	 }
375       }
376       else if (key == '7')
377       {
378 	 if (getbegy (button->win) > 0 && getbegx (button->win) > 0)
379 	 {
380 	    moveCDKButton (button, -1, -1, TRUE, TRUE);
381 	 }
382 	 else
383 	 {
384 	    Beep ();
385 	 }
386       }
387       else if (key == '9')
388       {
389 	 if (getbegx (button->win) + getmaxx (button->win) < getmaxx
390 	     (WindowOf (button)) - 1 &&
391 	     getbegy (button->win) > 0)
392 	 {
393 	    moveCDKButton (button, 1, -1, TRUE, TRUE);
394 	 }
395 	 else
396 	 {
397 	    Beep ();
398 	 }
399       }
400       else if (key == '1')
401       {
402 	 if (getbegx (button->win) > 0 && getbegx (button->win) +
403 	     getmaxx (button->win) < getmaxx (WindowOf (button)) - 1)
404 	 {
405 	    moveCDKButton (button, -1, 1, TRUE, TRUE);
406 	 }
407 	 else
408 	 {
409 	    Beep ();
410 	 }
411       }
412       else if (key == '3')
413       {
414 	 if (getbegx (button->win) + getmaxx (button->win) <
415 	     getmaxx (WindowOf (button)) - 1
416 	     && getbegy (button->win) + getmaxy (button->win) <
417 	     getmaxy (WindowOf (button)) - 1)
418 	 {
419 	    moveCDKButton (button, 1, 1, TRUE, TRUE);
420 	 }
421 	 else
422 	 {
423 	    Beep ();
424 	 }
425       }
426       else if (key == '5')
427       {
428 	 moveCDKButton (button, CENTER, CENTER, FALSE, TRUE);
429       }
430       else if (key == 't')
431       {
432 	 moveCDKButton (button, getbegx (button->win), TOP, FALSE, TRUE);
433       }
434       else if (key == 'b')
435       {
436 	 moveCDKButton (button, getbegx (button->win), BOTTOM, FALSE, TRUE);
437       }
438       else if (key == 'l')
439       {
440 	 moveCDKButton (button, LEFT, getbegy (button->win), FALSE, TRUE);
441       }
442       else if (key == 'r')
443       {
444 	 moveCDKButton (button, RIGHT, getbegy (button->win), FALSE, TRUE);
445       }
446       else if (key == 'c')
447       {
448 	 moveCDKButton (button, CENTER, getbegy (button->win), FALSE, TRUE);
449       }
450       else if (key == 'C')
451       {
452 	 moveCDKButton (button, getbegx (button->win), CENTER, FALSE, TRUE);
453       }
454       else if (key == CDK_REFRESH)
455       {
456 	 eraseCDKScreen (ScreenOf (button));
457 	 refreshCDKScreen (ScreenOf (button));
458       }
459       else if (key == KEY_ESC)
460       {
461 	 moveCDKButton (button, origX, origY, FALSE, TRUE);
462       }
463       else if (key != KEY_ENTER)
464       {
465 	 Beep ();
466       }
467    }
468 }
469 
470 /*
471  * This destroys the button object pointer.
472  */
_destroyCDKButton(CDKOBJS * object)473 static void _destroyCDKButton (CDKOBJS *object)
474 {
475    if (object != 0)
476    {
477       CDKBUTTON *button = (CDKBUTTON *)object;
478 
479       /* Free up the character pointers. */
480       freeChtype (button->info);
481 
482       /* Free up the window pointers. */
483       deleteCursesWindow (button->shadowWin);
484       deleteCursesWindow (button->win);
485 
486       /* Clean the key bindings. */
487       cleanCDKObjectBindings (vBUTTON, button);
488 
489       /* Unregister the object. */
490       unregisterCDKObject (vBUTTON, button);
491    }
492 }
493 
494 /*
495  * This injects a single character into the widget.
496  */
_injectCDKButton(CDKOBJS * object,chtype input)497 static int _injectCDKButton (CDKOBJS *object, chtype input)
498 {
499    CDKBUTTON *widget = (CDKBUTTON *)object;
500    int ret = unknownInt;
501    bool complete = FALSE;
502 
503    setExitType (widget, 0);
504 
505    /* Check a predefined binding. */
506    if (checkCDKObjectBind (vBUTTON, widget, input) != 0)
507    {
508       checkEarlyExit (widget);
509       complete = TRUE;
510    }
511    else
512    {
513       switch (input)
514       {
515       case KEY_ESC:
516 	 setExitType (widget, input);
517 	 complete = TRUE;
518 	 break;
519 
520       case KEY_ERROR:
521 	 setExitType (widget, input);
522 	 complete = TRUE;
523 	 break;
524 
525       case KEY_ENTER:
526       case SPACE:
527 	 if (widget->callback)
528 	    widget->callback (widget);
529 	 setExitType (widget, KEY_ENTER);
530 	 ret = 0;
531 	 complete = TRUE;
532 	 break;
533 
534       case CDK_REFRESH:
535 	 eraseCDKScreen (ScreenOf (widget));
536 	 refreshCDKScreen (ScreenOf (widget));
537 	 break;
538 
539       default:
540 	 Beep ();
541 	 break;
542       }
543    }
544 
545    if (!complete)
546    {
547       setExitType (widget, 0);
548    }
549 
550    ResultOf (widget).valueInt = ret;
551    return (ret != unknownInt);
552 }
553 
_focusCDKButton(CDKOBJS * object)554 static void _focusCDKButton (CDKOBJS *object)
555 {
556    CDKBUTTON *button = (CDKBUTTON *)object;
557 
558    drawCDKButtonText (button);
559    wrefresh (button->win);
560 }
561 
_unfocusCDKButton(CDKOBJS * object)562 static void _unfocusCDKButton (CDKOBJS *object)
563 {
564    CDKBUTTON *button = (CDKBUTTON *)object;
565 
566    drawCDKButtonText (button);
567    wrefresh (button->win);
568 }
569 
570 dummyRefreshData (Button)
571 
572 dummySaveData (Button)
573