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