]> git.ipfire.org Git - thirdparty/newt.git/blame - form.c
1) reworked to use wrapping code from later reflow implementation
[thirdparty/newt.git] / form.c
CommitLineData
139f06bc 1#include <slang.h>
6fb96a3f 2#include <stdarg.h>
3#include <stdlib.h>
4
5#include "newt.h"
6#include "newt_pr.h"
7
f5daa14e 8/****************************************************************************
9 These forms handle vertical scrolling of components with a height of 1
10
11 Horizontal scrolling won't work, and scrolling large widgets will fail
12 miserably. It shouldn't be too hard to fix either of those if anyone
13 cares to. I only use scrolling for listboxes and text boxes though so
14 I didn't bother.
15*****************************************************************************/
16
17struct element {
3da9c9a2 18 int top, left; /* Actual, not virtual. These are translated */
19 newtComponent co; /* into actual through vertOffset */
f5daa14e 20};
21
c4827b34 22struct form {
6fb96a3f 23 int numCompsAlloced;
f5daa14e 24 struct element * elements;
6fb96a3f 25 int numComps;
26 int currComp;
8c4e1047 27 int fixedHeight;
02b180e8 28 int flags;
f5daa14e 29 int vertOffset;
02b180e8 30 newtComponent vertBar, exitComp;
d4109c37 31 const char * help;
f1f3611f 32 int numRows;
da151ca8 33 int * hotKeys;
34 int numHotKeys;
8f4e87fc 35 int background;
3da9c9a2 36 int beenSet;
6fb96a3f 37};
38
c4827b34 39static void gotoComponent(struct form * form, int newComp);
40static struct eventResult formEvent(newtComponent co, struct event ev);
434c766b 41static struct eventResult sendEvent(newtComponent comp, struct event ev);
8f52cd47 42static void formPlace(newtComponent co, int left, int top);
c4827b34 43
8f52cd47 44/* this isn't static as grid.c tests against it to find forms */
45struct componentOps formOps = {
8b68158d 46 newtDrawForm,
c4827b34 47 formEvent,
48 newtFormDestroy,
8f52cd47 49 formPlace,
50 newtDefaultMappedHandler,
c4827b34 51} ;
52
f5daa14e 53static inline int componentFits(newtComponent co, int compNum) {
54 struct form * form = co->data;
55 struct element * el = form->elements + compNum;
56
57 if ((co->top + form->vertOffset) > el->top) return 0;
58 if ((co->top + form->vertOffset + co->height) <
59 (el->top + el->co->height)) return 0;
60
61 return 1;
62}
63
d4109c37 64newtComponent newtForm(newtComponent vertBar, const char * help, int flags) {
c4827b34 65 newtComponent co;
66 struct form * form;
67
68 co = malloc(sizeof(*co));
69 form = malloc(sizeof(*form));
70 co->data = form;
71 co->width = 0;
72 co->height = 0;
73 co->top = -1;
74 co->left = -1;
3da9c9a2 75 co->isMapped = 0;
c4827b34 76
8f52cd47 77 co->takesFocus = 0; /* we may have 0 components */
c4827b34 78 co->ops = &formOps;
6fb96a3f 79
02b180e8 80 form->help = help;
81 form->flags = flags;
6fb96a3f 82 form->numCompsAlloced = 5;
83 form->numComps = 0;
84 form->currComp = -1;
f5daa14e 85 form->vertOffset = 0;
8c4e1047 86 form->fixedHeight = 0;
f1f3611f 87 form->numRows = 0;
3da9c9a2 88 form->beenSet = 0;
f5daa14e 89 form->elements = malloc(sizeof(*(form->elements)) * form->numCompsAlloced);
6fb96a3f 90
8f4e87fc 91 form->background = COLORSET_WINDOW;
da151ca8 92 form->hotKeys = malloc(sizeof(int));
93 form->numHotKeys = 0;
4a93351d 94 if (!(form->flags & NEWT_FLAG_NOF12)) {
da151ca8 95 newtFormAddHotKey(co, NEWT_KEY_F12);
96 }
97
02b180e8 98 if (vertBar)
99 form->vertBar = vertBar;
f1f3611f 100 else
101 form->vertBar = NULL;
102
c4827b34 103 return co;
6fb96a3f 104}
105
2a2998a0 106newtComponent newtFormGetCurrent(newtComponent co) {
107 struct form * form = co->data;
108
109 return form->elements[form->currComp].co;
110}
111
7ea3dccd 112void newtFormSetCurrent(newtComponent co, newtComponent subco) {
113 struct form * form = co->data;
114 int i, new;
115
116 for (i = 0; i < form->numComps; i++) {
117 if (form->elements[i].co == subco) break;
118 }
119
120 if (form->elements[i].co != subco) return;
121 new = i;
122
3da9c9a2 123 if (co->isMapped && !componentFits(co, new)) {
7ea3dccd 124 gotoComponent(form, -1);
125 form->vertOffset = form->elements[new].top - co->top - 1;
d1a682d1 126 if (form->vertOffset > (form->numRows - co->height))
127 form->vertOffset = form->numRows - co->height;
7ea3dccd 128 }
129
130 gotoComponent(form, new);
131}
132
8c4e1047 133void newtFormSetHeight(newtComponent co, int height) {
f5daa14e 134 struct form * form = co->data;
135
8c4e1047 136 form->fixedHeight = 1;
f5daa14e 137 co->height = height;
138}
139
ea947804 140void newtFormSetWidth(newtComponent co, int width) {
141 co->width = width;
142}
143
c4827b34 144void newtFormAddComponent(newtComponent co, newtComponent newco) {
145 struct form * form = co->data;
6fb96a3f 146
8f52cd47 147 co->takesFocus = 1;
148
6fb96a3f 149 if (form->numCompsAlloced == form->numComps) {
150 form->numCompsAlloced += 5;
f5daa14e 151 form->elements = realloc(form->elements,
152 sizeof(*(form->elements)) * form->numCompsAlloced);
6fb96a3f 153 }
154
f7540d34 155 /* we grab real values for these a bit later */
156 form->elements[form->numComps].left = -2;
157 form->elements[form->numComps].top = -2;
f5daa14e 158 form->elements[form->numComps].co = newco;
f1f3611f 159
160 if (newco->takesFocus && form->currComp == -1)
161 form->currComp = form->numComps;
162
f5daa14e 163 form->numComps++;
6fb96a3f 164}
165
c4827b34 166void newtFormAddComponents(newtComponent co, ...) {
6fb96a3f 167 va_list ap;
c4827b34 168 newtComponent subco;
6fb96a3f 169
c4827b34 170 va_start(ap, co);
6fb96a3f 171
c4827b34 172 while ((subco = va_arg(ap, newtComponent)))
173 newtFormAddComponent(co, subco);
6fb96a3f 174
175 va_end(ap);
176}
177
8f52cd47 178static void formPlace(newtComponent co, int left, int top) {
179 struct form * form = co->data;
180 int vertDelta, horizDelta;
181 struct element * el;
182 int i;
183
184 newtFormSetSize(co);
185
186 vertDelta = top - co->top;
187 horizDelta = left - co->left;
188 co->top = top;
189 co->left = left;
190
191 for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
192 el->co->top += vertDelta;
193 el->top += vertDelta;
194 el->co->left += horizDelta;
195 el->left += horizDelta;
196 }
197}
198
8b68158d 199void newtDrawForm(newtComponent co) {
c4827b34 200 struct form * form = co->data;
f5daa14e 201 struct element * el;
6fb96a3f 202 int i;
6fb96a3f 203
3da9c9a2 204 newtFormSetSize(co);
205
8f4e87fc 206 SLsmg_set_color(form->background);
a1331450 207 newtClearBox(co->left, co->top, co->width, co->height);
f5daa14e 208 for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
8f52cd47 209 /* the scrollbar *always* fits somewhere */
210 if (el->co == form->vertBar) {
211 el->co->ops->mapped(el->co, 1);
f5daa14e 212 el->co->ops->draw(el->co);
8f52cd47 213 } else {
f1f3611f 214 /* only draw it if it'll fit on the screen vertically */
215 if (componentFits(co, i)) {
216 el->co->top = el->top - form->vertOffset;
8f52cd47 217 el->co->ops->mapped(el->co, 1);
f1f3611f 218 el->co->ops->draw(el->co);
219 } else {
8f52cd47 220 el->co->ops->mapped(el->co, 0);
f1f3611f 221 }
f5daa14e 222 }
6fb96a3f 223 }
f1f3611f 224
225 if (form->vertBar)
226 newtScrollbarSet(form->vertBar, form->vertOffset,
227 form->numRows - co->height);
c4827b34 228}
6fb96a3f 229
c4827b34 230static struct eventResult formEvent(newtComponent co, struct event ev) {
231 struct form * form = co->data;
f5daa14e 232 newtComponent subco = form->elements[form->currComp].co;
d1a682d1 233 int new, wrap = 0;
c4827b34 234 struct eventResult er;
d1a682d1 235 int dir = 0, page = 0;
434c766b 236 int i, num;
6fb96a3f 237
c4827b34 238 er.result = ER_IGNORED;
8f52cd47 239 if (!form->numComps) return er;
240
241 subco = form->elements[form->currComp].co;
6fb96a3f 242
434c766b 243 switch (ev.when) {
244 case EV_EARLY:
245 if (ev.event == EV_KEYPRESS) {
246 if (ev.u.key == NEWT_KEY_TAB) {
247 er.result = ER_SWALLOWED;
248 dir = 1;
249 wrap = 1;
250 } else if (ev.u.key == NEWT_KEY_UNTAB) {
251 er.result = ER_SWALLOWED;
252 dir = -1;
253 wrap = 1;
254 }
8c4e1047 255 }
6fb96a3f 256
8f52cd47 257 if (form->numComps) {
258 i = form->currComp;
259 num = 0;
260 while (er.result == ER_IGNORED && num != form->numComps ) {
261 er = form->elements[i].co->ops->event(form->elements[i].co, ev);
434c766b 262
8f52cd47 263 num++;
264 i++;
265 if (i == form->numComps) i = 0;
266 }
6fb96a3f 267 }
268
434c766b 269 break;
270
271 case EV_NORMAL:
272 er = subco->ops->event(subco, ev);
e90f9163 273 switch (er.result) {
274 case ER_NEXTCOMP:
275 er.result = ER_SWALLOWED;
276 dir = 1;
e90f9163 277 break;
278
02b180e8 279 case ER_EXITFORM:
280 form->exitComp = subco;
281 break;
282
e90f9163 283 default:
284 break;
285 }
434c766b 286 break;
287
288 case EV_LATE:
289 er = subco->ops->event(subco, ev);
290
6fb96a3f 291 if (er.result == ER_IGNORED) {
434c766b 292 switch (ev.u.key) {
293 case NEWT_KEY_UP:
294 case NEWT_KEY_LEFT:
295 case NEWT_KEY_BKSPC:
296 er.result = ER_SWALLOWED;
297 dir = -1;
434c766b 298 break;
299
300 case NEWT_KEY_DOWN:
301 case NEWT_KEY_RIGHT:
434c766b 302 er.result = ER_SWALLOWED;
303 dir = 1;
d1a682d1 304 break;
305
306 case NEWT_KEY_PGUP:
307 er.result = ER_SWALLOWED;
308 dir = -1;
309 page = 1;
310 break;
311
312 case NEWT_KEY_PGDN:
313 er.result = ER_SWALLOWED;
314 dir = 1;
315 page = 1;
434c766b 316 break;
6fb96a3f 317 }
318 }
c4827b34 319 }
6fb96a3f 320
f5daa14e 321 if (dir) {
322 new = form->currComp;
d1a682d1 323
324 if (page) {
325 new += dir * co->height;
326 if (new < 0)
327 new = 0;
328 else if (new >= form->numComps)
329 new = (form->numComps - 1);
330
331 while (!form->elements[new].co->takesFocus)
332 new = new - dir;
333 } else {
334 do {
335 new += dir;
336
337 if (wrap) {
338 if (new < 0)
339 new = form->numComps - 1;
340 else if (new >= form->numComps)
341 new = 0;
342 } else if (new < 0 || new >= form->numComps)
343 return er;
344 } while (!form->elements[new].co->takesFocus);
345 }
f5daa14e 346
347 /* make sure this component is visible */
348 if (!componentFits(co, new)) {
349 gotoComponent(form, -1);
350
351 if (dir < 0) {
352 /* make the new component the first one */
353 form->vertOffset = form->elements[new].top - co->top;
354 } else {
355 /* make the new component the last one */
356 form->vertOffset = (form->elements[new].top +
357 form->elements[new].co->height) -
358 (co->top + co->height);
359 }
360
361 if (form->vertOffset < 0) form->vertOffset = 0;
d1a682d1 362 if (form->vertOffset > (form->numRows - co->height))
363 form->vertOffset = form->numRows - co->height;
f5daa14e 364
8b68158d 365 newtDrawForm(co);
c4827b34 366 }
f5daa14e 367
368 gotoComponent(form, new);
369 er.result = ER_SWALLOWED;
c4827b34 370 }
6fb96a3f 371
c4827b34 372 return er;
6fb96a3f 373}
374
375/* this also destroys all of the components on the form */
c4827b34 376void newtFormDestroy(newtComponent co) {
c4827b34 377 newtComponent subco;
378 struct form * form = co->data;
f1f3611f 379 int i;
6fb96a3f 380
381 /* first, destroy all of the components */
382 for (i = 0; i < form->numComps; i++) {
f5daa14e 383 subco = form->elements[i].co;
c4827b34 384 if (subco->ops->destroy) {
385 subco->ops->destroy(subco);
6fb96a3f 386 } else {
c4827b34 387 if (subco->data) free(subco->data);
388 free(subco);
6fb96a3f 389 }
390 }
391
f5daa14e 392 free(form->elements);
6fb96a3f 393 free(form);
c4827b34 394 free(co);
395}
396
397newtComponent newtRunForm(newtComponent co) {
da151ca8 398 struct newtExitStruct es;
399
400 newtFormRun(co, &es);
401 if (es.reason == NEWT_EXIT_HOTKEY) {
402 if (es.u.key == NEWT_KEY_F12) {
403 es.reason = NEWT_EXIT_COMPONENT;
404 es.u.co = co;
405 } else {
406 return NULL;
407 }
408 }
409
410 return es.u.co;
411}
412
413void newtFormAddHotKey(newtComponent co, int key) {
414 struct form * form = co->data;
415
416 form->numHotKeys++;
417 form->hotKeys = realloc(form->hotKeys, sizeof(int) * form->numHotKeys);
418 form->hotKeys[form->numHotKeys - 1] = key;
419}
420
3da9c9a2 421void newtFormSetSize(newtComponent co) {
f7540d34 422 struct form * form = co->data;
423 int delta, i;
424 struct element * el;
425
3da9c9a2 426 if (form->beenSet) return;
427
428 form->beenSet = 1;
429
8f52cd47 430 if (!form->numComps) return;
431
f7540d34 432 co->width = 0;
3da9c9a2 433 if (!form->fixedHeight) co->height = 0;
434
f7540d34 435 co->top = form->elements[0].co->top;
436 co->left = form->elements[0].co->left;
437 for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
438 if (el->co->ops == &formOps)
439 newtFormSetSize(el->co);
440
441 el->left = el->co->left;
442 el->top = el->co->top;
443
444 if (co->left > el->co->left) {
445 delta = co->left - el->co->left;
446 co->left -= delta;
447 co->width += delta;
448 }
449
450 if (co->top > el->co->top) {
451 delta = co->top - el->co->top;
452 co->top -= delta;
453 if (!form->fixedHeight)
454 co->height += delta;
455 }
456
457 if ((co->left + co->width) < (el->co->left + el->co->width))
458 co->width = (el->co->left + el->co->width) - co->left;
459
460 if (!form->fixedHeight) {
461 if ((co->top + co->height) < (el->co->top + el->co->height))
462 co->height = (el->co->top + el->co->height) - co->top;
463 }
464
465 if ((el->co->top + el->co->height - co->top) > form->numRows) {
466 form->numRows = el->co->top + el->co->height - co->top;
467 }
468 }
469}
470
da151ca8 471void newtFormRun(newtComponent co, struct newtExitStruct * es) {
c4827b34 472 struct form * form = co->data;
473 struct event ev;
474 struct eventResult er;
da151ca8 475 int key, i;
476 int done = 0;
c4827b34 477
f7540d34 478 newtFormSetSize(co);
479 /* draw all of the components */
8b68158d 480 newtDrawForm(co);
c4827b34 481
f1f3611f 482 if (form->currComp == -1) {
c4827b34 483 gotoComponent(form, 0);
f1f3611f 484 } else
c4827b34 485 gotoComponent(form, form->currComp);
486
da151ca8 487 while (!done) {
c4827b34 488 newtRefresh();
489 key = newtGetKey();
490
ae1235d0 491 if (key == NEWT_KEY_RESIZE) {
492 /* newtResizeScreen(1); */
493 continue;
494 }
495
da151ca8 496 for (i = 0; i < form->numHotKeys; i++) {
497 if (form->hotKeys[i] == key) {
498 es->reason = NEWT_EXIT_HOTKEY;
499 es->u.key = key;
500 done = 1;
501 break;
502 }
503 }
c4827b34 504
da151ca8 505 if (!done) {
506 ev.event = EV_KEYPRESS;
507 ev.u.key = key;
508
509 er = sendEvent(co, ev);
510
511 if (er.result == ER_EXITFORM) {
512 done = 1;
513 es->reason = NEWT_EXIT_COMPONENT;
514 es->u.co = form->exitComp;
515 }
516 }
517 }
c4827b34 518
519 newtRefresh();
6fb96a3f 520}
521
434c766b 522static struct eventResult sendEvent(newtComponent co, struct event ev) {
523 struct eventResult er;
524
525 ev.when = EV_EARLY;
526 er = co->ops->event(co, ev);
527
528 if (er.result == ER_IGNORED) {
529 ev.when = EV_NORMAL;
530 er = co->ops->event(co, ev);
531 }
532
533 if (er.result == ER_IGNORED) {
534 ev.when = EV_LATE;
535 er = co->ops->event(co, ev);
536 }
537
538 return er;
539}
540
c4827b34 541static void gotoComponent(struct form * form, int newComp) {
6fb96a3f 542 struct event ev;
543
544 if (form->currComp != -1) {
545 ev.event = EV_UNFOCUS;
434c766b 546 sendEvent(form->elements[form->currComp].co, ev);
6fb96a3f 547 }
548
549 form->currComp = newComp;
f5daa14e 550
551 if (form->currComp != -1) {
552 ev.event = EV_FOCUS;
434c766b 553 ev.when = EV_NORMAL;
554 sendEvent(form->elements[form->currComp].co, ev);
f5daa14e 555 }
6fb96a3f 556}
da151ca8 557
558void newtComponentAddCallback(newtComponent co, newtCallback f, void * data) {
559 co->callback = f;
560 co->callbackData = data;
561}
562
41d86a3c 563void newtComponentTakesFocus(newtComponent co, int val) {
564 co->takesFocus = val;
565}
566
8f4e87fc 567void newtFormSetBackground(newtComponent co, int color) {
568 struct form * form = co->data;
569
570 form->background = color;
571}