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