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