1 /****************************************************************************
2 * Copyright (c) 1998-2009,2010 Free Software Foundation, Inc. *
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: *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
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. *
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 *
27 ****************************************************************************/
29 /****************************************************************************
30 * Author: Juergen Pfeifer, 1995,1997 *
31 ****************************************************************************/
33 /***************************************************************************
35 * Globally used internal routines and the default menu and item structures *
36 ***************************************************************************/
38 #include "menu.priv.h"
40 MODULE_ID("$Id: m_global.c,v 1.25 2010/01/23 21:20:10 tom Exp $")
42 static char mark
[] = "-";
44 NCURSES_EXPORT_VAR(MENU
) _nc_Default_Menu
= {
45 16, /* Nr. of chars high */
46 1, /* Nr. of chars wide */
47 16, /* Nr. of items high */
48 1, /* Nr. of items wide */
49 16, /* Nr. of formatted items high */
50 1, /* Nr. of formatted items wide */
51 16, /* Nr. of items high (actual) */
52 0, /* length of widest name */
53 0, /* length of widest description */
54 1, /* length of mark */
55 1, /* length of one item */
56 1, /* Spacing for descriptor */
57 1, /* Spacing for columns */
58 1, /* Spacing for rows */
59 (char *)0, /* buffer used to store match chars */
60 0, /* Index into pattern buffer */
61 (WINDOW
*)0, /* Window containing entire menu */
62 (WINDOW
*)0, /* Portion of menu displayed */
63 (WINDOW
*)0, /* User's window */
64 (WINDOW
*)0, /* User's subwindow */
65 (ITEM
**)0, /* List of items */
66 0, /* Total Nr. of items in menu */
67 (ITEM
*)0, /* Current item */
68 0, /* Top row of menu */
69 (chtype
)A_REVERSE
, /* Attribute for selection */
70 (chtype
)A_NORMAL
, /* Attribute for nonselection */
71 (chtype
)A_UNDERLINE
, /* Attribute for inactive */
72 ' ', /* Pad character */
73 (Menu_Hook
)0, /* Menu init */
74 (Menu_Hook
)0, /* Menu term */
75 (Menu_Hook
)0, /* Item init */
76 (Menu_Hook
)0, /* Item term */
77 (void *)0, /* userptr */
79 ALL_MENU_OPTS
, /* options */
83 NCURSES_EXPORT_VAR(ITEM
) _nc_Default_Item
= {
84 { (char *)0, 0 }, /* name */
85 { (char *)0, 0 }, /* description */
86 (MENU
*)0, /* Pointer to parent menu */
87 (char *)0, /* Userpointer */
88 ALL_ITEM_OPTS
, /* options */
94 (ITEM
*)0, /* right */
100 /*---------------------------------------------------------------------------
101 | Facility : libnmenu
102 | Function : static void ComputeMaximum_NameDesc_Lenths(MENU *menu)
104 | Description : Calculates the maximum name and description lengths
105 | of the items connected to the menu
108 +--------------------------------------------------------------------------*/
109 NCURSES_INLINE
static void
110 ComputeMaximum_NameDesc_Lengths(MENU
* menu
)
112 unsigned MaximumNameLength
= 0;
113 unsigned MaximumDescriptionLength
= 0;
117 assert(menu
&& menu
->items
);
118 for (items
= menu
->items
; *items
; items
++)
120 check
= _nc_Calculate_Text_Width(&((*items
)->name
));
121 if (check
> MaximumNameLength
)
122 MaximumNameLength
= check
;
124 check
= _nc_Calculate_Text_Width(&((*items
)->description
));
125 if (check
> MaximumDescriptionLength
)
126 MaximumDescriptionLength
= check
;
129 menu
->namelen
= MaximumNameLength
;
130 menu
->desclen
= MaximumDescriptionLength
;
131 T(("ComputeMaximum_NameDesc_Lengths %d,%d", menu
->namelen
, menu
->desclen
));
134 /*---------------------------------------------------------------------------
135 | Facility : libnmenu
136 | Function : static void ResetConnectionInfo(MENU *, ITEM **)
138 | Description : Reset all information in the menu and the items in
139 | the item array that indicates a connection
142 +--------------------------------------------------------------------------*/
143 NCURSES_INLINE
static void
144 ResetConnectionInfo(MENU
* menu
, ITEM
** items
)
148 assert(menu
&& items
);
149 for (item
= items
; *item
; item
++)
152 (*item
)->imenu
= (MENU
*) 0;
156 menu
->pattern
= (char *)0;
158 menu
->items
= (ITEM
**) 0;
162 /*---------------------------------------------------------------------------
163 | Facility : libnmenu
164 | Function : bool _nc_Connect_Items(MENU *menu, ITEM **items)
166 | Description : Connect the items in the item array to the menu.
167 | Decorate all the items with a number and a backward
168 | pointer to the menu.
170 | Return Values : TRUE - successful connection
171 | FALSE - connection failed
172 +--------------------------------------------------------------------------*/
174 _nc_Connect_Items(MENU
* menu
, ITEM
** items
)
177 unsigned int ItemCount
= 0;
181 for (item
= items
; *item
; item
++)
185 /* if a item is already connected, reject connection */
190 /* we reached the end, so there was no connected item */
192 for (item
= items
; *item
; item
++)
194 if (menu
->opt
& O_ONEVALUE
)
196 (*item
)->value
= FALSE
;
198 (*item
)->index
= ItemCount
++;
199 (*item
)->imenu
= menu
;
209 menu
->nitems
= ItemCount
;
210 ComputeMaximum_NameDesc_Lengths(menu
);
211 if ((menu
->pattern
= typeMalloc(char, (unsigned)(1 + menu
->namelen
))))
214 set_menu_format(menu
, menu
->frows
, menu
->fcols
);
215 menu
->curitem
= *items
;
221 /* If we fall through to this point, we have to reset all items connection
222 and inform about a reject connection */
223 ResetConnectionInfo(menu
, items
);
227 /*---------------------------------------------------------------------------
228 | Facility : libnmenu
229 | Function : void _nc_Disconnect_Items(MENU *menu)
231 | Description : Disconnect the menus item array from the menu
234 +--------------------------------------------------------------------------*/
236 _nc_Disconnect_Items(MENU
* menu
)
238 if (menu
&& menu
->items
)
239 ResetConnectionInfo(menu
, menu
->items
);
242 /*---------------------------------------------------------------------------
243 | Facility : libnmenu
244 | Function : int _nc_Calculate_Text_Width(const TEXT * item)
246 | Description : Calculate the number of columns for a TEXT.
248 | Return Values : the width
249 +--------------------------------------------------------------------------*/
251 _nc_Calculate_Text_Width(const TEXT
* item
/*FIXME: limit length */ )
253 #if USE_WIDEC_SUPPORT
254 int result
= item
->length
;
256 T((T_CALLED("_nc_menu_text_width(%p)"), (const void *)item
));
257 if (result
!= 0 && item
->str
!= 0)
259 int count
= mbstowcs(0, item
->str
, 0);
263 && (temp
= typeMalloc(wchar_t, 2 + count
)) != 0)
268 mbstowcs(temp
, item
->str
, (unsigned)count
);
269 for (n
= 0; n
< count
; ++n
)
271 int test
= wcwidth(temp
[n
]);
287 * Calculate the actual width of a menu entry for wide-characters.
289 #if USE_WIDEC_SUPPORT
291 calculate_actual_width(MENU
* menu
, bool name
)
297 assert(menu
&& menu
->items
);
299 if (menu
->items
!= 0)
301 for (items
= menu
->items
; *items
; items
++)
305 check
= _nc_Calculate_Text_Width(&((*items
)->name
));
309 check
= _nc_Calculate_Text_Width(&((*items
)->description
));
317 width
= (name
? menu
->namelen
: menu
->desclen
);
320 T(("calculate_actual_width %s = %d/%d",
321 name
? "name" : "desc",
323 name
? menu
->namelen
: menu
->desclen
));
327 #define calculate_actual_width(menu, name) (name ? menu->namelen : menu->desclen)
330 /*---------------------------------------------------------------------------
331 | Facility : libnmenu
332 | Function : void _nc_Calculate_Item_Length_and_Width(MENU *menu)
334 | Description : Calculate the length of an item and the width of the
338 +--------------------------------------------------------------------------*/
340 _nc_Calculate_Item_Length_and_Width(MENU
* menu
)
346 menu
->height
= 1 + menu
->spc_rows
* (menu
->arows
- 1);
348 l
= calculate_actual_width(menu
, TRUE
);
351 if ((menu
->opt
& O_SHOWDESC
) && (menu
->desclen
> 0))
353 l
+= calculate_actual_width(menu
, FALSE
);
359 l
+= (menu
->cols
- 1) * menu
->spc_cols
; /* for the padding between the columns */
362 T(("_nc_CalculateItem_Length_and_Width columns %d, item %d, width %d",
368 /*---------------------------------------------------------------------------
369 | Facility : libnmenu
370 | Function : void _nc_Link_Item(MENU *menu)
372 | Description : Statically calculate for every item its four neighbors.
373 | This depends on the orientation of the menu. This
374 | static approach simplifies navigation in the menu a lot.
377 +--------------------------------------------------------------------------*/
379 _nc_Link_Items(MENU
* menu
)
381 if (menu
&& menu
->items
&& *(menu
->items
))
385 int Number_Of_Items
= menu
->nitems
;
386 int col
= 0, row
= 0;
389 bool cycle
= (menu
->opt
& O_NONCYCLIC
) ? FALSE
: TRUE
;
391 menu
->status
&= ~_LINK_NEEDED
;
393 if (menu
->opt
& O_ROWMAJOR
)
395 int Number_Of_Columns
= menu
->cols
;
397 for (i
= 0; i
< Number_Of_Items
; i
++)
399 item
= menu
->items
[i
];
401 Last_in_Row
= row
* Number_Of_Columns
+ (Number_Of_Columns
- 1);
404 /* if we are not in the leftmost column, we can use the
405 predecessor in the items array */
407 (cycle
? menu
->items
[(Last_in_Row
>= Number_Of_Items
) ?
408 Number_Of_Items
- 1 :
412 item
->right
= ((col
< (Number_Of_Columns
- 1)) &&
413 ((i
+ 1) < Number_Of_Items
)
416 (cycle
? menu
->items
[row
* Number_Of_Columns
] :
420 Last_in_Column
= (menu
->rows
- 1) * Number_Of_Columns
+ col
;
422 item
->up
= (row
) ? menu
->items
[i
- Number_Of_Columns
] :
423 (cycle
? menu
->items
[(Last_in_Column
>= Number_Of_Items
) ?
424 Number_Of_Items
- 1 :
428 item
->down
= ((i
+ Number_Of_Columns
) < Number_Of_Items
)
430 menu
->items
[i
+ Number_Of_Columns
] :
431 (cycle
? menu
->items
[(row
+ 1) < menu
->rows
?
432 Number_Of_Items
- 1 : col
] :
436 if (++col
== Number_Of_Columns
)
445 int Number_Of_Rows
= menu
->rows
;
447 for (j
= 0; j
< Number_Of_Items
; j
++)
449 item
= menu
->items
[i
= (col
* Number_Of_Rows
+ row
)];
451 Last_in_Column
= (menu
->cols
- 1) * Number_Of_Rows
+ row
;
454 menu
->items
[i
- Number_Of_Rows
] :
455 (cycle
? (Last_in_Column
>= Number_Of_Items
) ?
456 menu
->items
[Last_in_Column
- Number_Of_Rows
] :
457 menu
->items
[Last_in_Column
] :
460 item
->right
= ((i
+ Number_Of_Rows
) < Number_Of_Items
)
462 menu
->items
[i
+ Number_Of_Rows
] :
463 (cycle
? menu
->items
[row
] : (ITEM
*) 0);
465 Last_in_Row
= col
* Number_Of_Rows
+ (Number_Of_Rows
- 1);
470 menu
->items
[(Last_in_Row
>= Number_Of_Items
) ?
471 Number_Of_Items
- 1 :
475 item
->down
= (row
< (Number_Of_Rows
- 1))
477 (menu
->items
[((i
+ 1) < Number_Of_Items
) ?
479 (col
- 1) * Number_Of_Rows
+ row
+ 1]) :
481 menu
->items
[col
* Number_Of_Rows
] :
487 if ((++row
) == Number_Of_Rows
)
497 /*---------------------------------------------------------------------------
498 | Facility : libnmenu
499 | Function : void _nc_Show_Menu(const MENU* menu)
501 | Description : Update the window that is associated with the menu
504 +--------------------------------------------------------------------------*/
506 _nc_Show_Menu(const MENU
* menu
)
512 if ((menu
->status
& _POSTED
) && !(menu
->status
& _IN_DRIVER
))
514 /* adjust the internal subwindow to start on the current top */
516 mvderwin(menu
->sub
, menu
->spc_rows
* menu
->toprow
, 0);
517 win
= Get_Menu_Window(menu
);
522 if (menu
->height
< maxy
)
524 if (menu
->width
< maxx
)
527 copywin(menu
->sub
, win
, 0, 0, 0, 0, maxy
- 1, maxx
- 1, 0);
528 pos_menu_cursor(menu
);
532 /*---------------------------------------------------------------------------
533 | Facility : libnmenu
534 | Function : void _nc_New_TopRow_and_CurrentItem(
537 | ITEM *new_current_item)
539 | Description : Redisplay the menu so that the given row becomes the
540 | top row and the given item becomes the new current
544 +--------------------------------------------------------------------------*/
546 _nc_New_TopRow_and_CurrentItem(
549 ITEM
* new_current_item
)
552 bool mterm_called
= FALSE
;
553 bool iterm_called
= FALSE
;
556 if (menu
->status
& _POSTED
)
558 if (new_current_item
!= menu
->curitem
)
560 Call_Hook(menu
, itemterm
);
563 if (new_toprow
!= menu
->toprow
)
565 Call_Hook(menu
, menuterm
);
569 cur_item
= menu
->curitem
;
571 menu
->toprow
= new_toprow
;
572 menu
->curitem
= new_current_item
;
576 Call_Hook(menu
, menuinit
);
580 /* this means, move from the old current_item to the new one... */
581 Move_To_Current_Item(menu
, cur_item
);
582 Call_Hook(menu
, iteminit
);
584 if (mterm_called
|| iterm_called
)
589 pos_menu_cursor(menu
);
592 { /* if we are not posted, this is quite simple */
593 menu
->toprow
= new_toprow
;
594 menu
->curitem
= new_current_item
;
598 /* m_global.c ends here */