internals.c revision 1.17 1 1.17 christos /* $NetBSD: internals.c,v 1.17 2013/10/18 19:53:59 christos 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.8 wiz * derived from this software without 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.12 lukem
29 1.12 lukem #include <sys/cdefs.h>
30 1.17 christos __RCSID("$NetBSD: internals.c,v 1.17 2013/10/18 19:53:59 christos Exp $");
31 1.1 blymn
32 1.1 blymn #include <menu.h>
33 1.1 blymn #include <ctype.h>
34 1.1 blymn #include <stdlib.h>
35 1.1 blymn #include <string.h>
36 1.1 blymn #include "internals.h"
37 1.1 blymn
38 1.1 blymn /* internal function prototypes */
39 1.1 blymn static void
40 1.15 blymn _menui_calc_neighbours(MENU *menu, int item_no);
41 1.6 blymn static void _menui_redraw_menu(MENU *menu, int old_top_row, int old_cur_item);
42 1.1 blymn
43 1.1 blymn /*
44 1.1 blymn * Link all the menu items together to speed up navigation. We need
45 1.1 blymn * to calculate the widest item entry, then work out how many columns
46 1.13 christos * of items the window will accommodate and then how many rows there will
47 1.1 blymn * be. Once the layout is determined the neighbours of each item is
48 1.1 blymn * calculated and the item structures updated.
49 1.1 blymn */
50 1.1 blymn int
51 1.6 blymn _menui_stitch_items(MENU *menu)
52 1.1 blymn {
53 1.15 blymn int i, row_major;
54 1.1 blymn
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.15 blymn menu->item_rows = menu->item_count / menu->cols;
63 1.15 blymn menu->item_cols = menu->cols;
64 1.15 blymn if (menu->item_count > (menu->item_rows * menu->item_cols))
65 1.15 blymn menu->item_rows += 1;
66 1.1 blymn
67 1.3 blymn _menui_max_item_size(menu);
68 1.1 blymn
69 1.1 blymn for (i = 0; i < menu->item_count; i++) {
70 1.1 blymn /* fill in the row and column value of the item */
71 1.1 blymn if (row_major) {
72 1.1 blymn menu->items[i]->row = i / menu->item_cols;
73 1.1 blymn menu->items[i]->col = i % menu->item_cols;
74 1.1 blymn } else {
75 1.1 blymn menu->items[i]->row = i % menu->item_rows;
76 1.1 blymn menu->items[i]->col = i / menu->item_rows;
77 1.1 blymn }
78 1.15 blymn
79 1.15 blymn _menui_calc_neighbours(menu, i);
80 1.1 blymn }
81 1.14 blymn
82 1.1 blymn return E_OK;
83 1.1 blymn }
84 1.1 blymn
85 1.1 blymn /*
86 1.15 blymn * Calculate the neighbours for an item in menu.
87 1.1 blymn */
88 1.1 blymn static void
89 1.15 blymn _menui_calc_neighbours(MENU *menu, int item_no)
90 1.1 blymn {
91 1.15 blymn int neighbour, cycle, row_major, edge;
92 1.15 blymn ITEM *item;
93 1.15 blymn
94 1.15 blymn row_major = ((menu->opts & O_ROWMAJOR) == O_ROWMAJOR);
95 1.15 blymn cycle = ((menu->opts & O_NONCYCLIC) != O_NONCYCLIC);
96 1.15 blymn item = menu->items[item_no];
97 1.1 blymn
98 1.15 blymn if (menu->item_rows < 2) {
99 1.1 blymn if (cycle) {
100 1.15 blymn item->up = item;
101 1.15 blymn item->down = item;
102 1.1 blymn } else {
103 1.15 blymn item->up = NULL;
104 1.15 blymn item->down = NULL;
105 1.1 blymn }
106 1.1 blymn } else {
107 1.15 blymn
108 1.15 blymn /* up */
109 1.15 blymn if (menu->item_cols < 2) {
110 1.15 blymn if (item_no == 0) {
111 1.15 blymn if (cycle)
112 1.15 blymn item->up =
113 1.15 blymn menu->items[menu->item_count - 1];
114 1.15 blymn else
115 1.15 blymn item->up = NULL;
116 1.1 blymn } else
117 1.15 blymn item->up = menu->items[item_no - 1];
118 1.15 blymn } else {
119 1.15 blymn edge = 0;
120 1.15 blymn if (row_major) {
121 1.15 blymn if (item->row == 0) {
122 1.15 blymn neighbour =
123 1.15 blymn (menu->item_rows - 1) * menu->item_cols
124 1.15 blymn + item->col;
125 1.15 blymn if (neighbour >= menu->item_count)
126 1.15 blymn neighbour -= menu->item_cols;
127 1.15 blymn edge = 1;
128 1.15 blymn } else
129 1.15 blymn neighbour = item_no - menu->item_cols;
130 1.15 blymn } else {
131 1.15 blymn if (item->row == 0) {
132 1.15 blymn neighbour = menu->item_rows * item->col
133 1.15 blymn + menu->item_rows - 1;
134 1.15 blymn if (neighbour >= menu->item_count)
135 1.15 blymn neighbour = menu->item_count - 1;
136 1.15 blymn edge = 1;
137 1.15 blymn } else
138 1.15 blymn neighbour = item_no - 1;
139 1.15 blymn }
140 1.15 blymn
141 1.14 blymn
142 1.15 blymn item->up = menu->items[neighbour];
143 1.15 blymn if ((!cycle) && (edge == 1))
144 1.15 blymn item->up = NULL;
145 1.15 blymn }
146 1.14 blymn
147 1.15 blymn /* Down */
148 1.15 blymn if (menu->item_cols < 2) {
149 1.15 blymn if (item_no == (menu->item_count - 1)) {
150 1.15 blymn if (cycle)
151 1.15 blymn item->down = menu->items[0];
152 1.15 blymn else
153 1.15 blymn item->down = NULL;
154 1.15 blymn } else
155 1.15 blymn item->down = menu->items[item_no + 1];
156 1.15 blymn } else {
157 1.15 blymn edge = 0;
158 1.15 blymn if (row_major) {
159 1.15 blymn if (item->row == menu->item_rows - 1) {
160 1.15 blymn neighbour = item->col;
161 1.15 blymn edge = 1;
162 1.15 blymn } else {
163 1.15 blymn neighbour = item_no + menu->item_cols;
164 1.15 blymn if (neighbour >= menu->item_count) {
165 1.15 blymn neighbour = item->col;
166 1.15 blymn edge = 1;
167 1.15 blymn }
168 1.15 blymn }
169 1.15 blymn } else {
170 1.15 blymn if (item->row == menu->item_rows - 1) {
171 1.15 blymn neighbour = item->col * menu->item_rows;
172 1.15 blymn edge = 1;
173 1.1 blymn } else {
174 1.15 blymn neighbour = item_no + 1;
175 1.15 blymn if (neighbour >= menu->item_count) {
176 1.15 blymn neighbour = item->col
177 1.15 blymn * menu->item_rows;
178 1.15 blymn edge = 1;
179 1.15 blymn }
180 1.15 blymn }
181 1.15 blymn }
182 1.1 blymn
183 1.15 blymn item->down = menu->items[neighbour];
184 1.15 blymn if ((!cycle) && (edge == 1))
185 1.15 blymn item->down = NULL;
186 1.15 blymn }
187 1.1 blymn }
188 1.14 blymn
189 1.15 blymn if (menu->item_cols < 2) {
190 1.1 blymn if (cycle) {
191 1.15 blymn item->left = item;
192 1.15 blymn item->right = item;
193 1.15 blymn } else {
194 1.15 blymn item->left = NULL;
195 1.15 blymn item->right = NULL;
196 1.15 blymn }
197 1.15 blymn } else {
198 1.15 blymn /* left */
199 1.15 blymn if (menu->item_rows < 2) {
200 1.15 blymn if (item_no == 0) {
201 1.15 blymn if (cycle)
202 1.15 blymn item->left =
203 1.15 blymn menu->items[menu->item_count - 1];
204 1.15 blymn else
205 1.15 blymn item->left = NULL;
206 1.15 blymn } else
207 1.15 blymn item->left = menu->items[item_no - 1];
208 1.15 blymn } else {
209 1.15 blymn edge = 0;
210 1.15 blymn if (row_major) {
211 1.15 blymn if (item->col == 0) {
212 1.15 blymn neighbour = item_no + menu->cols - 1;
213 1.15 blymn if (neighbour >= menu->item_count)
214 1.15 blymn neighbour = menu->item_count - 1;
215 1.15 blymn edge = 1;
216 1.15 blymn } else
217 1.15 blymn neighbour = item_no - 1;
218 1.1 blymn } else {
219 1.15 blymn if (item->col == 0) {
220 1.15 blymn neighbour = menu->item_rows
221 1.15 blymn * (menu->item_cols - 1) + item->row;
222 1.15 blymn if (neighbour >= menu->item_count)
223 1.15 blymn neighbour -= menu->item_rows;
224 1.15 blymn edge = 1;
225 1.1 blymn } else
226 1.15 blymn neighbour = item_no - menu->item_rows;
227 1.1 blymn }
228 1.14 blymn
229 1.15 blymn item->left = menu->items[neighbour];
230 1.15 blymn if ((!cycle) && (edge == 1))
231 1.15 blymn item->left = NULL;
232 1.15 blymn }
233 1.15 blymn
234 1.15 blymn /* right */
235 1.15 blymn if (menu->item_rows < 2) {
236 1.15 blymn if (item_no == menu->item_count - 1) {
237 1.15 blymn if (cycle)
238 1.15 blymn item->right = menu->items[0];
239 1.15 blymn else
240 1.15 blymn item->right = NULL;
241 1.15 blymn } else
242 1.15 blymn item->right = menu->items[item_no + 1];
243 1.15 blymn } else {
244 1.15 blymn edge = 0;
245 1.15 blymn if (row_major) {
246 1.15 blymn if (item->col == menu->item_cols - 1) {
247 1.15 blymn neighbour = item_no - menu->item_cols
248 1.15 blymn + 1;
249 1.15 blymn edge = 1;
250 1.15 blymn } else if (item_no == menu->item_count - 1) {
251 1.15 blymn neighbour = item->row * menu->item_cols;
252 1.15 blymn edge = 1;
253 1.15 blymn } else
254 1.15 blymn neighbour = item_no + 1;
255 1.1 blymn } else {
256 1.15 blymn if (item->col == menu->item_cols - 1) {
257 1.15 blymn neighbour = item->row;
258 1.15 blymn edge = 1;
259 1.15 blymn } else {
260 1.15 blymn neighbour = item_no + menu->item_rows;
261 1.15 blymn if (neighbour >= menu->item_count) {
262 1.15 blymn neighbour = item->row;
263 1.15 blymn edge = 1;
264 1.1 blymn }
265 1.15 blymn }
266 1.1 blymn }
267 1.15 blymn
268 1.15 blymn item->right = menu->items[neighbour];
269 1.15 blymn if ((!cycle) && (edge == 1))
270 1.15 blymn item->right = NULL;
271 1.15 blymn }
272 1.1 blymn }
273 1.1 blymn }
274 1.1 blymn
275 1.1 blymn /*
276 1.1 blymn * Goto the item pointed to by item and adjust the menu structure
277 1.1 blymn * accordingly. Call the term and init functions if required.
278 1.1 blymn */
279 1.1 blymn int
280 1.6 blymn _menui_goto_item(MENU *menu, ITEM *item, int new_top_row)
281 1.1 blymn {
282 1.1 blymn int old_top_row = menu->top_row, old_cur_item = menu->cur_item;
283 1.14 blymn
284 1.1 blymn /* If we get a null then the menu is not cyclic so deny request */
285 1.1 blymn if (item == NULL)
286 1.1 blymn return E_REQUEST_DENIED;
287 1.1 blymn
288 1.1 blymn menu->in_init = 1;
289 1.3 blymn if (menu->top_row != new_top_row) {
290 1.1 blymn if ((menu->posted == 1) && (menu->menu_term != NULL))
291 1.1 blymn menu->menu_term(menu);
292 1.3 blymn menu->top_row = new_top_row;
293 1.1 blymn
294 1.1 blymn if ((menu->posted == 1) && (menu->menu_init != NULL))
295 1.1 blymn menu->menu_init(menu);
296 1.1 blymn }
297 1.14 blymn
298 1.1 blymn /* this looks like wasted effort but it can happen.... */
299 1.1 blymn if (menu->cur_item != item->index) {
300 1.1 blymn
301 1.1 blymn if ((menu->posted == 1) && (menu->item_term != NULL))
302 1.1 blymn menu->item_term(menu);
303 1.1 blymn
304 1.1 blymn menu->cur_item = item->index;
305 1.1 blymn menu->cur_row = item->row;
306 1.1 blymn menu->cur_col = item->col;
307 1.1 blymn
308 1.1 blymn if (menu->posted == 1)
309 1.3 blymn _menui_redraw_menu(menu, old_top_row, old_cur_item);
310 1.14 blymn
311 1.1 blymn if ((menu->posted == 1) && (menu->item_init != NULL))
312 1.1 blymn menu->item_init(menu);
313 1.14 blymn
314 1.1 blymn }
315 1.1 blymn
316 1.1 blymn menu->in_init = 0;
317 1.1 blymn return E_OK;
318 1.1 blymn }
319 1.1 blymn
320 1.1 blymn /*
321 1.1 blymn * Attempt to match items with the pattern buffer in the direction given
322 1.1 blymn * by iterating over the menu items. If a match is found return E_OK
323 1.1 blymn * otherwise return E_NO_MATCH
324 1.1 blymn */
325 1.1 blymn int
326 1.6 blymn _menui_match_items(MENU *menu, int direction, int *item_matched)
327 1.1 blymn {
328 1.1 blymn int i, caseless;
329 1.1 blymn
330 1.1 blymn caseless = ((menu->opts & O_IGNORECASE) == O_IGNORECASE);
331 1.14 blymn
332 1.1 blymn i = menu->cur_item;
333 1.1 blymn if (direction == MATCH_NEXT_FORWARD) {
334 1.1 blymn if (++i >= menu->item_count) i = 0;
335 1.1 blymn } else if (direction == MATCH_NEXT_REVERSE) {
336 1.1 blymn if (--i < 0) i = menu->item_count - 1;
337 1.1 blymn }
338 1.1 blymn
339 1.14 blymn
340 1.1 blymn do {
341 1.1 blymn if (menu->items[i]->name.length >= menu->plen) {
342 1.1 blymn /* no chance if pattern is longer */
343 1.1 blymn if (caseless) {
344 1.1 blymn if (strncasecmp(menu->items[i]->name.string,
345 1.1 blymn menu->pattern,
346 1.3 blymn (size_t) menu->plen) == 0) {
347 1.1 blymn *item_matched = i;
348 1.1 blymn menu->match_len = menu->plen;
349 1.1 blymn return E_OK;
350 1.1 blymn }
351 1.1 blymn } else {
352 1.1 blymn if (strncmp(menu->items[i]->name.string,
353 1.3 blymn menu->pattern,
354 1.3 blymn (size_t) menu->plen) == 0) {
355 1.1 blymn *item_matched = i;
356 1.1 blymn menu->match_len = menu->plen;
357 1.1 blymn return E_OK;
358 1.1 blymn }
359 1.1 blymn }
360 1.1 blymn }
361 1.14 blymn
362 1.1 blymn if ((direction == MATCH_FORWARD) ||
363 1.1 blymn (direction == MATCH_NEXT_FORWARD)) {
364 1.1 blymn if (++i >= menu->item_count) i = 0;
365 1.1 blymn } else {
366 1.1 blymn if (--i <= 0) i = menu->item_count - 1;
367 1.1 blymn }
368 1.1 blymn } while (i != menu->cur_item);
369 1.1 blymn
370 1.1 blymn menu->match_len = 0; /* match did not succeed - kill the match len. */
371 1.1 blymn return E_NO_MATCH;
372 1.1 blymn }
373 1.1 blymn
374 1.1 blymn /*
375 1.14 blymn * Attempt to match the pattern buffer against the items. If c is a
376 1.1 blymn * printable character then add it to the pattern buffer prior to
377 1.1 blymn * performing the match. Direction determines the direction of matching.
378 1.1 blymn * If the match is successful update the item_matched variable with the
379 1.1 blymn * index of the item that matched the pattern.
380 1.1 blymn */
381 1.1 blymn int
382 1.7 itohy _menui_match_pattern(MENU *menu, int c, int direction, int *item_matched)
383 1.1 blymn {
384 1.1 blymn if (menu == NULL)
385 1.1 blymn return E_BAD_ARGUMENT;
386 1.1 blymn if (menu->items == NULL)
387 1.1 blymn return E_BAD_ARGUMENT;
388 1.1 blymn if (*menu->items == NULL)
389 1.1 blymn return E_BAD_ARGUMENT;
390 1.1 blymn
391 1.1 blymn if (isprint(c)) {
392 1.1 blymn /* add char to buffer - first allocate room for it */
393 1.1 blymn if ((menu->pattern = (char *)
394 1.1 blymn realloc(menu->pattern,
395 1.1 blymn menu->plen + sizeof(char) +
396 1.1 blymn ((menu->plen > 0)? 0 : 1)))
397 1.1 blymn == NULL)
398 1.1 blymn return E_SYSTEM_ERROR;
399 1.1 blymn menu->pattern[menu->plen] = c;
400 1.1 blymn menu->pattern[++menu->plen] = '\0';
401 1.1 blymn
402 1.1 blymn /* there is no chance of a match if pattern is longer
403 1.1 blymn than all the items */
404 1.1 blymn if (menu->plen >= menu->max_item_width) {
405 1.1 blymn menu->pattern[--menu->plen] = '\0';
406 1.1 blymn return E_NO_MATCH;
407 1.1 blymn }
408 1.14 blymn
409 1.3 blymn if (_menui_match_items(menu, direction,
410 1.1 blymn item_matched) == E_NO_MATCH) {
411 1.1 blymn menu->pattern[--menu->plen] = '\0';
412 1.1 blymn return E_NO_MATCH;
413 1.1 blymn } else
414 1.1 blymn return E_OK;
415 1.1 blymn } else {
416 1.3 blymn if (_menui_match_items(menu, direction,
417 1.1 blymn item_matched) == E_OK) {
418 1.1 blymn return E_OK;
419 1.1 blymn } else {
420 1.1 blymn return E_NO_MATCH;
421 1.1 blymn }
422 1.1 blymn }
423 1.1 blymn }
424 1.1 blymn
425 1.1 blymn /*
426 1.1 blymn * Draw an item in the subwindow complete with appropriate highlighting.
427 1.1 blymn */
428 1.1 blymn void
429 1.6 blymn _menui_draw_item(MENU *menu, int item)
430 1.1 blymn {
431 1.1 blymn int j, pad_len, mark_len;
432 1.14 blymn
433 1.1 blymn mark_len = max(menu->mark.length, menu->unmark.length);
434 1.14 blymn
435 1.9 blymn wmove(menu->scrwin,
436 1.1 blymn menu->items[item]->row - menu->top_row,
437 1.11 blymn menu->items[item]->col * (menu->col_width + 1));
438 1.6 blymn
439 1.10 blymn if (menu->cur_item == item)
440 1.9 blymn wattrset(menu->scrwin, menu->fore);
441 1.1 blymn if ((menu->items[item]->opts & O_SELECTABLE) != O_SELECTABLE)
442 1.9 blymn wattron(menu->scrwin, menu->grey);
443 1.1 blymn
444 1.1 blymn /* deal with the menu mark, if one is set.
445 1.1 blymn * We mark the selected items and write blanks for
446 1.1 blymn * all others unless the menu unmark string is set in which
447 1.1 blymn * case the unmark string is written.
448 1.1 blymn */
449 1.16 blymn if ((menu->items[item]->selected == 1) ||
450 1.16 blymn (((menu->opts & O_ONEVALUE) == O_ONEVALUE) &&
451 1.16 blymn (menu->cur_item == item))) {
452 1.1 blymn if (menu->mark.string != NULL) {
453 1.1 blymn for (j = 0; j < menu->mark.length; j++) {
454 1.9 blymn waddch(menu->scrwin,
455 1.1 blymn menu->mark.string[j]);
456 1.1 blymn }
457 1.1 blymn }
458 1.1 blymn /* blank any length difference between mark & unmark */
459 1.1 blymn for (j = menu->mark.length; j < mark_len; j++)
460 1.9 blymn waddch(menu->scrwin, ' ');
461 1.1 blymn } else {
462 1.1 blymn if (menu->unmark.string != NULL) {
463 1.1 blymn for (j = 0; j < menu->unmark.length; j++) {
464 1.9 blymn waddch(menu->scrwin,
465 1.1 blymn menu->unmark.string[j]);
466 1.1 blymn }
467 1.1 blymn }
468 1.1 blymn /* blank any length difference between mark & unmark */
469 1.1 blymn for (j = menu->unmark.length; j < mark_len; j++)
470 1.9 blymn waddch(menu->scrwin, ' ');
471 1.1 blymn }
472 1.14 blymn
473 1.1 blymn /* add the menu name */
474 1.1 blymn for (j=0; j < menu->items[item]->name.length; j++)
475 1.9 blymn waddch(menu->scrwin,
476 1.1 blymn menu->items[item]->name.string[j]);
477 1.14 blymn
478 1.1 blymn pad_len = menu->col_width - menu->items[item]->name.length
479 1.1 blymn - mark_len - 1;
480 1.1 blymn if ((menu->opts & O_SHOWDESC) == O_SHOWDESC) {
481 1.1 blymn pad_len -= menu->items[item]->description.length - 1;
482 1.1 blymn for (j = 0; j < pad_len; j++)
483 1.9 blymn waddch(menu->scrwin, menu->pad);
484 1.1 blymn for (j = 0; j < menu->items[item]->description.length; j++) {
485 1.9 blymn waddch(menu->scrwin,
486 1.1 blymn menu->items[item]->description.string[j]);
487 1.1 blymn }
488 1.1 blymn } else {
489 1.1 blymn for (j = 0; j < pad_len; j++)
490 1.9 blymn waddch(menu->scrwin, ' ');
491 1.1 blymn }
492 1.1 blymn menu->items[item]->visible = 1;
493 1.14 blymn
494 1.11 blymn /* kill any special attributes... */
495 1.11 blymn wattrset(menu->scrwin, menu->back);
496 1.11 blymn
497 1.6 blymn /*
498 1.6 blymn * Fill in the spacing between items, annoying but it looks
499 1.6 blymn * odd if the menu items are inverse because the spacings do not
500 1.6 blymn * have the same attributes as the items.
501 1.6 blymn */
502 1.11 blymn if ((menu->items[item]->col > 0) &&
503 1.11 blymn (menu->items[item]->col < (menu->item_cols - 1))) {
504 1.9 blymn wmove(menu->scrwin,
505 1.6 blymn menu->items[item]->row - menu->top_row,
506 1.11 blymn menu->items[item]->col * (menu->col_width + 1) - 1);
507 1.9 blymn waddch(menu->scrwin, ' ');
508 1.6 blymn }
509 1.14 blymn
510 1.1 blymn /* and position the cursor nicely */
511 1.1 blymn pos_menu_cursor(menu);
512 1.1 blymn }
513 1.1 blymn
514 1.1 blymn /*
515 1.1 blymn * Draw the menu in the subwindow provided.
516 1.1 blymn */
517 1.1 blymn int
518 1.6 blymn _menui_draw_menu(MENU *menu)
519 1.1 blymn {
520 1.17 christos int rowmajor, i, j, k, row = -1, stride;
521 1.15 blymn int incr, cur_row, offset, row_count;
522 1.14 blymn
523 1.1 blymn rowmajor = ((menu->opts & O_ROWMAJOR) == O_ROWMAJOR);
524 1.1 blymn
525 1.15 blymn if (rowmajor) {
526 1.15 blymn stride = 1;
527 1.15 blymn incr = menu->item_cols;
528 1.15 blymn } else {
529 1.15 blymn stride = menu->item_rows;
530 1.15 blymn incr = 1;
531 1.15 blymn }
532 1.15 blymn row_count = 0;
533 1.15 blymn
534 1.15 blymn for (i = 0; i < menu->item_count; i += incr) {
535 1.1 blymn if (menu->items[i]->row == menu->top_row)
536 1.1 blymn break;
537 1.15 blymn row_count++;
538 1.15 blymn for (j = 0; j < menu->item_cols; j++) {
539 1.15 blymn offset = j * stride + i;
540 1.15 blymn if (offset >= menu->item_count)
541 1.15 blymn break; /* done */
542 1.15 blymn menu->items[offset]->visible = 0;
543 1.15 blymn }
544 1.1 blymn }
545 1.1 blymn
546 1.9 blymn wmove(menu->scrwin, 0, 0);
547 1.1 blymn
548 1.9 blymn menu->col_width = getmaxx(menu->scrwin) / menu->cols;
549 1.1 blymn
550 1.15 blymn for (cur_row = 0; cur_row < menu->rows; cur_row++) {
551 1.15 blymn for (j = 0; j < menu->cols; j++) {
552 1.15 blymn offset = j * stride + i;
553 1.15 blymn if (offset >= menu->item_count) {
554 1.15 blymn /* no more items to draw, write background blanks */
555 1.15 blymn wattrset(menu->scrwin, menu->back);
556 1.15 blymn if (row < 0) {
557 1.15 blymn row = menu->items[menu->item_count - 1]->row;
558 1.15 blymn }
559 1.1 blymn
560 1.15 blymn wmove(menu->scrwin, cur_row,
561 1.15 blymn j * (menu->col_width + 1));
562 1.15 blymn for (k = 0; k < menu->col_width; k++)
563 1.15 blymn waddch(menu->scrwin, ' ');
564 1.1 blymn } else {
565 1.15 blymn _menui_draw_item(menu, offset);
566 1.1 blymn }
567 1.1 blymn }
568 1.1 blymn
569 1.15 blymn i += incr;
570 1.15 blymn row_count++;
571 1.1 blymn }
572 1.1 blymn
573 1.15 blymn if (row_count < menu->item_rows) {
574 1.15 blymn for (cur_row = row_count; cur_row < menu->item_rows; cur_row++) {
575 1.15 blymn for (j = 0; j < menu->item_cols; j++) {
576 1.15 blymn offset = j * stride + i;
577 1.15 blymn if (offset >= menu->item_count)
578 1.15 blymn break; /* done */
579 1.15 blymn menu->items[offset]->visible = 0;
580 1.15 blymn }
581 1.15 blymn i += incr;
582 1.15 blymn }
583 1.1 blymn }
584 1.14 blymn
585 1.1 blymn return E_OK;
586 1.1 blymn }
587 1.1 blymn
588 1.14 blymn
589 1.1 blymn /*
590 1.1 blymn * Calculate the widest menu item and stash it in the menu struct.
591 1.1 blymn *
592 1.1 blymn */
593 1.1 blymn void
594 1.6 blymn _menui_max_item_size(MENU *menu)
595 1.1 blymn {
596 1.1 blymn int i, with_desc, width;
597 1.1 blymn
598 1.1 blymn with_desc = ((menu->opts & O_SHOWDESC) == O_SHOWDESC);
599 1.14 blymn
600 1.1 blymn for (i = 0; i < menu->item_count; i++) {
601 1.1 blymn width = menu->items[i]->name.length
602 1.1 blymn + max(menu->mark.length, menu->unmark.length);
603 1.1 blymn if (with_desc)
604 1.1 blymn width += menu->items[i]->description.length + 1;
605 1.1 blymn
606 1.1 blymn menu->max_item_width = max(menu->max_item_width, width);
607 1.1 blymn }
608 1.1 blymn }
609 1.1 blymn
610 1.1 blymn
611 1.1 blymn /*
612 1.1 blymn * Redraw the menu on the screen. If the current item has changed then
613 1.1 blymn * unhighlight the old item and highlight the new one.
614 1.1 blymn */
615 1.1 blymn static void
616 1.6 blymn _menui_redraw_menu(MENU *menu, int old_top_row, int old_cur_item)
617 1.1 blymn {
618 1.1 blymn
619 1.1 blymn if (menu->top_row != old_top_row) {
620 1.1 blymn /* top row changed - redo the whole menu
621 1.1 blymn * XXXX this could be improved if we had wscrl implemented.
622 1.1 blymn
623 1.1 blymn * XXXX we could scroll the window and just fill in the
624 1.1 blymn * XXXX changed lines.
625 1.1 blymn */
626 1.9 blymn wclear(menu->scrwin);
627 1.3 blymn _menui_draw_menu(menu);
628 1.1 blymn } else {
629 1.1 blymn if (menu->cur_item != old_cur_item) {
630 1.1 blymn /* redo the old item as a normal one. */
631 1.3 blymn _menui_draw_item(menu, old_cur_item);
632 1.1 blymn }
633 1.1 blymn /* and then redraw the current item */
634 1.3 blymn _menui_draw_item(menu, menu->cur_item);
635 1.1 blymn }
636 1.1 blymn }
637