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