1 /* $NetBSD: driver.c,v 1.9 2003/03/09 01:08:48 lukem 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 <sys/cdefs.h> 30 __RCSID("$NetBSD: driver.c,v 1.9 2003/03/09 01:08:48 lukem Exp $"); 31 32 #include <menu.h> 33 #include <ctype.h> 34 #include <stdlib.h> 35 #include "internals.h" 36 37 /* 38 * The guts of the menu library. This function processes the character 39 * in c and performs actions based on the value of the character. If the 40 * character is a normal one then the driver attempts to match the character 41 * against the items. If the character is a recognised request then the 42 * request is processed by the driver, if the character is not a recognised 43 * request and is not printable then it assumed to be a user defined command. 44 */ 45 int 46 menu_driver(MENU *menu, int c) 47 { 48 int drv_top_row, drv_scroll, i, it, status = E_OK; 49 ITEM *drv_new_item; 50 51 i = 0; 52 53 if (menu == NULL) 54 return E_BAD_ARGUMENT; 55 if (menu->posted == 0) 56 return E_NOT_POSTED; 57 if (menu->items == NULL) 58 return E_NOT_CONNECTED; 59 if (*menu->items == NULL) 60 return E_NOT_CONNECTED; 61 if (menu->in_init == 1) 62 return E_BAD_STATE; 63 64 /* this one should never happen but just in case.... */ 65 if (menu->items[menu->cur_item] == NULL) 66 return E_SYSTEM_ERROR; 67 68 drv_new_item = menu->items[menu->cur_item]; 69 it = menu->cur_item; 70 drv_top_row = menu->top_row; 71 72 if ((c > REQ_BASE_NUM) && (c <= MAX_COMMAND)) { 73 /* is a known driver request - first check if the pattern 74 * buffer needs to be cleared, we do this on non-search 75 * type requests. 76 */ 77 if (! ((c == REQ_BACK_PATTERN) || (c == REQ_NEXT_MATCH) || 78 (c == REQ_PREV_MATCH))) { 79 if ((c == REQ_CLEAR_PATTERN) 80 && (menu->pattern == NULL)) 81 return E_REQUEST_DENIED; 82 free(menu->pattern); 83 menu->pattern = NULL; 84 menu->plen = 0; 85 menu->match_len = 0; 86 } 87 88 switch (c) { 89 case REQ_LEFT_ITEM: 90 drv_new_item = drv_new_item->left; 91 break; 92 case REQ_RIGHT_ITEM: 93 drv_new_item = drv_new_item->right; 94 break; 95 case REQ_UP_ITEM: 96 drv_new_item = drv_new_item->up; 97 break; 98 case REQ_DOWN_ITEM: 99 drv_new_item = drv_new_item->down; 100 break; 101 case REQ_SCR_ULINE: 102 if (drv_top_row == 0) 103 return E_REQUEST_DENIED; 104 drv_top_row--; 105 drv_new_item = drv_new_item->up; 106 break; 107 case REQ_SCR_DLINE: 108 drv_top_row++; 109 if ((drv_top_row + menu->rows - 1)> menu->item_rows) 110 return E_REQUEST_DENIED; 111 drv_new_item = drv_new_item->down; 112 break; 113 case REQ_SCR_DPAGE: 114 drv_scroll = menu->item_rows - menu->rows 115 - menu->top_row; 116 if (drv_scroll > menu->rows) { 117 drv_scroll = menu->rows; 118 } 119 120 if (drv_scroll <= 0) { 121 return E_REQUEST_DENIED; 122 } else { 123 drv_top_row += drv_scroll; 124 while (drv_scroll-- > 0) 125 drv_new_item = drv_new_item->down; 126 } 127 break; 128 case REQ_SCR_UPAGE: 129 if (menu->rows < menu->top_row) { 130 drv_scroll = menu->rows; 131 } else { 132 drv_scroll = menu->top_row; 133 } 134 if (drv_scroll == 0) 135 return E_REQUEST_DENIED; 136 137 drv_top_row -= drv_scroll; 138 while (drv_scroll-- > 0) 139 drv_new_item = drv_new_item->up; 140 break; 141 case REQ_FIRST_ITEM: 142 drv_new_item = menu->items[0]; 143 break; 144 case REQ_LAST_ITEM: 145 drv_new_item = menu->items[menu->item_count - 1]; 146 break; 147 case REQ_NEXT_ITEM: 148 if ((menu->cur_item + 1) >= menu->item_count) { 149 if ((menu->opts & O_NONCYCLIC) 150 == O_NONCYCLIC) { 151 return E_REQUEST_DENIED; 152 } else { 153 drv_new_item = menu->items[0]; 154 } 155 } else { 156 drv_new_item = 157 menu->items[menu->cur_item + 1]; 158 } 159 break; 160 case REQ_PREV_ITEM: 161 if (menu->cur_item == 0) { 162 if ((menu->opts & O_NONCYCLIC) 163 == O_NONCYCLIC) { 164 return E_REQUEST_DENIED; 165 } else { 166 drv_new_item = menu->items[ 167 menu->item_count - 1]; 168 } 169 } else { 170 drv_new_item = 171 menu->items[menu->cur_item - 1]; 172 } 173 break; 174 case REQ_TOGGLE_ITEM: 175 if ((menu->opts & (O_RADIO | O_ONEVALUE)) != 0) { 176 if ((menu->opts & O_RADIO) == O_RADIO) { 177 if ((drv_new_item->opts & O_SELECTABLE) 178 != O_SELECTABLE) 179 return E_NOT_SELECTABLE; 180 181 /* don't deselect selected item */ 182 if (drv_new_item->selected == 1) 183 return E_REQUEST_DENIED; 184 185 /* deselect all items */ 186 for (i = 0; i < menu->item_count; i++) { 187 if ((menu->items[i]->selected) && 188 (drv_new_item->index != i)) { 189 menu->items[i]->selected ^= 1; 190 _menui_draw_item(menu, 191 menu->items[i]->index); 192 } 193 } 194 195 /* turn on selected item */ 196 drv_new_item->selected ^= 1; 197 _menui_draw_item(menu, drv_new_item->index); 198 } else { 199 return E_REQUEST_DENIED; 200 } 201 } else { 202 if ((drv_new_item->opts 203 & O_SELECTABLE) == O_SELECTABLE) { 204 /* toggle select flag */ 205 drv_new_item->selected ^= 1; 206 /* update item in menu */ 207 _menui_draw_item(menu, 208 drv_new_item->index); 209 } else { 210 return E_NOT_SELECTABLE; 211 } 212 } 213 break; 214 case REQ_CLEAR_PATTERN: 215 /* this action is taken before the 216 case statement */ 217 break; 218 case REQ_BACK_PATTERN: 219 if (menu->pattern == NULL) 220 return E_REQUEST_DENIED; 221 222 if (menu->plen == 0) 223 return E_REQUEST_DENIED; 224 menu->pattern[menu->plen--] = '\0'; 225 break; 226 case REQ_NEXT_MATCH: 227 if (menu->pattern == NULL) 228 return E_REQUEST_DENIED; 229 230 status = _menui_match_pattern(menu, 0, 231 MATCH_NEXT_FORWARD, 232 &it); 233 drv_new_item = menu->items[it]; 234 break; 235 case REQ_PREV_MATCH: 236 if (menu->pattern == NULL) 237 return E_REQUEST_DENIED; 238 239 status = _menui_match_pattern(menu, 0, 240 MATCH_NEXT_REVERSE, 241 &it); 242 drv_new_item = menu->items[it]; 243 break; 244 } 245 } else if (c > MAX_COMMAND) { 246 /* must be a user command */ 247 return E_UNKNOWN_COMMAND; 248 } else if (isprint((unsigned char) c)) { 249 /* otherwise search items for the character. */ 250 status = _menui_match_pattern(menu, (unsigned char) c, 251 MATCH_FORWARD, &it); 252 drv_new_item = menu->items[it]; 253 254 /* update the position of the cursor if we are doing 255 * show match and the current item has not changed. If 256 * we don't do this here it won't get done since the 257 * display will not be updated due to the current item 258 * not changing. 259 */ 260 if ((drv_new_item->index == menu->cur_item) 261 && ((menu->opts & O_SHOWMATCH) == O_SHOWMATCH)) { 262 pos_menu_cursor(menu); 263 } 264 265 266 } else { 267 /* bad character */ 268 return E_BAD_ARGUMENT; 269 } 270 271 if (drv_new_item == NULL) 272 return E_REQUEST_DENIED; 273 274 if (drv_new_item->row < drv_top_row) drv_top_row = drv_new_item->row; 275 if (drv_new_item->row >= (drv_top_row + menu->rows)) 276 drv_top_row = drv_new_item->row - menu->rows + 1; 277 278 if ((drv_new_item->index != menu->cur_item) 279 || (drv_top_row != menu->top_row)) 280 _menui_goto_item(menu, drv_new_item, drv_top_row); 281 282 return status; 283 } 284 285 286 287 288 289