4 * A working menu system
6 * © 1993-1998 Straylight
9 /*----- Licensing note ----------------------------------------------------*
11 * This file is part of Straylight's Steel library.
13 * Steel is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2, or (at your option)
18 * Steel is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with Steel. If not, write to the Free Software Foundation,
25 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
45 extern void _dllEntry(menu__menuproc)(void *handle,char hits[]);
46 extern menu _dllEntry(menu__menumaker)(void *handle);
49 typedef struct menu__menustr
56 wimp_menustr *syshandle; /* This points to the actual structure, */
57 /* and 1 word ahead of a back-pointer to */
71 static menu__handlerstr menu__instant;
73 /*---------------------------------------------------------------------------
75 The syntax of menu strings is an extension of the system used by the
76 RISC_OSlib menu segment:
78 menu_description ::= <flags> <item> <sep> { <flags> <item> <sep> }
79 flags ::= '!' | '~' | '>' | ' ' | '+'
81 item ::= <a bunch of other characters>
83 flags have meanings as follows:
87 '>' item has a menu dbox attached
89 '+' open submenu even if item is shaded
91 ---------------------------------------------------------------------------*/
94 * static BOOL menu__ROparse(menu m,char **p,wimp_menuitem *item)
97 * Reads the next menu entry for a RISC_OSlib-style menu definition.
100 * menu m == the menu structure that this is being added to.
101 * char **p == pass-by-reference pointer to next item to parse. This is
102 * updated to point to the next item after successful termination, to the
103 * point where an error was discovered, or to zero to indicate successful
104 * completion of the entire menu.
105 * wimp_menuitem *item == pointer to structure for the routine to deposit
109 * TRUE for successful termination, or FALSE to indicate an error.
112 static BOOL menu__ROparse(menu m,char **p,wimp_menuitem *item)
128 item->submenu=(wimp_menustr *)-1;
142 item->submenu=(wimp_menustr *)1;
159 for (eptr=*p;*eptr!=0 && *eptr!='|' && *eptr!=',';eptr++,len++)
164 if (ind=mem_reAlloc(m->indirect,m->indbytes+len+1),!ind)
165 /* This will allocate memory if there isn't */
166 /* any indirected workspace yet */
171 msgs_lookup("menuNEM:Not enough memory to construct menu.")
175 itm=(wimp_menuitem *)(m->syshandle+1);
178 if (itm->iconflags & wimp_INDIRECT)
180 diff=itm->data.indirecttext.buffer-m->indirect;
181 if (diff<m->indbytes && diff>=0)
182 itm->data.indirecttext.buffer=ind+diff;
189 item->data.indirecttext.buffer=ind;
190 item->data.indirecttext.validstring=(char *)-1;
191 item->data.indirecttext.bufflen=len+1;
195 while (**p!=0 && **p!='|' && **p!=',')
213 * int menu__ROitemCount(char *string)
216 * Counts the number of menu items specified in a RISC_OSlib style menu
220 * char *s == pointer to the menu string
223 * The number of items specified
226 static int menu__ROitemCount(char *s)
246 * menu menu_new(char *title,char *items)
249 * Creates a menu as per the old RISC_OSlib system.
252 * char *title == the menu title (truncated to 12 chars if necessary)
253 * char *items == the menu item text. Data is indirected where required.
256 * A pointer to the menu if successful, or a NULL pointer if not.
259 menu menu_new(char *title,char *items)
265 int ino=menu__ROitemCount(items);
266 if (m=mem_alloc(sizeof(menu__menustr)),!m)
268 werr(FALSE,msgs_lookup("menuNEM:Not enough memory to construct menu."));
273 sizeof(menu)+sizeof(wimp_menuhdr)+ino*sizeof(wimp_menuitem)+4
278 werr(FALSE,msgs_lookup("menuNEM:Not enough memory to construct menu."));
281 m->syshandle=(wimp_menustr *)(t+1);
286 m->maxlen=strlen(title);
287 strcpy(m->syshandle->hdr.title,title);
288 m->syshandle->hdr.tit_fcol=7;
289 m->syshandle->hdr.tit_bcol=2;
290 m->syshandle->hdr.work_fcol=7;
291 m->syshandle->hdr.work_bcol=0;
292 m->syshandle->hdr.height=44;
293 m->syshandle->hdr.gap=0;
295 itm=((wimp_menuitem *)(m->syshandle+1))-1;
300 werr(TRUE,msgs_lookup("menuICOU:(menu_new): Menu item undercount."));
301 if (!menu__ROparse(m,&items,itm))
304 mem_free(m->indirect);
311 werr(TRUE,msgs_lookup("menuICOO:(menu_new): Menu item overcount."));
313 werr(TRUE,msgs_lookup("menuIMSC:(menu_new): Menu item count mismatch."));
314 itm->flags|=wimp_MLAST;
315 m->syshandle->hdr.width=16*m->maxlen+16;
320 * wimp_menuitem *menu__itmPointer(menu m,int i)
323 * Returns a pointer to the specified menu item. Items are numbered
327 * menu m == the menu to look up
328 * int i == the item number to find
331 * A pointer to the specified menu item
334 static wimp_menuitem *menu__itmPointer(menu m,int i)
336 return ((wimp_menuitem *)(m->syshandle+1)+(i-1));
340 * void menu_submenu(menu main,int item,menu submenu)
343 * Attaches a menu as a submenu, but it will put in a submenu warning flag,
344 * so the user-friendly too-many-windows messages come up right!
347 * menu main == the main menu
348 * int item == the menu item number
349 * menu submenu == the submenu
352 void menu_submenu(menu main,int item,menu submenu)
354 wimp_menuitem *i=menu__itmPointer(main,item);
357 i->flags|=wimp_MSUBLINKMSG;
358 i->submenu=(wimp_menuptr)(submenu->syshandle);
359 submenu->submenu=TRUE;
363 i->flags&=~wimp_MSUBLINKMSG;
364 i->submenu=(wimp_menuptr)-1;
369 * void menu_dispose(menu *m,BOOL recurse)
372 * Kill off a menu or menu tree. Won't work on submenus.
375 * menu *m == pointer to menu to Domestos-ise.
376 * BOOL recurse == do we want to kill its submenus too?
379 void menu_dispose(menu *m,BOOL recurse)
382 wimp_menuitem *itm=(wimp_menuitem *)((*m)->syshandle+1);
386 for (i=0;i<(*m)->items;i++);
388 if ((int)(itm->submenu)>=0x8000)
390 s=*((menu *)itm->submenu-1);
391 menu_dispose(&s,TRUE);
397 mem_free((*m)->indirect);
402 * wimp_menustr *menu_syshandle(menu m)
405 * Returns pointer to actual menu structure.
408 * menu m == menu handle for which structure is required.
411 * A pointer to the WIMP menu structure.
414 wimp_menustr *menu_syshandle(menu m)
416 return (m->syshandle);
420 * void menu_extend(menu m,char *items)
423 * Extend the given menu by a bit.
426 * menu m == the menu to extend
427 * char *items == the items to tag on the end
430 void menu_extend(menu m,char *items)
433 wimp_menuitem *start;
435 int ino=menu__ROitemCount(items);
438 (menu *)m->syshandle-1,
439 sizeof(menu)+sizeof(wimp_menuhdr)+(ino+m->items)*sizeof(wimp_menuitem)+4
443 werr(FALSE,msgs_lookup("menuNEME:Not enough memory to extend menu."));
446 m->syshandle=(wimp_menustr *)(t+1);
447 start=itm=menu__itmPointer(m,m->items);
450 itm->flags|=wimp_MSEPARATE;
456 if (!menu__ROparse(m,&items,itm))
459 start->flags&=~wimp_MLAST;
460 itm->flags|=wimp_MLAST;
461 m->syshandle->hdr.width=16*m->maxlen+16;
465 * void menu_setflags(menu m,int i,BOOL tick,BOOL shade)
468 * Changes menu item properties
471 * menu m == menu to change
472 * int i == menu item to change
473 * BOOL tick == tick the item
474 * BOOL shade == shade the item
477 void menu_setflags(menu m,int i,BOOL tick,BOOL shade)
479 wimp_menuitem *itm=menu__itmPointer(m,i);
481 itm->flags|=wimp_MTICK;
483 itm->flags&=~wimp_MTICK;
485 itm->iconflags|=wimp_INOSELECT;
487 itm->iconflags&=~wimp_INOSELECT;
491 * void menu_make_writeable(menu m,int i,char *buff,int bufflen,char *valid)
494 * Makes a menu entry writable (sorry about the spelling - it's Acorn's
498 * menu m == the menu in question
499 * int i == the item to be handled
500 * char *buff == where the data is to reside
501 * int bufflen == max length of data that can be crammed into buff
502 * char *valid == validation string (0 for none)
505 void menu_make_writeable(menu m,int i,char *buff,int bufflen,char *valid)
507 wimp_menuitem *itm=menu__itmPointer(m,i);
510 itm->iconflags|=wimp_INDIRECT;
511 itm->flags|=wimp_MWRITABLE;
512 itm->data.indirecttext.buffer=buff;
513 itm->data.indirecttext.bufflen=bufflen;
514 itm->data.indirecttext.validstring=valid;
518 * void menu_make_sprite(menu m,int i,char *name)
521 * Turns a menu entry into a sprite. Utterly useless, but there you go...
524 * menu m == the menu we're dealing with
525 * int i == the item to sprite-ise
526 * char *name == the sprite name
529 void menu_make_sprite(menu m,int i,char *name)
531 wimp_menuitem *itm=menu__itmPointer(m,i);
532 itm->iconflags|=wimp_INDIRECT|wimp_ISPRITE;
533 itm->iconflags&=~wimp_ITEXT;
534 itm->data.indirectsprite.name=name;
535 itm->data.indirectsprite.spritearea=resspr_area();
536 itm->data.indirectsprite.nameisname=TRUE;
540 * void menu_redirectItem(menu m,int i,char *buff,int bufflen,char *valid)
543 * Allows you to make a menu item's data point to your workspace, so you
544 * can change the text of an item at any time. The buffer length isn't
548 * menu m == the menu in question
549 * int i == the item to be handled
550 * char *buff == where the data is to reside
551 * int bufflen == max length of data that can be crammed into buff
552 * char *valid == validation string (0 for none)
555 void menu_redirectItem(menu m,int i,char *buff,int bufflen,char *valid)
557 wimp_menuitem *itm=menu__itmPointer(m,i);
560 itm->iconflags|=wimp_INDIRECT;
561 itm->data.indirecttext.buffer=buff;
562 itm->data.indirecttext.bufflen=bufflen;
563 itm->data.indirecttext.validstring=valid;
567 * void menu_minWidth(menu m,int min)
570 * Sets the minimum permissable width of a menu (in characters). Note that
571 * this call will not make the menu thinner than the width calculated
572 * during menu_new or menu_extend.
575 * menu m == the menu to change
576 * int min == the minumum allowable width fro the menu in characters. If
577 * 0 is passed, the width reverts to the calculated width.
580 void menu_minWidth(menu m,int min)
587 if (min<m->syshandle->hdr.width)
590 m->syshandle->hdr.width=min;
594 * void menu_settitle(menu m,char *title)
597 * Change a menu title.
600 * menu m == the menu to change
601 * char *title == the new title
604 void menu_settitle(menu m,char *title)
606 strncpy(m->syshandle->hdr.title,title,12);
610 * int *menu__processHits(int hit[])
613 * Processes a hit string as necessary (translates WIMP menu items to C
617 * int hit[] == PBR array to process, terminated by -1.
623 static int *menu__processHits(int hit[])
633 * menu menu__menumaker(void *handle)
636 * A surrogate menu maker.
639 * void *handle == pointer to information about the real maker
642 * The menu to display
645 _dll_static menu menu__menumaker(void *handle)
647 menu__handlerstr *m=handle;
648 return ((m->m)(m->handle));
652 * void menu__menuproc(void *handle,char hit[])
655 * General menu handler for menus registered using the menu functions
656 * rather than the standard event ones.
659 * void *handle == pointer to the control block for this menu
660 * char hit[] == an array of menu hits (ignored)
663 _dll_static void menu__menuproc(void *handle,char hit[])
665 menu__handlerstr *m=handle;
668 wimp_eventstr *e=wimpt_last_event();
670 switch (event_whyMenuEvent())
672 case event_MENUSELECT:
674 (m->sel)(menu__processHits(e->data.menu),m->handle);
676 case event_MENUDELETE:
678 (m->sel)(menu__processHits(&minusone),m->handle);
680 case event_MENUSUBMENU:
682 (m->sel)(menu__processHits(e->data.msg.data.words+3),m->handle);
687 wimpt_noerr(wimp_getmenustate(1,
689 e->data.msg.data.helprequest.m.w,
690 e->data.msg.data.helprequest.m.i));
691 (m->help)(menu__processHits(hits),m->handle);
695 werr(TRUE,msgs_lookup("menuUKNME:(menu__menuproc): "
696 "Unknown menu event type."));
705 * menu_selectProc sel,
706 * menu_helpProc help,
711 * Basically equivalent to event_attachmenu, only it handles help requests
712 * neatly etc. Source code compatibility *cannot* be assured, because I
713 * want to be able to expand this routine to cater for later changes. I
714 * will try to soften the blow (if any) by supplying macros that will work
715 * with older programs, but I can't guarantee anything.
718 * wimp_w w == the window to attach to
719 * menu m == the menu to attach
720 * menu_selectProc sel == procedure to handle most selection-type events
721 * menu_helpProc help == procedure to handle help requests for the menu
733 menu__handlerstr *h=0;
736 event_menu_maker omm;
740 if (h=mem_alloc(sizeof(menu__handlerstr)),!h)
745 msgs_lookup("menuNEM:Not enough memory to construct menu.")
753 event_attachedMenu(w,&om,&omm,&omp,&old);
754 if (omp==menu__menuproc)
756 event_attachmenu(w,m,_dllEntry(menu__menuproc),h);
760 * void menu_attachMaker
763 * event_menu_maker m,
764 * menu_selectProc sel,
765 * menu_helpProc help,
770 * This routine deals with event_attachmenumaker as menu_attach deals with
774 * wimp_w w == the window to attach to
775 * menu m == the menu to attach
776 * menu_selectProc sel == procedure to handle most selection-type events
777 * menu_helpProc help == procedure to handle help requests for the menu
780 void menu_attachMaker
789 menu__handlerstr *h=0;
792 event_menu_maker omm;
796 if (h=mem_alloc(sizeof(menu__handlerstr)),!h)
801 msgs_lookup("menuNEM:Not enough memory to construct menu.")
810 event_attachedMenu(w,&om,&omm,&omp,&old);
811 if (omp==menu__menuproc)
813 event_attachmenumaker(w,
814 _dllEntry(menu__menumaker),
815 _dllEntry(menu__menuproc),
820 * void menu_open(menu m,menu_selectProc sel,menu_helpProc help,void *handle)
823 * Analagous to event_openMenu().
829 void menu_open(menu m,menu_selectProc sel,menu_helpProc help,void *handle)
831 menu__instant.sel=sel;
832 menu__instant.help=help;
833 menu__instant.handle=handle;
834 event_openMenu(m,_dllEntry(menu__menuproc),&menu__instant);
838 * void menu_make(event_menu_maker m,menu_selectProc sel,menu_helpProc help,void *handle)
841 * Analagous to event_makeMenu().
847 void menu_make(event_menu_maker m,menu_selectProc sel,menu_helpProc help,void *handle)
849 menu__instant.sel=sel;
850 menu__instant.help=help;
851 menu__instant.handle=handle;
853 event_makeMenu(_dllEntry(menu__menumaker),
854 _dllEntry(menu__menuproc),
859 * void menu_saveHandler(wimp_w w,menu_handler *h)
862 * Saves information about the menu handle for the given window in the
863 * block specified. This can be used *only* to restore the handler for a
864 * window later (although it needn't be the same one). Note too that the
865 * window need not have to have menu handlers registered using the menu
866 * calls, or even have any at all.
869 * wimp_w w == the window whose menu handlers we are to save
870 * menu_handler *h == pointer to a chunk of memory to fill in.
873 void menu_saveHandler(wimp_w w,menu_handler *h)
879 menu__handlerstr *ha;
880 event_attachedMenu(w,&m,&mk,&p,&hand);
881 if (p==_dllEntry(menu__menuproc))
886 h->info.m.make=ha->m;
887 h->info.m.sel=ha->sel;
888 h->info.m.help=ha->help;
889 h->info.m.handle=ha->handle;
897 h->info.e.handle=hand;
902 * void menu_restoreHandler(wimp_w w,menu_handler *h)
905 * Restores handlers from a structure filled in by menu_saveHandler.
908 * wimp_w w == the window whose handlers we are to set up.
909 * menu_handler *h == pointer to a chunk of memory filled in correctly.
912 void menu_restoreHandler(wimp_w w,menu_handler *h)
936 event_attachmenu(w,h->info.e.m,h->info.e.proc,h->info.e.handle);
939 event_attachmenumaker(w,