1 /* $Id: ttymenu.c,v 2.2 2000/10/11 13:38:59 amura Exp $ */
2 /*
3 * ttymenu.c
4 * Amiga intuition menu handling routine for Ng 1.x
5 *
6 * Copyright (C) 2000, MURAMATSU Atsushi All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY "MURAMATSU Atsushi" AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 /*
32 * $Log: ttymenu.c,v $
33 * Revision 2.2 2000/10/11 13:38:59 amura
34 * change wildcard in ASL requester
35 *
36 * Revision 2.1 2000/10/02 14:03:14 amura
37 * rewrite from scratch
38 *
39 */
40
41 #include "config.h"
42 #ifdef DO_MENU
43 #include "def.h"
44
45 #include <exec/types.h>
46 #include <exec/memory.h>
47 #include <intuition/intuition.h>
48 #include <intuition/intuitionbase.h>
49 #include <graphics/gfxbase.h>
50 #include <clib/exec_protos.h>
51 #include <clib/intuition_protos.h>
52
53 #define MENU_SUB_ICON " \273"
54 #include "menumap.h"
55
56 struct Menu * InitEmacsMenu(struct Window *);
57 VOID DisposeMenus(struct Menu *);
58 struct MenuItem *MakeMenuItems(MenuMap *, struct TextAttr *);
59 VOID DisposeMenuItems(struct MenuItem *);
60 int amigamenu pro((int, int));
61
62 /*
63 * internal function prototypes
64 * these functions based on menulayout.c included
65 * in "AMIGA DEVELOPER CD 1.2"
66 */
67 static USHORT MaxLength(struct RastPort *textRPort,
68 struct MenuItem *first_item, USHORT char_size);
69 static VOID adjustItems(struct RastPort *textRPort,
70 struct MenuItem *first_item, USHORT char_size,
71 USHORT height, USHORT level, USHORT left_edge);
72 static VOID adjustMenus(struct Menu *first_menu, struct Window *win);
73
74 struct Menu *
InitEmacsMenu(win)75 InitEmacsMenu(win)
76 struct Window *win;
77 {
78 int i, num;
79 struct Menu *menu;
80
81 num = sizeof(MgMenus)/sizeof(MenuMap) - 1;
82
83 menu = (struct Menu *)AllocMem(num*sizeof(struct Menu),
84 MEMF_PUBLIC|MEMF_CLEAR);
85 if (menu == NULL)
86 return NULL;
87
88 for (i=0; i<num; i++)
89 {
90 menu[i].NextMenu = &menu[i+1];
91 menu[i].Flags = MENUENABLED;
92 menu[i].MenuName = MgMenus[i].face;
93 menu[i].FirstItem = (MgMenus[i].type==MENU_SUB) ?
94 MakeMenuItems((MenuMap*)MgMenus[i].func, win->WScreen->Font):
95 (struct MenuItem*)MENUNULL;
96 }
97 /* Menu Last mark */
98 menu[num-1].NextMenu = NULL;
99
100 adjustMenus(menu, win);
101 return menu;
102 }
103
104
105 VOID
DisposeMenus(menu)106 DisposeMenus(menu)
107 struct Menu *menu;
108 {
109 long num;
110 struct Menu *p;
111
112 if (menu == NULL)
113 return;
114 for (p=menu,num=0; p!=NULL; p=p->NextMenu,num++)
115 DisposeMenuItems(p->FirstItem);
116
117 FreeMem(menu, num*sizeof(struct Menu));
118 }
119
120
121 struct MenuItem *
MakeMenuItems(em,font)122 MakeMenuItems(em, font)
123 MenuMap *em;
124 struct TextAttr *font;
125 {
126 int i, num;
127 struct IntuiText *texts;
128 struct MenuItem *items;
129 MenuMap *p;
130
131 /* counting menu items */
132 for (p=em,num=0; p->type!=MENU_END; p++,num++);
133
134 texts = (struct IntuiText *)AllocMem(num*sizeof(struct IntuiText),
135 MEMF_PUBLIC|MEMF_CLEAR);
136 if (texts == NULL)
137 return NULL;
138 items = (struct MenuItem *)AllocMem(num*sizeof(struct MenuItem),
139 MEMF_PUBLIC|MEMF_CLEAR);
140 if (items == NULL)
141 {
142 FreeMem(texts, num*sizeof(struct IntuiText));
143 return NULL;
144 }
145
146 for (i=0; i<num; i++)
147 {
148 if (MENU_TYPE(em[i].type) == MENU_SUB)
149 {
150 items[i].SubItem = MakeMenuItems(em[i].func, font);
151 if (items[i].SubItem == NULL)
152 {
153
154 for (i--; i>=0; i--)
155 DisposeMenuItems(items[i].SubItem);
156
157 /* Dispose now making Items */
158 FreeMem(texts, num*sizeof(struct IntuiText));
159 FreeMem(items, num*sizeof(struct MenuItem));
160 return NULL;
161 }
162 }
163 else
164 items[i].SubItem = (struct MenuItem*)NULL;
165 items[i].NextItem = &items[i+1];
166 if (MENU_TYPE(em[i].type) == MENU_LINE)
167 items[i].Flags = ITEMTEXT|ITEMENABLED|HIGHNONE;
168 else
169 items[i].Flags = ITEMTEXT|ITEMENABLED|HIGHCOMP;
170 items[i].ItemFill = &texts[i];
171
172 /* Make IntuiText for menu face */
173 texts[i].FrontPen = 0;
174 texts[i].BackPen = 1;
175 texts[i].DrawMode = JAM2;
176 texts[i].LeftEdge = 0;
177 texts[i].TopEdge = 1;
178 texts[i].IText = (UBYTE*)em[i].face;
179 texts[i].ITextFont = font;
180 }
181 items[num-1].NextItem = NULL; /* Menu Last mark */
182
183 return items;
184 }
185
186
187 VOID
DisposeMenuItems(items)188 DisposeMenuItems(items)
189 struct MenuItem *items;
190 {
191 long num;
192 struct MenuItem *p;
193
194 if (items==NULL || items==(struct MenuItem *)MENUNULL)
195 return;
196
197 /* count menu items */
198 for (p=items,num=0; p!=NULL; p=p->NextItem,num++)
199 DisposeMenuItems(p->SubItem);
200
201 FreeMem(items->ItemFill, num*sizeof(struct IntuiText));
202 FreeMem(items, num*sizeof(struct MenuItem) );
203 }
204
205
206
207 /* Steps thru each item to determine the maximum width of the strip */
208 static USHORT
MaxLength(struct RastPort * textRPort,struct MenuItem * first_item,USHORT char_size)209 MaxLength(struct RastPort *textRPort,
210 struct MenuItem *first_item, USHORT char_size)
211 {
212 USHORT maxLength;
213 USHORT total_textlen;
214 struct MenuItem *cur_item;
215 struct IntuiText *itext;
216 USHORT extra_width;
217 USHORT maxCommCharWidth;
218 USHORT commCharWidth;
219
220 #ifdef notdef
221 extra_width = char_size; /* used as padding for each item. */
222 #endif
223
224 /*
225 * Find the maximum length of a command character, if any.
226 * If found, it will be added to the extra_width field.
227 */
228 maxCommCharWidth = 0;
229 for (cur_item=first_item; cur_item!=NULL; cur_item=cur_item->NextItem)
230 {
231 if (cur_item->Flags & COMMSEQ)
232 {
233 commCharWidth = TextLength(textRPort,&(cur_item->Command),1);
234 if (commCharWidth > maxCommCharWidth)
235 maxCommCharWidth = commCharWidth;
236 }
237 }
238
239 /*
240 * if we found a command sequence, add it to the extra required space.
241 * Add space for the Amiga key glyph plus space for the command
242 * character.
243 *
244 * Note this only works for HIRES screens, for LORES, use LOWCOMMWIDTH.
245 */
246 if (maxCommCharWidth > 0)
247 extra_width += maxCommCharWidth + COMMWIDTH;
248
249 /*
250 * Find the maximum length of the menu items, given the extra width
251 * calculated above.
252 */
253 maxLength = 0;
254 for (cur_item=first_item; cur_item!=NULL; cur_item=cur_item->NextItem)
255 {
256 itext = (struct IntuiText *)cur_item->ItemFill;
257 total_textlen = extra_width + itext->LeftEdge +
258 TextLength(textRPort, itext->IText, strlen(itext->IText));
259
260 /* returns the greater of the two */
261 if (total_textlen > maxLength)
262 maxLength = total_textlen;
263 }
264 return maxLength;
265 }
266
267
268 /* Adjust the MenuItems and SubItems */
269 static VOID
adjustItems(struct RastPort * textRPort,struct MenuItem * first_item,USHORT char_size,USHORT height,USHORT level,USHORT left_edge)270 adjustItems(struct RastPort *textRPort, struct MenuItem *first_item,
271 USHORT char_size, USHORT height,
272 USHORT level, USHORT left_edge)
273 {
274 register USHORT item_num;
275 struct MenuItem *cur_item;
276 USHORT strip_width, subitem_edge;
277
278 if (first_item==NULL || first_item==(struct MenuItem *)MENUNULL)
279 return;
280
281 /* The width of this strip is the maximum length of its members. */
282 strip_width = MaxLength(textRPort, first_item, char_size);
283
284 /* Position the items. */
285 for (cur_item=first_item,item_num=0; cur_item!=NULL;
286 cur_item=cur_item->NextItem,item_num++)
287 {
288 cur_item->TopEdge = (item_num * height) - level;
289 cur_item->LeftEdge = left_edge;
290 cur_item->Width = strip_width - left_edge;
291 cur_item->Height = height;
292
293 /* place the sub_item 3/4 of the way over on the item. */
294 subitem_edge = strip_width - (strip_width >> 2);
295 /* subitem_edge = strip_width >> 2; */
296
297 adjustItems(textRPort, cur_item->SubItem,
298 char_size, height, 1, subitem_edge);
299 }
300 }
301
302
303 /*
304 * The following routines adjust an entire menu system to conform to
305 * the specified fonts' width and height. Allows for Proportional Fonts.
306 * This is necessary for a clean look regardless of what the users
307 * preference in Fonts may be. Using these routines, you don't need to
308 * specify TopEdge, LeftEdge, Width or Height in the MenuItem structures.
309 *
310 * NOTE that this routine does not work for menus with images, but assumes
311 * that all menu items are rendered with IntuiText.
312 *
313 * This set of routines does NOT check/correct if the menu runs off
314 * the screen due to large fonts, too many items, lo-res screen.
315 */
316 VOID
adjustMenus(struct Menu * first_menu,struct Window * win)317 adjustMenus(struct Menu *first_menu, struct Window *win)
318 {
319 struct Menu *cur_menu;
320 USHORT start, char_size, height;
321
322 /* Get the Width of the Font */
323 char_size = TextLength(win->RPort, "n", 1);
324
325 /*
326 * To prevent crowding of the Amiga key when using COMMSEQ,
327 * don't allow the items to be less than 8 pixels high.
328 * Also, add an extra pixel for inter-line spacing.
329 */
330 if (FontHeight(win) > 8)
331 height = 1 + FontHeight(win);
332 else
333 height = 1 + 8;
334
335 start = 2; /* Set Starting Pixel */
336
337 /* Step thru the menu structure and adjust it */
338 for (cur_menu=first_menu; cur_menu!=NULL;
339 cur_menu=cur_menu->NextMenu)
340 {
341 cur_menu->LeftEdge = start;
342 cur_menu->Width = char_size +
343 TextLength(win->RPort, cur_menu->MenuName,
344 strlen(cur_menu->MenuName));
345 cur_menu->Height = height;
346 cur_menu->TopEdge = 0;
347 adjustItems(win->RPort, cur_menu->FirstItem,
348 char_size, height, 0, 0);
349 start += cur_menu->Width + char_size;
350 }
351 }
352
353 #ifdef ASL
354 #include <libraries/asl.h>
355 #include <clib/asl_protos.h>
356
357 #define ASL_OPEN 1
358 #define ASL_INSERT 2
359 #define ASL_WRITE 3
360
361 struct Library *AslBase;
362
363 static int
alsmenu(dir,mode,buff)364 alsmenu(dir, mode, buff)
365 char *dir;
366 char *buff;
367 {
368 struct FileRequester *fr;
369 char *text_OK, *title;
370 ULONG asl_flag;
371
372 if (AslBase = OpenLibrary("asl.library", 0L))
373 {
374 asl_flag = FILF_PATGAD;
375 buff[0] = '\0';
376 switch (mode)
377 {
378 case ASL_OPEN:
379 text_OK = "Open";
380 title = "Select File to Open";
381 break;
382 case ASL_INSERT:
383 text_OK = "Insert";
384 title = "Select File to Insert";
385 break;
386 case ASL_WRITE:
387 text_OK = "Save";
388 title = "Select File to Save to";
389 asl_flag |= FILF_SAVE;
390 break;
391 default:
392 text_OK = "OK";
393 title = "Select File";
394 }
395
396 if (fr = AllocAslRequestTags(ASL_FileRequest,
397 ASL_Hail, (ULONG)title,
398 ASL_Dir, (ULONG)dir,
399 ASL_Pattern, "~(#?'~)",
400 ASL_OKText, (ULONG)text_OK,
401 ASL_CancelText, (ULONG)"Cancel",
402 ASL_FuncFlags, asl_flag,
403 TAG_DONE
404 ))
405 {
406 if (AslRequest(fr, NULL))
407 {
408 strncpy(buff, fr->rf_Dir, NFILEN);
409 buff[NFILEN-1] = '\0';
410 if (!AddPart(buff, fr->rf_File, NFILEN))
411 buff[0] = '\0';
412 }
413 FreeAslRequest(fr);
414 }
415 CloseLibrary(AslBase);
416
417 return TRUE;
418 }
419 return FALSE;
420 }
421
422 int
aslopen(f,c)423 aslopen(f, c)
424 {
425 char fname[NFILEN];
426
427 alsmenu(curbp->b_cwd, ASL_OPEN, fname);
428 eargset(fname);
429 return filevisit(f, c);
430 }
431
432 int
aslinsert(f,c)433 aslinsert(f, c)
434 {
435 char fname[NFILEN];
436
437 alsmenu(curbp->b_cwd, ASL_INSERT, fname);
438 eargset(fname);
439 return fileinsert(f, c);
440 }
441
442 int
aslwrite(f,c)443 aslwrite(f, c)
444 {
445 char fname[NFILEN];
446
447 alsmenu(curbp->b_cwd, ASL_WRITE, fname);
448 eargset(fname);
449 return filewrite(f, c);
450 }
451 #endif /* ASL */
452
453 int
amigamenu(f,c)454 amigamenu(f, c)
455 int f, c;
456 {
457 MenuMap *em;
458 int menuNum,itemNum,subNum;
459
460 menuNum = getkbd() - MN_OFFSET;
461 itemNum = getkbd() - MN_OFFSET;
462 subNum = getkbd() - MN_OFFSET;
463
464 if (menuNum == NOITEM)
465 return TRUE;
466 em = MgMenus;
467 switch (MENU_TYPE(em[menuNum].type))
468 {
469 case MENU_LINE:
470 return TRUE;
471 case MENU_FUNC:
472 return ((int (*)())em[menuNum].func)(f, c);
473 case MENU_SUB:
474 if (itemNum == NOITEM)
475 return TRUE;
476 em = (MenuMap*)(em[menuNum].func);
477 switch (MENU_TYPE(em[itemNum].type))
478 {
479 case MENU_LINE:
480 return TRUE;
481 case MENU_FUNC:
482 return ((int (*)())em[itemNum].func)(f, c);
483 case MENU_SUB:
484 if (subNum == NOITEM)
485 return TRUE;
486 em = (MenuMap*)(em[itemNum].func);
487 switch (MENU_TYPE(em[subNum].type))
488 {
489 case MENU_LINE:
490 return TRUE;
491 case MENU_FUNC:
492 return ((int (*)())em[subNum].func)(f, c);
493 }
494 }
495
496 }
497
498 ewprintf("BUGS in amiga menu execute");
499 return FALSE;
500 }
501
502 #endif /* DO_MENU */
503