ODPopup.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. /* OpenDoors Online Software Programming Toolkit
  2. * (C) Copyright 1991 - 1999 by Brian Pirie.
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. *
  18. *
  19. * File: ODPopUp.c
  20. *
  21. * Description: Implements od_popup_menu(), for displaying a menu in
  22. * a window, allowing the user to make a selection using
  23. * "hot keys" or by using arrow keys.
  24. *
  25. * Revisions: Date Ver Who Change
  26. * ---------------------------------------------------------------
  27. * Oct 13, 1994 6.00 BP New file header format.
  28. * Dec 09, 1994 6.00 BP Standardized coding style.
  29. * Jan 15, 1995 6.00 BP Free menu structure on menu destroy.
  30. * Feb 02, 1995 6.00 BP Added od_yield() call in for(;;) loop.
  31. * Aug 19, 1995 6.00 BP 32-bit portability.
  32. * Nov 11, 1995 6.00 BP Removed register keyword.
  33. * Nov 14, 1995 6.00 BP Change valid range of nLevel to 0-10.
  34. * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h.
  35. * Nov 17, 1995 6.00 BP Use new input queue mechanism.
  36. * Dec 12, 1995 6.00 BP Added entry, exit and kernel macros.
  37. * Dec 23, 1995 6.00 BP Restore original color on exit.
  38. * Dec 30, 1995 6.00 BP Added ODCALL for calling convention.
  39. * Jan 04, 1996 6.00 BP Use od_get_input().
  40. * Jan 12, 1996 6.00 BP Claim exclusive use of arrow keys.
  41. * Jan 30, 1996 6.00 BP Replaced od_yield() with od_sleep().
  42. * Jan 31, 1996 6.00 BP Added timeout for od_get_input().
  43. * Jan 31, 1996 6.00 BP Add ODPopupCheckForKey() wait param.
  44. * Jan 31, 1996 6.00 BP Ignore left & right if !MENU_PULLDOWN.
  45. * Feb 13, 1996 6.00 BP Added od_get_input() flags parameter.
  46. * Feb 19, 1996 6.00 BP Changed version number to 6.00.
  47. * Mar 03, 1996 6.10 BP Begin version 6.10.
  48. * Aug 10, 2003 6.23 SH *nix support
  49. */
  50. #define BUILDING_OPENDOORS
  51. #include <ctype.h>
  52. #include <string.h>
  53. #include <stdlib.h>
  54. #include "OpenDoor.h"
  55. #include "ODCore.h"
  56. #include "ODGen.h"
  57. #include "ODPlat.h"
  58. #include "ODKrnl.h"
  59. #include "ODStat.h"
  60. /* Configurable od_popup_menu() parameters. */
  61. /* Maximum menu level. */
  62. #define MENU_LEVELS 11
  63. /* Maximum number of items in a menu. */
  64. #define MAX_MENU_ITEMS 21
  65. /* Maximum width of any menu item. */
  66. #define MAX_ITEM_WIDTH 76
  67. /* Other manifest constants. */
  68. #define NO_COMMAND -10
  69. /* Local data types. */
  70. /* Information on an individual menu item. */
  71. typedef struct
  72. {
  73. char szItemText[MAX_ITEM_WIDTH + 1];
  74. BYTE btKeyIndex;
  75. } tMenuItem;
  76. /* Information on a popup menu level. */
  77. typedef struct
  78. {
  79. tMenuItem *paMenuItems;
  80. BYTE btNumMenuItems;
  81. BYTE btWidth;
  82. BYTE btRight;
  83. BYTE btBottom;
  84. BYTE btCursor;
  85. BYTE btLeft;
  86. BYTE btTop;
  87. WORD wFlags;
  88. void *pWindow;
  89. } tMenuLevelInfo;
  90. /* Private variables. */
  91. /* Array of information on each menu level. */
  92. tMenuLevelInfo MenuLevelInfo[MENU_LEVELS];
  93. /* Current menu settings. */
  94. static BYTE btCorrectItem;
  95. static INT nCommand;
  96. static WORD wCurrentFlags;
  97. static BYTE btCurrentNumMenuItems;
  98. static INT nCurrentLevel;
  99. /* Private helper functions used by od_popup_menu(). */
  100. static void ODPopupCheckForKey(BOOL bWaitForInput);
  101. static void ODPopupDisplayMenuItem(BYTE btLeft, BYTE btTop,
  102. tMenuItem *paMenuItems, BYTE btItemIndex, BOOL bHighlighted, BYTE btWidth,
  103. BOOL bPositionCursor);
  104. /* ----------------------------------------------------------------------------
  105. * od_popup_menu()
  106. *
  107. * Displays a popup menu on the local and remote screens.
  108. *
  109. * Parameters: pszTitle - Text to show as the window title of the popup menu.
  110. * If no title is desired, this parameter should be set
  111. * to either "" or NULL.
  112. *
  113. * pszText - String which contains the menu definition. In the
  114. * menu definition string, individual menu items are
  115. * separated by a pipe ('|') character, and hotkeys are
  116. * proceeded by a carat ('^') character.
  117. *
  118. * nLeft - The 1-based column number of the upper right corner
  119. * of the menu.
  120. *
  121. * nTop - The 1-based row number of the upper right corner of
  122. * the menu.
  123. *
  124. * nLevel - Menu level, which must be a value between 0 and
  125. * MENU_LEVELS.
  126. *
  127. * uFlags - One or more flags, combined by the bitwise or (|)
  128. * operator.
  129. *
  130. * Return: POPUP_ERROR on error, POPUP_ESCAPE if user pressed the Escape
  131. * key, POPUP_LEFT if the user choose to move to the next menu to
  132. * the left, POPUP_RIGHT if the user choose to move to the next
  133. * menu to the right, or a postive value if the user choose an item
  134. * from the menu. In this case, the return value is the 1-based
  135. * index of the selected menu item.
  136. */
  137. ODAPIDEF INT ODCALL od_popup_menu(char *pszTitle, char *pszText, INT nLeft,
  138. INT nTop, INT nLevel, WORD uFlags)
  139. {
  140. tMenuItem *paMenuItems = NULL;
  141. BYTE btCount;
  142. BYTE btWidth;
  143. BYTE btRight;
  144. BYTE btBottom;
  145. BYTE btCursor;
  146. BYTE btLeft;
  147. BYTE btTop;
  148. void *pWindow;
  149. BYTE btBetweenSize;
  150. BYTE btTitleSize;
  151. BYTE btRemaining;
  152. BYTE btLineCount;
  153. INT16 nOriginalAttrib;
  154. /* Log function entry if running in trace mode. */
  155. TRACE(TRACE_API, "od_popup_menu()");
  156. /* Initialize OpenDoors, if not already done. */
  157. if(!bODInitialized) od_init();
  158. OD_API_ENTRY();
  159. /* Setup od_box_chars appropriately. */
  160. if(od_control.od_box_chars[BOX_BOTTOM] == 0)
  161. {
  162. od_control.od_box_chars[BOX_BOTTOM] = od_control.od_box_chars[BOX_TOP];
  163. }
  164. if(od_control.od_box_chars[BOX_RIGHT] == 0)
  165. {
  166. od_control.od_box_chars[BOX_RIGHT] = od_control.od_box_chars[BOX_LEFT];
  167. }
  168. /* Store initial display color. */
  169. nOriginalAttrib = od_control.od_cur_attrib;
  170. /* check level bounds */
  171. if(nLevel < 0 || nLevel > MENU_LEVELS)
  172. {
  173. od_control.od_error = ERR_LIMIT;
  174. OD_API_EXIT();
  175. return(POPUP_ERROR);
  176. }
  177. /* normalize level */
  178. nCurrentLevel = nLevel;
  179. if(MenuLevelInfo[nLevel].pWindow == NULL)
  180. {
  181. btLeft = nLeft;
  182. btTop = nTop;
  183. wCurrentFlags = uFlags;
  184. if(pszText == NULL)
  185. {
  186. od_control.od_error = ERR_PARAMETER;
  187. OD_API_EXIT();
  188. return(POPUP_ERROR);
  189. }
  190. if(paMenuItems == NULL)
  191. {
  192. if((paMenuItems = malloc(sizeof(tMenuItem) * MAX_MENU_ITEMS)) == NULL)
  193. {
  194. od_control.od_error = ERR_PARAMETER;
  195. OD_API_EXIT();
  196. return(POPUP_ERROR);
  197. }
  198. }
  199. MenuLevelInfo[nLevel].paMenuItems = paMenuItems;
  200. btCurrentNumMenuItems = 0;
  201. btWidth = 0;
  202. btCount = 0;
  203. nCommand = NO_COMMAND;
  204. paMenuItems[0].btKeyIndex = 0;
  205. while(*pszText && btCurrentNumMenuItems < MAX_MENU_ITEMS)
  206. {
  207. switch(*pszText)
  208. {
  209. case '|':
  210. paMenuItems[btCurrentNumMenuItems++].szItemText[btCount]
  211. = '\0';
  212. if(btCount > btWidth) btWidth = btCount;
  213. btCount = 0;
  214. paMenuItems[btCurrentNumMenuItems].btKeyIndex = 0;
  215. break;
  216. case '^':
  217. if(btCount < MAX_ITEM_WIDTH)
  218. {
  219. paMenuItems[btCurrentNumMenuItems].btKeyIndex = btCount;
  220. }
  221. break;
  222. default:
  223. if(btCount < MAX_ITEM_WIDTH)
  224. {
  225. paMenuItems[btCurrentNumMenuItems].szItemText[btCount++] =
  226. *pszText;
  227. }
  228. }
  229. ++pszText;
  230. }
  231. /* If we were in the middle of a menu item when we encountered the end */
  232. /* of the string, then it should form an additional menu entry. This */
  233. /* handles the case of a menu string to no terminating | for the last */
  234. /* entry. */
  235. if(btCount != 0)
  236. {
  237. /* null-terminate current menu entry string */
  238. paMenuItems[btCurrentNumMenuItems++].szItemText[btCount] = '\0';
  239. /* If this is the widest entry, update he menu width appropriately */
  240. if(btCount > btWidth) btWidth = btCount;
  241. }
  242. /* If the menu description string does not contain any menu items */
  243. if(btCurrentNumMenuItems == 0)
  244. {
  245. /* Return with parameter error */
  246. od_control.od_error = ERR_PARAMETER;
  247. OD_API_EXIT();
  248. return(POPUP_ERROR);
  249. }
  250. /* Adjust menu width to allow title to fit, if possible */
  251. /* If a title string was passed, and that string is wider than widest */
  252. /* menu entry ... */
  253. if(pszTitle != NULL && strlen(pszTitle) + 2 > btWidth)
  254. {
  255. /* Then width of menu window should be large enough to allow up to */
  256. /* the first 76 characters of the title to fit. */
  257. btWidth = strlen(pszTitle) + 2 > MAX_ITEM_WIDTH
  258. ? MAX_ITEM_WIDTH : strlen(pszTitle) + 2;
  259. }
  260. /* Based on number and size of menu items, and width of title, */
  261. /* determine the bottom, right and inside width of the menu. */
  262. btBottom = btTop + btCurrentNumMenuItems + 1;
  263. btRight = btLeft + btWidth + 3;
  264. btBetweenSize = (btRight - btLeft) - 1;
  265. /* If neither ANSI nor AVATAR mode is available, return with an error */
  266. if(!(od_control.user_ansi || od_control.user_avatar))
  267. {
  268. od_control.od_error = ERR_NOGRAPHICS;
  269. OD_API_EXIT();
  270. return(POPUP_ERROR);
  271. }
  272. /* If menu would "fall off" edge of screen, return with an error */
  273. if(btLeft < 1 || btTop < 1 || btRight > OD_SCREEN_WIDTH
  274. || btBottom > OD_SCREEN_HEIGHT || btRight - btLeft < 2
  275. || btBottom - btTop < 2)
  276. {
  277. od_control.od_error = ERR_PARAMETER;
  278. OD_API_EXIT();
  279. return(POPUP_ERROR);
  280. }
  281. /* Allocate space to store window information. If unable to allocate */
  282. /* enough space, return with an error. */
  283. if((pWindow = malloc((btRight - btLeft + 1) * 2
  284. + (btBottom - btTop + 1) * 160)) == NULL)
  285. {
  286. od_control.od_error = ERR_MEMORY;
  287. OD_API_EXIT();
  288. return(POPUP_ERROR);
  289. }
  290. /* Store contents of screen where memu will be drawn in the temporary */
  291. /* buffer. */
  292. if(!od_gettext(btLeft, btTop, btRight, btBottom, pWindow))
  293. {
  294. free(pWindow);
  295. pWindow = NULL;
  296. /* Note that od_error code has been set in od_gettext(). */
  297. OD_API_EXIT();
  298. return(POPUP_ERROR);
  299. }
  300. /* Determine number of characters of title to be displayed */
  301. if(pszTitle == NULL)
  302. {
  303. btTitleSize = 0;
  304. }
  305. else
  306. {
  307. if((btTitleSize = strlen(pszTitle)) > (btBetweenSize - 4))
  308. {
  309. btTitleSize = btBetweenSize - 4;
  310. }
  311. }
  312. od_set_cursor(btTop,btLeft);
  313. od_set_attrib(od_control.od_menu_border_col);
  314. od_putch(od_control.od_box_chars[BOX_UPPERLEFT]);
  315. if(btTitleSize == 0)
  316. {
  317. od_repeat(od_control.od_box_chars[BOX_TOP], btBetweenSize);
  318. }
  319. else
  320. {
  321. od_repeat(od_control.od_box_chars[BOX_TOP],
  322. btRemaining = ((btBetweenSize - btTitleSize - 2) / 2));
  323. od_set_attrib(od_control.od_menu_title_col);
  324. od_putch(' ');
  325. od_disp(pszTitle,btTitleSize, TRUE);
  326. od_putch(' ');
  327. od_set_attrib(od_control.od_menu_border_col);
  328. od_repeat(od_control.od_box_chars[BOX_TOP],
  329. (BYTE)(btBetweenSize - btRemaining - btTitleSize - 2));
  330. }
  331. od_putch(od_control.od_box_chars[BOX_UPPERRIGHT]);
  332. btLineCount = btTop + 1;
  333. btCorrectItem = 0;
  334. ODPopupCheckForKey(FALSE);
  335. btCursor = btCorrectItem;
  336. for(btCount = 0; btCount < btCurrentNumMenuItems
  337. && btLineCount < btBottom; ++btCount)
  338. {
  339. ODPopupCheckForKey(FALSE);
  340. if(nCommand != NO_COMMAND && !(wCurrentFlags & MENU_KEEP))
  341. {
  342. goto exit_now;
  343. }
  344. od_set_cursor(btLineCount,btLeft);
  345. od_putch(od_control.od_box_chars[BOX_LEFT]);
  346. od_set_attrib(od_control.od_menu_text_col);
  347. if(btCount == btCursor)
  348. {
  349. ODPopupDisplayMenuItem(btLeft, btTop, paMenuItems, btCount,
  350. TRUE, btWidth, FALSE);
  351. }
  352. else
  353. {
  354. ODPopupDisplayMenuItem(btLeft, btTop, paMenuItems, btCount,
  355. FALSE, btWidth, FALSE);
  356. }
  357. od_set_attrib(od_control.od_menu_border_col);
  358. od_putch(od_control.od_box_chars[BOX_RIGHT]);
  359. ++btLineCount;
  360. }
  361. od_set_cursor(btBottom, btLeft);
  362. od_putch(od_control.od_box_chars[BOX_LOWERLEFT]);
  363. od_repeat(od_control.od_box_chars[BOX_BOTTOM], btBetweenSize);
  364. od_putch(od_control.od_box_chars[BOX_LOWERRIGHT]);
  365. od_set_cursor(btTop + 1, btLeft + 1);
  366. }
  367. else
  368. {
  369. paMenuItems = MenuLevelInfo[nLevel].paMenuItems;
  370. btCurrentNumMenuItems = MenuLevelInfo[nLevel].btNumMenuItems;
  371. btWidth = MenuLevelInfo[nLevel].btWidth;
  372. btRight = MenuLevelInfo[nLevel].btRight;
  373. btBottom = MenuLevelInfo[nLevel].btBottom;
  374. btLeft = MenuLevelInfo[nLevel].btLeft;
  375. btTop = MenuLevelInfo[nLevel].btTop;
  376. wCurrentFlags = MenuLevelInfo[nLevel].wFlags;
  377. pWindow = MenuLevelInfo[nLevel].pWindow;
  378. btCorrectItem = btCursor = MenuLevelInfo[nLevel].btCursor;
  379. nCommand = NO_COMMAND;
  380. if(uFlags & MENU_DESTROY)
  381. {
  382. nCommand = POPUP_ESCAPE;
  383. goto destroy;
  384. }
  385. /* Otherwise, position flashing hardware cursor appropriately */
  386. od_set_cursor(btTop + btCursor + 1, btLeft + 1);
  387. }
  388. /* Claim exclusive use of arrow keys. */
  389. ODStatStartArrowUse();
  390. for(;;)
  391. {
  392. ODPopupCheckForKey(TRUE);
  393. if(btCorrectItem != btCursor)
  394. {
  395. ODPopupDisplayMenuItem(btLeft, btTop, paMenuItems, btCursor,
  396. FALSE, btWidth, TRUE);
  397. btCursor = btCorrectItem;
  398. ODWaitDrain(25);
  399. ODPopupCheckForKey(FALSE);
  400. ODPopupDisplayMenuItem(btLeft, btTop, paMenuItems, btCursor,
  401. TRUE, btWidth, TRUE);
  402. }
  403. if(nCommand != NO_COMMAND)
  404. {
  405. goto exit_now;
  406. }
  407. }
  408. exit_now:
  409. if((!(wCurrentFlags & MENU_KEEP)) || nCommand <= 0)
  410. {
  411. destroy:
  412. od_puttext(btLeft, btTop, btRight, btBottom, pWindow);
  413. free(pWindow);
  414. MenuLevelInfo[nLevel].pWindow = NULL;
  415. if(paMenuItems != NULL)
  416. {
  417. free(paMenuItems);
  418. MenuLevelInfo[nLevel].paMenuItems = NULL;
  419. }
  420. }
  421. else if(wCurrentFlags & MENU_KEEP)
  422. {
  423. MenuLevelInfo[nLevel].paMenuItems = paMenuItems;
  424. MenuLevelInfo[nLevel].btNumMenuItems = btCurrentNumMenuItems;
  425. MenuLevelInfo[nLevel].btWidth = btWidth;
  426. MenuLevelInfo[nLevel].btRight = btRight;
  427. MenuLevelInfo[nLevel].btBottom = btBottom;
  428. MenuLevelInfo[nLevel].btCursor = btCursor;
  429. MenuLevelInfo[nLevel].btLeft = btLeft;
  430. MenuLevelInfo[nLevel].btTop = btTop;
  431. MenuLevelInfo[nLevel].wFlags = wCurrentFlags;
  432. MenuLevelInfo[nLevel].pWindow = pWindow;
  433. }
  434. /* Restore original display color. */
  435. od_set_attrib(nOriginalAttrib);
  436. /* Release exclusive use of arrow keys. */
  437. ODStatEndArrowUse();
  438. OD_API_EXIT();
  439. return(nCommand);
  440. }
  441. /* ----------------------------------------------------------------------------
  442. * ODPopupCheckForKey() *** PRIVATE FUNCTION ***
  443. *
  444. * Checks whether or not the user has pressed any key. If one or more keys
  445. * have been pressed, then these keystrokes are processed. This function
  446. * returns when no more keys are waiting in the inbound buffer, or when a key
  447. * has been pressed that requires immediate action (such as the [ENTER] key).
  448. *
  449. * Parameters: bWaitForInput - Indicates whether this function should return
  450. * immediately if no input is waiting (FALSE), or
  451. * wait for the next input even before returning
  452. * (TRUE).
  453. *
  454. * Return: void
  455. */
  456. static void ODPopupCheckForKey(BOOL bWaitForInput)
  457. {
  458. BYTE btCount;
  459. tODInputEvent InputEvent;
  460. BOOL bDoneAnythingYet = FALSE;
  461. /* Loop, processing keys. If a command has been selected, stop looping */
  462. /* immediately. If there are no more keys waiting, stop looping */
  463. while(nCommand == NO_COMMAND)
  464. {
  465. CALL_KERNEL_IF_NEEDED();
  466. if(!od_get_input(&InputEvent, bWaitForInput && !bDoneAnythingYet
  467. ? OD_NO_TIMEOUT : 0, GETIN_NORMAL))
  468. {
  469. /* Return right away if no input event is waiting. */
  470. return;
  471. }
  472. bDoneAnythingYet = TRUE;
  473. if(InputEvent.EventType == EVENT_EXTENDED_KEY)
  474. {
  475. switch(InputEvent.chKeyPress)
  476. {
  477. case OD_KEY_UP:
  478. up_arrow:
  479. if(btCorrectItem == 0)
  480. {
  481. btCorrectItem = btCurrentNumMenuItems - 1;
  482. }
  483. else
  484. {
  485. --btCorrectItem;
  486. }
  487. break;
  488. case OD_KEY_DOWN:
  489. down_arrow:
  490. if(++btCorrectItem >= btCurrentNumMenuItems)
  491. {
  492. btCorrectItem = 0;
  493. }
  494. break;
  495. case OD_KEY_LEFT:
  496. left_arrow:
  497. if(wCurrentFlags & MENU_PULLDOWN)
  498. {
  499. nCommand = POPUP_LEFT;
  500. return;
  501. }
  502. break;
  503. case OD_KEY_RIGHT:
  504. right_arrow:
  505. if(wCurrentFlags & MENU_PULLDOWN)
  506. {
  507. nCommand = POPUP_RIGHT;
  508. return;
  509. }
  510. break;
  511. }
  512. }
  513. else if(InputEvent.EventType == EVENT_CHARACTER)
  514. {
  515. if(InputEvent.chKeyPress == '\n' || InputEvent.chKeyPress == '\r')
  516. {
  517. nCommand = btCorrectItem + 1;
  518. return;
  519. }
  520. else if(InputEvent.chKeyPress == 27)
  521. {
  522. if(wCurrentFlags & MENU_ALLOW_CANCEL)
  523. {
  524. nCommand = POPUP_ESCAPE;
  525. return;
  526. }
  527. }
  528. else
  529. {
  530. /* Check whether key is a menu "hot key" */
  531. for(btCount = 0; btCount < btCurrentNumMenuItems; ++btCount)
  532. {
  533. if(toupper(MenuLevelInfo[nCurrentLevel].paMenuItems[btCount]
  534. .szItemText[MenuLevelInfo[nCurrentLevel].paMenuItems[btCount]
  535. .btKeyIndex]) == toupper(InputEvent.chKeyPress))
  536. {
  537. btCorrectItem = btCount;
  538. nCommand = btCorrectItem + 1;
  539. return;
  540. }
  541. }
  542. /* At this point, we know that key was not one of the "hot keys" */
  543. /* Check for 4, 6, 8 and 2 keys as arrow keys. */
  544. if(InputEvent.chKeyPress == '4')
  545. {
  546. goto left_arrow;
  547. }
  548. else if(InputEvent.chKeyPress == '6')
  549. {
  550. goto right_arrow;
  551. }
  552. else if(InputEvent.chKeyPress == '8')
  553. {
  554. goto up_arrow;
  555. }
  556. else if(InputEvent.chKeyPress == '2')
  557. {
  558. goto down_arrow;
  559. }
  560. }
  561. }
  562. }
  563. }
  564. /* ----------------------------------------------------------------------------
  565. * ODPopupDisplayMenuItem() *** PRIVATE FUNCTION ***
  566. *
  567. * Displays an individual menu item.
  568. *
  569. * Parameters: btLeft - Column number where the menu item will be
  570. * displayed.
  571. *
  572. * btTop - Row number where the menu item will be
  573. * displayed.
  574. *
  575. * paMenuItems - Pointer to array of available menu items.
  576. *
  577. * btItemIndex - Index into paMenuItems of the menu item that
  578. * is to be displayed.
  579. *
  580. * bHighlighted - TRUE if the items is to be displayed as
  581. * highlighted, FALSE if it is to be displayed as
  582. * non-highlighted.
  583. *
  584. * btWidth - Width of the menu item, in characters.
  585. *
  586. * bPositionCursor - TRUE if the cursor needs to be positioned
  587. * prior to drawing the menu item, FALSE if the
  588. * cursor is already in the required position.
  589. *
  590. * Return: void
  591. */
  592. static void ODPopupDisplayMenuItem(BYTE btLeft, BYTE btTop,
  593. tMenuItem *paMenuItems, BYTE btItemIndex, BOOL bHighlighted, BYTE btWidth,
  594. BOOL bPositionCursor)
  595. {
  596. BYTE btCount;
  597. char *pchItemText;
  598. BYTE btKeyPosition;
  599. BYTE btTextColor;
  600. BYTE btKeyColor;
  601. /* Check that parameters are reasonable when operating in debug mode. */
  602. ASSERT(paMenuItems != NULL);
  603. ASSERT(btItemIndex < MAX_MENU_ITEMS);
  604. ASSERT(btWidth < OD_SCREEN_WIDTH);
  605. ++btLeft;
  606. ++btTop;
  607. btTextColor = bHighlighted ? od_control.od_menu_highlight_col
  608. : od_control.od_menu_text_col;
  609. btKeyColor = bHighlighted ? od_control.od_menu_highkey_col
  610. : od_control.od_menu_key_col;
  611. pchItemText = (char *)(paMenuItems[btItemIndex].szItemText);
  612. btKeyPosition = paMenuItems[btItemIndex].btKeyIndex;
  613. if(bPositionCursor) od_set_cursor(btTop + btItemIndex, btLeft);
  614. od_set_attrib(btTextColor);
  615. od_putch(' ');
  616. for(btCount = 0; btCount < btWidth && *pchItemText; ++btCount)
  617. {
  618. if(btCount == btKeyPosition)
  619. {
  620. od_set_attrib(btKeyColor);
  621. od_putch(*pchItemText++);
  622. od_set_attrib(btTextColor);
  623. }
  624. else
  625. {
  626. od_putch(*pchItemText++);
  627. }
  628. }
  629. od_repeat(' ', (BYTE)((btWidth - btCount) + 1));
  630. if(bPositionCursor) od_set_cursor(btTop + btItemIndex, btLeft);
  631. }