m_global.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. /****************************************************************************
  2. * Copyright (c) 1998-2004,2005 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. * Author: Juergen Pfeifer, 1995,1997 *
  30. ****************************************************************************/
  31. /***************************************************************************
  32. * Module m_global *
  33. * Globally used internal routines and the default menu and item structures *
  34. ***************************************************************************/
  35. #include "menu.priv.h"
  36. MODULE_ID("$Id: m_global.c,v 1.23 2005/12/31 21:51:52 tom Exp $")
  37. static char mark[] = "-";
  38. /* *INDENT-OFF* */
  39. NCURSES_EXPORT_VAR(MENU) _nc_Default_Menu = {
  40. 16, /* Nr. of chars high */
  41. 1, /* Nr. of chars wide */
  42. 16, /* Nr. of items high */
  43. 1, /* Nr. of items wide */
  44. 16, /* Nr. of formatted items high */
  45. 1, /* Nr. of formatted items wide */
  46. 16, /* Nr. of items high (actual) */
  47. 0, /* length of widest name */
  48. 0, /* length of widest description */
  49. 1, /* length of mark */
  50. 1, /* length of one item */
  51. 1, /* Spacing for descriptor */
  52. 1, /* Spacing for columns */
  53. 1, /* Spacing for rows */
  54. (char *)0, /* buffer used to store match chars */
  55. 0, /* Index into pattern buffer */
  56. (WINDOW *)0, /* Window containing entire menu */
  57. (WINDOW *)0, /* Portion of menu displayed */
  58. (WINDOW *)0, /* User's window */
  59. (WINDOW *)0, /* User's subwindow */
  60. (ITEM **)0, /* List of items */
  61. 0, /* Total Nr. of items in menu */
  62. (ITEM *)0, /* Current item */
  63. 0, /* Top row of menu */
  64. (chtype)A_REVERSE, /* Attribute for selection */
  65. (chtype)A_NORMAL, /* Attribute for nonselection */
  66. (chtype)A_UNDERLINE, /* Attribute for inactive */
  67. ' ', /* Pad character */
  68. (Menu_Hook)0, /* Menu init */
  69. (Menu_Hook)0, /* Menu term */
  70. (Menu_Hook)0, /* Item init */
  71. (Menu_Hook)0, /* Item term */
  72. (void *)0, /* userptr */
  73. mark, /* mark */
  74. ALL_MENU_OPTS, /* options */
  75. 0 /* status */
  76. };
  77. NCURSES_EXPORT_VAR(ITEM) _nc_Default_Item = {
  78. { (char *)0, 0 }, /* name */
  79. { (char *)0, 0 }, /* description */
  80. (MENU *)0, /* Pointer to parent menu */
  81. (char *)0, /* Userpointer */
  82. ALL_ITEM_OPTS, /* options */
  83. 0, /* Item Nr. */
  84. 0, /* y */
  85. 0, /* x */
  86. FALSE, /* value */
  87. (ITEM *)0, /* left */
  88. (ITEM *)0, /* right */
  89. (ITEM *)0, /* up */
  90. (ITEM *)0 /* down */
  91. };
  92. /* *INDENT-ON* */
  93. /*---------------------------------------------------------------------------
  94. | Facility : libnmenu
  95. | Function : static void ComputeMaximum_NameDesc_Lenths(MENU *menu)
  96. |
  97. | Description : Calculates the maximum name and description lengths
  98. | of the items connected to the menu
  99. |
  100. | Return Values : -
  101. +--------------------------------------------------------------------------*/
  102. NCURSES_INLINE static void
  103. ComputeMaximum_NameDesc_Lengths(MENU * menu)
  104. {
  105. unsigned MaximumNameLength = 0;
  106. unsigned MaximumDescriptionLength = 0;
  107. ITEM **items;
  108. unsigned check;
  109. assert(menu && menu->items);
  110. for (items = menu->items; *items; items++)
  111. {
  112. check = _nc_Calculate_Text_Width(&((*items)->name));
  113. if (check > MaximumNameLength)
  114. MaximumNameLength = check;
  115. check = _nc_Calculate_Text_Width(&((*items)->description));
  116. if (check > MaximumDescriptionLength)
  117. MaximumDescriptionLength = check;
  118. }
  119. menu->namelen = MaximumNameLength;
  120. menu->desclen = MaximumDescriptionLength;
  121. T(("ComputeMaximum_NameDesc_Lengths %d,%d", menu->namelen, menu->desclen));
  122. }
  123. /*---------------------------------------------------------------------------
  124. | Facility : libnmenu
  125. | Function : static void ResetConnectionInfo(MENU *, ITEM **)
  126. |
  127. | Description : Reset all informations in the menu and the items in
  128. | the item array that indicates a connection
  129. |
  130. | Return Values : -
  131. +--------------------------------------------------------------------------*/
  132. NCURSES_INLINE static void
  133. ResetConnectionInfo(MENU * menu, ITEM ** items)
  134. {
  135. ITEM **item;
  136. assert(menu && items);
  137. for (item = items; *item; item++)
  138. {
  139. (*item)->index = 0;
  140. (*item)->imenu = (MENU *) 0;
  141. }
  142. if (menu->pattern)
  143. free(menu->pattern);
  144. menu->pattern = (char *)0;
  145. menu->pindex = 0;
  146. menu->items = (ITEM **) 0;
  147. menu->nitems = 0;
  148. }
  149. /*---------------------------------------------------------------------------
  150. | Facility : libnmenu
  151. | Function : bool _nc_Connect_Items(MENU *menu, ITEM **items)
  152. |
  153. | Description : Connect the items in the item array to the menu.
  154. | Decorate all the items with a number and a backward
  155. | pointer to the menu.
  156. |
  157. | Return Values : TRUE - successful connection
  158. | FALSE - connection failed
  159. +--------------------------------------------------------------------------*/
  160. NCURSES_EXPORT(bool)
  161. _nc_Connect_Items(MENU * menu, ITEM ** items)
  162. {
  163. ITEM **item;
  164. unsigned int ItemCount = 0;
  165. if (menu && items)
  166. {
  167. for (item = items; *item; item++)
  168. {
  169. if ((*item)->imenu)
  170. {
  171. /* if a item is already connected, reject connection */
  172. break;
  173. }
  174. }
  175. if (!(*item))
  176. /* we reached the end, so there was no connected item */
  177. {
  178. for (item = items; *item; item++)
  179. {
  180. if (menu->opt & O_ONEVALUE)
  181. {
  182. (*item)->value = FALSE;
  183. }
  184. (*item)->index = ItemCount++;
  185. (*item)->imenu = menu;
  186. }
  187. }
  188. }
  189. else
  190. return (FALSE);
  191. if (ItemCount != 0)
  192. {
  193. menu->items = items;
  194. menu->nitems = ItemCount;
  195. ComputeMaximum_NameDesc_Lengths(menu);
  196. if ((menu->pattern = typeMalloc(char, (unsigned)(1 + menu->namelen))))
  197. {
  198. Reset_Pattern(menu);
  199. set_menu_format(menu, menu->frows, menu->fcols);
  200. menu->curitem = *items;
  201. menu->toprow = 0;
  202. return (TRUE);
  203. }
  204. }
  205. /* If we fall through to this point, we have to reset all items connection
  206. and inform about a reject connection */
  207. ResetConnectionInfo(menu, items);
  208. return (FALSE);
  209. }
  210. /*---------------------------------------------------------------------------
  211. | Facility : libnmenu
  212. | Function : void _nc_Disconnect_Items(MENU *menu)
  213. |
  214. | Description : Disconnect the menus item array from the menu
  215. |
  216. | Return Values : -
  217. +--------------------------------------------------------------------------*/
  218. NCURSES_EXPORT(void)
  219. _nc_Disconnect_Items(MENU * menu)
  220. {
  221. if (menu && menu->items)
  222. ResetConnectionInfo(menu, menu->items);
  223. }
  224. /*---------------------------------------------------------------------------
  225. | Facility : libnmenu
  226. | Function : int _nc_Calculate_Text_Width(const TEXT * item)
  227. |
  228. | Description : Calculate the number of columns for a TEXT.
  229. |
  230. | Return Values : the width
  231. +--------------------------------------------------------------------------*/
  232. NCURSES_EXPORT(int)
  233. _nc_Calculate_Text_Width(const TEXT * item /*FIXME: limit length */ )
  234. {
  235. #if USE_WIDEC_SUPPORT
  236. int result = item->length;
  237. T((T_CALLED("_nc_menu_text_width(%p)"), item));
  238. if (result != 0 && item->str != 0)
  239. {
  240. int count = mbstowcs(0, item->str, 0);
  241. wchar_t *temp = 0;
  242. if (count > 0
  243. && (temp = typeMalloc(wchar_t, 2 + count)) != 0)
  244. {
  245. int n;
  246. result = 0;
  247. mbstowcs(temp, item->str, (unsigned)count);
  248. for (n = 0; n < count; ++n)
  249. {
  250. int test = wcwidth(temp[n]);
  251. if (test <= 0)
  252. test = 1;
  253. result += test;
  254. }
  255. free(temp);
  256. }
  257. }
  258. returnCode(result);
  259. #else
  260. return item->length;
  261. #endif
  262. }
  263. /*
  264. * Calculate the actual width of a menu entry for wide-characters.
  265. */
  266. #if USE_WIDEC_SUPPORT
  267. static int
  268. calculate_actual_width(MENU * menu, bool name)
  269. {
  270. int width = 0;
  271. int check = 0;
  272. ITEM **items;
  273. assert(menu && menu->items);
  274. if (menu->items != 0)
  275. {
  276. for (items = menu->items; *items; items++)
  277. {
  278. if (name)
  279. {
  280. check = _nc_Calculate_Text_Width(&((*items)->name));
  281. }
  282. else
  283. {
  284. check = _nc_Calculate_Text_Width(&((*items)->description));
  285. }
  286. if (check > width)
  287. width = check;
  288. }
  289. }
  290. else
  291. {
  292. width = (name ? menu->namelen : menu->desclen);
  293. }
  294. T(("calculate_actual_width %s = %d/%d",
  295. name ? "name" : "desc",
  296. width,
  297. name ? menu->namelen : menu->desclen));
  298. return width;
  299. }
  300. #else
  301. #define calculate_actual_width(menu, name) (name ? menu->namelen : menu->desclen)
  302. #endif
  303. /*---------------------------------------------------------------------------
  304. | Facility : libnmenu
  305. | Function : void _nc_Calculate_Item_Length_and_Width(MENU *menu)
  306. |
  307. | Description : Calculate the length of an item and the width of the
  308. | whole menu.
  309. |
  310. | Return Values : -
  311. +--------------------------------------------------------------------------*/
  312. NCURSES_EXPORT(void)
  313. _nc_Calculate_Item_Length_and_Width(MENU * menu)
  314. {
  315. int l;
  316. assert(menu);
  317. menu->height = 1 + menu->spc_rows * (menu->arows - 1);
  318. l = calculate_actual_width(menu, TRUE);
  319. l += menu->marklen;
  320. if ((menu->opt & O_SHOWDESC) && (menu->desclen > 0))
  321. {
  322. l += calculate_actual_width(menu, FALSE);
  323. l += menu->spc_desc;
  324. }
  325. menu->itemlen = l;
  326. l *= menu->cols;
  327. l += (menu->cols - 1) * menu->spc_cols; /* for the padding between the columns */
  328. menu->width = l;
  329. T(("_nc_CalculateItem_Length_and_Width columns %d, item %d, width %d",
  330. menu->cols,
  331. menu->itemlen,
  332. menu->width));
  333. }
  334. /*---------------------------------------------------------------------------
  335. | Facility : libnmenu
  336. | Function : void _nc_Link_Item(MENU *menu)
  337. |
  338. | Description : Statically calculate for every item its four neighbors.
  339. | This depends on the orientation of the menu. This
  340. | static approach simplifies navigation in the menu a lot.
  341. |
  342. | Return Values : -
  343. +--------------------------------------------------------------------------*/
  344. NCURSES_EXPORT(void)
  345. _nc_Link_Items(MENU * menu)
  346. {
  347. if (menu && menu->items && *(menu->items))
  348. {
  349. int i, j;
  350. ITEM *item;
  351. int Number_Of_Items = menu->nitems;
  352. int col = 0, row = 0;
  353. int Last_in_Row;
  354. int Last_in_Column;
  355. bool cycle = (menu->opt & O_NONCYCLIC) ? FALSE : TRUE;
  356. menu->status &= ~_LINK_NEEDED;
  357. if (menu->opt & O_ROWMAJOR)
  358. {
  359. int Number_Of_Columns = menu->cols;
  360. for (i = 0; i < Number_Of_Items; i++)
  361. {
  362. item = menu->items[i];
  363. Last_in_Row = row * Number_Of_Columns + (Number_Of_Columns - 1);
  364. item->left = (col) ?
  365. /* if we are not in the leftmost column, we can use the
  366. predecessor in the items array */
  367. menu->items[i - 1] :
  368. (cycle ? menu->items[(Last_in_Row >= Number_Of_Items) ?
  369. Number_Of_Items - 1 :
  370. Last_in_Row] :
  371. (ITEM *) 0);
  372. item->right = ((col < (Number_Of_Columns - 1)) &&
  373. ((i + 1) < Number_Of_Items)
  374. )?
  375. menu->items[i + 1] :
  376. (cycle ? menu->items[row * Number_Of_Columns] :
  377. (ITEM *) 0
  378. );
  379. Last_in_Column = (menu->rows - 1) * Number_Of_Columns + col;
  380. item->up = (row) ? menu->items[i - Number_Of_Columns] :
  381. (cycle ? menu->items[(Last_in_Column >= Number_Of_Items) ?
  382. Number_Of_Items - 1 :
  383. Last_in_Column] :
  384. (ITEM *) 0);
  385. item->down = ((i + Number_Of_Columns) < Number_Of_Items)
  386. ?
  387. menu->items[i + Number_Of_Columns] :
  388. (cycle ? menu->items[(row + 1) < menu->rows ?
  389. Number_Of_Items - 1 : col] :
  390. (ITEM *) 0);
  391. item->x = col;
  392. item->y = row;
  393. if (++col == Number_Of_Columns)
  394. {
  395. row++;
  396. col = 0;
  397. }
  398. }
  399. }
  400. else
  401. {
  402. int Number_Of_Rows = menu->rows;
  403. for (j = 0; j < Number_Of_Items; j++)
  404. {
  405. item = menu->items[i = (col * Number_Of_Rows + row)];
  406. Last_in_Column = (menu->cols - 1) * Number_Of_Rows + row;
  407. item->left = (col) ?
  408. menu->items[i - Number_Of_Rows] :
  409. (cycle ? (Last_in_Column >= Number_Of_Items) ?
  410. menu->items[Last_in_Column - Number_Of_Rows] :
  411. menu->items[Last_in_Column] :
  412. (ITEM *) 0);
  413. item->right = ((i + Number_Of_Rows) < Number_Of_Items)
  414. ?
  415. menu->items[i + Number_Of_Rows] :
  416. (cycle ? menu->items[row] : (ITEM *) 0);
  417. Last_in_Row = col * Number_Of_Rows + (Number_Of_Rows - 1);
  418. item->up = (row) ?
  419. menu->items[i - 1] :
  420. (cycle ?
  421. menu->items[(Last_in_Row >= Number_Of_Items) ?
  422. Number_Of_Items - 1 :
  423. Last_in_Row] :
  424. (ITEM *) 0);
  425. item->down = (row < (Number_Of_Rows - 1))
  426. ?
  427. (menu->items[((i + 1) < Number_Of_Items) ?
  428. i + 1 :
  429. (col - 1) * Number_Of_Rows + row + 1]) :
  430. (cycle ?
  431. menu->items[col * Number_Of_Rows] :
  432. (ITEM *) 0
  433. );
  434. item->x = col;
  435. item->y = row;
  436. if ((++row) == Number_Of_Rows)
  437. {
  438. col++;
  439. row = 0;
  440. }
  441. }
  442. }
  443. }
  444. }
  445. /*---------------------------------------------------------------------------
  446. | Facility : libnmenu
  447. | Function : void _nc_Show_Menu(const MENU *menu)
  448. |
  449. | Description : Update the window that is associated with the menu
  450. |
  451. | Return Values : -
  452. +--------------------------------------------------------------------------*/
  453. NCURSES_EXPORT(void)
  454. _nc_Show_Menu(const MENU * menu)
  455. {
  456. WINDOW *win;
  457. int maxy, maxx;
  458. assert(menu);
  459. if ((menu->status & _POSTED) && !(menu->status & _IN_DRIVER))
  460. {
  461. /* adjust the internal subwindow to start on the current top */
  462. assert(menu->sub);
  463. mvderwin(menu->sub, menu->spc_rows * menu->toprow, 0);
  464. win = Get_Menu_Window(menu);
  465. maxy = getmaxy(win);
  466. maxx = getmaxx(win);
  467. if (menu->height < maxy)
  468. maxy = menu->height;
  469. if (menu->width < maxx)
  470. maxx = menu->width;
  471. copywin(menu->sub, win, 0, 0, 0, 0, maxy - 1, maxx - 1, 0);
  472. pos_menu_cursor(menu);
  473. }
  474. }
  475. /*---------------------------------------------------------------------------
  476. | Facility : libnmenu
  477. | Function : void _nc_New_TopRow_and_CurrentItem(
  478. | MENU *menu,
  479. | int new_toprow,
  480. | ITEM *new_current_item)
  481. |
  482. | Description : Redisplay the menu so that the given row becomes the
  483. | top row and the given item becomes the new current
  484. | item.
  485. |
  486. | Return Values : -
  487. +--------------------------------------------------------------------------*/
  488. NCURSES_EXPORT(void)
  489. _nc_New_TopRow_and_CurrentItem
  490. (MENU * menu, int new_toprow, ITEM * new_current_item)
  491. {
  492. ITEM *cur_item;
  493. bool mterm_called = FALSE;
  494. bool iterm_called = FALSE;
  495. assert(menu);
  496. if (menu->status & _POSTED)
  497. {
  498. if (new_current_item != menu->curitem)
  499. {
  500. Call_Hook(menu, itemterm);
  501. iterm_called = TRUE;
  502. }
  503. if (new_toprow != menu->toprow)
  504. {
  505. Call_Hook(menu, menuterm);
  506. mterm_called = TRUE;
  507. }
  508. cur_item = menu->curitem;
  509. assert(cur_item);
  510. menu->toprow = new_toprow;
  511. menu->curitem = new_current_item;
  512. if (mterm_called)
  513. {
  514. Call_Hook(menu, menuinit);
  515. }
  516. if (iterm_called)
  517. {
  518. /* this means, move from the old current_item to the new one... */
  519. Move_To_Current_Item(menu, cur_item);
  520. Call_Hook(menu, iteminit);
  521. }
  522. if (mterm_called || iterm_called)
  523. {
  524. _nc_Show_Menu(menu);
  525. }
  526. else
  527. pos_menu_cursor(menu);
  528. }
  529. else
  530. { /* if we are not posted, this is quite simple */
  531. menu->toprow = new_toprow;
  532. menu->curitem = new_current_item;
  533. }
  534. }
  535. /* m_global.c ends here */