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