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