1 /*
2  *  MNU.C
3  *
4  *  Written on 10-Jul-94 by John Dennis and released to the public domain.
5  *
6  *  Routines to display horizontal and vertical menus with full drag/browse
7  *  mouse support.
8  */
9 
10 #include <string.h>
11 #include <stdlib.h>
12 #include "winsys.h"
13 #include "keys.h"
14 #include "menu.h"
15 
16 int PullDown = 0;
17 int ExitType = 0;
18 
19 static int bc = WHITE | _CYAN;
20 static int nc = BLACK | _CYAN;
21 static int sc = WHITE | _BLACK;
22 
GetFocus(cmd * cmdtab,int num,int id)23 static int GetFocus(cmd * cmdtab, int num, int id)
24 {
25     int i;
26 
27     for (i = 0; i < num; i++)
28     {
29         if (cmdtab[i].id == id)
30         {
31             return i;
32         }
33     }
34 
35     return -1;
36 }
37 
DispItem(cmd * c,unsigned char attr,int indent,int slen,int type)38 static void DispItem(cmd * c, unsigned char attr, int indent, int slen, int type)
39 {
40     char text[255];
41     int len;
42 
43     if (!c || !c->itmtxt)
44     {
45         return;
46     }
47 
48     len = strlen(c->itmtxt);
49     memset(text, ' ', slen + 2);
50     strncpy(text + indent, c->itmtxt, len);
51     *(text + slen) = '\0';
52     if (type == CMD_VER)
53     {
54         WndPutsn(0, c->row, slen, attr, text);
55     }
56     else
57     {
58         WndPutsn(c->col, c->row, slen, attr, text);
59     }
60 }
61 
NextItem(int num,int cur)62 static int NextItem(int num, int cur)
63 {
64     cur++;
65     if (cur == num)
66     {
67         cur = 0;
68     }
69     return cur;
70 }
71 
PrevItem(int num,int cur)72 static int PrevItem(int num, int cur)
73 {
74     cur--;
75     if (cur < 0)
76     {
77         cur = num - 1;
78     }
79     return cur;
80 }
81 
82 /*
83  *  Displays a horizontal menu in a window, according to the info in
84  *  the passed MC structure.
85  *
86  *  The current mouse position is passed to the function to pinpoint
87  *  the item where the mouse hit before calling this function.
88  */
89 
ProcessMenu(MC * m,EVT * event,int show)90 int ProcessMenu(MC * m, EVT * event, int show)
91 {
92     HotGroup Hot;
93     WND *hCurr, *hWnd = NULL;
94     cmd *cmdtab = m->cmdtab;
95     int num = m->num;
96     int Focus = m->cur;
97     int mnu = m->mode;
98     int len = m->len;
99     int OldFoc;
100     int done = 0;
101     int select = 0;
102     int Msg;         /* Msg is used unitialised here. I did not yet
103                         investigate it. FIXME! */
104     int NewFoc;
105     int i, j;
106 
107     if (m->btype & INSBDR)
108     {
109         m->btype = SBDR;
110     }
111 
112     hCurr = WndTop();
113     if (!show && !(m->mode & CMD_PRT))
114     {
115         hWnd = WndOpen(m->x1, m->y1, m->x2, m->y2, m->btype, bc, nc);
116         if (hWnd == NULL)
117         {
118             WndCurr(hCurr);
119             return WND_ERROR;
120         }
121     }
122 
123     if (m->btype & NBDR)
124     {
125         j = 0;
126     }
127     else
128     {
129         j = 1;
130     }
131 
132     for (i = 0; i < num; i++)
133     {
134         Hot.harr[i].id = cmdtab[i].id;
135         Hot.harr[i].x1 = m->x1 + j + cmdtab[i].col;
136         Hot.harr[i].x2 = m->x1 + j + cmdtab[i].col + len;
137         Hot.harr[i].y1 = m->y1 + j + cmdtab[i].row;
138         Hot.harr[i].y2 = m->y1 + j + cmdtab[i].row;
139         DispItem(&cmdtab[i], (unsigned char)nc, m->indent, m->len, mnu);
140     }
141 
142     if (show)
143     {
144         return 0;
145     }
146 
147     Hot.num = num;
148     Hot.wid = WND_WN_MENU;
149 
150     PushHotGroup(&Hot);
151 
152     if (event->msg)
153     {
154         if (event->msgtype == WND_WM_COMMAND)
155         {
156             Focus = GetFocus(cmdtab, m->num, event->id);
157         }
158         else
159         {
160             if (event->msgtype == WND_WM_MOUSE)
161             {
162                 Focus = LocateHotItem(event->x, event->y, WND_WN_MENU);
163                 if (Focus)
164                 {
165                     Focus = GetFocus(cmdtab, m->num, Focus);
166                 }
167             }
168         }
169         if (Focus == -1)
170         {
171             Focus = 0;
172         }
173     }
174 
175     DispItem(&cmdtab[Focus], (unsigned char)sc, m->indent, m->len, mnu);
176 
177     while (!done)
178     {
179         if (select)
180         {
181             if (cmdtab[Focus].m_sub)
182             {
183                 ProcessMenu(cmdtab[Focus].m_sub, event, 0);
184             }
185             else
186             {
187                 if (cmdtab[Focus].flags & CMD_EXIT)
188                 {
189                     done = TRUE;
190                     continue;
191                 }
192                 else
193                 {
194                     if (cmdtab[Focus].itmfunc != NULL)
195                     {
196                         (*cmdtab[Focus].itmfunc) ();
197                     }
198                     done = TRUE;  /* should we exit here? */
199                     continue;
200                 }
201             }
202             select = 0;
203         }
204         else
205         {
206             Msg = MnuGetMsg(event, WND_WN_MENU);
207         }
208 
209         OldFoc = Focus;
210 
211         switch (event->msgtype)
212         {
213         case WND_WM_COMMAND:
214             NewFoc = GetFocus(cmdtab, m->num, event->id);
215             if (NewFoc != -1)
216             {
217                 switch (Msg)
218                 {
219                 case MOU_LBTUP:
220                 case LMOU_CLCK:
221                     Focus = NewFoc;
222                     select = TRUE;
223                     break;
224 
225                 case MOU_LBTDN:
226                 case LMOU_RPT:
227                 case MOUSE_EVT:
228                     Focus = NewFoc;
229                     if (cmdtab[Focus].m_sub)
230                     {
231                         select = TRUE;
232                     }
233                     break;
234 
235                 default:
236                     break;
237                 }
238             }
239             else
240             {
241                 if (mnu == CMD_VER && event->msg != m->parent)
242                 {
243                     done = TRUE;
244                 }
245             }
246             break;
247 
248         case WND_WM_MOUSE:
249             switch (Msg)
250             {
251             case LMOU_CLCK:
252             case MOU_LBTUP:
253                 done = TRUE;
254                 break;
255 
256             default:
257                 break;
258             }
259             break;
260 
261         case WND_WM_CHAR:
262             switch (Msg)
263             {
264             case Key_Up:
265                 if (mnu == CMD_VER)
266                 {
267                     Focus = PrevItem(m->num, Focus);
268                 }
269                 break;
270 
271             case Key_Dwn:
272                 if (cmdtab[Focus].m_sub)
273                 {
274                     select = TRUE;
275                 }
276                 if (mnu == CMD_VER)
277                 {
278                     Focus = NextItem(m->num, Focus);
279                 }
280                 break;
281 
282             case Key_Lft:
283                 if (mnu == CMD_HOR)
284                 {
285                     Focus = PrevItem(m->num, Focus);
286                 }
287                 else
288                 {
289                     done = TRUE;
290                 }
291                 break;
292 
293             case Key_Rgt:
294                 if (mnu == CMD_HOR)
295                 {
296                     Focus = NextItem(m->num, Focus);
297                 }
298                 else
299                 {
300                     done = TRUE;
301                 }
302                 break;
303 
304             case Key_Esc:
305                 done = TRUE;
306                 break;
307 
308             case Key_Ent:
309                 select = TRUE;
310                 break;
311 
312             default:
313                 break;
314             }
315             break;
316 
317         default:
318             break;
319         }
320         if (Focus != OldFoc)
321         {
322             DispItem(&cmdtab[OldFoc], (unsigned char)nc, m->indent, m->len, mnu);
323             DispItem(&cmdtab[Focus], (unsigned char)sc, m->indent, m->len, mnu);
324         }
325     }
326     DispItem(&cmdtab[Focus], (unsigned char)nc, m->indent, m->len, mnu);
327     PopHotGroup();
328     if (!(m->mode & CMD_PRT))
329     {
330         WndClose(hWnd);
331         WndCurr(hCurr);
332     }
333     if (cmdtab[Focus].flags & CMD_EXIT && select)
334     {
335         /* then return the ID of ret item */
336 
337         event->msgtype = WND_WM_CHAR;
338         event->msg = 0;
339 
340         return cmdtab[Focus].id;
341     }
342     else
343     {
344         return 0;
345     }
346 }
347 
MnuSetColours(int nbc,int nnc,int nsc)348 void MnuSetColours(int nbc, int nnc, int nsc)
349 {
350     bc = nbc;
351     nc = nnc;
352     sc = nsc;
353 }
354