internals.c revision 1.4.2.2 1 1.4.2.2 wrstuden /* $Id: internals.c,v 1.4.2.2 1999/12/27 18:30:03 wrstuden Exp $ */
2 1.4.2.2 wrstuden
3 1.4.2.2 wrstuden /*-
4 1.4.2.2 wrstuden * Copyright (c) 1998-1999 Brett Lymn (blymn (at) baea.com.au, brett_lymn (at) yahoo.com.au)
5 1.4.2.2 wrstuden * All rights reserved.
6 1.4.2.2 wrstuden *
7 1.4.2.2 wrstuden * Redistribution and use in source and binary forms, with or without
8 1.4.2.2 wrstuden * modification, are permitted provided that the following conditions
9 1.4.2.2 wrstuden * are met:
10 1.4.2.2 wrstuden * 1. Redistributions of source code must retain the above copyright
11 1.4.2.2 wrstuden * notice, this list of conditions and the following disclaimer.
12 1.4.2.2 wrstuden * 2. The name of the author may not be used to endorse or promote products
13 1.4.2.2 wrstuden * derived from this software withough specific prior written permission
14 1.4.2.2 wrstuden *
15 1.4.2.2 wrstuden * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 1.4.2.2 wrstuden * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 1.4.2.2 wrstuden * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 1.4.2.2 wrstuden * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 1.4.2.2 wrstuden * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 1.4.2.2 wrstuden * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 1.4.2.2 wrstuden * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 1.4.2.2 wrstuden * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 1.4.2.2 wrstuden * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 1.4.2.2 wrstuden * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 1.4.2.2 wrstuden *
26 1.4.2.2 wrstuden *
27 1.4.2.2 wrstuden */
28 1.4.2.2 wrstuden
29 1.4.2.2 wrstuden #include <menu.h>
30 1.4.2.2 wrstuden #include <ctype.h>
31 1.4.2.2 wrstuden #include <stdlib.h>
32 1.4.2.2 wrstuden #include <string.h>
33 1.4.2.2 wrstuden #include "internals.h"
34 1.4.2.2 wrstuden
35 1.4.2.2 wrstuden /* internal function prototypes */
36 1.4.2.2 wrstuden static void
37 1.4.2.2 wrstuden _menui_calc_neighbours(MENU *, int, int, int, int, ITEM **, ITEM **,
38 1.4.2.2 wrstuden ITEM **, ITEM **);
39 1.4.2.2 wrstuden static void _menui_redraw_menu __P((MENU *, int, int));
40 1.4.2.2 wrstuden
41 1.4.2.2 wrstuden /*
42 1.4.2.2 wrstuden * Link all the menu items together to speed up navigation. We need
43 1.4.2.2 wrstuden * to calculate the widest item entry, then work out how many columns
44 1.4.2.2 wrstuden * of items the window will accomodate and then how many rows there will
45 1.4.2.2 wrstuden * be. Once the layout is determined the neighbours of each item is
46 1.4.2.2 wrstuden * calculated and the item structures updated.
47 1.4.2.2 wrstuden */
48 1.4.2.2 wrstuden int
49 1.4.2.2 wrstuden _menui_stitch_items(menu)
50 1.4.2.2 wrstuden MENU *menu;
51 1.4.2.2 wrstuden {
52 1.4.2.2 wrstuden int i, cycle, row_major;
53 1.4.2.2 wrstuden
54 1.4.2.2 wrstuden cycle = ((menu->opts & O_NONCYCLIC) != O_NONCYCLIC);
55 1.4.2.2 wrstuden row_major = ((menu->opts & O_ROWMAJOR) == O_ROWMAJOR);
56 1.4.2.2 wrstuden
57 1.4.2.2 wrstuden if (menu->posted == 1)
58 1.4.2.2 wrstuden return E_POSTED;
59 1.4.2.2 wrstuden if (menu->items == NULL)
60 1.4.2.2 wrstuden return E_BAD_ARGUMENT;
61 1.4.2.2 wrstuden
62 1.4.2.2 wrstuden if (row_major) {
63 1.4.2.2 wrstuden menu->item_rows = menu->item_count / menu->cols;
64 1.4.2.2 wrstuden menu->item_cols = menu->cols;
65 1.4.2.2 wrstuden if (menu->item_count > (menu->item_rows * menu->item_cols))
66 1.4.2.2 wrstuden menu->item_rows += 1;
67 1.4.2.2 wrstuden } else {
68 1.4.2.2 wrstuden menu->item_cols = menu->item_count / menu->rows;
69 1.4.2.2 wrstuden menu->item_rows = menu->rows;
70 1.4.2.2 wrstuden if (menu->item_count > (menu->item_rows * menu->item_cols))
71 1.4.2.2 wrstuden menu->item_cols += 1;
72 1.4.2.2 wrstuden }
73 1.4.2.2 wrstuden
74 1.4.2.2 wrstuden
75 1.4.2.2 wrstuden _menui_max_item_size(menu);
76 1.4.2.2 wrstuden
77 1.4.2.2 wrstuden for (i = 0; i < menu->item_count; i++) {
78 1.4.2.2 wrstuden /* Calculate the neighbours. The ugliness here deals with
79 1.4.2.2 wrstuden * the differing menu layout styles. The layout affects
80 1.4.2.2 wrstuden * the neighbour calculation so we change the arguments
81 1.4.2.2 wrstuden * around depending on the layout style.
82 1.4.2.2 wrstuden */
83 1.4.2.2 wrstuden _menui_calc_neighbours(menu, i, cycle,
84 1.4.2.2 wrstuden (row_major) ? menu->item_rows
85 1.4.2.2 wrstuden : menu->item_cols,
86 1.4.2.2 wrstuden (row_major) ? menu->item_cols
87 1.4.2.2 wrstuden : menu->item_rows,
88 1.4.2.2 wrstuden (row_major) ? &menu->items[i]->right
89 1.4.2.2 wrstuden : &menu->items[i]->down,
90 1.4.2.2 wrstuden (row_major) ? &menu->items[i]->left
91 1.4.2.2 wrstuden : &menu->items[i]->up,
92 1.4.2.2 wrstuden (row_major) ? &menu->items[i]->down
93 1.4.2.2 wrstuden : &menu->items[i]->right,
94 1.4.2.2 wrstuden (row_major) ? &menu->items[i]->up
95 1.4.2.2 wrstuden : &menu->items[i]->left);
96 1.4.2.2 wrstuden
97 1.4.2.2 wrstuden /* fill in the row and column value of the item */
98 1.4.2.2 wrstuden if (row_major) {
99 1.4.2.2 wrstuden menu->items[i]->row = i / menu->item_cols;
100 1.4.2.2 wrstuden menu->items[i]->col = i % menu->item_cols;
101 1.4.2.2 wrstuden } else {
102 1.4.2.2 wrstuden menu->items[i]->row = i % menu->item_rows;
103 1.4.2.2 wrstuden menu->items[i]->col = i / menu->item_rows;
104 1.4.2.2 wrstuden }
105 1.4.2.2 wrstuden }
106 1.4.2.2 wrstuden
107 1.4.2.2 wrstuden return E_OK;
108 1.4.2.2 wrstuden }
109 1.4.2.2 wrstuden
110 1.4.2.2 wrstuden /*
111 1.4.2.2 wrstuden * Calculate the neighbours for an item in menu. This routine deliberately
112 1.4.2.2 wrstuden * does not refer to up/down/left/right as these concepts depend on the menu
113 1.4.2.2 wrstuden * layout style (row major or not). By arranging the arguments in the right
114 1.4.2.2 wrstuden * order the caller can generate the the neighbours for either menu layout
115 1.4.2.2 wrstuden * style.
116 1.4.2.2 wrstuden */
117 1.4.2.2 wrstuden static void
118 1.4.2.2 wrstuden _menui_calc_neighbours(menu, item_no, cycle, item_rows, item_cols, next, prev,
119 1.4.2.2 wrstuden major_next, major_prev)
120 1.4.2.2 wrstuden MENU *menu;
121 1.4.2.2 wrstuden int item_no;
122 1.4.2.2 wrstuden int cycle;
123 1.4.2.2 wrstuden int item_rows;
124 1.4.2.2 wrstuden int item_cols;
125 1.4.2.2 wrstuden ITEM **next;
126 1.4.2.2 wrstuden ITEM **prev;
127 1.4.2.2 wrstuden ITEM **major_next;
128 1.4.2.2 wrstuden ITEM **major_prev;
129 1.4.2.2 wrstuden {
130 1.4.2.2 wrstuden int neighbour;
131 1.4.2.2 wrstuden
132 1.4.2.2 wrstuden if (item_rows < 2) {
133 1.4.2.2 wrstuden if (cycle) {
134 1.4.2.2 wrstuden *major_next = menu->items[item_no];
135 1.4.2.2 wrstuden *major_prev = menu->items[item_no];
136 1.4.2.2 wrstuden } else {
137 1.4.2.2 wrstuden *major_next = NULL;
138 1.4.2.2 wrstuden *major_prev = NULL;
139 1.4.2.2 wrstuden }
140 1.4.2.2 wrstuden } else {
141 1.4.2.2 wrstuden neighbour = item_no + item_cols;
142 1.4.2.2 wrstuden if (neighbour >= menu->item_count) {
143 1.4.2.2 wrstuden if (cycle) {
144 1.4.2.2 wrstuden if (item_rows == 2) {
145 1.4.2.2 wrstuden neighbour = item_no - item_cols;
146 1.4.2.2 wrstuden if (neighbour < 0)
147 1.4.2.2 wrstuden neighbour = item_no;
148 1.4.2.2 wrstuden *major_next = menu->items[neighbour];
149 1.4.2.2 wrstuden } else {
150 1.4.2.2 wrstuden *major_next =
151 1.4.2.2 wrstuden menu->items[item_no % item_cols];
152 1.4.2.2 wrstuden }
153 1.4.2.2 wrstuden } else
154 1.4.2.2 wrstuden *major_next = NULL;
155 1.4.2.2 wrstuden } else
156 1.4.2.2 wrstuden *major_next = menu->items[neighbour];
157 1.4.2.2 wrstuden
158 1.4.2.2 wrstuden
159 1.4.2.2 wrstuden neighbour = item_no - item_cols;
160 1.4.2.2 wrstuden if (neighbour < 0) {
161 1.4.2.2 wrstuden if (cycle) {
162 1.4.2.2 wrstuden if (item_rows == 2) {
163 1.4.2.2 wrstuden neighbour = item_no + item_cols;
164 1.4.2.2 wrstuden if (neighbour >= menu->item_count)
165 1.4.2.2 wrstuden neighbour = item_no;
166 1.4.2.2 wrstuden *major_prev = menu->items[neighbour];
167 1.4.2.2 wrstuden } else {
168 1.4.2.2 wrstuden neighbour = item_no +
169 1.4.2.2 wrstuden (item_rows - 1) * item_cols;
170 1.4.2.2 wrstuden
171 1.4.2.2 wrstuden if (neighbour >= menu->item_count)
172 1.4.2.2 wrstuden neighbour = item_no +
173 1.4.2.2 wrstuden (item_rows - 2)
174 1.4.2.2 wrstuden * item_cols;
175 1.4.2.2 wrstuden
176 1.4.2.2 wrstuden *major_prev = menu->items[neighbour];
177 1.4.2.2 wrstuden }
178 1.4.2.2 wrstuden } else
179 1.4.2.2 wrstuden *major_prev = NULL;
180 1.4.2.2 wrstuden } else
181 1.4.2.2 wrstuden *major_prev = menu->items[neighbour];
182 1.4.2.2 wrstuden }
183 1.4.2.2 wrstuden
184 1.4.2.2 wrstuden if ((item_no % item_cols) == 0) {
185 1.4.2.2 wrstuden if (cycle) {
186 1.4.2.2 wrstuden if (item_cols < 2) {
187 1.4.2.2 wrstuden *prev = menu->items[item_no];
188 1.4.2.2 wrstuden } else {
189 1.4.2.2 wrstuden neighbour = item_no + item_cols - 1;
190 1.4.2.2 wrstuden if (neighbour >= menu->item_count) {
191 1.4.2.2 wrstuden if (item_cols == 2) {
192 1.4.2.2 wrstuden *prev = menu->items[item_no];
193 1.4.2.2 wrstuden } else {
194 1.4.2.2 wrstuden *prev = menu->items[menu->item_count - 1];
195 1.4.2.2 wrstuden }
196 1.4.2.2 wrstuden } else
197 1.4.2.2 wrstuden *prev = menu->items[neighbour];
198 1.4.2.2 wrstuden }
199 1.4.2.2 wrstuden } else
200 1.4.2.2 wrstuden *prev = NULL;
201 1.4.2.2 wrstuden } else
202 1.4.2.2 wrstuden *prev = menu->items[item_no - 1];
203 1.4.2.2 wrstuden
204 1.4.2.2 wrstuden if ((item_no % item_cols) == (item_cols - 1)) {
205 1.4.2.2 wrstuden if (cycle) {
206 1.4.2.2 wrstuden if (item_cols < 2) {
207 1.4.2.2 wrstuden *next = menu->items[item_no];
208 1.4.2.2 wrstuden } else {
209 1.4.2.2 wrstuden neighbour = item_no - item_cols + 1;
210 1.4.2.2 wrstuden if (neighbour >= menu->item_count) {
211 1.4.2.2 wrstuden if (item_cols == 2) {
212 1.4.2.2 wrstuden *next = menu->items[item_no];
213 1.4.2.2 wrstuden } else {
214 1.4.2.2 wrstuden neighbour = item_cols * item_no / item_cols;
215 1.4.2.2 wrstuden
216 1.4.2.2 wrstuden *next = menu->items[neighbour];
217 1.4.2.2 wrstuden }
218 1.4.2.2 wrstuden } else
219 1.4.2.2 wrstuden *next = menu->items[neighbour];
220 1.4.2.2 wrstuden }
221 1.4.2.2 wrstuden } else
222 1.4.2.2 wrstuden *next = NULL;
223 1.4.2.2 wrstuden } else {
224 1.4.2.2 wrstuden neighbour = item_no + 1;
225 1.4.2.2 wrstuden if (neighbour >= menu->item_count) {
226 1.4.2.2 wrstuden if (cycle) {
227 1.4.2.2 wrstuden neighbour = item_cols * (item_rows - 1);
228 1.4.2.2 wrstuden *next = menu->items[neighbour];
229 1.4.2.2 wrstuden } else
230 1.4.2.2 wrstuden *next = NULL;
231 1.4.2.2 wrstuden } else
232 1.4.2.2 wrstuden *next = menu->items[neighbour];
233 1.4.2.2 wrstuden }
234 1.4.2.2 wrstuden }
235 1.4.2.2 wrstuden
236 1.4.2.2 wrstuden /*
237 1.4.2.2 wrstuden * Goto the item pointed to by item and adjust the menu structure
238 1.4.2.2 wrstuden * accordingly. Call the term and init functions if required.
239 1.4.2.2 wrstuden */
240 1.4.2.2 wrstuden int
241 1.4.2.2 wrstuden _menui_goto_item(menu, item, new_top_row)
242 1.4.2.2 wrstuden MENU *menu;
243 1.4.2.2 wrstuden ITEM *item;
244 1.4.2.2 wrstuden int new_top_row;
245 1.4.2.2 wrstuden {
246 1.4.2.2 wrstuden int old_top_row = menu->top_row, old_cur_item = menu->cur_item;
247 1.4.2.2 wrstuden
248 1.4.2.2 wrstuden /* If we get a null then the menu is not cyclic so deny request */
249 1.4.2.2 wrstuden if (item == NULL)
250 1.4.2.2 wrstuden return E_REQUEST_DENIED;
251 1.4.2.2 wrstuden
252 1.4.2.2 wrstuden menu->in_init = 1;
253 1.4.2.2 wrstuden if (menu->top_row != new_top_row) {
254 1.4.2.2 wrstuden if ((menu->posted == 1) && (menu->menu_term != NULL))
255 1.4.2.2 wrstuden menu->menu_term(menu);
256 1.4.2.2 wrstuden menu->top_row = new_top_row;
257 1.4.2.2 wrstuden
258 1.4.2.2 wrstuden if ((menu->posted == 1) && (menu->menu_init != NULL))
259 1.4.2.2 wrstuden menu->menu_init(menu);
260 1.4.2.2 wrstuden }
261 1.4.2.2 wrstuden
262 1.4.2.2 wrstuden /* this looks like wasted effort but it can happen.... */
263 1.4.2.2 wrstuden if (menu->cur_item != item->index) {
264 1.4.2.2 wrstuden
265 1.4.2.2 wrstuden if ((menu->posted == 1) && (menu->item_term != NULL))
266 1.4.2.2 wrstuden menu->item_term(menu);
267 1.4.2.2 wrstuden
268 1.4.2.2 wrstuden menu->cur_item = item->index;
269 1.4.2.2 wrstuden menu->cur_row = item->row;
270 1.4.2.2 wrstuden menu->cur_col = item->col;
271 1.4.2.2 wrstuden
272 1.4.2.2 wrstuden if (menu->posted == 1)
273 1.4.2.2 wrstuden _menui_redraw_menu(menu, old_top_row, old_cur_item);
274 1.4.2.2 wrstuden
275 1.4.2.2 wrstuden if ((menu->posted == 1) && (menu->item_init != NULL))
276 1.4.2.2 wrstuden menu->item_init(menu);
277 1.4.2.2 wrstuden
278 1.4.2.2 wrstuden }
279 1.4.2.2 wrstuden
280 1.4.2.2 wrstuden menu->in_init = 0;
281 1.4.2.2 wrstuden return E_OK;
282 1.4.2.2 wrstuden }
283 1.4.2.2 wrstuden
284 1.4.2.2 wrstuden /*
285 1.4.2.2 wrstuden * Attempt to match items with the pattern buffer in the direction given
286 1.4.2.2 wrstuden * by iterating over the menu items. If a match is found return E_OK
287 1.4.2.2 wrstuden * otherwise return E_NO_MATCH
288 1.4.2.2 wrstuden */
289 1.4.2.2 wrstuden int
290 1.4.2.2 wrstuden _menui_match_items(menu, direction, item_matched)
291 1.4.2.2 wrstuden MENU *menu;
292 1.4.2.2 wrstuden int direction;
293 1.4.2.2 wrstuden int *item_matched;
294 1.4.2.2 wrstuden {
295 1.4.2.2 wrstuden int i, caseless;
296 1.4.2.2 wrstuden
297 1.4.2.2 wrstuden caseless = ((menu->opts & O_IGNORECASE) == O_IGNORECASE);
298 1.4.2.2 wrstuden
299 1.4.2.2 wrstuden i = menu->cur_item;
300 1.4.2.2 wrstuden if (direction == MATCH_NEXT_FORWARD) {
301 1.4.2.2 wrstuden if (++i >= menu->item_count) i = 0;
302 1.4.2.2 wrstuden } else if (direction == MATCH_NEXT_REVERSE) {
303 1.4.2.2 wrstuden if (--i < 0) i = menu->item_count - 1;
304 1.4.2.2 wrstuden }
305 1.4.2.2 wrstuden
306 1.4.2.2 wrstuden
307 1.4.2.2 wrstuden do {
308 1.4.2.2 wrstuden if (menu->items[i]->name.length >= menu->plen) {
309 1.4.2.2 wrstuden /* no chance if pattern is longer */
310 1.4.2.2 wrstuden if (caseless) {
311 1.4.2.2 wrstuden if (strncasecmp(menu->items[i]->name.string,
312 1.4.2.2 wrstuden menu->pattern,
313 1.4.2.2 wrstuden (size_t) menu->plen) == 0) {
314 1.4.2.2 wrstuden *item_matched = i;
315 1.4.2.2 wrstuden menu->match_len = menu->plen;
316 1.4.2.2 wrstuden return E_OK;
317 1.4.2.2 wrstuden }
318 1.4.2.2 wrstuden } else {
319 1.4.2.2 wrstuden if (strncmp(menu->items[i]->name.string,
320 1.4.2.2 wrstuden menu->pattern,
321 1.4.2.2 wrstuden (size_t) menu->plen) == 0) {
322 1.4.2.2 wrstuden *item_matched = i;
323 1.4.2.2 wrstuden menu->match_len = menu->plen;
324 1.4.2.2 wrstuden return E_OK;
325 1.4.2.2 wrstuden }
326 1.4.2.2 wrstuden }
327 1.4.2.2 wrstuden }
328 1.4.2.2 wrstuden
329 1.4.2.2 wrstuden if ((direction == MATCH_FORWARD) ||
330 1.4.2.2 wrstuden (direction == MATCH_NEXT_FORWARD)) {
331 1.4.2.2 wrstuden if (++i >= menu->item_count) i = 0;
332 1.4.2.2 wrstuden } else {
333 1.4.2.2 wrstuden if (--i <= 0) i = menu->item_count - 1;
334 1.4.2.2 wrstuden }
335 1.4.2.2 wrstuden } while (i != menu->cur_item);
336 1.4.2.2 wrstuden
337 1.4.2.2 wrstuden menu->match_len = 0; /* match did not succeed - kill the match len. */
338 1.4.2.2 wrstuden return E_NO_MATCH;
339 1.4.2.2 wrstuden }
340 1.4.2.2 wrstuden
341 1.4.2.2 wrstuden /*
342 1.4.2.2 wrstuden * Attempt to match the pattern buffer against the items. If c is a
343 1.4.2.2 wrstuden * printable character then add it to the pattern buffer prior to
344 1.4.2.2 wrstuden * performing the match. Direction determines the direction of matching.
345 1.4.2.2 wrstuden * If the match is successful update the item_matched variable with the
346 1.4.2.2 wrstuden * index of the item that matched the pattern.
347 1.4.2.2 wrstuden */
348 1.4.2.2 wrstuden int
349 1.4.2.2 wrstuden _menui_match_pattern(menu, c, direction, item_matched)
350 1.4.2.2 wrstuden MENU *menu;
351 1.4.2.2 wrstuden char c;
352 1.4.2.2 wrstuden int direction;
353 1.4.2.2 wrstuden int *item_matched;
354 1.4.2.2 wrstuden {
355 1.4.2.2 wrstuden if (menu == NULL)
356 1.4.2.2 wrstuden return E_BAD_ARGUMENT;
357 1.4.2.2 wrstuden if (menu->items == NULL)
358 1.4.2.2 wrstuden return E_BAD_ARGUMENT;
359 1.4.2.2 wrstuden if (*menu->items == NULL)
360 1.4.2.2 wrstuden return E_BAD_ARGUMENT;
361 1.4.2.2 wrstuden
362 1.4.2.2 wrstuden if (isprint(c)) {
363 1.4.2.2 wrstuden /* add char to buffer - first allocate room for it */
364 1.4.2.2 wrstuden if ((menu->pattern = (char *)
365 1.4.2.2 wrstuden realloc(menu->pattern,
366 1.4.2.2 wrstuden menu->plen + sizeof(char) +
367 1.4.2.2 wrstuden ((menu->plen > 0)? 0 : 1)))
368 1.4.2.2 wrstuden == NULL)
369 1.4.2.2 wrstuden return E_SYSTEM_ERROR;
370 1.4.2.2 wrstuden menu->pattern[menu->plen] = c;
371 1.4.2.2 wrstuden menu->pattern[++menu->plen] = '\0';
372 1.4.2.2 wrstuden
373 1.4.2.2 wrstuden /* there is no chance of a match if pattern is longer
374 1.4.2.2 wrstuden than all the items */
375 1.4.2.2 wrstuden if (menu->plen >= menu->max_item_width) {
376 1.4.2.2 wrstuden menu->pattern[--menu->plen] = '\0';
377 1.4.2.2 wrstuden return E_NO_MATCH;
378 1.4.2.2 wrstuden }
379 1.4.2.2 wrstuden
380 1.4.2.2 wrstuden if (_menui_match_items(menu, direction,
381 1.4.2.2 wrstuden item_matched) == E_NO_MATCH) {
382 1.4.2.2 wrstuden menu->pattern[--menu->plen] = '\0';
383 1.4.2.2 wrstuden return E_NO_MATCH;
384 1.4.2.2 wrstuden } else
385 1.4.2.2 wrstuden return E_OK;
386 1.4.2.2 wrstuden } else {
387 1.4.2.2 wrstuden if (_menui_match_items(menu, direction,
388 1.4.2.2 wrstuden item_matched) == E_OK) {
389 1.4.2.2 wrstuden return E_OK;
390 1.4.2.2 wrstuden } else {
391 1.4.2.2 wrstuden return E_NO_MATCH;
392 1.4.2.2 wrstuden }
393 1.4.2.2 wrstuden }
394 1.4.2.2 wrstuden }
395 1.4.2.2 wrstuden
396 1.4.2.2 wrstuden /*
397 1.4.2.2 wrstuden * Draw an item in the subwindow complete with appropriate highlighting.
398 1.4.2.2 wrstuden */
399 1.4.2.2 wrstuden void
400 1.4.2.2 wrstuden _menui_draw_item(menu, item)
401 1.4.2.2 wrstuden MENU *menu;
402 1.4.2.2 wrstuden int item;
403 1.4.2.2 wrstuden {
404 1.4.2.2 wrstuden int j, pad_len, mark_len;
405 1.4.2.2 wrstuden
406 1.4.2.2 wrstuden mark_len = max(menu->mark.length, menu->unmark.length);
407 1.4.2.2 wrstuden
408 1.4.2.2 wrstuden wmove(menu->menu_subwin,
409 1.4.2.2 wrstuden menu->items[item]->row - menu->top_row,
410 1.4.2.2 wrstuden menu->items[item]->col * (menu->col_width + 1));
411 1.4.2.2 wrstuden
412 1.4.2.2 wrstuden if ((menu->cur_item == item) || (menu->items[item]->selected == 1))
413 1.4.2.2 wrstuden wattron(menu->menu_subwin, menu->fore);
414 1.4.2.2 wrstuden if ((menu->items[item]->opts & O_SELECTABLE) != O_SELECTABLE)
415 1.4.2.2 wrstuden wattron(menu->menu_subwin, menu->grey);
416 1.4.2.2 wrstuden
417 1.4.2.2 wrstuden /* deal with the menu mark, if one is set.
418 1.4.2.2 wrstuden * We mark the selected items and write blanks for
419 1.4.2.2 wrstuden * all others unless the menu unmark string is set in which
420 1.4.2.2 wrstuden * case the unmark string is written.
421 1.4.2.2 wrstuden */
422 1.4.2.2 wrstuden if (menu->items[item]->selected == 1) {
423 1.4.2.2 wrstuden if (menu->mark.string != NULL) {
424 1.4.2.2 wrstuden for (j = 0; j < menu->mark.length; j++) {
425 1.4.2.2 wrstuden waddch(menu->menu_subwin,
426 1.4.2.2 wrstuden menu->mark.string[j]);
427 1.4.2.2 wrstuden }
428 1.4.2.2 wrstuden }
429 1.4.2.2 wrstuden /* blank any length difference between mark & unmark */
430 1.4.2.2 wrstuden for (j = menu->mark.length; j < mark_len; j++)
431 1.4.2.2 wrstuden waddch(menu->menu_subwin, ' ');
432 1.4.2.2 wrstuden } else {
433 1.4.2.2 wrstuden if (menu->unmark.string != NULL) {
434 1.4.2.2 wrstuden for (j = 0; j < menu->unmark.length; j++) {
435 1.4.2.2 wrstuden waddch(menu->menu_subwin,
436 1.4.2.2 wrstuden menu->unmark.string[j]);
437 1.4.2.2 wrstuden }
438 1.4.2.2 wrstuden }
439 1.4.2.2 wrstuden /* blank any length difference between mark & unmark */
440 1.4.2.2 wrstuden for (j = menu->unmark.length; j < mark_len; j++)
441 1.4.2.2 wrstuden waddch(menu->menu_subwin, ' ');
442 1.4.2.2 wrstuden }
443 1.4.2.2 wrstuden
444 1.4.2.2 wrstuden /* add the menu name */
445 1.4.2.2 wrstuden for (j=0; j < menu->items[item]->name.length; j++)
446 1.4.2.2 wrstuden waddch(menu->menu_subwin,
447 1.4.2.2 wrstuden menu->items[item]->name.string[j]);
448 1.4.2.2 wrstuden
449 1.4.2.2 wrstuden pad_len = menu->col_width - menu->items[item]->name.length
450 1.4.2.2 wrstuden - mark_len - 1;
451 1.4.2.2 wrstuden if ((menu->opts & O_SHOWDESC) == O_SHOWDESC) {
452 1.4.2.2 wrstuden pad_len -= menu->items[item]->description.length - 1;
453 1.4.2.2 wrstuden for (j = 0; j < pad_len; j++)
454 1.4.2.2 wrstuden waddch(menu->menu_subwin, menu->pad);
455 1.4.2.2 wrstuden for (j = 0; j < menu->items[item]->description.length; j++) {
456 1.4.2.2 wrstuden waddch(menu->menu_subwin,
457 1.4.2.2 wrstuden menu->items[item]->description.string[j]);
458 1.4.2.2 wrstuden }
459 1.4.2.2 wrstuden } else {
460 1.4.2.2 wrstuden for (j = 0; j < pad_len; j++)
461 1.4.2.2 wrstuden waddch(menu->menu_subwin, ' ');
462 1.4.2.2 wrstuden }
463 1.4.2.2 wrstuden menu->items[item]->visible = 1;
464 1.4.2.2 wrstuden /* kill any special attributes... */
465 1.4.2.2 wrstuden wattrset(menu->menu_subwin, menu->back);
466 1.4.2.2 wrstuden
467 1.4.2.2 wrstuden /* and position the cursor nicely */
468 1.4.2.2 wrstuden pos_menu_cursor(menu);
469 1.4.2.2 wrstuden }
470 1.4.2.2 wrstuden
471 1.4.2.2 wrstuden /*
472 1.4.2.2 wrstuden * Draw the menu in the subwindow provided.
473 1.4.2.2 wrstuden */
474 1.4.2.2 wrstuden int
475 1.4.2.2 wrstuden _menui_draw_menu(menu)
476 1.4.2.2 wrstuden MENU *menu;
477 1.4.2.2 wrstuden {
478 1.4.2.2 wrstuden int rowmajor, i, j, max_items, last_item, row = -1, col = -1;
479 1.4.2.2 wrstuden
480 1.4.2.2 wrstuden rowmajor = ((menu->opts & O_ROWMAJOR) == O_ROWMAJOR);
481 1.4.2.2 wrstuden
482 1.4.2.2 wrstuden for (i = 0; i < menu->item_count; i++) {
483 1.4.2.2 wrstuden if (menu->items[i]->row == menu->top_row)
484 1.4.2.2 wrstuden break;
485 1.4.2.2 wrstuden menu->items[i]->visible = 0;
486 1.4.2.2 wrstuden }
487 1.4.2.2 wrstuden
488 1.4.2.2 wrstuden wmove(menu->menu_subwin, 0, 0);
489 1.4.2.2 wrstuden
490 1.4.2.2 wrstuden menu->col_width = getmaxx(menu->menu_subwin) / menu->cols;
491 1.4.2.2 wrstuden
492 1.4.2.2 wrstuden /*if ((menu->opts & O_SHOWDESC) == O_SHOWDESC)
493 1.4.2.2 wrstuden menu->col_width++;*/
494 1.4.2.2 wrstuden
495 1.4.2.2 wrstuden max_items = menu->rows * menu->cols;
496 1.4.2.2 wrstuden last_item = ((max_items + i) > menu->item_count) ? menu->item_count :
497 1.4.2.2 wrstuden (max_items + i);
498 1.4.2.2 wrstuden
499 1.4.2.2 wrstuden for (; i < last_item; i++) {
500 1.4.2.2 wrstuden if (i > menu->item_count) {
501 1.4.2.2 wrstuden /* no more items to draw, write background blanks */
502 1.4.2.2 wrstuden wattron(menu->menu_subwin, menu->back);
503 1.4.2.2 wrstuden if (row < 0) {
504 1.4.2.2 wrstuden row = menu->items[menu->item_count - 1]->row;
505 1.4.2.2 wrstuden col = menu->items[menu->item_count - 1]->col;
506 1.4.2.2 wrstuden }
507 1.4.2.2 wrstuden
508 1.4.2.2 wrstuden if (rowmajor) {
509 1.4.2.2 wrstuden col++;
510 1.4.2.2 wrstuden if (col > menu->cols) {
511 1.4.2.2 wrstuden col = 0;
512 1.4.2.2 wrstuden row++;
513 1.4.2.2 wrstuden }
514 1.4.2.2 wrstuden } else {
515 1.4.2.2 wrstuden row++;
516 1.4.2.2 wrstuden if (row > menu->rows) {
517 1.4.2.2 wrstuden row = 0;
518 1.4.2.2 wrstuden col++;
519 1.4.2.2 wrstuden }
520 1.4.2.2 wrstuden }
521 1.4.2.2 wrstuden wmove(menu->menu_subwin, row,
522 1.4.2.2 wrstuden col * (menu->col_width + 1));
523 1.4.2.2 wrstuden for (j = 0; j < menu->col_width; j++)
524 1.4.2.2 wrstuden waddch(menu->menu_subwin, ' ');
525 1.4.2.2 wrstuden } else {
526 1.4.2.2 wrstuden _menui_draw_item(menu, i);
527 1.4.2.2 wrstuden
528 1.4.2.2 wrstuden }
529 1.4.2.2 wrstuden
530 1.4.2.2 wrstuden }
531 1.4.2.2 wrstuden
532 1.4.2.2 wrstuden if (last_item < menu->item_count) {
533 1.4.2.2 wrstuden for (j = last_item; j < menu->item_count; j++)
534 1.4.2.2 wrstuden menu->items[j]->visible = 0;
535 1.4.2.2 wrstuden }
536 1.4.2.2 wrstuden
537 1.4.2.2 wrstuden return E_OK;
538 1.4.2.2 wrstuden }
539 1.4.2.2 wrstuden
540 1.4.2.2 wrstuden
541 1.4.2.2 wrstuden /*
542 1.4.2.2 wrstuden * Calculate the widest menu item and stash it in the menu struct.
543 1.4.2.2 wrstuden *
544 1.4.2.2 wrstuden */
545 1.4.2.2 wrstuden void
546 1.4.2.2 wrstuden _menui_max_item_size(menu)
547 1.4.2.2 wrstuden MENU *menu;
548 1.4.2.2 wrstuden {
549 1.4.2.2 wrstuden int i, with_desc, width;
550 1.4.2.2 wrstuden
551 1.4.2.2 wrstuden with_desc = ((menu->opts & O_SHOWDESC) == O_SHOWDESC);
552 1.4.2.2 wrstuden
553 1.4.2.2 wrstuden for (i = 0; i < menu->item_count; i++) {
554 1.4.2.2 wrstuden width = menu->items[i]->name.length
555 1.4.2.2 wrstuden + max(menu->mark.length, menu->unmark.length);
556 1.4.2.2 wrstuden if (with_desc)
557 1.4.2.2 wrstuden width += menu->items[i]->description.length + 1;
558 1.4.2.2 wrstuden
559 1.4.2.2 wrstuden menu->max_item_width = max(menu->max_item_width, width);
560 1.4.2.2 wrstuden }
561 1.4.2.2 wrstuden }
562 1.4.2.2 wrstuden
563 1.4.2.2 wrstuden
564 1.4.2.2 wrstuden /*
565 1.4.2.2 wrstuden * Redraw the menu on the screen. If the current item has changed then
566 1.4.2.2 wrstuden * unhighlight the old item and highlight the new one.
567 1.4.2.2 wrstuden */
568 1.4.2.2 wrstuden static void
569 1.4.2.2 wrstuden _menui_redraw_menu(menu, old_top_row, old_cur_item)
570 1.4.2.2 wrstuden MENU *menu;
571 1.4.2.2 wrstuden int old_top_row;
572 1.4.2.2 wrstuden int old_cur_item;
573 1.4.2.2 wrstuden {
574 1.4.2.2 wrstuden
575 1.4.2.2 wrstuden if (menu->top_row != old_top_row) {
576 1.4.2.2 wrstuden /* top row changed - redo the whole menu
577 1.4.2.2 wrstuden * XXXX this could be improved if we had wscrl implemented.
578 1.4.2.2 wrstuden
579 1.4.2.2 wrstuden * XXXX we could scroll the window and just fill in the
580 1.4.2.2 wrstuden * XXXX changed lines.
581 1.4.2.2 wrstuden */
582 1.4.2.2 wrstuden wclear(menu->menu_subwin);
583 1.4.2.2 wrstuden _menui_draw_menu(menu);
584 1.4.2.2 wrstuden } else {
585 1.4.2.2 wrstuden if (menu->cur_item != old_cur_item) {
586 1.4.2.2 wrstuden /* redo the old item as a normal one. */
587 1.4.2.2 wrstuden _menui_draw_item(menu, old_cur_item);
588 1.4.2.2 wrstuden }
589 1.4.2.2 wrstuden /* and then redraw the current item */
590 1.4.2.2 wrstuden _menui_draw_item(menu, menu->cur_item);
591 1.4.2.2 wrstuden }
592 1.4.2.2 wrstuden }
593