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