1 /*
2  *  MENU.C
3  *
4  *  Written on 10-Jul-94 by John Dennis and released to the public domain.
5  *
6  *  Moving bar menu code for Msged.
7  */
8 
9 #include <stdio.h>
10 #include <string.h>
11 #include <ctype.h>
12 #include <time.h>
13 #include "winsys.h"
14 #include "unused.h"
15 #include "menu.h"
16 #include "addr.h"
17 #include "nedit.h"
18 #include "msged.h"
19 #include "main.h"
20 #include "keys.h"
21 #include "strextra.h"
22 #include "areas.h"
23 #include "memextra.h"
24 
SelShowItem(char * text,int y,int len,int Attr,int indent)25 void SelShowItem(char *text, int y, int len, int Attr, int indent)
26 {
27     char line[256];
28     memset(line, ' ', 40);
29     strcpy(line + indent, text);
30     WndPutsn(indent, y, len, Attr, line);
31 }
32 
SelShowPage(char ** text,int top,int bot,int len,int pos,int Attr,int indent)33 void SelShowPage(char **text, int top, int bot, int len, int pos, int Attr, int indent)
34 {
35     int i;
36     int y = top;
37 
38     for (i = pos; text[i] != NULL; i++)
39     {
40         if (y > bot)
41         {
42             break;
43         }
44 
45         SelShowItem(text[i], y++, len, Attr, indent);
46     }
47     if (y <= bot)
48     {
49         while (y <= bot)
50         {
51             SelShowItem(" ", y++, len, Attr, indent);
52         }
53     }
54 }
55 
CalcDef(int max,int cur,int * top,int miny,int maxy,int * y)56 void CalcDef(int max, int cur, int *top, int miny, int maxy, int *y)
57 {
58     int dif = maxy - miny;
59 
60     unused(cur);
61     if (max - 1 - *top < dif && max > dif)
62     {
63         *y = maxy;
64         *top = (max - 1) - dif;
65     }
66 }
67 
SelBox(char ** Itms,int y1,int y2,int len,int def,WND * hPrev,WND * hWnd,int Sel,int Norm,int selbox_id,char * topMsg)68 int SelBox(char **Itms, int y1, int y2, int len, int def, WND * hPrev, WND * hWnd, int Sel, int Norm, int selbox_id, char *topMsg)
69 {
70     EVT e;
71     char find[30];
72     int itemCnt, Stuff, done, curY, Msg, currItem, Top, page, i;
73 
74     itemCnt = 0;
75     Stuff = 0;
76     for (i = 0; Itms[i] != NULL; i++)
77     {
78         itemCnt++;
79     }
80 
81     if (itemCnt < y2)
82     {
83         y2 = itemCnt;
84     }
85     currItem = def;
86     curY = y1;
87     page = y2 - y1;
88     Top = currItem;
89 
90     if (currItem + y1 < y1)
91     {
92         curY = y1 + currItem;
93         Top = 0;
94     }
95     else
96     {
97         if (itemCnt - currItem <= y2 - y1)
98         {
99             Top -= ((y2 - y1 + 1) - (itemCnt - Top));
100             curY = y1 + def - Top;
101             if (Top < 0)
102             {
103                 Top = 0;
104                 curY--;
105             }
106         }
107     }
108     done = 0;
109 
110     SelShowPage(Itms, y1, y2, len, Top, Norm, 1);
111     SelShowItem(Itms[currItem], curY, len, Sel, 1);
112 
113     /* clear input queue */
114     TTClearQue();
115 
116     memset(find, '\0', sizeof find);
117     while (!done)
118     {
119         if (*topMsg && selbox_id == SELBOX_REPLYOTH && !*find)
120         {
121             WndCurr(hPrev);
122             WndClear(strlen(topMsg) + 3, 0, maxx - 32, 0, cm[MN_NTXT]);
123             WndPrintf(0, 0, cm[MN_NTXT], ">>%s:", topMsg);
124             WndCurr(hWnd);
125         }
126         if (!Stuff)
127         {
128             Msg = MnuGetMsg(&e, hWnd->wid);
129         }
130         else
131         {
132             e.msgtype = WND_WM_CHAR;
133             Msg = Stuff;
134             Stuff = 0;
135         }
136 
137         switch (e.msgtype)
138         {
139         case WND_WM_MOUSE:
140             switch (Msg)
141             {
142             case RMOU_CLCK:
143             case MOU_RBTUP:
144                 return -1;
145 
146             case LMOU_RPT:
147             case MOU_LBTDN:
148             case LMOU_CLCK:
149                 {
150                     int x, y;
151 
152                     WndGetRel(e.x, e.y, &x, &y);
153                     if (y >= y1 && y <= y2)  /* in window */
154                     {
155                         Stuff = 0;
156                         if (x >= 0 && x < len)
157                         {
158                             if (y == curY)
159                             {
160                                 if (Msg == LMOU_CLCK || Msg == MOU_LBTUP)
161                                 {
162                                     return currItem;
163                                 }
164                                 else
165                                 {
166                                     continue;
167                                 }
168                             }
169                             SelShowItem(Itms[currItem], curY, len, Norm, 1);
170 
171                             if (y > curY)
172                             {
173                                 currItem += y - curY;
174                             }
175                             else
176                             {
177                                 currItem -= curY - y;
178                             }
179 
180                             curY = y;
181 
182                             SelShowItem(Itms[currItem], curY, len, Sel, 1);
183 
184                             if (Msg == LMOU_CLCK || Msg == MOU_LBTUP)
185                             {
186                                 return currItem;
187                             }
188                         }
189                     }
190                     else
191                     {
192                         if (Msg != LMOU_CLCK)
193                         {
194                             if (y < y1)
195                             {
196                                 Stuff = Key_Up;
197                             }
198                             else
199                             {
200                                 Stuff = Key_Dwn;
201                             }
202                         }
203                     }
204                 }
205                 memset(find, '\0', sizeof find);
206                 break;
207 
208             default:
209                 break;
210             }
211             break;
212 
213         case WND_WM_CHAR:
214             switch (Msg)
215             {
216             case Key_Home:
217                 if (!currItem)
218                 {
219                     break;
220                 }
221                 SelShowItem(Itms[currItem], curY, len, Norm, 1);
222                 currItem = 0;
223                 Top = 0;
224                 curY = y1;
225                 SelShowPage(Itms, y1, y2, len, Top, Norm, 1);
226                 SelShowItem(Itms[currItem], curY, len, Sel, 1);
227                 memset(find, '\0', sizeof find);
228                 break;
229 
230             case Key_End:
231                 if (currItem == itemCnt - 1)
232                 {
233                     break;
234                 }
235                 SelShowItem(Itms[currItem], curY, len, Norm, 1);
236                 currItem = itemCnt - 1;
237                 while (currItem && currItem >= itemCnt - page)
238                 {
239                     currItem--;
240                 }
241                 Top = currItem;
242                 currItem = itemCnt - 1;
243                 curY = currItem - Top + y1;
244                 CalcDef(itemCnt, currItem, &Top, y1, y2, &curY);
245                 SelShowPage(Itms, y1, y2, len, Top, Norm, 1);
246                 SelShowItem(Itms[currItem], curY, len, Sel, 1);
247                 memset(find, '\0', sizeof find);
248                 break;
249 
250             case Key_Dwn:
251                 if (currItem == itemCnt - 1)
252                 {
253                     break;
254                 }
255 
256                 SelShowItem(Itms[currItem], curY, len, Norm, 1);
257                 currItem++;
258                 if (curY == y2)
259                 {
260                     WndScroll(1, y1, len, y2, 1);
261                     Top++;
262                 }
263                 else
264                 {
265                     curY++;
266                 }
267                 SelShowItem(Itms[currItem], curY, len, Sel, 1);
268                 memset(find, '\0', sizeof find);
269                 break;
270 
271             case Key_Up:
272                 if (!currItem)
273                 {
274                     break;
275                 }
276                 SelShowItem(Itms[currItem], curY, len, Norm, 1);
277                 currItem--;
278                 if (curY == y1)
279                 {
280                     WndScroll(1, y1, len, y2, 0);
281                     if (Top)
282                     {
283                         Top--;
284                     }
285                 }
286                 else
287                 {
288                     curY--;
289                 }
290                 SelShowItem(Itms[currItem], curY, len, Sel, 1);
291                 memset(find, '\0', sizeof find);
292                 break;
293 
294             case Key_PgUp:
295                 if (!currItem)
296                 {
297                     break;
298                 }
299                 SelShowItem(Itms[currItem], curY, len, Norm, 1);
300                 currItem -= page;
301                 if (currItem < 0)
302                 {
303                     currItem = 0;
304                 }
305                 Top = currItem;
306                 curY = y1;
307                 SelShowPage(Itms, y1, y2, len, Top, Norm, 1);
308                 SelShowItem(Itms[currItem], curY, len, Sel, 1);
309                 memset(find, '\0', sizeof find);
310                 break;
311 
312             case Key_PgDn:
313                 if (currItem == itemCnt - 1)
314                 {
315                     break;
316                 }
317                 SelShowItem(Itms[currItem], curY, len, Norm, 1);
318                 Top = currItem;
319                 currItem += page;
320                 if (currItem > itemCnt - 1)
321                 {
322                     currItem = itemCnt - 1;
323                 }
324                 curY = currItem - Top + y1;
325                 CalcDef(itemCnt, currItem, &Top, y1, y2, &curY);
326                 SelShowPage(Itms, y1, y2, len, Top, Norm, 1);
327                 SelShowItem(Itms[currItem], curY, len, Sel, 1);
328                 memset(find, '\0', sizeof find);
329                 break;
330 
331             case Key_Rgt:
332             case Key_Ent:
333                 {
334                     size_t i;
335                     i = (size_t) strchr(Itms[currItem] + 1, ' ') - 1 -
336                         (size_t) Itms[currItem];
337 
338                     if (i > 28)
339                     {
340                         i = 28;
341                     }
342                     strncpy(find, Itms[currItem] + 1, i);
343                     *(find + i) = '\0';
344                     strupr(find);
345                     /* I did figure out that this code produces garbage on
346                        screen.  I did not figure out however, in
347                        when situations it is necessary.  So I
348                        decided to comment it out and see what
349                        happens ...
350                        WndCurr(hPrev);
351                        WndWriteStr(strlen(topMsg) + 4, 0, cm[MN_NTXT], find);
352                      */
353                     WndCurr(hWnd);
354                     return currItem;
355                 }
356 
357             case Key_A_X:
358             case Key_Esc:
359                 return -1;
360 
361             case '*':
362             case Key_A_S:
363                 if (selbox_id == SELBOX_REPLYOTH)
364                 {
365                     arealist_area_scan(1);
366                     for (i = 0; i < SW->areas; i++)
367                     {
368                         xfree(alist2[i]);
369                     }
370                     xfree(alist2);
371                     BuildList(&alist2);
372                     Itms = alist2;
373                     SelShowPage(Itms, y1, y2, len, Top, Norm, 1);
374                     SelShowItem(Itms[currItem], curY, len, Sel, 1);
375                     memset(find, '\0', sizeof find);
376                     CurArea.messages = MsgAreaOpen(&CurArea);
377                 }
378                 break;
379 
380             default:
381                 if (Msg > 32 && Msg < 127)
382                 {
383                     if (*topMsg && selbox_id == SELBOX_REPLYOTH)
384                     {
385                         if (strlen(find) >= 28)
386                         {
387                             break;
388                         }
389                         *(find + strlen(find)) = (char)toupper((char)Msg);
390                         WndCurr(hPrev);
391                         WndWriteStr(strlen(topMsg) + 4, 0, cm[MN_NTXT], find);
392                         WndCurr(hWnd);
393                     }
394                     else
395                     {
396                         *find = (char)toupper((char)Msg);
397                     }
398 
399                     i = currItem;
400 
401                     while (i < itemCnt)
402                     {
403                         if (selbox_id == SELBOX_REPLYOTH)
404                         {
405                             if (stristr(Itms[i] + 1, find) == Itms[i] + 1)
406                             {
407                                 break;
408                             }
409                         }
410                         else
411                         {
412                             if (toupper(*Itms[i]) == *find)
413                             {
414                                 if (selbox_id == SELBOX_MOVEMSG ||
415                                   selbox_id == SELBOX_WRTMODE ||
416                                   selbox_id == SELBOX_WRTOVER)
417                                 {
418                                     SelShowItem(Itms[currItem], curY, len, Norm, 1);
419                                     return i;
420                                 }
421                             }
422                         }
423                         i++;
424                     }
425                     if (i == itemCnt)
426                     {
427                         for (i = 0; i < currItem; i++)
428                         {
429                             if (selbox_id == SELBOX_REPLYOTH)
430                             {
431                                 if (stristr(Itms[i] + 1, find) == Itms[i] + 1)
432                                 {
433                                     break;
434                                 }
435                             }
436                             else
437                             {
438                                 if (toupper(*Itms[i]) == *find)
439                                 {
440                                     if (selbox_id == SELBOX_MOVEMSG ||
441                                       selbox_id == SELBOX_WRTMODE ||
442                                       selbox_id == SELBOX_WRTOVER)
443                                     {
444                                         SelShowItem(Itms[currItem], curY, len, Norm, 1);
445                                         return i;
446                                     }
447                                 }
448                             }
449                         }
450                     }
451                     if (i != currItem)
452                     {
453                         SelShowItem(Itms[currItem], curY, len, Norm, 1);
454                         currItem = i;
455                         curY = y1;
456                         Top = currItem;
457 
458                         /* Get the cursor position right... */
459 
460                         if (itemCnt - 1 - currItem < y2 - y1)
461                         {
462                             if (currItem > y2 - y1)
463                             {
464                                 curY = y2;
465                                 Top = currItem - (y2 - y1);
466                             }
467                             else
468                             {
469                                 curY = currItem + y1;
470                                 Top = 0;
471                             }
472                         }
473                         SelShowPage(Itms, y1, y2, len, Top, Norm, 1);
474                         SelShowItem(Itms[currItem], curY, len, Sel, 1);
475                     }
476                 }
477                 else if (Msg == '\b' && *find)
478                 {
479                     if (*topMsg && selbox_id == SELBOX_REPLYOTH)
480                     {
481                         *(find + strlen(find) - 1) = '\0';
482                         WndCurr(hPrev);
483                         WndClear(strlen(topMsg) + 3 + strlen(find), 0, maxx - 32, 0, cm[MN_NTXT]);
484                         WndCurr(hWnd);
485                     }
486                 }
487                 else
488                 {
489                     memset(find, '\0', sizeof find);
490                 }
491                 break;
492 
493             }
494             break;
495         }
496     }
497     return -1;
498 }
499 
500 #ifndef NODOMENU
501 
DoMenu(int x1,int y1,int x2,int y2,char ** Itms,int def,int selbox_id,char * topMsg)502 int DoMenu(int x1, int y1, int x2, int y2, char **Itms, int def, int selbox_id, char *topMsg)
503 {
504     WND *hCurr, *hWnd;
505     int ret;
506 
507     hCurr = WndTop();
508     hWnd = WndOpen(x1 - 1, y1 - 1, x2 + 3, y2 + 1, DBDR | SHADOW, cm[MN_BTXT], cm[MN_NTXT]);
509 
510     if (!hWnd)
511     {
512         return -1;
513     }
514 
515     if (selbox_id >= SELBOX_CHARSET)
516     {
517         WndTitle(topMsg, cm[MN_TTXT]);
518     }
519 
520     ret = SelBox(Itms, 0, y2 - y1, x2 - x1 + 2, def, hCurr, hWnd, cm[MN_STXT], cm[MN_NTXT], selbox_id, topMsg);
521 
522     WndClose(hWnd);
523     WndCurr(hCurr);
524 
525     return ret;
526 }
527 
528 #endif
529