home *** CD-ROM | disk | FTP | other *** search
- // **************************************************************************
- // Copyright 1996 David Allison
- //
- // VV VV IIIIII SSSSS TTTTTT AA
- // VV VV II SS TT AA AA
- // VV VV II SSSS TT AA AA
- // VV VV II SS TT AAAAAAAA
- // VV IIIIII SSSS TT AA AA
- //
- // MULTI-THREADED C++ WIMP CLASS LIBRARY
- // for RISC OS
- // **************************************************************************
- //
- // P U B L I C D O M A I N L I C E N C E
- // -------------------------------------------
- //
- // This library is copyright. You may not sell the library for
- // profit, but you may sell products which use it providing
- // those products are presented as executable code and are not
- // libraries themselves. The library is supplied without any
- // warranty and the copyright owner cannot be held responsible for
- // damage resulting from failure of any part of this library.
- //
- // See the User Manual for details of the licence.
- //
- // *************************************************************************
-
- //
- // menu.c
- //
-
- #include "Vista:icon.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <new.h>
- #include <ctype.h>
- #include <swis.h>
- #include <kernel.h>
- #include <stdarg.h>
-
- #ifndef __EASY_C
-
- // an exception here needs to close the file pointer used for the parser. This
- // trick redefines the throw macro to close the file and then call __throw
-
- static FILE *menu_fp ;
-
- #undef throw
- #define throw menu_fp?fclose(menu_fp):0,__throw
-
- #endif
-
- MenuItem::MenuItem (char *n, Menu *m, char *text, int length)
- {
- name = n ;
- next = NULL ;
- menu = m ;
- submenu = NULL ;
- index = m->add_item(this) ; // add a new menu item
- MenuItemData *item = &m->data->items[index] ;
- item->item_flags = 0 ;
- item->window_handle = -1 ;
- item->icon_flags = Icon::ITEXT + Icon::IFILLED + Icon::IVCENTRE + 7*Icon::IFORECOL ;
- print (text) ;
- }
-
- MenuItem::MenuItem (char *name, Menu *menu, char *sprite, void *sprite_area)
- {
- }
-
- void MenuItem::tick()
- {
- menu->data->items[index].item_flags |= TICKED ;
- }
-
- void MenuItem::untick()
- {
- menu->data->items[index].item_flags &= ~TICKED ;
- }
-
- void MenuItem::fade()
- {
- menu->data->items[index].icon_flags |= Icon::INOSELECT ;
- }
-
- void MenuItem::unfade()
- {
- menu->data->items[index].icon_flags &= ~Icon::INOSELECT ;
- }
-
- int MenuItem::flags(int f, int m)
- {
- int old = menu->data->items[index].item_flags ;
- menu->data->items[index].item_flags = (old & ~m) | f ;
- return old ;
- }
-
- int MenuItem::is_ticked()
- {
- return menu->data->items[index].item_flags & TICKED ;
- }
-
- int MenuItem::is_faded()
- {
- return menu->data->items[index].icon_flags & Icon::INOSELECT ;
- }
-
- MenuItem::operator int()
- {
- return index ;
- }
-
- MenuItem::operator char *()
- {
- return name ;
- }
-
- void MenuItem::make_writeable (char *buffer, int length, char *valid)
- {
- MenuItemData *i = &menu->data->items[index] ;
- i->icon_data.indirecttext.buffer = buffer ;
- i->icon_data.indirecttext.bufflen = length ;
- i->icon_data.indirecttext.validstring = valid ;
- i->icon_flags |= Icon::BWRITABLE * Icon::IBTYPE + Icon::INDIRECT +
- Icon::IHCENTRE + Icon::IVCENTRE + Icon::ITEXT ;
- i->item_flags |= WRITEABLE ;
- }
-
- void MenuItem::set_submenu(Menu *submenu)
- {
- this->submenu = submenu ;
- menu->data->items[index].submenu = submenu->data ;
- }
-
- void Menu::init (char *n, char *title)
- {
- name = n ;
- next = NULL ;
- num_items = 0 ;
- max_items = 5 ;
- item_adjust = 0 ;
- if ((data = (MenuData*)malloc (sizeof (MenuData) + sizeof (MenuItemData) * max_items)) == NULL)
- throw ("Out of memory") ;
- items = NULL ;
- max_width = 0 ;
- strncpy (data->title, title, 12) ;
- data->title_fore_colour = 7 ;
- data->title_back_colour = 2 ;
- data->work_fore_colour = 7 ;
- data->work_back_colour = 0 ;
- data->item_width = strlen(title) * 16;
- data->item_height = 44 ;
- data->item_gap = 0 ;
- }
-
- Menu::Menu (char *name, char *title)
- {
- init (name, title) ;
- }
-
- Menu::Menu (char *name, char *title, MenuItem *item)
- {
- init (name, title) ;
- item->set_submenu (this) ;
- }
-
- Menu::~Menu()
- {
- }
-
- int Menu::add_item (MenuItem *item)
- {
- if (num_items == max_items) // out of item space?
- {
- max_items += 5 ;
- if ((data = (MenuData*)realloc (data, sizeof (MenuData) + sizeof (MenuItemData) * max_items)) == NULL)
- throw ("Out of memory") ;
- }
- item->next = items ; // add to list
- items = item ;
- return num_items++ ;
- }
-
- void Menu::finish()
- {
- items->flags(MenuItem::LAST) ; // set last item
- }
-
- void Menu::open (int x, int y)
- {
- _kernel_swi_regs r ;
- _kernel_oserror *e ;
- r.r[1] = (int)data ;
- r.r[2] = x ;
- r.r[3] = y ;
- if ((e = _kernel_swi (Wimp_CreateMenu, &r, &r)) != NULL)
- throw (e) ;
- }
-
- void Menu::close()
- {
- _kernel_swi_regs r ;
- _kernel_oserror *e ;
- r.r[1] = -1 ;
- if ((e = _kernel_swi (Wimp_CreateMenu, &r, &r)) != NULL)
- throw (e) ;
- }
-
- void Menu::iconbar_adjust (int &x, int &y)
- {
- x -= 16 ;
- y = 96 ;
- y += num_items * (data->item_height + data->item_gap) + item_adjust ;
- }
-
- MenuItem *Menu::selection (int *hits)
- {
- int i ;
- MenuItem *item ;
- Menu *m = this ;
- for (i = 0 ; ; i++)
- if (hits[i] == -1)
- break ;
- MenuItem *out_items = (MenuItem*)malloc ((i+1) * sizeof (MenuItem)) ;
- if (out_items == NULL)
- throw ("Out of memory") ;
- for (i = 0 ; hits[i] != -1 ; i++)
- for (item = m->items ; item != NULL ; item = item->next)
- if (item->index == hits[i])
- {
- out_items[i] = *item ;
- if (hits[i+1] != -1)
- m = item->submenu ;
- break ;
- }
- out_items[i].name = NULL ;
- out_items[i].index = -1 ;
- return out_items ;
- }
-
- bool Menu::invalid_selection (int *hits)
- {
- int i ;
- MenuItem *item ;
- MenuItem *last_item = NULL ;
- Menu *m = this ;
- for (i = 0 ; hits[i] != -1 ; i++)
- for (item = m->items ; item != NULL ; item = item->next)
- if (item->index == hits[i])
- {
- last_item = item ;
- if (hits[i+1] != -1)
- m = item->submenu ;
- break ;
- }
- #ifdef __EASY_C
- return last_item != NULL && (last_item->flags() & MenuItem::MENUWARNING) ;
- #else
- return (bool)(last_item != NULL && (last_item->flags() & MenuItem::MENUWARNING)) ;
- #endif
- }
-
- MenuItem *Menu::item (char *iname)
- {
- for (MenuItem *item = items ; item != NULL ; item = item->next)
- if (strcmp (item->name, iname) == 0)
- return item ;
- return NULL ;
- }
-
-
- void Menu::print (char *item_name, char *format ...)
- {
- MenuItem *i = item (item_name) ;
- if (i == NULL)
- throw ("No such menu item") ;
- va_list ap ;
- va_start (ap, format) ;
- i->vprint (format, ap) ;
- }
-
- void MenuItem::print (char *format...)
- {
- char str[1024] ;
- va_list arg ;
- va_start (arg,format) ;
- vprint (format, arg) ;
- }
-
- void MenuItem::vprint (char *format, va_list ap)
- {
- char str[1024] ;
- vsprintf (str,format,ap) ;
- int length = strlen (str) ;
- MenuItemData *item = &menu->data->items[index] ;
- if (length > menu->max_width)
- {
- menu->max_width = length ;
- int l = (length + 1) * 16 ;
- if (l > menu->data->item_width)
- menu->data->item_width = l ;
- }
- if (length <= 12)
- {
- item->icon_flags &= ~Icon::INDIRECT ;
- strncpy (item->icon_data.text, str, length) ;
- if (length < 12)
- item->icon_data.text[length] = 0 ;
- }
- else
- {
- item->icon_flags |= Icon::INDIRECT ;
- item->icon_data.indirecttext.buffer = new char [length+1] ;
- item->icon_data.indirecttext.validstring = (char *)-1 ;
- item->icon_data.indirecttext.bufflen = length+1 ;
- strcpy (item->icon_data.indirecttext.buffer, str) ;
- }
- }
-
- void Menu::read (char *item_name, int &i)
- {
- MenuItem *it = item(item_name) ;
- if (it == NULL)
- throw ("No such menu item") ;
- it->read (i) ;
- }
-
- void MenuItem::read (int &i)
- {
- char str[1024] ;
- read (str) ;
- sscanf (str,"%d",&i) ;
- }
-
- void Menu::read (char *item_name, char *s)
- {
- MenuItem *i = item(item_name) ;
- if (i == NULL)
- throw ("No such menu item") ;
- i->read (s) ;
- }
-
- void MenuItem::read (char *s)
- {
- MenuItemData *item = &menu->data->items[index] ;
- if (item->icon_flags & Icon::INDIRECT)
- strcpy (s, item->icon_data.indirecttext.buffer) ;
- else
- for (int i = 0 ; i < 12 ; i++)
- s[i] = item->icon_data.text[i] ;
- }
-
- //
- // menu file parser
- //
-
- // tokens recognised
-
- #define T_LBRACK 1
- #define T_RBRACK 2
- #define T_IDENTIFIER 3
- #define T_OTHER 4
- #define T_EQUALS 5
- #define T_STRING 6
- #define T_SEMICOLON 7
- #define T_COMMA 8
- #define T_COLON 9
- #define T_LBRACE 10
- #define T_RBRACE 11
- #define T_MENU 12
- #define T_SEPARATOR 13
- #define T_TICKED 14
- #define T_WRITEABLE 15
- #define T_MESSAGE 16
- #define T_OPEN 17
- #define T_WINDOW 18
- #define T_NUMBER 19
-
- static char spelling[256] ;
- static char input[1024] ;
- static char *ch ;
- static int value ;
- static FILE *fp ;
-
- static int reserved_word() ;
-
- static void read_line()
- {
- for (;;)
- {
- if (fgets (input, 1024, fp) == NULL)
- {
- input[0] = '$' ;
- ch = input ;
- break ;
- }
- else
- {
- ch = input ;
- while (isspace (*ch) && *ch != 0)
- ch++ ;
- if (*ch == '#' || *ch == 0)
- continue ;
- else
- break ;
- }
- }
- }
-
- static int next_char()
- {
- if (*ch == 0)
- read_line() ;
- return *ch++ ;
- }
-
- static int next_token (void)
- {
- int c;
- char str[256] ;
- char *ptr ;
-
- while (isspace (*ch)) next_char() ;
- switch (c = next_char())
- {
- case ':':
- return T_COLON ;
- case ';':
- return T_SEMICOLON ;
- case '=':
- return T_EQUALS ;
- case ',':
- return T_COMMA ;
- case '{':
- return T_LBRACE ;
- case '}':
- return T_RBRACE ;
- case '(':
- return T_LBRACK ;
- case ')':
- return T_RBRACK ;
-
- default:
- if (isdigit(c))
- {
- int i = 0 ;
- do
- {
- spelling[i] = c ;
- c = next_char() ;
- i++ ;
- }
- while (isdigit(c)) ;
- spelling[i] = 0 ;
- ch-- ;
- sscanf (spelling, "%d", &value) ;
- return T_NUMBER ;
- }
- else if (isalpha (c) || c == '_')
- {
- ptr = spelling ;
- do
- {
- *ptr++ = c ;
- c = next_char() ;
- }
- while (isalnum (c) || c == '_') ;
- *ptr = '\0' ;
- ch-- ;
- if ((c = reserved_word()) != 0)
- return c ;
- return T_IDENTIFIER ;
- }
- else if (c == '"')
- {
- ptr = spelling ;
- while ((c = next_char()) != '"')
- {
- if (c == 0)
- throw ("Bad string") ;
- if (c == '\\')
- switch (c = next_char())
- {
- case 'n':
- *ptr++ = '\n' ;
- continue ;
- case 'r':
- *ptr++ = '\r' ;
- continue ;
- case 't':
- *ptr++ = '\t' ;
- continue ;
- case 'b':
- *ptr++ = '\b' ;
- continue ;
- case 'f':
- *ptr++ = '\f' ;
- continue ;
- case 'a':
- *ptr++ = '\a' ;
- continue ;
- case 'v':
- *ptr++ = '\v' ;
- continue ;
- default:
- *ptr++ = c ;
- continue ;
- }
- else
- *ptr++ = c ;
- }
- *ptr = 0 ;
- return T_STRING ;
- }
- else
- return T_OTHER ;
- }
-
- }
-
- int this_symbol ;
-
- static void next_symbol()
- {
- this_symbol = next_token() ;
- }
-
-
- static struct
- {
- char *word ;
- int value ;
- } res_words[] = {
- {"menu", T_MENU},
- {"ticked", T_TICKED},
- {"writeable", T_WRITEABLE},
- {"message", T_MESSAGE},
- {"open", T_OPEN},
- {"separator", T_SEPARATOR},
- {"window", T_WINDOW},
- {NULL, 0}
- } ;
-
- static int reserved_word()
- {
- int i ;
- for (i = 0 ; res_words[i].word != NULL ; i++)
- if (strcmp (res_words[i].word, spelling) == 0)
- return res_words[i].value ;
- return 0 ;
- }
-
- static void accept (int token, char *error = "Syntax error")
- {
- if (this_symbol == token)
- next_symbol() ;
- else
- throw (error) ;
- }
-
-
- static char *stralloc (char *name)
- {
- char *p = new char [strlen(name) + 1] ;
- strcpy (p, name) ;
- return p ;
- }
-
- static char *accept_name (int token, char *error = "Expected name")
- {
- char *s ;
- if (this_symbol == token)
- {
- s = stralloc (spelling) ;
- next_symbol() ;
- return s ;
- }
- else
- throw (error) ;
- }
-
- void MenuSet::parse_menu()
- {
- char *mname ;
- char *title ;
- Menu *menu ;
- mname = accept_name (T_IDENTIFIER, "Menu name expected") ;
- title = accept_name (T_STRING, "Missing menu title") ;
- accept (T_EQUALS, "Missing =") ;
- menu = new Menu (mname, title) ;
- add_menu (menu) ;
- parse_menu_details (menu) ; // at end this_symbol == }
- menu->finish() ;
- }
-
- void MenuSet::parse_menu_details(Menu *menu)
- {
- accept (T_LBRACE, "Missing {") ;
- while (this_symbol != T_RBRACE)
- parse_item (menu) ;
- }
-
- void MenuSet::parse_item (Menu *menu)
- {
- char *name;
- char *text ;
- char *sprite ;
- int has_submenu = 0 ;
- MenuItem *item ;
- name = accept_name (T_IDENTIFIER, "Missing item name") ;
- switch (this_symbol)
- {
- case T_STRING:
- text = stralloc (spelling) ;
- item = new MenuItem (name, menu, text, strlen (text)) ;
- next_symbol() ;
- break ;
- case T_IDENTIFIER: // sprite
- default:
- throw ("Syntax error") ;
- }
- if (this_symbol == T_COLON)
- {
- next_symbol() ;
- for (;;)
- {
- switch (this_symbol)
- {
- case T_TICKED:
- item->tick() ;
- break ;
- case T_WRITEABLE:
- {
- next_symbol() ;
- accept (T_LBRACK, "Missing (") ;
- accept (T_NUMBER, "Missing writeable buffer size") ;
- accept (T_COMMA, "Missing ,") ;
- char *valid = accept_name (T_STRING, "Missing validation string") ;
- if (this_symbol != T_RBRACK)
- throw ("Missing )") ;
- char *s = new char [value] ;
- s[0] = 0 ;
- item->make_writeable (s, value, valid) ;
- break;
- }
- case T_SEPARATOR:
- item->flags (MenuItem::SEPARATOR) ;
- menu->item_adjust += 24 ; // add separator adjust
- break ;
- case T_MESSAGE:
- item->flags (MenuItem::MENUWARNING) ;
- if (has_submenu)
- throw ("Submenu already exists") ;
- has_submenu = 1 ;
- item->set_submenu ((Menu*)1) ;
- break ;
- case T_OPEN:
- item->flags (MenuItem::OPENANYWAY) ;
- break ;
- case T_MENU:
- if (has_submenu)
- throw ("Submenu already exists") ;
- has_submenu = 1 ;
- next_symbol() ;
- switch (this_symbol)
- {
- case T_IDENTIFIER:
- {
- Menu *m = find (spelling) ;
- if (m == 0)
- throw ("Unknown menu") ;
- item->set_submenu (m) ;
- break ;
- }
- case T_STRING:
- {
- char *title = stralloc (spelling) ;
- Menu *submenu = new Menu ("", title, item) ;
- next_symbol() ;
- parse_menu_details (submenu) ;
- submenu->finish() ;
- break ;
- }
- default:
- throw ("Syntax error") ;
- }
- break ;
- case T_WINDOW:
- break ;
- }
- next_symbol() ;
- if (this_symbol != T_COMMA)
- break ;
- next_symbol() ;
- }
- }
- accept (T_SEMICOLON, "Missing ;") ;
- }
-
- void MenuSet::add_menu(Menu *menu)
- {
- menu->next = menus ;
- menus = menu ;
- }
-
- Menu *MenuSet::find (char *name)
- {
- Menu *m ;
- for (m = menus ; m != NULL ; m = m->next)
- if (strcmp (name, m->name) == 0)
- return m ;
- return NULL ;
- }
-
- MenuSet::MenuSet(Task *t, char *filename)
- {
- menus = NULL ; // no menu yet
- if ((fp = fopen (filename, "r")) == NULL)
- #ifdef __EASY_C
- throw "Cant open Menu file" ;
- #else
- __throw ("Cant open Menu file") ;
- #endif
-
- #ifdef __EASY_C
- try
- #endif
- {
- #ifndef __EASY_C
- menu_fp = fp ;
- #endif
- task = t ;
- read_line() ;
- next_symbol() ;
- while (this_symbol == T_MENU)
- {
- next_symbol() ;
- parse_menu() ;
- next_symbol() ;
- }
- fclose (fp) ;
- }
- #ifdef __EASY_C
- catch (char *t)
- {
- fclose (fp) ;
- throw ; // rethrow exception
- }
- #endif
- }
-
- MenuSet::~MenuSet()
- {
- }
-
-