1 /* $NetBSD: driver.c,v 1.7 2001/06/13 10:45:59 wiz Exp $ */ 2 3 /*- 4 * Copyright (c) 1998-1999 Brett Lymn (blymn@baea.com.au, brett_lymn@yahoo.com.au) 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * 27 */ 28 29 #include <menu.h> 30 #include <ctype.h> 31 #include <stdlib.h> 32 #include "internals.h" 33 34 /* 35 * The guts of the menu library. This function processes the character 36 * in c and performs actions based on the value of the character. If the 37 * character is a normal one then the driver attempts to match the character 38 * against the items. If the character is a recognised request then the 39 * request is processed by the driver, if the character is not a recognised 40 * request and is not printable then it assumed to be a user defined command. 41 */ 42 int 43 menu_driver(MENU *menu, int c) 44 { 45 int drv_top_row, drv_scroll, it, status = E_OK; 46 ITEM *drv_new_item; 47 48 if (menu == NULL) 49 return E_BAD_ARGUMENT; 50 if (menu->posted == 0) 51 return E_NOT_POSTED; 52 if (menu->items == NULL) 53 return E_NOT_CONNECTED; 54 if (*menu->items == NULL) 55 return E_NOT_CONNECTED; 56 if (menu->in_init == 1) 57 return E_BAD_STATE; 58 59 /* this one should never happen but just in case.... */ 60 if (menu->items[menu->cur_item] == NULL) 61 return E_SYSTEM_ERROR; 62 63 drv_new_item = menu->items[menu->cur_item]; 64 it = menu->cur_item; 65 drv_top_row = menu->top_row; 66 67 if ((c > REQ_BASE_NUM) && (c <= MAX_COMMAND)) { 68 /* is a known driver request - first check if the pattern 69 * buffer needs to be cleared, we do this on non-search 70 * type requests. 71 */ 72 if (! ((c == REQ_BACK_PATTERN) || (c == REQ_NEXT_MATCH) || 73 (c == REQ_PREV_MATCH))) { 74 if ((c == REQ_CLEAR_PATTERN) 75 && (menu->pattern == NULL)) 76 return E_REQUEST_DENIED; 77 free(menu->pattern); 78 menu->pattern = NULL; 79 menu->plen = 0; 80 menu->match_len = 0; 81 } 82 83 switch (c) { 84 case REQ_LEFT_ITEM: 85 drv_new_item = drv_new_item->left; 86 break; 87 case REQ_RIGHT_ITEM: 88 drv_new_item = drv_new_item->right; 89 break; 90 case REQ_UP_ITEM: 91 drv_new_item = drv_new_item->up; 92 break; 93 case REQ_DOWN_ITEM: 94 drv_new_item = drv_new_item->down; 95 break; 96 case REQ_SCR_ULINE: 97 if (drv_top_row == 0) 98 return E_REQUEST_DENIED; 99 drv_top_row--; 100 drv_new_item = drv_new_item->up; 101 break; 102 case REQ_SCR_DLINE: 103 drv_top_row++; 104 if ((drv_top_row + menu->rows - 1)> menu->item_rows) 105 return E_REQUEST_DENIED; 106 drv_new_item = drv_new_item->down; 107 break; 108 case REQ_SCR_DPAGE: 109 drv_scroll = menu->item_rows - menu->rows 110 - menu->top_row; 111 if (drv_scroll > menu->rows) { 112 drv_scroll = menu->rows; 113 } 114 115 if (drv_scroll <= 0) { 116 return E_REQUEST_DENIED; 117 } else { 118 drv_top_row += drv_scroll; 119 while (drv_scroll-- > 0) 120 drv_new_item = drv_new_item->down; 121 } 122 break; 123 case REQ_SCR_UPAGE: 124 if (menu->rows < menu->top_row) { 125 drv_scroll = menu->rows; 126 } else { 127 drv_scroll = menu->top_row; 128 } 129 if (drv_scroll == 0) 130 return E_REQUEST_DENIED; 131 132 drv_top_row -= drv_scroll; 133 while (drv_scroll-- > 0) 134 drv_new_item = drv_new_item->up; 135 break; 136 case REQ_FIRST_ITEM: 137 drv_new_item = menu->items[0]; 138 break; 139 case REQ_LAST_ITEM: 140 drv_new_item = menu->items[menu->item_count - 1]; 141 break; 142 case REQ_NEXT_ITEM: 143 if ((menu->cur_item + 1) >= menu->item_count) { 144 if ((menu->opts & O_NONCYCLIC) 145 == O_NONCYCLIC) { 146 return E_REQUEST_DENIED; 147 } else { 148 drv_new_item = menu->items[0]; 149 } 150 } else { 151 drv_new_item = 152 menu->items[menu->cur_item + 1]; 153 } 154 break; 155 case REQ_PREV_ITEM: 156 if (menu->cur_item == 0) { 157 if ((menu->opts & O_NONCYCLIC) 158 == O_NONCYCLIC) { 159 return E_REQUEST_DENIED; 160 } else { 161 drv_new_item = menu->items[ 162 menu->item_count - 1]; 163 } 164 } else { 165 drv_new_item = 166 menu->items[menu->cur_item - 1]; 167 } 168 break; 169 case REQ_TOGGLE_ITEM: 170 if ((menu->opts & O_ONEVALUE) == O_ONEVALUE) { 171 return E_REQUEST_DENIED; 172 } else { 173 if ((drv_new_item->opts 174 & O_SELECTABLE) == O_SELECTABLE) { 175 /* toggle select flag */ 176 drv_new_item->selected ^= 1; 177 /* update item in menu */ 178 _menui_draw_item(menu, 179 drv_new_item->index); 180 } else { 181 return E_NOT_SELECTABLE; 182 } 183 } 184 break; 185 case REQ_CLEAR_PATTERN: 186 /* this action is taken before the 187 case statement */ 188 break; 189 case REQ_BACK_PATTERN: 190 if (menu->pattern == NULL) 191 return E_REQUEST_DENIED; 192 193 if (menu->plen == 0) 194 return E_REQUEST_DENIED; 195 menu->pattern[menu->plen--] = '\0'; 196 break; 197 case REQ_NEXT_MATCH: 198 if (menu->pattern == NULL) 199 return E_REQUEST_DENIED; 200 201 status = _menui_match_pattern(menu, 0, 202 MATCH_NEXT_FORWARD, 203 &it); 204 drv_new_item = menu->items[it]; 205 break; 206 case REQ_PREV_MATCH: 207 if (menu->pattern == NULL) 208 return E_REQUEST_DENIED; 209 210 status = _menui_match_pattern(menu, 0, 211 MATCH_NEXT_REVERSE, 212 &it); 213 drv_new_item = menu->items[it]; 214 break; 215 } 216 } else if (c > MAX_COMMAND) { 217 /* must be a user command */ 218 return E_UNKNOWN_COMMAND; 219 } else if (isprint((unsigned char) c)) { 220 /* otherwise search items for the character. */ 221 status = _menui_match_pattern(menu, (unsigned char) c, 222 MATCH_FORWARD, &it); 223 drv_new_item = menu->items[it]; 224 225 /* update the position of the cursor if we are doing 226 * show match and the current item has not changed. If 227 * we don't do this here it won't get done since the 228 * display will not be updated due to the current item 229 * not changing. 230 */ 231 if ((drv_new_item->index == menu->cur_item) 232 && ((menu->opts & O_SHOWMATCH) == O_SHOWMATCH)) { 233 pos_menu_cursor(menu); 234 } 235 236 237 } else { 238 /* bad character */ 239 return E_BAD_ARGUMENT; 240 } 241 242 if (drv_new_item == NULL) 243 return E_REQUEST_DENIED; 244 245 if (drv_new_item->row < drv_top_row) drv_top_row = drv_new_item->row; 246 if (drv_new_item->row >= (drv_top_row + menu->rows)) 247 drv_top_row = drv_new_item->row - menu->rows + 1; 248 249 if ((drv_new_item->index != menu->cur_item) 250 || (drv_top_row != menu->top_row)) 251 _menui_goto_item(menu, drv_new_item, drv_top_row); 252 253 return status; 254 } 255 256 257 258 259 260