]> git.ipfire.org Git - thirdparty/newt.git/blame - form.c
clean should remove testobjs
[thirdparty/newt.git] / form.c
CommitLineData
2a2998a0 1#include <slang/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 {
18 int top, left; /* actual, not virtual */
19 newtComponent co;
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;
31 char * help;
f1f3611f 32 int numRows;
da151ca8 33 int * hotKeys;
34 int numHotKeys;
8f4e87fc 35 int background;
6fb96a3f 36};
37
c4827b34 38static void gotoComponent(struct form * form, int newComp);
39static struct eventResult formEvent(newtComponent co, struct event ev);
434c766b 40static struct eventResult sendEvent(newtComponent comp, struct event ev);
c4827b34 41
42static struct componentOps formOps = {
8b68158d 43 newtDrawForm,
c4827b34 44 formEvent,
45 newtFormDestroy,
46} ;
47
f5daa14e 48static inline int componentFits(newtComponent co, int compNum) {
49 struct form * form = co->data;
50 struct element * el = form->elements + compNum;
51
52 if ((co->top + form->vertOffset) > el->top) return 0;
53 if ((co->top + form->vertOffset + co->height) <
54 (el->top + el->co->height)) return 0;
55
56 return 1;
57}
58
02b180e8 59newtComponent newtForm(newtComponent vertBar, char * help, int flags) {
c4827b34 60 newtComponent co;
61 struct form * form;
62
63 co = malloc(sizeof(*co));
64 form = malloc(sizeof(*form));
65 co->data = form;
66 co->width = 0;
67 co->height = 0;
68 co->top = -1;
69 co->left = -1;
70
f5daa14e 71 co->takesFocus = 1;
c4827b34 72 co->ops = &formOps;
6fb96a3f 73
02b180e8 74 form->help = help;
75 form->flags = flags;
6fb96a3f 76 form->numCompsAlloced = 5;
77 form->numComps = 0;
78 form->currComp = -1;
f5daa14e 79 form->vertOffset = 0;
8c4e1047 80 form->fixedHeight = 0;
f1f3611f 81 form->numRows = 0;
f5daa14e 82 form->elements = malloc(sizeof(*(form->elements)) * form->numCompsAlloced);
6fb96a3f 83
8f4e87fc 84 form->background = COLORSET_WINDOW;
da151ca8 85 form->hotKeys = malloc(sizeof(int));
86 form->numHotKeys = 0;
87 if (!(form->flags & NEWT_FORM_NOF12)) {
88 newtFormAddHotKey(co, NEWT_KEY_F12);
89 }
90
02b180e8 91 if (vertBar)
92 form->vertBar = vertBar;
f1f3611f 93 else
94 form->vertBar = NULL;
95
c4827b34 96 return co;
6fb96a3f 97}
98
2a2998a0 99newtComponent newtFormGetCurrent(newtComponent co) {
100 struct form * form = co->data;
101
102 return form->elements[form->currComp].co;
103}
104
7ea3dccd 105void newtFormSetCurrent(newtComponent co, newtComponent subco) {
106 struct form * form = co->data;
107 int i, new;
108
109 for (i = 0; i < form->numComps; i++) {
110 if (form->elements[i].co == subco) break;
111 }
112
113 if (form->elements[i].co != subco) return;
114 new = i;
115
116 if (!componentFits(co, new)) {
117 gotoComponent(form, -1);
118 form->vertOffset = form->elements[new].top - co->top - 1;
d1a682d1 119 if (form->vertOffset > (form->numRows - co->height))
120 form->vertOffset = form->numRows - co->height;
7ea3dccd 121 }
122
123 gotoComponent(form, new);
124}
125
8c4e1047 126void newtFormSetHeight(newtComponent co, int height) {
f5daa14e 127 struct form * form = co->data;
128
8c4e1047 129 form->fixedHeight = 1;
f5daa14e 130 co->height = height;
131}
132
ea947804 133void newtFormSetWidth(newtComponent co, int width) {
134 co->width = width;
135}
136
c4827b34 137void newtFormAddComponent(newtComponent co, newtComponent newco) {
138 struct form * form = co->data;
139 int delta;
6fb96a3f 140
6fb96a3f 141 if (form->numCompsAlloced == form->numComps) {
142 form->numCompsAlloced += 5;
f5daa14e 143 form->elements = realloc(form->elements,
144 sizeof(*(form->elements)) * form->numCompsAlloced);
6fb96a3f 145 }
146
f5daa14e 147 form->elements[form->numComps].left = newco->left;
148 form->elements[form->numComps].top = newco->top;
149 form->elements[form->numComps].co = newco;
f1f3611f 150
151 if (newco->takesFocus && form->currComp == -1)
152 form->currComp = form->numComps;
153
f5daa14e 154 form->numComps++;
c4827b34 155
156 if (co->left == -1) {
157 co->left = newco->left;
158 co->top = newco->top;
8c4e1047 159 co->width = newco->width;
160 if (!form->fixedHeight) {
f5daa14e 161 co->height = newco->height;
162 }
c4827b34 163 } else {
164 if (co->left > newco->left) {
165 delta = co->left - newco->left;
166 co->left -= delta;
8c4e1047 167 co->width += delta;
c4827b34 168 }
169
170 if (co->top > newco->top) {
171 delta = co->top - newco->top;
172 co->top -= delta;
8c4e1047 173 if (!form->fixedHeight)
f5daa14e 174 co->height += delta;
c4827b34 175 }
176
8c4e1047 177 if ((co->left + co->width) < (newco->left + newco->width))
178 co->width = (newco->left + newco->width) - co->left;
c4827b34 179
8c4e1047 180 if (!form->fixedHeight) {
f5daa14e 181 if ((co->top + co->height) < (newco->top + newco->height))
182 co->height = (newco->top + newco->height) - co->top;
183 }
c4827b34 184 }
2a2998a0 185
186 if ((newco->top + newco->height - co->top) > form->numRows) {
187 form->numRows = newco->top + newco->height - co->top;
188 }
189
6fb96a3f 190}
191
c4827b34 192void newtFormAddComponents(newtComponent co, ...) {
6fb96a3f 193 va_list ap;
c4827b34 194 newtComponent subco;
6fb96a3f 195
c4827b34 196 va_start(ap, co);
6fb96a3f 197
c4827b34 198 while ((subco = va_arg(ap, newtComponent)))
199 newtFormAddComponent(co, subco);
6fb96a3f 200
201 va_end(ap);
202}
203
8b68158d 204void newtDrawForm(newtComponent co) {
c4827b34 205 struct form * form = co->data;
f5daa14e 206 struct element * el;
6fb96a3f 207 int i;
6fb96a3f 208
8f4e87fc 209 SLsmg_set_color(form->background);
a1331450 210 newtClearBox(co->left, co->top, co->width, co->height);
f5daa14e 211 for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
f1f3611f 212 /* the scrollbar *always* fits */
213 if (el->co == form->vertBar)
f5daa14e 214 el->co->ops->draw(el->co);
f1f3611f 215 else {
216 /* only draw it if it'll fit on the screen vertically */
217 if (componentFits(co, i)) {
218 el->co->top = el->top - form->vertOffset;
219 el->co->ops->draw(el->co);
220 } else {
221 el->co->top = -1; /* tell it not to draw itself */
222 }
f5daa14e 223 }
6fb96a3f 224 }
f1f3611f 225
226 if (form->vertBar)
227 newtScrollbarSet(form->vertBar, form->vertOffset,
228 form->numRows - co->height);
c4827b34 229}
6fb96a3f 230
c4827b34 231static struct eventResult formEvent(newtComponent co, struct event ev) {
232 struct form * form = co->data;
f5daa14e 233 newtComponent subco = form->elements[form->currComp].co;
d1a682d1 234 int new, wrap = 0;
c4827b34 235 struct eventResult er;
d1a682d1 236 int dir = 0, page = 0;
434c766b 237 int i, num;
6fb96a3f 238
c4827b34 239 er.result = ER_IGNORED;
6fb96a3f 240
434c766b 241 switch (ev.when) {
242 case EV_EARLY:
243 if (ev.event == EV_KEYPRESS) {
244 if (ev.u.key == NEWT_KEY_TAB) {
245 er.result = ER_SWALLOWED;
246 dir = 1;
247 wrap = 1;
248 } else if (ev.u.key == NEWT_KEY_UNTAB) {
249 er.result = ER_SWALLOWED;
250 dir = -1;
251 wrap = 1;
252 }
8c4e1047 253 }
6fb96a3f 254
434c766b 255 i = form->currComp;
256 num = 0;
257 while (er.result == ER_IGNORED && num != form->numComps ) {
258 er = form->elements[i].co->ops->event(form->elements[i].co, ev);
259
260 num++;
261 i++;
262 if (i == form->numComps) i = 0;
6fb96a3f 263 }
264
434c766b 265 break;
266
267 case EV_NORMAL:
268 er = subco->ops->event(subco, ev);
e90f9163 269 switch (er.result) {
270 case ER_NEXTCOMP:
271 er.result = ER_SWALLOWED;
272 dir = 1;
e90f9163 273 break;
274
02b180e8 275 case ER_EXITFORM:
276 form->exitComp = subco;
277 break;
278
e90f9163 279 default:
280 break;
281 }
434c766b 282 break;
283
284 case EV_LATE:
285 er = subco->ops->event(subco, ev);
286
6fb96a3f 287 if (er.result == ER_IGNORED) {
434c766b 288 switch (ev.u.key) {
289 case NEWT_KEY_UP:
290 case NEWT_KEY_LEFT:
291 case NEWT_KEY_BKSPC:
292 er.result = ER_SWALLOWED;
293 dir = -1;
434c766b 294 break;
295
296 case NEWT_KEY_DOWN:
297 case NEWT_KEY_RIGHT:
434c766b 298 er.result = ER_SWALLOWED;
299 dir = 1;
d1a682d1 300 break;
301
302 case NEWT_KEY_PGUP:
303 er.result = ER_SWALLOWED;
304 dir = -1;
305 page = 1;
306 break;
307
308 case NEWT_KEY_PGDN:
309 er.result = ER_SWALLOWED;
310 dir = 1;
311 page = 1;
434c766b 312 break;
6fb96a3f 313 }
314 }
c4827b34 315 }
6fb96a3f 316
f5daa14e 317 if (dir) {
318 new = form->currComp;
d1a682d1 319
320 if (page) {
321 new += dir * co->height;
322 if (new < 0)
323 new = 0;
324 else if (new >= form->numComps)
325 new = (form->numComps - 1);
326
327 while (!form->elements[new].co->takesFocus)
328 new = new - dir;
329 } else {
330 do {
331 new += dir;
332
333 if (wrap) {
334 if (new < 0)
335 new = form->numComps - 1;
336 else if (new >= form->numComps)
337 new = 0;
338 } else if (new < 0 || new >= form->numComps)
339 return er;
340 } while (!form->elements[new].co->takesFocus);
341 }
f5daa14e 342
343 /* make sure this component is visible */
344 if (!componentFits(co, new)) {
345 gotoComponent(form, -1);
346
347 if (dir < 0) {
348 /* make the new component the first one */
349 form->vertOffset = form->elements[new].top - co->top;
350 } else {
351 /* make the new component the last one */
352 form->vertOffset = (form->elements[new].top +
353 form->elements[new].co->height) -
354 (co->top + co->height);
355 }
356
357 if (form->vertOffset < 0) form->vertOffset = 0;
d1a682d1 358 if (form->vertOffset > (form->numRows - co->height))
359 form->vertOffset = form->numRows - co->height;
f5daa14e 360
8b68158d 361 newtDrawForm(co);
c4827b34 362 }
f5daa14e 363
364 gotoComponent(form, new);
365 er.result = ER_SWALLOWED;
c4827b34 366 }
6fb96a3f 367
c4827b34 368 return er;
6fb96a3f 369}
370
371/* this also destroys all of the components on the form */
c4827b34 372void newtFormDestroy(newtComponent co) {
c4827b34 373 newtComponent subco;
374 struct form * form = co->data;
f1f3611f 375 int i;
6fb96a3f 376
377 /* first, destroy all of the components */
378 for (i = 0; i < form->numComps; i++) {
f5daa14e 379 subco = form->elements[i].co;
c4827b34 380 if (subco->ops->destroy) {
381 subco->ops->destroy(subco);
6fb96a3f 382 } else {
c4827b34 383 if (subco->data) free(subco->data);
384 free(subco);
6fb96a3f 385 }
386 }
387
f5daa14e 388 free(form->elements);
6fb96a3f 389 free(form);
c4827b34 390 free(co);
391}
392
393newtComponent newtRunForm(newtComponent co) {
da151ca8 394 struct newtExitStruct es;
395
396 newtFormRun(co, &es);
397 if (es.reason == NEWT_EXIT_HOTKEY) {
398 if (es.u.key == NEWT_KEY_F12) {
399 es.reason = NEWT_EXIT_COMPONENT;
400 es.u.co = co;
401 } else {
402 return NULL;
403 }
404 }
405
406 return es.u.co;
407}
408
409void newtFormAddHotKey(newtComponent co, int key) {
410 struct form * form = co->data;
411
412 form->numHotKeys++;
413 form->hotKeys = realloc(form->hotKeys, sizeof(int) * form->numHotKeys);
414 form->hotKeys[form->numHotKeys - 1] = key;
415}
416
417void newtFormRun(newtComponent co, struct newtExitStruct * es) {
c4827b34 418 struct form * form = co->data;
419 struct event ev;
420 struct eventResult er;
da151ca8 421 int key, i;
422 int done = 0;
c4827b34 423
424 /* first, draw all of the components */
8b68158d 425 newtDrawForm(co);
c4827b34 426
f1f3611f 427 if (form->currComp == -1) {
c4827b34 428 gotoComponent(form, 0);
f1f3611f 429 } else
c4827b34 430 gotoComponent(form, form->currComp);
431
da151ca8 432 while (!done) {
c4827b34 433 newtRefresh();
434 key = newtGetKey();
435
da151ca8 436 for (i = 0; i < form->numHotKeys; i++) {
437 if (form->hotKeys[i] == key) {
438 es->reason = NEWT_EXIT_HOTKEY;
439 es->u.key = key;
440 done = 1;
441 break;
442 }
443 }
c4827b34 444
da151ca8 445 if (!done) {
446 ev.event = EV_KEYPRESS;
447 ev.u.key = key;
448
449 er = sendEvent(co, ev);
450
451 if (er.result == ER_EXITFORM) {
452 done = 1;
453 es->reason = NEWT_EXIT_COMPONENT;
454 es->u.co = form->exitComp;
455 }
456 }
457 }
c4827b34 458
459 newtRefresh();
6fb96a3f 460}
461
434c766b 462static struct eventResult sendEvent(newtComponent co, struct event ev) {
463 struct eventResult er;
464
465 ev.when = EV_EARLY;
466 er = co->ops->event(co, ev);
467
468 if (er.result == ER_IGNORED) {
469 ev.when = EV_NORMAL;
470 er = co->ops->event(co, ev);
471 }
472
473 if (er.result == ER_IGNORED) {
474 ev.when = EV_LATE;
475 er = co->ops->event(co, ev);
476 }
477
478 return er;
479}
480
c4827b34 481static void gotoComponent(struct form * form, int newComp) {
6fb96a3f 482 struct event ev;
483
484 if (form->currComp != -1) {
485 ev.event = EV_UNFOCUS;
434c766b 486 sendEvent(form->elements[form->currComp].co, ev);
6fb96a3f 487 }
488
489 form->currComp = newComp;
f5daa14e 490
491 if (form->currComp != -1) {
492 ev.event = EV_FOCUS;
434c766b 493 ev.when = EV_NORMAL;
494 sendEvent(form->elements[form->currComp].co, ev);
f5daa14e 495 }
6fb96a3f 496}
da151ca8 497
498void newtComponentAddCallback(newtComponent co, newtCallback f, void * data) {
499 co->callback = f;
500 co->callbackData = data;
501}
502
8f4e87fc 503void newtFormSetBackground(newtComponent co, int color) {
504 struct form * form = co->data;
505
506 form->background = color;
507}