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