another update from CVS HEAD, for QA
[alioth/jupp.git] / menu.c
1 /*
2  *      Menu selection window
3  *      Copyright
4  *              (C) 1992 Joseph H. Allen
5  *
6  *      This file is part of JOE (Joe's Own Editor)
7  */
8 #include "config.h"
9 #include "types.h"
10
11 __RCSID("$MirOS: contrib/code/jupp/menu.c,v 1.14 2017/12/08 02:28:05 tg Exp $");
12
13 #include <stdlib.h>
14 #include <string.h>
15
16 #include "menu.h"
17 #include "scrn.h"
18 #include "utils.h"
19 #include "va.h"
20 #include "vs.h"
21 #include "utf8.h"
22 #include "w.h"
23
24 extern int dostaupd;
25
26 static void mconfig(MENU *);
27
28 static void menufllw(jobject jO)
29 {
30         MENU *m = jO.menu;
31         if (m->cursor < m->top)
32                 m->top = m->cursor - m->cursor % m->perline;
33         else if (m->cursor >= m->top+m->perline*m->h)
34                 m->top = m->cursor - m->cursor % m->perline - m->perline*(m->h-1);
35 }
36
37 static void menudisp(jobject jO, int flg __attribute__((__unused__)))
38 {
39         MENU *m = jO.menu;
40         int col;
41         int x;
42         int y;
43         int *s = m->t->t->scrn + m->x + m->y * m->t->t->co;
44         int *a = m->t->t->attr + m->x + m->y * m->t->t->co;
45         struct utf8_sm sm;
46
47         utf8_init(&sm);
48
49         if (m->t->t->co != m->saved_co)
50                 mconfig(m);
51
52         for (y = 0; y != m->h; ++y) {
53                 col = 0;
54                 for (x = 0; x != m->perline && y*m->perline+x+m->top<m->nitems; ++x) {
55                         int atr;
56
57                         if (x + y*m->perline + m->top == m->cursor)
58                                 atr = INVERSE;
59                         else
60                                 atr = 0;
61
62                         if (col == m->w)
63                                 break;
64
65                         /* Generate field */
66                         genfield(m->t->t,
67                             s + col,
68                             a + col,
69                             m->x + col,
70                             m->y + y,
71                             0,
72                             m->list[x + y*m->perline + m->top],
73                             strlen((char *)m->list[x + y*m->perline + m->top]),
74                             atr,
75                             m->width,
76                             0,
77                             NULL);
78
79                         col += m->width;
80
81                         /* Space between columns */
82                         if (col != m->w) {
83                                 outatr(locale_map, m->t->t, s + col, a + col, m->x + col, m->y+y, ' ', 0);
84                                 ++col;
85                         }
86                 }
87                 /* Clear to end of line */
88                 if (col != m->w)
89                         eraeol(m->t->t, m->x + col, m->y + y);
90                 s += m->t->t->co;
91                 a += m->t->t->co;
92         }
93         m->parent->cury = (m->cursor - m->top) / (m->perline ? m->perline : 1);
94         col = txtwidth(m->list[m->cursor],strlen((char *)m->list[m->cursor]));
95         m->parent->curx = ((m->cursor - m->top) % (m->perline ? m->perline : 1)) *
96             (m->width + 1) + (col < m->width ? col : m->width);
97 }
98
99 static void menumove(jobject jO, int x, int y)
100 {
101         MENU *m = jO.menu;
102         m->x = x;
103         m->y = y;
104 }
105
106 static void menuresz(jobject jO, int wi, int he)
107 {
108         MENU *m = jO.menu;
109         m->w = wi;
110         m->h = he;
111 }
112
113 static int mlines(unsigned char **s, int w)
114 {
115         int x;
116         int lines;
117         int width;
118         int nitems;
119         int perline;
120
121         for (x = 0, width = 0; s[x]; ++x) {
122                 int d = txtwidth(s[x],strlen((char *)(s[x])));
123                 if (d > width)
124                         width = d;
125         }
126         nitems = x;
127         if (width > w)
128                 width = w - 1;
129         perline = w / (width + 1);
130
131         lines = (nitems + perline - 1) / perline;
132
133         return lines;
134 }
135
136 static void mconfig(MENU *m)
137 {
138         /* Configure menu display parameters */
139         if (m->list) {
140                 int x;
141                 /* int lines; */
142
143                 m->top = 0;
144                 for (x = 0, m->width = 0; m->list[x]; ++x) {
145                         int d = txtwidth(m->list[x],strlen((char *)(m->list[x])));
146                         if (d > m->width)
147                                 m->width = d;
148                 }
149                 m->nitems = x;
150                 if (m->width > m->w)
151                         m->width = m->w - 1;
152                 m->perline = m->w / (m->width + 1);
153
154                 /* lines = (m->nitems + m->perline - 1) / m->perline; */
155
156                 m->saved_co = m->t->t->co;
157         }
158 }
159
160 int umbol(MENU *m)
161 {
162         m->cursor -= m->cursor % m->perline;
163         return 0;
164 }
165
166 int umbof(MENU *m)
167 {
168         m->cursor = 0;
169         return 0;
170 }
171
172 int umeof(MENU *m)
173 {
174         if (m->nitems)
175                 m->cursor = m->nitems - 1;
176         return 0;
177 }
178
179 int umeol(MENU *m)
180 {
181         m->cursor -= m->cursor % m->perline;
182
183         if (m->cursor+m->perline-1 >= m->nitems)
184                 m->cursor = m->nitems - 1;
185         else
186                 m->cursor += m->perline - 1;
187
188         return 0;
189 }
190
191 int umrtarw(MENU *m)
192 {
193         if (m->cursor + 1 < m->nitems) {
194                 ++m->cursor;
195                 return 0;
196         } else
197                 return -1;
198 }
199
200 int umtab(MENU *m)
201 {
202         if (m->cursor + 1 >= m->nitems)
203                 m->cursor = 0;
204         else
205                 ++ m->cursor;
206         return 0;
207 }
208
209 int umltarw(MENU *m)
210 {
211         if (m->cursor) {
212                 --m->cursor;
213                 return 0;
214         } else
215                 return -1;
216 }
217
218 int umuparw(MENU *m)
219 {
220         if (m->cursor >= m->perline) {
221                 m->cursor -= m->perline;
222                 return 0;
223         } else
224                 return -1;
225 }
226
227 int umdnarw(MENU *m)
228 {
229         int col = m->cursor % m->perline;
230
231         m->cursor -= col;
232
233         if (m->cursor + m->perline < m->nitems) {
234                 m->cursor += m->perline;
235                 if (m->cursor + col >= m->nitems)
236                         if (m->nitems)
237                                 m->cursor = m->nitems - 1;
238                         else
239                                 m->cursor = 0;
240                 else
241                         m->cursor += col;
242                 return 0;
243         } else {
244                 m->cursor += col;
245                 return -1;
246         }
247 }
248
249 int umpgup(MENU *m)
250 {
251         int amnt = (m->h+1)/2;
252         if (m->top >= amnt*m->perline) {
253                 m->top -= amnt*m->perline;
254                 m->cursor -= amnt*m->perline;
255                 return 0;
256         } else if (m->top) {
257                 m->cursor -= m->top;
258                 m->top = 0;
259                 return 0;
260         } else if (m->cursor >= m->perline) {
261                 m->cursor = m->cursor % m->perline;
262                 return 0;
263         } else
264                 return -1;
265 }
266
267 int umpgdn(MENU *m)
268 {
269         int amnt = (m->h+1)/2;
270         int col = m->cursor % m->perline;
271         int y = m->cursor / m->perline;
272         int h = (m->nitems + m->perline - 1) / m->perline;
273         int t = m->top / m->perline;
274         m->cursor -= col;
275
276         if (t + m->h + amnt <= h) {
277                 m->top += amnt*m->perline;
278                 m->cursor += amnt*m->perline;
279                 if (m->cursor + col >= m->nitems)
280                         if (m->nitems)
281                                 m->cursor = m->nitems - 1;
282                         else
283                                 m->cursor = 0;
284                 else
285                         m->cursor += col;
286                 return 0;
287         } else if (t + m->h < h) {
288                 amnt = h - (t + m->h);
289                 m->top += amnt*m->perline;
290                 m->cursor += amnt*m->perline;
291                 if (m->cursor + col >= m->nitems)
292                         if (m->nitems)
293                                 m->cursor = m->nitems - 1;
294                         else
295                                 m->cursor = 0;
296                 else
297                         m->cursor += col;
298                 return 0;
299         } else if (y+1!=h) {
300                 m->cursor = (h-1)*m->perline;
301                 if (m->cursor + col >= m->nitems)
302                         if (m->nitems)
303                                 m->cursor = m->nitems - 1;
304                         else
305                                 m->cursor = 0;
306                 else
307                         m->cursor += col;
308                 return 0;
309         } else {
310                 m->cursor += col;
311                 return -1;
312         }
313
314 }
315
316 static int umrtn(jobject jO)
317 {
318         MENU *m = jO.menu;
319         dostaupd = 1;
320         if (m->func)
321                 return m->func(m, m->cursor, m->object, 0);
322         else
323                 return -1;
324 }
325
326 int umbacks(MENU *m)
327 {
328         if (m->backs)
329                 return m->backs(m, m->cursor, m->object);
330         else
331                 return -1;
332 }
333
334 static int umkey(jobject jO, int c)
335 {
336         MENU *m = jO.menu;
337         int x;
338         int n = 0;
339
340         if (c == '0') {
341                 if (m->func)
342                         return m->func(m, m->cursor, m->object, -1);
343                 else
344                         return -1;
345         }
346         if (c == '1') {
347                 if (m->func)
348                         return m->func(m, m->cursor, m->object, 1);
349                 else
350                         return -1;
351         }
352         if (!(((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))))
353                 return -1;
354         c &= 0x1F;
355         for (x = 0; x != m->nitems; ++x)
356                 if ((m->list[x][0] & 0x1F) == c)
357                         ++n;
358         if (!n)
359                 return -1;
360         if (n == 1)
361                 for (x = 0; x != m->nitems; ++x)
362                         if ((m->list[x][0] & 0x1F) == c) {
363                                 m->cursor = x;
364                                 return umrtn(jO);
365                         }
366         do {
367                 ++m->cursor;
368                 if (m->cursor == m->nitems)
369                         m->cursor = 0;
370         } while ((m->list[m->cursor][0] & 0x1F) != c);
371
372         return -1;
373 }
374
375 static int menuabort(jobject jO)
376 {
377         MENU *m = jO.menu;
378         W *w = m->parent;
379         jpoly_int *func = m->abrt;
380         void *object = m->object;
381         int x = m->cursor;
382         W *win = w->win;
383
384         free(m);
385         if (func)
386                 return func(win->object, x, object);
387         else
388                 return -1;
389 }
390
391 WATOM watommenu = {
392         US "menu",
393         menudisp,
394         menufllw,
395         menuabort,
396         umrtn,
397         umkey,
398         menuresz,
399         menumove,
400         NULL,
401         NULL,
402         TYPEMENU
403 };
404
405 void ldmenu(MENU *m, unsigned char **s, int cursor)
406 {
407         m->list = s;
408         m->cursor = cursor;
409         mconfig(m);
410 }
411
412 MENU *mkmenu(W *w, unsigned char **s, jpoly_int *func, jpoly_int *abrt, jpoly_int *backs, int cursor, void *object, int *notify)
413 {
414         W *new;
415         MENU *m;
416         int lines;
417         int h = (w->main->h*40) / 100; /* 40% of window size */
418         if (!h)
419                 h = 1;
420
421         if (s) {
422                 lines = mlines(s,w->t->w-1);
423                 if (lines < h)
424                         h = lines;
425         }
426
427         new = wcreate(w->t, &watommenu, w, w, w->main, h, NULL, notify);
428
429         if (!new) {
430                 if (notify)
431                         *notify = 1;
432                 return NULL;
433         }
434         wfit(new->t);
435         new->object.menu = m = malloc(sizeof(MENU));
436         m->parent = new;
437         m->func = func;
438         m->abrt = abrt;
439         m->backs = backs;
440         m->object = object;
441         m->t = w->t;
442         m->h = new->h;
443         m->w = new->w;
444         m->x = new->x;
445         m->y = new->y;
446         m->top = 0;
447         m->saved_co = 0;
448         ldmenu(m, s, cursor);
449         w->t->curwin = new;
450         return m;
451 }
452
453 static unsigned char *cull(unsigned char *a, unsigned char *b)
454 {
455         int x;
456
457         for (x = 0; a[x] && b[x] && a[x] == b[x]; ++x) ;
458         return vstrunc(a, x);
459 }
460
461 unsigned char *find_longest(unsigned char **lst)
462 {
463         unsigned char *com;
464         int x;
465
466         if (!lst || !aLEN(lst))
467                 return vstrunc(NULL, 0);
468         com = vsncpy(NULL, 0, sv(lst[0]));
469         for (x = 1; x != aLEN(lst); ++x)
470                 com = cull(com, lst[x]);
471         return com;
472 }
473
474 unsigned char *mcomplete(MENU *m)
475 {
476         unsigned char *com;
477         int x;
478
479         if (!m->nitems)
480                 return vstrunc(NULL, 0);
481         com = vsncpy(NULL, 0, sz(m->list[0]));
482         for (x = 1; x != m->nitems; ++x)
483                 com = cull(com, m->list[x]);
484         return com;
485 }