1 /* $OpenBSD: m_post.c,v 1.8 2023/10/17 09:52:10 nicm Exp $ */
2
3 /****************************************************************************
4 * Copyright 2020-2021,2022 Thomas E. Dickey *
5 * Copyright 1998-2010,2012 Free Software Foundation, Inc. *
6 * *
7 * Permission is hereby granted, free of charge, to any person obtaining a *
8 * copy of this software and associated documentation files (the *
9 * "Software"), to deal in the Software without restriction, including *
10 * without limitation the rights to use, copy, modify, merge, publish, *
11 * distribute, distribute with modifications, sublicense, and/or sell *
12 * copies of the Software, and to permit persons to whom the Software is *
13 * furnished to do so, subject to the following conditions: *
14 * *
15 * The above copyright notice and this permission notice shall be included *
16 * in all copies or substantial portions of the Software. *
17 * *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
21 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
24 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
25 * *
26 * Except as contained in this notice, the name(s) of the above copyright *
27 * holders shall not be used in advertising or otherwise to promote the *
28 * sale, use or other dealings in this Software without prior written *
29 * authorization. *
30 ****************************************************************************/
31
32 /****************************************************************************
33 * Author: Juergen Pfeifer, 1995,1997 *
34 ****************************************************************************/
35
36 /***************************************************************************
37 * Module m_post *
38 * Write or erase menus from associated subwindows *
39 ***************************************************************************/
40
41 #include "menu.priv.h"
42
43 MODULE_ID("$Id: m_post.c,v 1.8 2023/10/17 09:52:10 nicm Exp $")
44
45 /*---------------------------------------------------------------------------
46 | Facility : libnmenu
47 | Function : void _nc_Post_Item(MENU *menu, ITEM *item)
48 |
49 | Description : Draw the item in the menus window at the current
50 | window position
51 |
52 | Return Values : -
53 +--------------------------------------------------------------------------*/
MENU_EXPORT(void)54 MENU_EXPORT(void)
55 _nc_Post_Item(const MENU *menu, const ITEM *item)
56 {
57 int i;
58 chtype ch;
59 int item_x, item_y;
60 int count = 0;
61 bool isfore = FALSE, isback = FALSE, isgrey = FALSE;
62 int name_len;
63
64 assert(menu->win);
65
66 getyx(menu->win, item_y, item_x);
67
68 /* We need a marker iff
69 - it is a onevalued menu and it is the current item
70 - or it has a selection value
71 */
72 wattron(menu->win, (int)menu->back);
73 if (item->value || (item == menu->curitem))
74 {
75 if (menu->marklen)
76 {
77 /* In a multi selection menu we use the fore attribute
78 for a selected marker that is not the current one.
79 This improves visualization of the menu, because now
80 always the 'normal' marker denotes the current
81 item. */
82 if (!(menu->opt & O_ONEVALUE) && item->value && item != menu->curitem)
83 {
84 wattron(menu->win, (int)menu->fore);
85 isfore = TRUE;
86 }
87 waddstr(menu->win, menu->mark);
88 if (isfore)
89 {
90 wattron(menu->win, (int)menu->fore);
91 isfore = FALSE;
92 }
93 }
94 }
95 else /* otherwise we have to wipe out the marker area */
96 for (ch = ' ', i = menu->marklen; i > 0; i--)
97 waddch(menu->win, ch);
98 wattroff(menu->win, (int)menu->back);
99 count += menu->marklen;
100
101 /* First we have to calculate the attribute depending on selectability
102 and selection status
103 */
104 if (!(item->opt & O_SELECTABLE))
105 {
106 wattron(menu->win, (int)menu->grey);
107 isgrey = TRUE;
108 }
109 else
110 {
111 if (item->value || item == menu->curitem)
112 {
113 wattron(menu->win, (int)menu->fore);
114 isfore = TRUE;
115 }
116 else
117 {
118 wattron(menu->win, (int)menu->back);
119 isback = TRUE;
120 }
121 }
122
123 waddnstr(menu->win, item->name.str, item->name.length);
124 name_len = _nc_Calculate_Text_Width(&(item->name));
125 for (ch = ' ', i = menu->namelen - name_len; i > 0; i--)
126 {
127 waddch(menu->win, ch);
128 }
129 count += menu->namelen;
130
131 /* Show description if required and available */
132 if ((menu->opt & O_SHOWDESC) && menu->desclen > 0)
133 {
134 int m = menu->spc_desc / 2;
135 int cy = -1, cx = -1;
136 int desc_len;
137
138 for (ch = ' ', i = 0; i < menu->spc_desc; i++)
139 {
140 if (i == m)
141 {
142 waddch(menu->win, menu->pad);
143 getyx(menu->win, cy, cx);
144 }
145 else
146 waddch(menu->win, ch);
147 }
148 if (item->description.length)
149 waddnstr(menu->win, item->description.str, item->description.length);
150 desc_len = _nc_Calculate_Text_Width(&(item->description));
151 for (ch = ' ', i = menu->desclen - desc_len; i > 0; i--)
152 {
153 waddch(menu->win, ch);
154 }
155 count += menu->desclen + menu->spc_desc;
156
157 if (menu->spc_rows > 1)
158 {
159 int j, k, ncy, ncx;
160
161 assert(cx >= 0 && cy >= 0);
162 getyx(menu->win, ncy, ncx);
163 if (isgrey)
164 wattroff(menu->win, (int)menu->grey);
165 else if (isfore)
166 wattroff(menu->win, (int)menu->fore);
167 wattron(menu->win, (int)menu->back);
168 for (j = 1; j < menu->spc_rows; j++)
169 {
170 if ((item_y + j) < getmaxy(menu->win))
171 {
172 wmove(menu->win, item_y + j, item_x);
173 for (k = 0; k < count; k++)
174 waddch(menu->win, ' ');
175 }
176 if ((cy + j) < getmaxy(menu->win))
177 (void)mvwaddch(menu->win, cy + j, cx - 1, menu->pad);
178 }
179 wmove(menu->win, ncy, ncx);
180 if (!isback)
181 wattroff(menu->win, (int)menu->back);
182 }
183 }
184
185 /* Remove attributes */
186 if (isfore)
187 wattroff(menu->win, (int)menu->fore);
188 if (isback)
189 wattroff(menu->win, (int)menu->back);
190 if (isgrey)
191 wattroff(menu->win, (int)menu->grey);
192 }
193
194 /*---------------------------------------------------------------------------
195 | Facility : libnmenu
196 | Function : void _nc_Draw_Menu(const MENU *)
197 |
198 | Description : Display the menu in its windows
199 |
200 | Return Values : -
201 +--------------------------------------------------------------------------*/
202 MENU_EXPORT(void)
_nc_Draw_Menu(const MENU * menu)203 _nc_Draw_Menu(const MENU *menu)
204 {
205 ITEM *item = menu->items[0];
206 ITEM *lastvert;
207 ITEM *hitem;
208 chtype s_bkgd;
209
210 assert(item && menu->win);
211
212 s_bkgd = getbkgd(menu->win);
213 wbkgdset(menu->win, menu->back);
214 werase(menu->win);
215 wbkgdset(menu->win, s_bkgd);
216
217 lastvert = (menu->opt & O_NONCYCLIC) ? (ITEM *)0 : item;
218
219 if (item != NULL)
220 {
221 int y = 0;
222
223 do
224 {
225 ITEM *lasthor;
226
227 wmove(menu->win, y, 0);
228
229 hitem = item;
230 lasthor = (menu->opt & O_NONCYCLIC) ? (ITEM *)0 : hitem;
231
232 do
233 {
234 _nc_Post_Item(menu, hitem);
235
236 wattron(menu->win, (int)menu->back);
237 if (((hitem = hitem->right) != lasthor) && hitem)
238 {
239 int i, j, cy, cx;
240 chtype ch = ' ';
241
242 getyx(menu->win, cy, cx);
243 for (j = 0; j < menu->spc_rows; j++)
244 {
245 wmove(menu->win, cy + j, cx);
246 for (i = 0; i < menu->spc_cols; i++)
247 {
248 waddch(menu->win, ch);
249 }
250 }
251 wmove(menu->win, cy, cx + menu->spc_cols);
252 }
253 }
254 while (hitem && (hitem != lasthor));
255 wattroff(menu->win, (int)menu->back);
256
257 item = item->down;
258 y += menu->spc_rows;
259
260 }
261 while (item && (item != lastvert));
262 }
263 }
264
265 /*---------------------------------------------------------------------------
266 | Facility : libnmenu
267 | Function : int post_menu(MENU* menu)
268 |
269 | Description : Post a menu to the screen. This makes it visible.
270 |
271 | Return Values : E_OK - success
272 | E_BAD_ARGUMENT - not a valid menu pointer
273 | E_SYSTEM_ERROR - error in lower layers
274 | E_NOT_CONNECTED - No items connected to menu
275 | E_BAD_STATE - Menu in userexit routine
276 | E_POSTED - Menu already posted
277 +--------------------------------------------------------------------------*/
278 MENU_EXPORT(int)
post_menu(MENU * menu)279 post_menu(MENU *menu)
280 {
281 T((T_CALLED("post_menu(%p)"), (void *)menu));
282
283 if (!menu)
284 RETURN(E_BAD_ARGUMENT);
285
286 if (menu->status & _IN_DRIVER)
287 RETURN(E_BAD_STATE);
288
289 if (menu->status & _POSTED)
290 RETURN(E_POSTED);
291
292 if (menu->items && *(menu->items))
293 {
294 int h = 1 + menu->spc_rows * (menu->rows - 1);
295
296 WINDOW *win = Get_Menu_Window(menu);
297 int maxy = getmaxy(win);
298
299 if ((menu->win = newpad(h, menu->width)))
300 {
301 int y = (maxy >= h) ? h : maxy;
302
303 if (y >= menu->height)
304 y = menu->height;
305 if (!(menu->sub = subpad(menu->win, y, menu->width, 0, 0)))
306 RETURN(E_SYSTEM_ERROR);
307 }
308 else
309 RETURN(E_SYSTEM_ERROR);
310
311 if (menu->status & _LINK_NEEDED)
312 _nc_Link_Items(menu);
313 }
314 else
315 RETURN(E_NOT_CONNECTED);
316
317 SetStatus(menu, _POSTED);
318
319 if (!(menu->opt & O_ONEVALUE))
320 {
321 ITEM **items;
322
323 for (items = menu->items; *items; items++)
324 {
325 (*items)->value = FALSE;
326 }
327 }
328
329 _nc_Draw_Menu(menu);
330
331 Call_Hook(menu, menuinit);
332 Call_Hook(menu, iteminit);
333
334 _nc_Show_Menu(menu);
335
336 RETURN(E_OK);
337 }
338
339 /*---------------------------------------------------------------------------
340 | Facility : libnmenu
341 | Function : int unpost_menu(MENU*)
342 |
343 | Description : Detach menu from screen
344 |
345 | Return Values : E_OK - success
346 | E_BAD_ARGUMENT - not a valid menu pointer
347 | E_BAD_STATE - menu in userexit routine
348 | E_NOT_POSTED - menu is not posted
349 +--------------------------------------------------------------------------*/
350 MENU_EXPORT(int)
unpost_menu(MENU * menu)351 unpost_menu(MENU *menu)
352 {
353 WINDOW *win;
354
355 T((T_CALLED("unpost_menu(%p)"), (void *)menu));
356
357 if (!menu)
358 RETURN(E_BAD_ARGUMENT);
359
360 if (menu->status & _IN_DRIVER)
361 RETURN(E_BAD_STATE);
362
363 if (!(menu->status & _POSTED))
364 RETURN(E_NOT_POSTED);
365
366 Call_Hook(menu, itemterm);
367 Call_Hook(menu, menuterm);
368
369 win = Get_Menu_Window(menu);
370 werase(win);
371 wsyncup(win);
372
373 assert(menu->sub);
374 delwin(menu->sub);
375 menu->sub = (WINDOW *)0;
376
377 assert(menu->win);
378 delwin(menu->win);
379 menu->win = (WINDOW *)0;
380
381 ClrStatus(menu, _POSTED);
382
383 RETURN(E_OK);
384 }
385
386 /* m_post.c ends here */
387