Mercurial > illumos > onarm
annotate usr/src/cmd/fmli/menu/mdefault.c @ 4:1a15d5aaf794
synchronized with onnv_86 (6202) in onnv-gate
author | Koji Uno <koji.uno@sun.com> |
---|---|
date | Mon, 31 Aug 2009 14:38:03 +0900 |
parents | c9caec207d52 |
children |
rev | line source |
---|---|
0 | 1 /* |
2 * CDDL HEADER START | |
3 * | |
4 * The contents of this file are subject to the terms of the | |
5 * Common Development and Distribution License, Version 1.0 only | |
6 * (the "License"). You may not use this file except in compliance | |
7 * with the License. | |
8 * | |
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
10 * or http://www.opensolaris.org/os/licensing. | |
11 * See the License for the specific language governing permissions | |
12 * and limitations under the License. | |
13 * | |
14 * When distributing Covered Code, include this CDDL HEADER in each | |
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
16 * If applicable, add the following below this CDDL HEADER, with the | |
17 * fields enclosed by brackets "[]" replaced with your own identifying | |
18 * information: Portions Copyright [yyyy] [name of copyright owner] | |
19 * | |
20 * CDDL HEADER END | |
21 */ | |
22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ | |
23 /* All Rights Reserved */ | |
24 | |
25 | |
26 /* | |
27 * Copyright (c) 1986 AT&T | |
28 * All Rights Reserved | |
29 */ | |
30 | |
4
1a15d5aaf794
synchronized with onnv_86 (6202) in onnv-gate
Koji Uno <koji.uno@sun.com>
parents:
0
diff
changeset
|
31 #ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.22 */ |
0 | 32 |
33 #include <stdio.h> | |
34 #include "wish.h" | |
35 #include "menu.h" | |
36 #include "menudefs.h" | |
37 #include "vtdefs.h" | |
38 #include "terror.h" | |
39 #include "ctl.h" | |
40 #include "sizes.h" | |
41 | |
42 char *shrink_descriptor(); | |
43 | |
44 #define MAX_MITEMS 10 | |
45 | |
46 menu_id | |
47 menu_make(num, title, flags, startrow, startcol, menurows, menucols, disp, arg) | |
48 int num; /* menu number */ | |
49 char *title; /* menu title */ | |
50 unsigned flags; /* menu/vt flags */ | |
51 int startrow; /* start row for the menu frame */ | |
52 int startcol; /* start column for the menu frame */ | |
53 int menurows; /* default menu rows */ | |
54 int menucols; /* default menu cols */ | |
55 struct menu_line (*disp)(); | |
56 char *arg; | |
57 { | |
58 register int total; /* total items */ | |
59 register int itemwidth; /* width of longest item */ | |
60 register int descwidth; /* width of longest description */ | |
61 register int menuwidth; /* width of the menu */ | |
62 int cols_specified; /* are number of cols specified? */ | |
63 int rows_specified; /* are number of rows specified? */ | |
64 struct menu_line ml; /* item offset into menu */ | |
65 vt_id vid; /* vt identifier of new frame */ | |
66 int probrows, probcols, probwidth; /* tmp vars */ | |
67 int oitemwidth, chop, i_num; /* tmp vars */ | |
68 int mflags = flags; /* menu flags (as opposed to vt flags) */ | |
69 bool has_description = FALSE; | |
70 | |
71 /* | |
72 * Determine ITEMWIDTH and DESCRIPTION WIDTH | |
73 * as well as the TOTAL number of items | |
74 */ | |
75 itemwidth = descwidth = 0; | |
76 ml = (*disp)(0, arg); | |
77 for (total = 0; ml.highlight; ml = (*disp)(++total, arg)) | |
78 { | |
79 ml.highlight = shrink_descriptor(ml.highlight, FIXED_COLS); | |
80 itemwidth = max(itemwidth, strlen(ml.highlight)); | |
81 if ((ml.description != NULL) && (*(ml.description) != '\0')) { | |
82 has_description = TRUE; | |
83 } /* no description */ | |
84 } | |
85 if (!total) | |
86 return((menu_id) FAIL); /* empty menu */ | |
87 | |
88 /* an item which fits may still need truncation to show that description | |
89 * didn't fit. - 4 becaue of " - " and min 1 char of description | |
90 */ | |
91 if (has_description && (itemwidth >= COLS - FIXED_COLS - 4) ) | |
92 { | |
93 mflags |= MENU_TRUNC; | |
94 descwidth = 1; | |
95 } | |
96 else /* full name fits, truncate description if needed */ | |
97 { | |
98 for (i_num = 0; i_num < total; i_num++) | |
99 { | |
100 ml = (*disp)(i_num, arg); | |
101 if (ml.description) | |
102 { | |
103 /* the "3" below is for the " - " separator */ | |
104 | |
105 ml.description = shrink_descriptor(ml.description, | |
106 FIXED_COLS + itemwidth + 3 -1); | |
107 descwidth = max(descwidth, strlen(ml.description)); | |
108 } | |
109 } | |
110 } | |
111 | |
112 rows_specified = (menurows > 0 ? TRUE : FALSE); | |
113 cols_specified = (menucols > 0 ? TRUE : FALSE); | |
114 | |
115 if (descwidth) { | |
116 /* | |
117 * If ANY item has a description, then stay single column, | |
118 * | |
119 * width = longest highlight + | |
120 * longest description + | |
121 * 3 (for the " - ") + | |
122 * 2 (for space between text and sides) | |
123 * | |
124 */ | |
125 if (rows_specified) { | |
126 /* | |
127 * actual rows = min(specified rows, | |
128 * fittable rows, | |
129 * needed rows); | |
130 */ | |
131 for ( ; !fits(flags, menurows, 1); menurows--) | |
132 ; | |
133 if (menurows > total) | |
134 menurows = total; | |
135 } | |
136 else { | |
137 /* | |
138 * actual rows = min(MAX_MITEMS, needed rows); | |
139 */ | |
140 menurows = min(total, MAX_MITEMS); | |
141 } | |
142 menucols = 1; | |
143 menuwidth = itemwidth + descwidth + 5; | |
144 | |
145 /* | |
146 * if the description is too long, then truncate | |
147 */ | |
148 for ( ; !fits(flags, menurows, menuwidth); menuwidth--) | |
149 ; | |
150 | |
151 } | |
152 else if (rows_specified && !cols_specified) { | |
153 /* | |
154 * determine probable rows, then probable columns | |
155 * | |
156 * probable rows = min(specified rows, "fittable" rows) | |
157 */ | |
158 for (probrows = menurows; !fits(flags, probrows, 1); probrows--) | |
159 ; | |
160 probcols = (total / probrows) + (total % probrows ? 1 : 0); | |
161 probwidth = 1 + probcols * (1 + itemwidth); | |
162 | |
163 /* | |
164 * determine actual rows and columns | |
165 */ | |
166 if (!fits(flags, probrows, probwidth)) { | |
167 /* | |
168 * menu not displayable in multi-columns ... | |
169 * | |
170 * actual rows = probable rows | |
171 * actual cols = 1 | |
172 * | |
173 * truncate the menu if necessary | |
174 */ | |
175 menurows = probrows; | |
176 menucols = 1; | |
177 menuwidth = 2 + itemwidth; | |
178 for (; !fits(flags, 1, menuwidth); ) | |
179 menuwidth--; | |
180 } | |
181 else { | |
182 /* | |
183 * actual rows = probable cols == 1 ? | |
184 * min(specified rows, fittable rows) : | |
185 * probable rows | |
186 * actual cols = probable cols | |
187 */ | |
188 if (probcols == 1) { | |
189 for ( ; !fits(flags, menurows, 1); menurows--) | |
190 ; | |
191 } | |
192 else | |
193 menurows = probrows; | |
194 menucols = probcols; | |
195 menuwidth = probwidth; | |
196 } | |
197 | |
198 /* | |
199 * Eliminate white-space from unused rows | |
200 */ | |
201 if (menurows > total) | |
202 menurows = total; | |
203 } | |
204 else if (cols_specified && !rows_specified) { | |
205 /* | |
206 * determine probable columns, then probable rows | |
207 * | |
208 * If necessary, truncate the length of each | |
209 * column until the menu fits | |
210 */ | |
211 probcols = menucols; | |
212 probwidth = 1 + probcols * (1 + itemwidth); | |
213 oitemwidth = itemwidth; | |
214 while (!fits(flags, 1, probwidth)) { | |
215 itemwidth--; | |
216 probwidth = 1 + probcols * (1 + itemwidth); | |
217 if (itemwidth <= 0) { | |
218 /* | |
219 * give up ... | |
220 * default to single column and | |
221 * truncate the menu if necessary. | |
222 */ | |
223 probcols = 1; | |
224 itemwidth = oitemwidth; | |
225 probwidth = 2 + itemwidth; | |
226 for (; !fits(flags, 1, probwidth); ) | |
227 probwidth--; | |
228 break; | |
229 } | |
230 } | |
231 probrows = (total / probcols) + (total % probcols ? 1 : 0); | |
232 | |
233 /* | |
234 * determine actual rows and columns | |
235 */ | |
236 if (!fits(flags, probrows, probwidth)) { | |
237 /* | |
238 * menu too big ... | |
239 * | |
240 * actual cols = 1 | |
241 * actual rows = min(MAX_MITEMS, total) | |
242 */ | |
243 menucols = 1; | |
244 menuwidth = 2 + itemwidth; | |
245 for (; !fits(flags, 1, menuwidth); ) | |
246 menuwidth--; | |
247 menurows = min(MAX_MITEMS, total); | |
248 } | |
249 else { | |
250 menucols = probcols; | |
251 menuwidth = probwidth; | |
252 menurows = probrows; | |
253 } | |
254 | |
255 /* | |
256 * Eliminate white-space from unused columns ... | |
257 * First compute the number of columns to chop and | |
258 * then subtract it from menucols | |
259 */ | |
260 if (menucols > 1) { | |
261 chop = ((menurows * menucols) - total) / menurows; | |
262 if (chop) { | |
263 menucols -= chop; | |
264 menuwidth = 1 + menucols * (1 + itemwidth); | |
265 } | |
266 } | |
267 } | |
268 else if (rows_specified && cols_specified) { | |
269 /* | |
270 * determine probable columns, then probable rows | |
271 * | |
272 * If necessary, truncate the length of each | |
273 * column until the menu fits | |
274 */ | |
275 probcols = menucols; | |
276 probwidth = 1 + probcols * (1 + itemwidth); | |
277 oitemwidth = itemwidth; | |
278 while (!fits(flags, 1, probwidth)) { | |
279 itemwidth--; | |
280 probwidth = 1 + probcols * (1 + itemwidth); | |
281 if (itemwidth <= 0) { | |
282 /* | |
283 * give up ... | |
284 * default to single column and | |
285 * truncate the menu if necessary. | |
286 */ | |
287 probcols = 1; | |
288 itemwidth = oitemwidth; | |
289 probwidth = 2 + itemwidth; | |
290 for (; !fits(flags, 1, probwidth); ) | |
291 probwidth--; | |
292 break; | |
293 } | |
294 } | |
295 probrows = (total / probcols) + (total % probcols ? 1 : 0); | |
296 | |
297 /* | |
298 * determine actual rows and columns | |
299 */ | |
300 if (!fits(flags, probrows, probwidth)) { | |
301 /* | |
302 * Menu can't be displayed in multi-columns ... | |
303 * | |
304 * actual cols = 1; | |
305 * actual rows = min(specified rows, fittable rows); | |
306 */ | |
307 menucols = 1; | |
308 menuwidth = 2 + itemwidth; | |
309 for (; !fits(flags, 1, menuwidth); ) | |
310 menuwidth--; | |
311 for ( ; !fits(flags, menurows, 1); menurows--) | |
312 ; | |
313 } | |
314 else { | |
315 /* | |
316 * actual rows = probable cols == 1 ? | |
317 * min(specified rows, fittable rows) : | |
318 * probable rows | |
319 * actual cols = probable cols | |
320 */ | |
321 if (probcols == 1) { | |
322 for ( ; !fits(flags, menurows, 1); menurows--) | |
323 ; | |
324 } | |
325 else | |
326 menurows = probrows; | |
327 menucols = probcols; | |
328 menuwidth = probwidth; | |
329 } | |
330 | |
331 /* | |
332 * Eliminate white-space from unused columns ... | |
333 * First compute the number of columns to chop and | |
334 * then subtract it from menucols | |
335 */ | |
336 if (menucols > 1) { | |
337 chop = ((menurows * menucols) - total) / menurows; | |
338 if (chop) { | |
339 menucols -= chop; | |
340 menuwidth = 1 + menucols * (1 + itemwidth); | |
341 } | |
342 } | |
343 } | |
344 else { | |
345 /* | |
346 * ROWS and COLUMNS are not specified so churn away ... | |
347 */ | |
348 if (total <= MAX_MITEMS) { | |
349 /* | |
350 * use single column ... truncate menu if necessary | |
351 */ | |
352 menurows = min(total, MAX_MITEMS); | |
353 menucols = 1; | |
354 menuwidth = itemwidth + 2; /* 1 column */ | |
355 while (!fits(flags, 1, menuwidth)) | |
356 menuwidth--; /* truncate until it fits */ | |
357 } | |
358 else { | |
359 /* | |
360 * 1) make menu at least as wide as the title, | |
361 * | |
362 * 2) make its aspect as close to 1:3 | |
363 * (height:width) as possible). | |
364 * | |
365 * These are arbitrarily pleasing values. | |
366 * | |
367 */ | |
368 menucols = 1; | |
369 menuwidth = itemwidth + 2; | |
370 menurows = MAX_MITEMS; | |
371 | |
372 while (fits(flags, menurows, menuwidth)) { | |
373 if ((menurows * 3 <= menuwidth) && | |
374 (menuwidth >= strlen(title) + 3)) | |
375 break; | |
376 menucols++; | |
377 menuwidth = 1 + menucols * (1 + itemwidth); | |
378 menurows = (total + menucols - 1) / menucols; | |
379 } | |
380 if (!fits(flags, menurows, menuwidth)) { | |
381 /* | |
382 * try "backing-off" one column and | |
383 * recomputing rows. | |
384 */ | |
385 menucols = max(menucols - 1, 1); | |
386 menuwidth = 1 + menucols * (1 + itemwidth); | |
387 menurows = (total + menucols - 1) / menucols; | |
388 | |
389 if (!fits(flags, menurows, menuwidth)) { | |
390 /* | |
391 * if all else fails ... resort to | |
392 * single column. | |
393 */ | |
394 menucols = 1; | |
395 menuwidth = itemwidth + 2; | |
396 menurows = min(total, MAX_MITEMS); | |
397 while (!fits(flags, 1, menuwidth)) | |
398 menuwidth--; | |
399 } | |
400 } | |
401 if (menucols == 1) | |
402 menurows = min(menurows, MAX_MITEMS); | |
403 } | |
404 } | |
405 | |
406 /* | |
407 * Make sure the menu VT (frame) can house the title | |
408 * vt_create adds the border cols hence FIXED_TITLE - 2 | |
409 */ | |
410 | |
411 menuwidth = max(menuwidth, strlen(title) + FIXED_TITLE - 2); /* abs f16 */ | |
412 | |
413 | |
414 /* | |
415 * Create a VT (frame) to house the menu | |
416 */ | |
417 if ((vid = vt_create(title, flags, startrow, startcol, menurows, | |
418 menuwidth)) == VT_UNDEFINED) | |
419 { | |
420 | |
421 /* | |
422 * try putting the VT anywhere | |
423 */ | |
424 vid = vt_create(title, flags, VT_UNDEFINED, VT_UNDEFINED, | |
425 menurows, menuwidth); | |
426 } | |
427 /* | |
428 * If the menu still can't be displayed then return FAIL | |
429 */ | |
430 if (vid == VT_UNDEFINED) { | |
431 mess_temp("Object can not be displayed, frame may be too large for the screen"); | |
432 return((menu_id) FAIL); | |
433 } | |
434 | |
435 if (num >= 0) | |
436 vt_ctl(vid, CTSETWDW, num); | |
437 return(menu_custom(vid, mflags, menucols, itemwidth, descwidth, total, disp, arg)); | |
438 } | |
439 | |
440 | |
441 menu_id | |
442 menu_reinit(mid, flags, menurows, menucols, disp, arg) | |
443 menu_id mid; | |
444 unsigned flags; | |
445 int menurows; | |
446 int menucols; | |
447 struct menu_line (*disp)(); | |
448 char *arg; | |
449 { | |
450 char *s; | |
451 register menu_id newmid; | |
452 register vt_id oldvid; | |
453 register menu_id oldmid; | |
454 int top, line; | |
455 | |
456 oldmid = MNU_curid; | |
457 oldvid = vt_current(MNU_array[mid].vid); | |
458 vt_ctl(VT_UNDEFINED, CTGETITLE, &s); | |
459 newmid = menu_make(vt_ctl(VT_UNDEFINED, CTGETWDW), s, | |
460 flags | VT_COVERCUR, VT_UNDEFINED, VT_UNDEFINED, | |
461 menurows, menucols, disp, arg); | |
462 menu_ctl(mid, CTGETPARMS, &top, &line); | |
463 menu_close(mid); | |
464 menu_ctl(newmid, CTSETPARMS, top, line); | |
465 menu_current(newmid); | |
466 if (MNU_array[mid].vid != oldvid) { | |
467 menu_noncurrent(); | |
468 if (oldmid >= 0) | |
469 menu_current(oldmid); | |
470 else | |
471 vt_current(oldvid); | |
472 } | |
473 return newmid; | |
474 } | |
475 | |
476 | |
477 /* shrink_descriptor truncates the provided string so it will fit in a | |
478 ** window thats the screen width minus reserved_col wide. The | |
479 ** end of the string is replaced with TRUNCATE_STR to show that | |
480 ** the string was truncated. | |
481 ** RETURN VALUE: Pointer to the truncated string. | |
482 ** SIDE AFFECTS: The string parameter is itself may be modified. | |
483 ** this routine does not make a copy before truncation. | |
484 ** If called with the result of a multi_eval, the | |
485 ** cur field of the attribute will be modified, affecting | |
486 ** future multi_evals if the descriptor is not | |
487 ** EVAL_ALWAYS | |
488 */ | |
489 char * | |
490 shrink_descriptor(str, reserved_cols) | |
491 char *str; | |
492 int reserved_cols; | |
493 { | |
494 int max_len; | |
495 | |
496 max_len = COLS - reserved_cols; /* longest string desired */ | |
497 if (strlen(str) > max_len && max_len >= LEN_TRUNC_STR) | |
498 strcpy((str + max_len - LEN_TRUNC_STR), TRUNCATE_STR); | |
499 return(str); | |
500 } |