Commit 91926745 authored by Robert Sprowson's avatar Robert Sprowson
Browse files

Put ctl in the attic

The ctl part of rlib has various memory leaks (ref https://www.riscosopen.org/forum/forums/4/topics/9503) reflecting its abandoned state. See the FrontEnd module for a more flexible implementation of the same GUI-in-a-text-file scripting language.
The ctl API was not in C release 3 (it post dates that) nor in C release 4 manual, and the whole of rlib was removed from C release 5 in favour of the Toolbox.
The change log at the top of rlib/s/rl_spare shows it was briefly added in early 1990 then removed in April 1991. 26 years later, cull it from the Makefile too.

Version 5.94. Tagged as 'RISC_OSLib-5_94'
parent d89ca652
Control Files
=============
Author: William Stoye
History:
0.01
0.02
0.03 - 19-June-89 - remarks about help, and icons.
0.04 - 04-July-89 - ctl_make becomes ctl_init()
0.05 - 11-July-89 - more updates
0.06 - 12-July-89 - more updates
02-Jan-90 - I realise now that there are various shortcomings,
this thing has lain fallow for some time.
Key-bindings must be specific to specific contexts,
as different windows might have different ones.
Interactive help on menu entries (perhaps via Messages
file) should be supported. Should better use of
DecodeArgs be made? None of these issues have yet been
investigated.
0.10 - 31-Jan-90 RMokady - Major changes to syntax !
* actions use OS_ReadArgs.
* Nested action blocks.
- Added interactive help support.
- Changed key bindings.
0.11 - 08-Feb-90 RMokady - Some more changes to syntax.
* added external menus.
* added colourmenu menu.
* added action on non leaf entries.
* added noreopen option for dbox.
* added submenu -1 support.
- added section about built in actions.
- added onclick section.
To do:
------
Escape sequences in quoted strings.
Help actions.
Better key names.
The 'ctl' module is a set of library facilities, written in C, allowing a
program to put a great deal of user event decoding into a resource file.
This file controls the mapping of menu, dialogue box and key events into
textually named actions, which are then executed by the program. It makes
programs easier to construct, and means that the result is customisable (to
some extent) by the user.
This is always called Control, and is a resource file within an application
directory.
File Syntax
-----------
# starts a comment line. Blank lines are ignored.
Each line is split into symbols, separated by spaces.
A symbol is any character sequence in matching quote marks, OR any
alphanumeric char sequence (underscore is also allowed, and the first
character may not be a number).
Escape sequences within quoted symbols are currently not supported.
Examples: hello
delete_file
"Hello there"
Symbol comparison is case-sensitive. Conventionally all keywords within a
Control file are entirely in lower case.
In the ensuring descriptions, items in angle brackets (unless otherwise
stated) are all symbols.
Actions and Action sequences
----------------------------
An action is a symbol.
Anything after the action on the same line is treated as arguments to the
action, arguments can be continued on the next line if the NL is immediately
preceded by \, otherwise a NL character is treated as space.
The symbol is the name of an operation that the application supports,
the actual set of operations available is defined by the application.
An action block is a sequence of one or more actions grouped inside
matching '{' , '}'. Action blocks can appear anywhere a single action can
appear. Action blocks can be nested. The closing '}' should be on a separate
line, otherwise it will be taken to be part of the argument list for the
preceding action.
so an action block should look something like:
... {
action1 args
action2 args
action3 args
} ...
You can have other symbols on the line following the '}' as it is not
an action.
Actions return an integer return code which is then passed on to the next
action executed.
Built in actions.
-----------------
The following built-in actions are always available:
error <error message> -- Produce the specified error message,
in the standard Wimp error message
window.
oscli .... -- The argument is passed to the OS_CLI.
OR * ...
showdbox <dbox name> -- Cancel the current menu and show
this dialogue box as a menu. (I.E. clicks
outside it close it).
quit -- Quit the application (I.E. calls exit(0)).
process -- See hot keys section below.
if <expr> -- Tests the return code returned from the last
action, if it is equal to <expr> the following
action or action block is executed, if not
the action or action block is skipped.
else -- Can only come after an if action, if the if
test failed the action or action block following
this action will be executed, if not it will be
skipped.
<Number> -- A number on its own simply sets the return code
to its value.
For example:
5 an_action
will pass a return code of 5 into an_action.
A control object header
-----------------------
Syntax: ctl <logical control object name>
This starts entries in a named control object.
A menu header
-------------
Syntax: menu <menu name> <menu title> <menu body>
OR menu <menu name> <menu title> colourmenu
OR menu <menu name> external
Used to start the declaration of a menu.
The first form defines a simple menu:
<menu title> is the text used for the menu title, if it is a valid
message token from the Messages file, the message text is used,
otherwise the actual text is used.
<menu body> is the menu body in the syntax used for menu_new, again this is
first matched against message tokens in the Messages file.
Note:
The menu body text should not include the ! and > symbols,
as submenus, and greying of menu entries is handled by the
ctl module (see below).
The second form is like the first form, but the menu body is a colour
selection menu (like the one used by edit to set the text colours).
The third form defines a menu who's title and body are specified by the
application at run time. Range checking on entry and submenu numbers is only
done when the application attaches the wimp menu structure at run time.
A Menu help token /action
--------------------------
Syntax: help token <token>
OR help action <action> (or action block) <-- NOT YET IMPLEMENTED
The first form gives a token for the interactive help messages to be used
with this menu the entry number (starting with 1) will be appended to the
token before it is searched for in the Messages file.
The second form gives the action sequence to be performed when help is
requested, the result code passed to the first (or only) action is the menu
entry number.
A menu open action
------------------
Syntax: onopen <action> (or action block)
This describes the actions to be performed when the menu is opened.
A menu reopen action
--------------------
Syntax: onreopen <action> (or action block)
This describes the actions to be performed when the menu is reopened,
as a result of the user using the ADJUST button.
A menu entry
------------
Syntax: entry <entry number> action (or action block)
This describes the actions to be performed when the user clicks
on the entry.
Entry numbers are checked against the number of entries in the menu,
and errors are generated if you try to specify an out of range entry number.
Entries on the menu which don't have actions defined for them, are greyed
out (unless they have submenus attached to them, see below).
An entry number of -1 means 'default' , if actions are specified for entry
-1 , entries with no actions will not be greyed out, but the actions
specified for entry -1 will be used for them.
The return code passed to the first action is the entry number on which
the user clicked.
A submenu
----------
Syntax: submenu <entry number> menu <submenu name>
OR submenu <entry number> dbox <dbox name>
OR submenu <entry number> warning action (or action block)
OR submenu <entry number> menu <submenu name> action (or action block)
OR submenu <entry number> dbox <dbox name> action (or action block)
The first form indicates a non-leaf menu entry. The submenu name must refer
to a previously defined menu, and matches the menu name given in the menu
header.
The second form indicates a non-leaf menu leading to a dbox. The dbox name
must refer to a previously defined dbox, and matches the dbox name given in
the dbox header.
The third form indicates a non-leaf menu entry which leads to some actions
this is different from entry n action ... because a right arrow will be
displayed in this position on the parent menu.
The fourth form is like the first form but allows you to specify the actions
to be performed if the user clicks on the menu entry leading to the submenu.
The fifth form is like the second form but allows you to specify the actions
to be performed if the user clicks on the menu entry leading to the dbox.
You can not have both
entry n action ...
and submenu n ...
for the same menu.
If you use -1 as the entry number, all entries without specific actions / or
submenus will lead to the submenu / dbox specified.
The end of a menu
-----------------
Syntax: endmenu
This should appear at the end of a menu description. Menu descriptions
cannot be nested.
A dialogue box header
---------------------
Syntax: dbox <dbox name>
Used to start the declaration of a dbox.
A dialogue box template name.
-----------------------------
Syntax template <template name>
The correspondingly named template
(typically in the resource file Templates) will be used to describe the
visual appearance of the dialogue box. The template directive must appear
before any icon actions in the dbox description.
A dialogue box help token /action
---------------------------------
Syntax: help token <token>
OR help action <action> (or action block) <-- NOT YET IMPLEMENTED
The first form gives a token for the interactive help messages to be used
with this dbox the icon number (starting with 0) will be appended to the
token before it is searched for in the Messages file. Unless the pointer is
not over an icon in which case the unmodified token will be used.
The second form gives the action sequence to be performed when help
is requested, the result code passed to the first (or only) action
is the icon number (or -1 if not over an icon).
A dialogue box open action
--------------------------
Syntax: onopen <action sequence>
This describes the actions to be obeyed every time a dialogue box is opened
(and just before it is first displayed).
A dialogue box reopen action
----------------------------
Syntax: onreopen <action sequence>
This describes the actions to be obeyed every time a dialogue box is
reopened (as a result of the user clicking ADJUST on an icon).
Dialogue boxes with noreopen.
-----------------------------
Syntax: noreopen
This prevents the dbox from being reopened by a right click.
If the user right clicks in the dbox the menu tree from which the dbox is
hanging will remain open, but the dbox will be closed.
You can not have both onreopen and noreopen in the same dbox description.
A dialogue box close action
---------------------------
Syntax: onclose <action sequence>
This describes the actions to be obeyed every time a dialogue box is closed.
A dialogue box icon action
--------------------------
Syntax: icon <icon number> <action sequence>
This describes the action to be taken when a hit occurs on the specified
icon.
Icons which don't have an action defined for them will be greyed out, unless
their button type is 'Never'.
An icon number of -1 means 'Default', if actions are specified for icon -1,
icons without actions will not be greyed out, but the actions specified for
icon -1 will be used for them.
The return code passed to the first action is the icon number.
The end of a dbox
-----------------
Syntax: enddbox
This should appear at the end of a dbox description. Dialogue box
descriptions cannot be nested.
Keystrokes
----------
Syntax: onkey keycode <action> (or action block)
OR: onkey [S][C] <keyname> <action> (or action block)
OR: onkey <Default> <action> (or action block)
with the first form the keycode (as returned by the W)mp is given)
with the second form, the key name is given, key names are:
For any normal key the symbol on the key (i.e. a for unshifted a or A for
shift+a). For special keys <keyname> (i.e. <f5> or <Print> with the angle
brackets as part of the name). The key name can be preceded by C to specify
Control+key or by S to specify Shift+key. S and C can be combined, so SC<f1>
is Shift+Control+<f1>.
Example:
onkey Sa action
onkey A action
onkey 65 action
are all equivalent.
Note: To specify Uppercase s or Uppercase c use Ss & Sc as S or C will
result in a syntax error. to specify # use S3 as # will begin a comment.
The key name <Default> is used to mean any other key.
The result code passed to the first action on the list is the key code.
The action process passes the key to the wimp, so
onkey <Default> process
will result in all undefined key presses being passed to the wimp.
The onclick action.
-------------------
Syntax: onclick action (or action block)
This specifies the actions to be executed when the user clicks on an icon in
the window to which the ctl is attached. The main use of this is for ctls
attached to the iconbar.
The return code passed to the first action on executed is the mouse button
state as returned from the wimp in the wimp_EBUT event.
The end of a 'ctl'
------------------
Syntax: endctl
......@@ -190,7 +190,6 @@ HEADERS =\
RISC_OSLib:h.colourpick \
RISC_OSLib:h.colourtran \
RISC_OSLib:h.coords \
RISC_OSLib:h.ctl \
RISC_OSLib:h.dbox \
RISC_OSLib:h.dboxfile \
RISC_OSLib:h.dboxquery \
......@@ -398,7 +397,7 @@ ROM_OBJS =\
#
RLIB_OBJS =\
o_rl.akbd o_rl.alarm o_rl.baricon o_rl.bastxt o_rl.bbc o_rl.colourmenu \
o_rl.colourtran o_rl.coords o_rl.ctl o_rl.dbox o_rl.dboxfile o_rl.dboxquery \
o_rl.colourtran o_rl.coords o_rl.dbox o_rl.dboxfile o_rl.dboxquery \
o_rl.dboxtcol o_rl.dragasprit o_rl.drawcheck o_rl.drawfdiag o_rl.drawfiles \
o_rl.drawfobj o_rl.drawmod o_rl.drawtextc o_rl.event o_rl.fileicon o_rl.flex \
o_rl.font o_rl.fontlist o_rl.fontselect o_rl.heap o_rl.help o_rl.jpeg o_rl.magnify o_rl.menu \
......@@ -413,7 +412,7 @@ RLIB_OBJS =\
#
RLIB_MOD_OBJS =\
m_o_rl.akbd m_o_rl.alarm m_o_rl.baricon m_o_rl.bastxt m_o_rl.bbc \
m_o_rl.colourmenu m_o_rl.colourtran m_o_rl.coords m_o_rl.ctl m_o_rl.dbox \
m_o_rl.colourmenu m_o_rl.colourtran m_o_rl.coords m_o_rl.dbox \
m_o_rl.dboxfile m_o_rl.dboxquery m_o_rl.dboxtcol m_o_rl.dragasprit \
m_o_rl.drawcheck m_o_rl.drawfdiag m_o_rl.drawfiles m_o_rl.drawfobj m_o_rl.drawmod \
m_o_rl.drawtextc m_o_rl.event m_o_rl.fileicon m_o_rl.flex m_o_rl.font \
......@@ -704,7 +703,6 @@ RISC_OSLib:h.colourmenu: rlib.h.colourmenu; ${CP} rlib.h.colourmenu $@ ${CPFLAG
RISC_OSLib:h.colourpick: rlib.h.colourpick; ${CP} rlib.h.colourpick $@ ${CPFLAGS}
RISC_OSLib:h.colourtran: rlib.h.colourtran; ${CP} rlib.h.colourtran $@ ${CPFLAGS}
RISC_OSLib:h.coords: rlib.h.coords; ${CP} rlib.h.coords $@ ${CPFLAGS}
RISC_OSLib:h.ctl: rlib.h.ctl; ${CP} rlib.h.ctl $@ ${CPFLAGS}
RISC_OSLib:h.dbox: rlib.h.dbox; ${CP} rlib.h.dbox $@ ${CPFLAGS}
RISC_OSLib:h.dboxfile: rlib.h.dboxfile; ${CP} rlib.h.dboxfile $@ ${CPFLAGS}
RISC_OSLib:h.dboxquery: rlib.h.dboxquery; ${CP} rlib.h.dboxquery $@ ${CPFLAGS}
......
......@@ -11,13 +11,13 @@
GBLS Module_HelpVersion
GBLS Module_ComponentName
GBLS Module_ComponentPath
Module_MajorVersion SETS "5.93"
Module_Version SETA 593
Module_MajorVersion SETS "5.94"
Module_Version SETA 594
Module_MinorVersion SETS ""
Module_Date SETS "03 Sep 2017"
Module_ApplicationDate SETS "03-Sep-17"
Module_Date SETS "29 Oct 2017"
Module_ApplicationDate SETS "29-Oct-17"
Module_ComponentName SETS "RISC_OSLib"
Module_ComponentPath SETS "castle/RiscOS/Sources/Lib/RISC_OSLib"
Module_FullVersion SETS "5.93"
Module_HelpVersion SETS "5.93 (03 Sep 2017)"
Module_FullVersion SETS "5.94"
Module_HelpVersion SETS "5.94 (29 Oct 2017)"
END
/* (5.93)
/* (5.94)
*
* This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.1.
*
*/
#define Module_MajorVersion_CMHG 5.93
#define Module_MajorVersion_CMHG 5.94
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 03 Sep 2017
#define Module_Date_CMHG 29 Oct 2017
#define Module_MajorVersion "5.93"
#define Module_Version 593
#define Module_MajorVersion "5.94"
#define Module_Version 594
#define Module_MinorVersion ""
#define Module_Date "03 Sep 2017"
#define Module_Date "29 Oct 2017"
#define Module_ApplicationDate "03-Sep-17"
#define Module_ApplicationDate "29-Oct-17"
#define Module_ComponentName "RISC_OSLib"
#define Module_ComponentPath "castle/RiscOS/Sources/Lib/RISC_OSLib"
#define Module_FullVersion "5.93"
#define Module_HelpVersion "5.93 (03 Sep 2017)"
#define Module_LibraryVersionInfo "5:93"
#define Module_FullVersion "5.94"
#define Module_HelpVersion "5.94 (29 Oct 2017)"
#define Module_LibraryVersionInfo "5:94"
/* Copyright 1996 Acorn Computers Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* ctl.c
*
* User interface Control file handling.
*
* Author: Ran Mokady.
*
* History:
* 09-Feb-90 Linked into Risc_OSLib.
*
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "kernel.h"
#include "swis.h"
#include "msgs.h"
#include "wimp.h"
#include "wimpt.h"
#include "win.h"
#include "werr.h"
#include "event.h"
#include "res.h"
#include "menu.h"
#include "dbox.h"
#include "akbd.h"
#include "template.h"
#include "colourmenu.h"
#include "ctl.h"
#ifdef LOG
static FILE *logfile;
#endif
#ifndef Wimp_GetMenuState
#define Wimp_GetMenuState 0x400f4
#endif
#define MAX(a,b) a>b?a:b
#define MIN(a,b) a<b?a:b
/****************************** Data types *********************************/
typedef enum {
ctl_ACT_FUNCTION = 1,
ctl_ACT_STRING = 2,
ctl_ACT_LABEL = 3
} ctl__actiontype;
typedef enum {
ctl_TOK_STRING = -4,
ctl_TOK_NUMBER = -3,
ctl_TOK_ACTION = -2,
ctl_TOK_UNKNOWN = -1,
ctl_TOK_EOF = 0,
ctl_TOK_CTL = 1,
ctl_TOK_MENU = 2,
ctl_TOK_ENTRY = 3,
ctl_TOK_ENDMENU = 4,
ctl_TOK_ONOPEN = 5,
ctl_TOK_ONCLOSE = 6,
ctl_TOK_DBOX = 7,
ctl_TOK_ICON = 8,
ctl_TOK_ENDDBOX = 9,
ctl_TOK_ONKEY = 10,
ctl_TOK_EOL = 11,
ctl_TOK_OPENBLOCK = 12,
ctl_TOK_CLOSEBLOCK = 13,
ctl_TOK_ENDCTL = 14,
ctl_TOK_SUBMENU = 15,
ctl_TOK_COMMENT = 16,
ctl_TOK_WARNING = 17,
ctl_TOK_ONREOPEN = 18,
ctl_TOK_TEMPLATE = 19,
ctl_TOK_HELP = 20,
ctl_TOK_TOKEN = 21,
ctl_TOK_HELPACTION = 22,
ctl_TOK_COLOURMENU = 23,
ctl_TOK_EXTERNAL = 24,
ctl_TOK_NOREOPEN = 25,
ctl_TOK_ONCLICK = 26
} ctl__token;
typedef enum {
ctl_ST_PRELOAD = 0,
ctl_ST_LOADING = 1,
ctl_ST_LOADED = 2,
ctl_ST_CTLDEF = 3,
ctl_ST_MENUDEF = 4,
ctl_ST_DBOXDEF = 5,
ctl_ST_GETACTION = 6,
ctl_ST_GETACTIONBLOCK = 7
} ctl__state;
typedef struct ctl__actstr {
char *name;
char *syntax;
BOOL internal;
BOOL disabled;
struct{
ctl_action_proc function;
void *handle;
}function;
struct ctl__actstr *next;
}ctl__actionstr;
typedef struct ctl__act {
ctl__actiontype type;
union
{
char *name;
ctl__actionstr *address;
} action;
char *args;
int line;
int nest;
struct ctl__act *next;
}ctl__action;
typedef union
{
ctl__action action;
int num;
char *string;
}ctl__tokenstr;
typedef struct ctl__mentry {
int num;
int disabled;
ctl__action *action;
ctl__action *help_action;
struct ctl__mentry *next;
} ctl__menu_entry;
typedef struct ctl__mnu {
char *name;
ctl__action *onopen;
ctl__action *onreopen;
ctl__menu_entry *entries;
menu menu_body;
char *mih_token;
int entrycount;
BOOL external;
wimp_menuitem *parent;
struct ctl__mnu *next;
} ctl__menu;
typedef struct ctl__icn {
int num;
int disabled;
BOOL ticked;
BOOL writeable; /*for possible future error chk when dbox is opened*/
ctl__action *action;
ctl__action *help_action;
struct ctl__icn *next;
} ctl__icon;
typedef union {
ctl__menu_entry *menu_entry;
ctl__icon *icon;
}ctl__entry;
typedef struct ctl__dbx {
char *name;
char *template;
ctl__action *onopen;
ctl__action *onreopen;
ctl__action *onclose;
ctl__icon *icons;
dbox dbox_body;
char *mih_token;
int iconcount;
BOOL displayed;
struct ctl__dbx *next;
}ctl__dbox;
typedef union {
ctl__menu *parent_menu;
ctl__dbox *parent_dbox;
}ctl__parent;
typedef struct ctl_ky {
int keycode;
ctl__action *action;
struct ctl_ky *next;
BOOL disabled;
}ctl__key;
typedef struct ctl_ctl {
char *name;
ctl__menu *menus;
ctl__dbox *dboxes;
ctl__key *keys;
ctl__action *onclick;
struct ctl_ctl *next;
}ctl;
typedef struct hndl
{
event_w w;
void *user_handle;
ctl *the_ctl;
ctl__menu *mnu;
ctl__dbox *the_dbox;
char *help_token;
struct hndl *next;
}ctl__handlestr;
typedef struct
{
char *name;
int code;
} ctl__keyvalstr;
typedef struct {
ctl__state state;
ctl *ctls;
ctl__actionstr *actions;
ctl__handlestr *handles;
ctl__handlestr *current_handle;
ctl__menu *current_menu;
ctl__menu *top_menu;
ctl__dbox *current_dbox;
int current_char;
int current_icon;
FILE *file;
int line;
int nest;
int return_code;
char last_menu_hit[30];
char external_hit[30];
int skip;
} ctl__statestr;
#define Argbuf_LEN 256
typedef union
{
int words[Argbuf_LEN];
char text[Argbuf_LEN*4];
} ctl__argbuf;
typedef struct
{
char *buffer;
int len;
char *valid;
int flag;
}ctl__indirectstr;
/*************************** Constants ************************************/
static ctl__keyvalstr ctl__keynames(int indx)
{
ctl__keyvalstr tmp;
tmp.name="ENDLIST";
tmp.code=-1;
switch (indx)
{
case 0: tmp.name="<f1>"; tmp.code= akbd_Fn+1; break;
case 1: tmp.name="<f2>"; tmp.code= akbd_Fn+2; break;
case 2: tmp.name="<f3>"; tmp.code= akbd_Fn+3; break;
case 3: tmp.name="<f4>"; tmp.code= akbd_Fn+4; break;
case 4: tmp.name="<f5>"; tmp.code= akbd_Fn+5; break;
case 5: tmp.name="<f6>"; tmp.code= akbd_Fn+6; break;
case 6: tmp.name="<f7>"; tmp.code= akbd_Fn+7; break;
case 7: tmp.name="<f8>"; tmp.code= akbd_Fn+8; break;
case 8: tmp.name="<f9>"; tmp.code= akbd_Fn+9; break;
case 9: tmp.name="<f10>"; tmp.code= akbd_Fn10; break;
case 10: tmp.name="<f11>"; tmp.code= akbd_Fn11; break;
case 11: tmp.name="<f12>"; tmp.code= akbd_Fn12; break;
case 12: tmp.name="<Print>"; tmp.code= akbd_Fn+0; break;
case 13: tmp.name="<Esc>"; tmp.code= 27; break;
case 14: tmp.name="<Insert>"; tmp.code=akbd_InsertK; break;
case 15: tmp.name="<Home>"; tmp.code= 30; break;
case 16: tmp.name="<PageUp>"; tmp.code=akbd_PageUpK; break;
case 17: tmp.name="<PageDown>"; tmp.code=akbd_PageDownK; break;
case 18: tmp.name="<Delete>"; tmp.code= 127; break;
case 19: tmp.name="<<-|>"; tmp.code= 8; break;
case 20: tmp.name="<Return>"; tmp.code= 13; break;
case 21: tmp.name="<Up>"; tmp.code= akbd_UpK; break;
case 22: tmp.name="<Down>"; tmp.code= akbd_DownK; break;
case 23: tmp.name="<Left>"; tmp.code= akbd_LeftK; break;
case 24: tmp.name="<Right>"; tmp.code= akbd_UpK; break;
case 25: tmp.name="<Tab>"; tmp.code= akbd_TabK; break;
case 26: tmp.name="<Break>"; tmp.code= 27; break;
case 27: tmp.name="<Copy>"; tmp.code= akbd_CopyK; break;
case 28: tmp.name="<Default>"; tmp.code= -1; break;
case 29: tmp.name="ENDLIST"; tmp.code= -1; break;
}
return tmp;
}
static char * ctl__tokens(int indx)
{
switch (indx)
{
case 0: return "ctl";
case 1: return "menu";
case 2: return "entry";
case 3: return "endmenu";
case 4: return "onopen";
case 5: return "onclose";
case 6: return "dbox";
case 7: return "icon";
case 8: return "enddbox";
case 9: return "onkey";
case 10: return "\n";
case 11: return "{";
case 12: return "}";
case 13: return "endctl";
case 14: return "submenu";
case 15: return "#";
case 16: return "warning";
case 17: return "onreopen";
case 18: return "template";
case 19: return "help";
case 20: return "token";
case 21: return "action";
case 22: return "colourmenu";
case 23: return "external";
case 24: return "noreopen";
case 25: return "onclick";
case 26: return "ENDLIST";
}
return "ENDLIST";
}
/*************************** Variables ************************************/
static ctl__statestr *ctls=NULL;
/******************************* Errors ***********************************/
static char * ctl__errtxt(int num)
{
switch (num)
{
case 0:
return "ctsyntx:Syntax error in Control file at line %i: %s"; /* 0 */
case 1:
return "ctnosp:Control: Not enough space."; /* 1 */
case 2:
return "ctinit:ctl_init called twice."; /* 2 */
case 3:
return "ctdupact:Duplicate definision for action %s."; /* 3 */
case 4:
return "ctdupld:ctl_load called twice."; /* 4 */
case 5:
return "ctnofil:Unable to open Control file."; /* 5 */
case 6:
return "ctlngth:Token too long."; /* 6 */
case 7:
return "cteof:Expected arguments but found EOF."; /* 7 */
case 8:
return "ctlnlng:Line too long."; /* 8 */
case 9:
return "ctunxeof:Unexpected EOF in Control file."; /* 9 */
case 10:
return "ctunxctl:Ctl not at top level."; /* 10 */
case 11:
return "ctmisctln:Ctl name not found."; /* 11 */
case 12:
return "ctunxmnu:Menu not in ctl top level."; /* 12 */
case 13:
return "ctmismnam:Menu name not found."; /* 13 */
case 14:
return "ctunxono:Onopen not in Menu or Dbox."; /* 14 */
case 15:
return "ctdupono:Duplicate Onopen in Menu or Dbox %s."; /* 15 */
case 16:
return "ctunxopb:command expected but found '{'"; /* 16 */
case 17:
return "ctunxedbx:enddbox not in dbox."; /* 17 */
case 18:
return "ctunxemnu:endmenu not in menu."; /* 18 */
case 19:
return "ctunxectl:endctl not in ctl."; /* 19 */
case 20:
return "ctunxeblk:unexpected '}'."; /* 20 */
case 21:
return "ctunxeact:command expected but found action."; /* 21 */
case 22:
return "ctunxestr:command expected but found string."; /* 22 */
case 23:
return "ctundfact:Undefined action."; /* 23 */
case 24:
return "ctunxent:entry not in menu."; /* 24 */
case 25:
return "ctbadent:bad entry number."; /* 25 */
case 26:
return "ctbadentn:invalid entry number (n<1 or n>last entry)."; /* 26 */
case 27:
return "ctdupent:duplicate entry number."; /* 27 */
case 28:
return "ctunxnst:'}' found at top level."; /* 28 */
case 29:
return "ctuexpnst:'}' expected."; /* 29 */
case 30:
return "ctunxdbx:dbox not in ctl top level."; /* 30 */
case 31:
return "ctmisdbxn:dbox name not found."; /* 31 */
case 32:
return "ctbaddbx:Unable to create dbox %s."; /* 32 */
case 33:
return "ctunxonc:onclose not in dbox."; /* 33 */
case 34:
return "ctduponc:duplicate onclose in dbox %s."; /* 34 */
case 35:
return "ctunxicn:icon not in dbox."; /* 35 */
case 36:
return "ctbadicn:bad icon number."; /* 36 */
case 37:
return "ctbadicnn:invalid icon number (n<0 or n>last icon)."; /* 37 */
case 38:
return "ctdupicn:duplicate icon number."; /* 38 */
case 39:
return "ctunxkey:onkey not in ctl top level."; /* 39 */
case 40:
return "ctbadkey:bad key name."; /* 40 */
case 41:
return "ctdupkey:duplicate hot key."; /* 41 */
case 42:
return "ctctlmis:Ctl %s not defined."; /* 42 */
case 43:
return "ctunksubm:Unknown submenu type."; /* 43 */
case 44:
return "ctunkact:Unknown action %s"; /* 44 */
case 45:
return "ctquoeof:EOF found in quoted string."; /* 45 */
case 46:
return "ctquoeol:EOL found in quoted string."; /* 46 */
case 47:
return "ctunsmnu:Dbox menus not supported by this wimp version.";/* 47 */
case 48:
return "ctnotact:'%s' is not an action."; /* 48 */
case 49:
return "ctnotact:dbox %s already displayed."; /* 49 */
case 50:
return "ctnotact:Unknown action %s in enable/disable action."; /* 50 */
case 51:
return "ctnotact:Unknown action %s in make action writeable."; /* 51 */
case 52:
return "ctunxtmp:Template not in dbox."; /* 52 */
case 53:
return "ctmistmpn:Template %s not found."; /* 53 */
case 54:
return "ctmistmp:missing template name."; /* 54 */
case 55:
return "ctmistmpd:No template defined for dbox %s."; /* 55 */
case 56:
return "ctduptmp:Duplicate template defined for dbox %s."; /* 56 */
case 57:
return "ctmismnut:Missing menu title."; /* 57 */
case 58:
return "ctmistbdy:Missing menu body."; /* 58 */
case 59:
return "ctmistmpd:Help not in menu / dbox."; /* 59 */
case 60:
return "ctmistmpd:Duplicate help token."; /* 60 */
case 61:
return "ctmistmpd:Missing help token."; /* 61 */
case 62:
return "ctmistmpd:Invalid help type."; /* 62 */
case 63:
return "ctdupcart:Duplicate entries for writeable action %s."; /* 63 */
case 64:
return "ctdupcart:External menu %s not defined by application."; /* 64 */
case 65:
return "ctexpextm:Menu %s should be an external menu."; /* 65 */
case 66:
return "ctdupcart:Main attached menu %s cannot be external."; /* 66 */
case 67:
return "ctdbxndisp:Dbox %s not displayed in make writable."; /* 67 */
case 68:
return "ctunxclk:onclick not in ctl top level."; /* 68 */
case 69:
return "ctdupclk:Duplicate onclick action."; /* 69 */
case 70:
return "ctunxels:else without if."; /* 70 */
case 71:
return "ctdupenth:duplicate help entry number."; /* 71 */
}
return "Internal error.";
}
static void ctl__syntax_error(int errnum,BOOL fatal)
{
if (fatal) fclose(ctls->file);
werr(fatal,msgs_lookup(ctl__errtxt(0)),ctls->line,
msgs_lookup(ctl__errtxt(errnum)));
}
static void ctl__error(int errnum,char *arg,BOOL fatal)
{
if (fatal) fclose(ctls->file);
if ((ctls==NULL) || (ctls->line==0))
werr(fatal,msgs_lookup(ctl__errtxt(errnum)),arg);
else
{
char errbuf[100];
sprintf(errbuf,msgs_lookup("ctlat: %s in Control line %%i"),
msgs_lookup(ctl__errtxt(errnum)));
werr(fatal,errbuf,arg,ctls->line);
}
}
/****************************** General Functions *************************/
static void *ctl__malloc(int size)
{
void *result=malloc(size);
if (result == NULL) ctl__error(1,NULL,TRUE);
return result;
}
static void ctl__free(void *ptr)
{
free(ptr);
}
/*
* ctl__iconcount(dbox *d)
*
* return number of icons in the dbox.
*
*/
static int ctl__iconcount(dbox *d)
{
wimp_i buffer[256];
wimp_which_block blk;
int i;
blk.window=dbox_syshandle(*d);
blk.bit_mask=0;
blk.bit_set=0;
wimp_which_icon(&blk,buffer);
for (i=0;buffer[i]!=-1;i++);
return i;
}
/*
* ctl__keynum(char *c)
*
* return number of a key from its name.
*
*/
static int ctl__keynum(char *c)
{
int shift=0,i=0,keynum;
for (i=0;i<2;i++)
{
if (*c=='S') { shift+=akbd_Sh; c++; }
if (*c=='C') { shift+=akbd_Ctl; c++; }
}
/* now we have the shift factor and c points to the name */
/* first try to find as special name */
i=0;
for (i=0;strcmp(ctl__keynames(i).name,"ENDLIST")!=0;i++)
{
if (strcmp(ctl__keynames(i).name,c)==0)
return ctl__keynames(i).code+shift;
}
if (*(c+1)!='\0') return -1; /* More than one char must be bad name */
keynum=*c;
if (shift & akbd_Sh) { if ((keynum & 32)==0) return -1; else keynum&=~32; }
if (shift & akbd_Ctl){ if ((keynum & 64)==0) return -1; else keynum&=~96; }
return keynum;
}
static wimp_menuitem *ctl__menu_item(menu m,int entry)
{
wimp_menuitem *item;
item=(wimp_menuitem *)((int)menu_syshandle(m)+sizeof(wimp_menuhdr));
return item+(entry-1);
}
static int ctl__count_menu_entries(wimp_menustr *m)
{
int count=1;
wimp_menuitem *item;
item=(wimp_menuitem *)((int)m+sizeof(wimp_menuhdr));
for (count=1;(item->flags & wimp_MLAST)==0;count++) item++;
return count;
}
static void ctl__read_args(char *syntax,char *line,ctl__argbuf *buffer)
{
_kernel_swi_regs r;
_kernel_oserror *e;
r.r[0]=(int)syntax;
r.r[1]=(int)line;
r.r[2]=(int)buffer;
r.r[3]=Argbuf_LEN*4;
if (e=_kernel_swi(XOS_Bit | OS_ReadArgs,&r,&r),e!=NULL)
werr(TRUE,msgs_lookup(ctl__errtxt(0)),ctls->line,e->errmess);
}
/* some things we need but need us. */
static void ctl__run(ctl__action *act);
static ctl__icon *ctl__find_icon(int num,ctl__dbox *a_dbox);
static BOOL ctl__process_event(wimp_eventstr *e);
static ctl__menu_entry *ctl__find_entry(int num,ctl__menu *a_menu);
static ctl__dbox *ctl__find_dbox(char *name,ctl *a_ctl);
/*************************** Internal action handlers**********************/
static ctl__handlestr *ctl__add_handle(event_w w,
void *userhandle,ctl *ct,ctl__menu *mnu)
{
ctl__handlestr *a_handle;
#ifdef LOG
fprintf(logfile,"New handle:\n");
#endif
if (ctls->handles==NULL)
a_handle = (ctls->handles=ctl__malloc(sizeof(ctl__handlestr)));
else
{
for(a_handle=ctls->handles;
(a_handle->next !=NULL) && (a_handle->w != w);
a_handle=a_handle->next);
if (a_handle->w!=w)
a_handle = (a_handle->next=ctl__malloc(sizeof(ctl__handlestr)));
}
a_handle->w=w;
a_handle->mnu=mnu;
a_handle->the_ctl=ct;
a_handle->user_handle=userhandle;
a_handle->help_token=NULL;
a_handle->next=NULL;
a_handle->the_dbox=NULL;
return a_handle;
}
static void ctl__remove_handle(event_w w)
{
ctl__handlestr *a_handle,*tmp;
if (ctls->handles==NULL) return;
if (ctls->handles->w==w)
{
a_handle=ctls->handles->next;
ctl__free(ctls->handles);
ctls->handles=a_handle;
return;
}
for(a_handle=ctls->handles;
(a_handle->next != NULL) && (a_handle->next->w != w);
a_handle=a_handle->next);
if (a_handle->next==NULL) return;
tmp=a_handle->next;
a_handle->next=a_handle->next->next;
ctl__free(tmp);
}
static ctl__handlestr *ctl__find_handle(event_w w)
{
ctl__handlestr *a_handle;
for(a_handle=ctls->handles;a_handle!=NULL;a_handle=a_handle->next)
if (a_handle->w==w) return a_handle;
return NULL;
}
static void ctl__dbox_event_handler(dbox d,ctl__dbox *a_dbox)
{
int inum=ctls->current_icon;
ctl__icon *icon;
d=d;
if ((inum==-1) && (wimpt_last_event()->e==wimp_EKEY)) return;
if ((inum==-1) && (wimpt_last_event()->e==wimp_EBUT) &&
(inum=wimpt_last_event()->data.but.m.i,inum<0))
return; if (inum==-1) return;
icon=ctl__find_icon(inum,a_dbox);
ctls->return_code=inum;
if (icon!=NULL) ctl__run(icon->action);
else if (icon=ctl__find_icon(-1,a_dbox),icon!=NULL)
ctl__run(icon->action);
}
static BOOL ctl__dbox_raw_event_handler(dbox d,wimp_eventstr *e,ctl__dbox *handle)
{
wimp_eventstr ev;
wimp_caretstr c,c1;
ctls->current_icon=-1;
if ((e->e==wimp_EKEY) && (e->data.key.chcode==13))
{
wimp_get_caret_pos(&c);
ctls->current_icon=e->data.key.c.i;
ctl__dbox_event_handler(d,handle);
wimp_get_caret_pos(&c1);
if ((c.w==c1.w) && (c.i==c1.i))
{
ctls->current_icon=-1;
return FALSE;
} else return TRUE;
}
else if ((e->e==wimp_ESEND) || (e->e==wimp_ESENDWANTACK))
return (ctl__process_event(e));
else if (e->e!=wimp_EBUT) return FALSE;
ctls->current_icon=-1;
if (e->data.but.m.bbits!=2) return FALSE;
ctls->current_icon=e->data.but.m.i;
ev.e=wimp_ESEND;
ev.data.msg.hdr.action=wimp_MMENUWARN;
ev.data.msg.data.menuwarn.x=e->data.but.m.x;
ev.data.msg.data.menuwarn.y=e->data.but.m.y;
wimpt_fake_event(&ev);
wimpt_poll(0,&ev);
ctl__dbox_event_handler(d,handle);
return TRUE;
}
static int ctl__quit_action(void *handle,void *type,void *arg,int rc)
{
handle=handle;
type=type;
arg=arg;
exit(0);
return rc;
}
static int ctl__showdbox(void *handle,void *type,void *arg,int rc)
{
ctl__argbuf *buf=(ctl__argbuf *)arg;
char dbox_name[20];
int len,i;
/* wimp_eventstr e; */
wimp_mousestr m;
ctl__dbox *a_dbox;
dbox d;
BOOL flag;
wimp_icon icn;
ctl__icon *icon;
handle=handle;
type=type;
wimp_create_menu((wimp_menustr *)-1,0,0);
len=*(char *)(buf->words[0]);
strncpy(dbox_name,(char *)(buf->words[0])+2,MIN(19,len));
dbox_name[MIN(len,20)]='\0';
a_dbox=ctl__find_dbox(dbox_name,ctls->current_handle->the_ctl);
if (a_dbox->displayed)
{
ctl__error(49,a_dbox->name,FALSE);
return 0;
}
d=dbox_new(a_dbox->template);
if (d==NULL) ctl__error(32,a_dbox->name,TRUE);
icon=ctl__find_icon(-1,a_dbox);
/* reflect state of actions on the icons. */
for (i=0;i<a_dbox->iconcount;i++)
{
wimp_get_icon_info(dbox_syshandle(d),i,&icn);
if ((icon!=NULL) || ((icn.flags & (0xf<<12))==wimp_BIGNORE))
dbox_unfadefield(d,i);
else dbox_fadefield(d,i);
}
for (icon=a_dbox->icons;icon!=NULL;icon=icon->next)
{
dbox_unfadefield(d,icon->num);
if (icon->ticked)
wimp_set_icon_state(
dbox_syshandle(d),icon->num,wimp_ISELECTED,wimp_ISELECTED);
else wimp_set_icon_state(dbox_syshandle(d),
icon->num,0,wimp_ISELECTED);
if (icon->disabled)
wimp_set_icon_state(
dbox_syshandle(d),icon->num,wimp_INOSELECT,wimp_INOSELECT);
else wimp_set_icon_state(dbox_syshandle(d),
icon->num,0,wimp_INOSELECT);
}
dbox_raw_eventhandler(d,
(dbox_raw_handler_proc) ctl__dbox_raw_event_handler,
a_dbox);
dbox_eventhandler(d,
(dbox_handler_proc) ctl__dbox_event_handler,a_dbox);
a_dbox->displayed=TRUE;
a_dbox->dbox_body=d;
ctls->current_dbox=a_dbox;
if (a_dbox->mih_token!=NULL)
{
ctl__handlestr *handle=
ctl__add_handle(dbox_syshandle(d),(void *) NULL,NULL,NULL);
handle->help_token=a_dbox->mih_token;
handle->the_ctl=NULL;
handle->the_dbox=a_dbox;
}
ctl__run(a_dbox->onopen);
wimp_get_point_info(&m);
dbox_show(d);
do
{
ctls->current_icon=-1;
if (dbox_fillin(d)==-1) break;
flag=dbox_persist();
if (flag) ctl__run(a_dbox->onreopen);
} while (flag);
ctl__run(a_dbox->onclose);
dbox_eventhandler(d,(dbox_handler_proc)0,a_dbox);
dbox_raw_eventhandler(d,(dbox_raw_handler_proc) 0,a_dbox);
a_dbox->displayed=FALSE;
if (a_dbox->mih_token!=NULL)
ctl__remove_handle(dbox_syshandle(d));
dbox_dispose(&d);
ctls->current_dbox=NULL;
return rc;
}
static int ctl__if_action(void *handle,void *type,void *arg,int rc)
{
ctl__argbuf *buf=(ctl__argbuf *)arg;
handle=handle;
type=type;
arg=arg;
if (rc!=*((int *) ( (char *) (buf->words[0])+1) ) )
{
ctls->skip=-2;
} else ctls->skip=-3;
return rc;
}
static int ctl__else_action(void *handle,void *type,void *arg,int rc)
{
handle=handle;
type=type;
arg=arg;
if (ctls->skip==-1) ctl__syntax_error(70,TRUE);
if (ctls->skip==-3) ctls->skip=-2; else ctls->skip=-1;
return rc;
}
static int ctl__error_action(void *handle,void *type,void *arg,int rc)
{
handle=handle;
type=type;
werr(0,(char *)arg);
return rc;
}
static int ctl__oscli_action(void *handle,void *type,void *arg,int rc)
{
handle=handle;
type=type;
arg=arg;
_kernel_oscli((char *)arg);
return rc;
}
static int ctl__number_action(void *handle,void *type,void *arg,int status)
{
handle=handle;
type=type;
status=status;
ctls->return_code=(int)arg;
return (int)arg;
}
static int ctl__processkey_action(void *handle,void *type,void *arg,int status)
{
handle=handle;
type=type;
arg=arg;
wimp_processkey(status);
ctls->return_code=status;
return status;
}
static int ctl__submenu_request(void *handle,void *type,void *arg,int status)
{
int i,stat;
ctl__icon *icon;
stat=(int)type;
handle=handle;
status=status;
if (wimpt_last_event()->e!=wimp_ESEND) return status;
switch ((int)type)
{
case 1:
case 3:
ctl__run(((ctl__menu *)arg)->onopen);
if ((((ctl__menu *)arg)->external) &&
(((ctl__menu *)arg)->menu_body==NULL))
ctl__error(64,((ctl__menu *)arg)->name,TRUE);
if (((ctl__menu *)arg)->external)
{
((ctl__menu *)arg)->parent->submenu=
(wimp_menustr *)(((ctl__menu *)arg)->menu_body);
wimp_create_submenu(
(wimp_menustr *)(((ctl__menu *)arg)->menu_body),
wimpt_last_event()->data.msg.data.menuwarn.x,
wimpt_last_event()->data.msg.data.menuwarn.y);
}
else wimp_create_submenu(
menu_syshandle(((ctl__menu *)arg)->menu_body),
wimpt_last_event()->data.msg.data.words[1],
wimpt_last_event()->data.msg.data.words[2]);
ctls->current_menu=(ctl__menu *)arg;
break;
case 2:
case 4:
{
dbox d;
BOOL flag;
wimp_icon icn;
ctl__handlestr *handle;
ctl__dbox *a_dbox=(ctl__dbox *)arg;
if (a_dbox->displayed)
{
ctl__error(49,a_dbox->name,FALSE);
return 0;
}
d=dbox_new(a_dbox->template);
if (d==NULL) ctl__error(32,a_dbox->name,TRUE);
icon=ctl__find_icon(-1,a_dbox);
/* reflect state of actions on the icons. */
for (i=0;i<a_dbox->iconcount;i++)
{
wimp_get_icon_info(dbox_syshandle(d),i,&icn);
if ((icon!=NULL) || ((icn.flags & (0xf<<12))==wimp_BIGNORE))
dbox_unfadefield(d,i);
else dbox_fadefield(d,i);
}
for (icon=a_dbox->icons;icon!=NULL;icon=icon->next)
{
dbox_unfadefield(d,icon->num);
if (icon->ticked)
wimp_set_icon_state(
dbox_syshandle(d),icon->num,wimp_ISELECTED,wimp_ISELECTED);
else wimp_set_icon_state(dbox_syshandle(d),
icon->num,0,wimp_ISELECTED);
if (icon->disabled)
wimp_set_icon_state(
dbox_syshandle(d),icon->num,wimp_INOSELECT,wimp_INOSELECT);
else wimp_set_icon_state(dbox_syshandle(d),
icon->num,0,wimp_INOSELECT);
}
dbox_raw_eventhandler(d,
(dbox_raw_handler_proc) ctl__dbox_raw_event_handler,
a_dbox);
dbox_eventhandler(d,
(dbox_handler_proc) ctl__dbox_event_handler,a_dbox);
a_dbox->displayed=TRUE;
a_dbox->dbox_body=d;
ctls->current_dbox=a_dbox;
handle=ctl__add_handle(dbox_syshandle(d),(void *) NULL,NULL,NULL);
handle->help_token=a_dbox->mih_token;
handle->the_ctl=NULL;
ctl__run(a_dbox->onopen);
dbox_show(d);
do
{
ctls->current_icon=-1;
if (dbox_fillin(d)==-1) break;
flag=dbox_persist();
if (flag)
{
ctl__menu *mnu=ctls->current_handle->mnu;
ctl__menu_entry *entry;
char *c;
for (c=ctls->last_menu_hit;*(c+1);c++)
{
ctl__run(mnu->onreopen);
entry=ctl__find_entry(*c,mnu);
if (entry==NULL) entry=ctl__find_entry(-1,mnu);
mnu=(ctl__menu *) entry->action->args;
}
ctl__run(mnu->onreopen);
if (!mnu->external)
ctl__menu_item(mnu->menu_body,*c)->submenu=
((a_dbox->onreopen)==(ctl__action *)-1) ?
(wimp_menustr *) 1 :
(wimp_menustr *) dbox_syshandle(d);
else
((wimp_menuitem *)
(((wimp_menustr *)mnu->menu_body)+1)+*c-1)
->submenu=
((a_dbox->onreopen)==(ctl__action *)-1) ?
(wimp_menustr *) 1 :
(wimp_menustr *) dbox_syshandle(d);
wimp_create_menu(
menu_syshandle(ctls->current_handle->mnu->menu_body),0,0);
ctl__run(((ctl__dbox *)arg)->onreopen);
}
} while (flag);
ctl__run(a_dbox->onclose);
dbox_eventhandler(d,(dbox_handler_proc)0,a_dbox);
dbox_raw_eventhandler(d,(dbox_raw_handler_proc) 0,a_dbox);
a_dbox->displayed=FALSE;
ctl__remove_handle(dbox_syshandle(d));
dbox_dispose(&d);
ctls->current_dbox=NULL;
}
break;
default:
break;
}
return status;
}
/*************************** Internal functions ***************************/
/*
* ctl__find_ctl(char *name):
*
* find named ctl.
*
*/
static ctl *ctl__find_ctl(char *name)
{
ctl *a_ctl;
for (a_ctl=ctls->ctls;a_ctl!=NULL;a_ctl=a_ctl->next)
if (strcmp(a_ctl->name,name)==0) return a_ctl;
ctl__error(42,name,TRUE);
/* NEVER */
return NULL;
}
/*
* ctl__find_menu(char *name,ctl *a_ctl):
*
* find named menu in given ctl.
*
*/
static ctl__menu *ctl__find_menu(char *name,ctl *a_ctl)
{
ctl__menu *a_menu;
for (a_menu=a_ctl->menus;a_menu!=NULL;a_menu=a_menu->next)
if (strcmp(a_menu->name,name)==0) return a_menu;
if (ctls->line==0)
werr(TRUE,msgs_lookup("mismnu:Menu %s mot defined in Ctl %s.")
,name,a_ctl->name);
else
werr(TRUE,
msgs_lookup("mismnu1:Menu %s mot defined in Ctl %s. at line %i.")
,name,a_ctl->name,ctls->line);
/* NEVER */
return NULL;
}
/*
* ctl__find_dbox(char *name,ctl *a_ctl):
*
* find named dbox in given ctl.
*
*/
static ctl__dbox *ctl__find_dbox(char *name,ctl *a_ctl)
{
ctl__dbox *a_dbox;
for (a_dbox=a_ctl->dboxes;a_dbox!=NULL;a_dbox=a_dbox->next)
if (strcmp(a_dbox->name,name)==0) return a_dbox;
if (ctls->line==0)
werr(TRUE,msgs_lookup("misdbx:Dbox %s mot defined in Ctl %s.")
,name,a_ctl->name);
else
werr(TRUE,
msgs_lookup("misdbx1:Dbox %s mot defined in Ctl %s. at line %i.")
,name,a_ctl->name,ctls->line);
/* NEVER */
return NULL;
}
/*
* ctl__find_entry(int num,ctl__menu *a_menu):
*
* find an entry in given menu return NULL if not found.
*
*/
static ctl__menu_entry *ctl__find_entry(int num,ctl__menu *a_menu)
{
ctl__menu_entry *an_entry;
for (an_entry=a_menu->entries;an_entry!=NULL;an_entry=an_entry->next)
if (an_entry->num==num) return an_entry;
return NULL;
}
/*
* ctl__find_icon(int num,ctl__dbox *a_dbox):
*
* find an icon in given dbox return NULL if not found.
*
*/
static ctl__icon *ctl__find_icon(int num,ctl__dbox *a_dbox)
{
ctl__icon *an_icon;
for (an_icon=a_dbox->icons;an_icon!=NULL;an_icon=an_icon->next)
if (an_icon->num==num) return an_icon;
return NULL;
}
static ctl__actionstr *ctl__find_action(ctl__actionstr *action,
ctl__actionstr *list,BOOL add,BOOL internal)
{
if (add && ctls->actions==NULL)
{
#ifdef LOG
fprintf(logfile,"New action %s:\n",action->name);
#endif
ctls->actions=(ctl__actionstr *)ctl__malloc(sizeof(ctl__actionstr));
*ctls->actions=*action;
return NULL;
}
if (list==NULL) return NULL;
else if ( (*(list->name)==*(action->name)) &&
(strcmp(list->name,action->name)==0) &&
(internal || !list->internal)) return list;
if (add && (list->next==NULL))
{
#ifdef LOG
fprintf(logfile,"New action %s:\n",action->name);
#endif
list->next=(ctl__actionstr *)ctl__malloc(sizeof(ctl__actionstr));
*list->next=*action;
return NULL;
}
return ctl__find_action(action,list->next,add,internal);
}
static void ctl__add_action(char *name,char *syntax,ctl_action_proc func,void *arg,
BOOL internal)
{
ctl__actionstr act;
act.name=name;
act.syntax=syntax;
act.next=NULL;
act.function.function=func;
act.function.handle=arg;
act.internal=internal;
act.disabled=FALSE;
if (ctl__find_action(&act,ctls->actions,TRUE,internal)!=NULL)
ctl__error(3,name,TRUE);
}
static void ctl__init(void)
{
if (ctls!=NULL) ctl__error(2,NULL,TRUE);
#ifdef LOG
logfile=fopen("adfs::0.$.ctllog","w");
fprintf(logfile,"Init:\n");
#endif
ctls=(ctl__statestr *)ctl__malloc(sizeof(ctl__statestr));
/* Space for state */
ctls->state=ctl_ST_PRELOAD;
ctls->ctls=NULL;
ctls->actions=NULL;
ctls->current_char=' ';
ctls->handles=NULL;
ctls->current_handle=NULL;
ctls->current_menu=NULL;
ctls->top_menu=NULL;
ctls->current_dbox=NULL;
ctls->line=1;
ctls->return_code=0;
ctls->current_icon=-1;
ctls->external_hit[0]='\0';
/* Define stanfard actions. */
/* Name Sntx Function Handle Intern? */
ctl__add_action("<submenu>" ,NULL, ctl__submenu_request, (void *) 1,TRUE);
ctl__add_action("<subdbox>" ,NULL, ctl__submenu_request, (void *) 2,TRUE);
ctl__add_action("<dsubmenu>" ,NULL, ctl__submenu_request, (void *) 3,TRUE);
ctl__add_action("<dsubdbox>" ,NULL, ctl__submenu_request, (void *) 4,TRUE);
ctl__add_action("<number>" ,NULL, ctl__number_action , (void *) 0,TRUE);
ctl__add_action("process" ,NULL, ctl__processkey_action,(void *) 0,FALSE);
ctl__add_action("quit" ,NULL, ctl__quit_action ,(void *) 0,FALSE);
ctl__add_action("if" ,"/e", ctl__if_action ,(void *) 0,FALSE);
ctl__add_action("else" ,NULL, ctl__else_action ,(void *) 0,FALSE);
ctl__add_action("error" ,NULL, ctl__error_action ,(void *) 0,FALSE);
ctl__add_action("oscli" ,NULL, ctl__oscli_action ,(void *) 0,FALSE);
ctl__add_action("*" ,NULL, ctl__oscli_action ,(void *) 0,FALSE);
ctl__add_action("showdbox" ,"/g", ctl__showdbox ,(void *) 0,FALSE);
}
#define TOKENLEN 256
#define LINELEN 255
/* ctl__skip_toeol:
* skip this line in input file.
* checks for length and eof.
*/
static void ctl__skip_toeol(void)
{
char c;
if (ctls->current_char==EOF) ctl__syntax_error(7,TRUE);
do
{
c=ctls->current_char;
ctls->current_char=fgetc(ctls->file);
if ((ctls->current_char=='\n') && (c=='\\'))
{
ctls->line++;
ctls->current_char=' ';
}
}
while ((ctls->current_char!='\n') && (ctls->current_char!=EOF));
}
/* ctl__readtoeol:
* read next word from input file. skip any leading spaces
* and tabs.
* checks for length and eof.
*/
static void ctl__readtoeol(char *buffer)
{
char *c=buffer;
if (ctls->current_char==EOF) ctl__syntax_error(7,TRUE);
do
{
*c++=ctls->current_char;
if (ctls->current_char=='\n') break;
if ((c-buffer)==LINELEN) ctl__syntax_error(8,TRUE);
ctls->current_char=fgetc(ctls->file);
if ((ctls->current_char=='\n') && (*(c-1)=='\\'))
{
*(c-1)=ctls->current_char=' ';
ctls->line++;
}
}
while ((ctls->current_char!='\n') && (ctls->current_char!=EOF));
*c++='\n';
*c='\0';
}
/* ctl__readword:
* read next word from input file. skip any leading spaces
* and tabs.
* checks for length and eof.
*/
static int ctl__readword(char *buffer)
{
char *c=buffer,sep;
if (ctls->current_char==EOF)
{
return EOF;
}
while (((ctls->current_char==' ') || (ctls->current_char=='\t'))
&& !feof(ctls->file)) ctls->current_char=fgetc(ctls->file);
if (ctls->current_char=='"')
{
sep='"';
ctls->current_char=fgetc(ctls->file);
} else sep=' ';
do
{
*c++=ctls->current_char;
if (c-buffer==TOKENLEN) ctl__syntax_error(6,TRUE);
ctls->current_char=fgetc(ctls->file);
}
while ((ctls->current_char!=sep) && (ctls->current_char!=EOF)
&& (ctls->current_char!='\n') && (*(c-1)!='\n') );
*c='\0';
if (sep=='"')
switch(ctls->current_char)
{
case EOF:
ctl__syntax_error(45,TRUE);
break;
case '\n':
ctl__syntax_error(46,TRUE);
break;
default:
ctls->current_char=fgetc(ctls->file);
break;
}
return 0;
}
/* read next token.
* Reads in the next token from the file return token id.
*/
static ctl__token ctl__read_next_token(ctl__tokenstr *value)
{
char buffer[TOKENLEN];
int n;
if (ctl__readword(buffer)==EOF) return ctl_TOK_EOF;
n=0;
while (strcmp(ctl__tokens(n),"ENDLIST")!=0)
{
if (strcmp(ctl__tokens(n),buffer)==0) return n+1;
n++;
}
if (sscanf(buffer,"%i",&value->num)==1)
{
if ((ctls->state!=ctl_ST_GETACTION) &&
(ctls->state!=ctl_ST_GETACTIONBLOCK)) return ctl_TOK_NUMBER;
else
{
ctl__actionstr act;
act.name="<number>";
value->action.args=(char *)(value->num);
value->action.type=ctl_ACT_FUNCTION;
value->action.action.address=
ctl__find_action(&act,ctls->actions,FALSE,TRUE);
return ctl_TOK_ACTION;
}
}
else
{
ctl__actionstr act;
act.name=buffer;
if (
(value->action.action.address=
ctl__find_action(&act,ctls->actions,FALSE,FALSE))!=NULL)
{
value->action.type=ctl_ACT_FUNCTION;
ctl__readtoeol(buffer);
#ifdef LOG
fprintf(logfile,"Action arguments:\n");
#endif
value->action.args=ctl__malloc(strlen(buffer)+1);
strcpy(value->action.args,buffer);
return ctl_TOK_ACTION;
}
else
{
#ifdef LOG
fprintf(logfile,"String:\n");
#endif
value->string=ctl__malloc(strlen(buffer)+1);
strcpy(value->string,buffer);
return ctl_TOK_STRING;
}
}
/* SHOULD NEVER GET HERE !!!!! */
return ctl_TOK_UNKNOWN;
}
/*
* ctl__new_ctl():
* Define a new ctl.
*/
static ctl *ctl__new_ctl(void)
{
ctl *a_ctl;
ctl__tokenstr tokenval;
#ifdef LOG
fprintf(logfile,"New ctl:\n");
#endif
if (ctls->ctls==NULL) /* First one */
{
ctls->ctls=(ctl *)ctl__malloc(sizeof(ctl));
a_ctl=ctls->ctls;
}
else
{
a_ctl=ctls->ctls;
while (a_ctl->next != NULL) a_ctl=a_ctl->next;
a_ctl->next=(ctl *)ctl__malloc(sizeof(ctl));
a_ctl=a_ctl->next;
}
/* Now a_ctl points to new space. */
if (ctl__read_next_token(&tokenval)!=ctl_TOK_STRING)
ctl__syntax_error(11,TRUE);
a_ctl->name=tokenval.string;
a_ctl->menus=NULL;
a_ctl->dboxes=NULL;
a_ctl->keys=NULL;
a_ctl->onclick=NULL;
a_ctl->next=NULL;
return a_ctl;
}
/* ctl__new_menu(ctl *current_ctl)
*
* define a new menu in the given ctl.
*
*/
static ctl__menu *ctl__new_menu(ctl *cctl)
{
ctl__menu *a_menu;
char *c,*body,*title;
ctl__tokenstr tokenval;
ctl__token token;
int i;
BOOL external=FALSE;
#ifdef LOG
fprintf(logfile,"New Menu:\n");
#endif
if (cctl->menus==NULL) /* First one */
{
cctl->menus=(ctl__menu *)ctl__malloc(sizeof(ctl__menu));
a_menu=cctl->menus;
}
else
{
a_menu=cctl->menus;
while (a_menu->next != NULL) a_menu=a_menu->next;
a_menu->next=(ctl__menu *)ctl__malloc(sizeof(ctl__menu));
a_menu=a_menu->next;
}
/* Now a_menu points to new space. */
if (ctl__read_next_token(&tokenval)!=ctl_TOK_STRING)
ctl__syntax_error(13,TRUE);
a_menu->name=tokenval.string;
a_menu->onopen=NULL;
a_menu->onreopen=NULL;
a_menu->entries=NULL;
a_menu->next=NULL;
a_menu->mih_token=NULL;
if ((token=ctl__read_next_token(&tokenval))==ctl_TOK_EXTERNAL)
{
a_menu->menu_body=NULL;
a_menu->entrycount=0;
external=TRUE;
a_menu->external=external;
return a_menu;
} else if (token!=ctl_TOK_STRING) ctl__syntax_error(57,TRUE);
title=tokenval.string;
if ((token=ctl__read_next_token(&tokenval))==ctl_TOK_COLOURMENU)
{
a_menu->menu_body=colourmenu_make(msgs_lookup(title),FALSE);
a_menu->entrycount=16;
ctl__free(title);
} else if (token!=ctl_TOK_STRING)
ctl__syntax_error(58,TRUE);
else
{
body=tokenval.string;
a_menu->menu_body=menu_new(msgs_lookup(title),msgs_lookup(body));
a_menu->entrycount=1;
for(c=msgs_lookup(body);*c!='\0';c++)
if ((*c==',') || (*c=='|')) a_menu->entrycount++;
ctl__free(title);
ctl__free(body);
}
a_menu->external=external;
if (!external) for (i=1;i<=a_menu->entrycount;i++)
menu_setflags(a_menu->menu_body,i,0,1);
return a_menu;
}
/* ctl__new_dbox(ctl *current_ctl)
*
* define a new dbox in the given ctl.
*
*/
static ctl__dbox *ctl__new_dbox(ctl *cctl)
{
ctl__dbox *a_dbox;
ctl__tokenstr tokenval;
#ifdef LOG
fprintf(logfile,"New Dbox:\n");
#endif
if (cctl->dboxes==NULL) /* First one */
{
cctl->dboxes=(ctl__dbox *)ctl__malloc(sizeof(ctl__dbox));
a_dbox=cctl->dboxes;
}
else
{
a_dbox=cctl->dboxes;
while (a_dbox->next != NULL) a_dbox=a_dbox->next;
a_dbox->next=(ctl__dbox *)ctl__malloc(sizeof(ctl__dbox));
a_dbox=a_dbox->next;
}
/* Now a_dbox points to new space. */
if (ctl__read_next_token(&tokenval)!=ctl_TOK_STRING)
ctl__syntax_error(31,TRUE);
a_dbox->name=tokenval.string;
a_dbox->onopen =NULL;
a_dbox->onreopen =NULL;
a_dbox->onclose =NULL;
a_dbox->icons =NULL;
a_dbox->next =NULL;
a_dbox->mih_token=NULL;
a_dbox->displayed=FALSE;
a_dbox->template=NULL;
return a_dbox;
}
/* ctl__add_to_actionlist
*
* add an action at the end of an action list.
*
*/
static ctl__action *ctl__add_to_actionlist(ctl__action *list,ctl__tokenstr *act)
{
if (list->action.name!=NULL)
{
#ifdef LOG
fprintf(logfile,"New action in action list:\n");
#endif
list->next=ctl__malloc(sizeof(ctl__action));
list=list->next;
}
*list=act->action;
list->line=ctls->line;
list->nest=ctls->nest;
list->next=NULL;
return list;
}
/*
* ctl__add_string_to_actionlist
*
* add a string as an action at the end of the actionlist.
*
*/
static ctl__action *ctl__add_string_to_actionlist(ctl__action *list,
ctl__tokenstr *act)
{
char buffer[LINELEN];
#ifdef LOG
fprintf(logfile,"String in action list:\n");
#endif
ctl__readtoeol(buffer);
act->action.action.name=act->string;
act->action.args=ctl__malloc(strlen(buffer)+1);
strcpy(act->action.args,buffer);
if ((act->string[0]=='(') && (act->string[strlen(act->string)-1]==')'))
act->action.type=ctl_ACT_LABEL;
else act->action.type=ctl_ACT_STRING;
return ctl__add_to_actionlist(list,act);
}
/*
* ctl__new_entry
*
* add new entry to given menu.
* return pointer to action list for the new entry.
*
*/
static ctl__action *ctl__new_entry(ctl__menu *menu,int entry)
{
ctl__menu_entry *an_entry;
int i;
#ifdef LOG
fprintf(logfile,"New Menu Entry:\n");
#endif
if (
(entry!=-1) &&
(!menu->external) &&
((entry<1) || (entry>menu->entrycount))
)
ctl__syntax_error(26,TRUE);
else if (!menu->external)
{
if (entry>0) menu_setflags(menu->menu_body,entry,0,0);
else for (i=1;i<=menu->entrycount;i++)
menu_setflags(menu->menu_body,i,0,0);
}
if (menu->entries==NULL) /* first entry */
{
menu->entries=(ctl__menu_entry *)ctl__malloc(sizeof(ctl__menu_entry));
an_entry=menu->entries;
}
else
{
an_entry=menu->entries;
if (an_entry->num==entry)
{
if (an_entry->action->action.name!=NULL) ctl__syntax_error(27,TRUE);
else return an_entry->action;
}
while (an_entry->next != NULL)
{
an_entry=an_entry->next;
if (an_entry->num==entry)
{
if (an_entry->action->action.name!=NULL) ctl__syntax_error(27,TRUE);
else return an_entry->action;
}
}
an_entry->next=(ctl__menu_entry *)ctl__malloc(sizeof(ctl__menu_entry));
an_entry=an_entry->next;
}
an_entry->num=entry;
an_entry->action=(ctl__action *)ctl__malloc(sizeof(ctl__action));
an_entry->action->action.name=NULL;
an_entry->disabled=0;
an_entry->next=NULL;
an_entry->help_action=NULL;
return an_entry->action;
}
/* add a new entry help action entry number is next token in file.
*
*
*
*/
static ctl__action *ctl__add_entry_help(ctl__menu *menu)
{
ctl__tokenstr tokenval;
ctl__menu_entry *an_entry;
#ifdef LOG
fprintf(logfile,"New Entry Help Action:\n");
#endif
if (ctl__read_next_token(&tokenval)!=ctl_TOK_NUMBER)
ctl__syntax_error(25,TRUE);
if ((an_entry=ctl__find_entry(tokenval.num,menu))==NULL)
{
ctl__new_entry(menu,tokenval.num);
an_entry=ctl__find_entry(tokenval.num,menu);
}
if (an_entry->help_action==NULL)
{
an_entry->help_action=(ctl__action *)ctl__malloc(sizeof(ctl__action));
an_entry->help_action->action.name=NULL;
return an_entry->help_action;
}
else ctl__syntax_error(71,TRUE);
/* Should never get here. */
return NULL;
}
/* add a new entry, entry number is next token in file.
*
*
*
*/
static ctl__action *ctl__add_new_entry_from_file(ctl__menu *menu)
{
ctl__tokenstr tokenval;
ctl__token token;
if ((token=ctl__read_next_token(&tokenval))==ctl_TOK_HELP)
return ctl__add_entry_help(menu);
if (token!=ctl_TOK_NUMBER)
ctl__syntax_error(25,TRUE);
return ctl__new_entry(menu,tokenval.num);
}
/*
* ctl__new_icon
*
* add new icon to given dbox.
*
*/
static ctl__action *ctl__new_icon(ctl__dbox *dbox,int inum)
{
ctl__icon *an_icon;
#ifdef LOG
fprintf(logfile,"New Icon:\n");
#endif
if ((inum!=-1) && ((inum<0) || (inum>=dbox->iconcount)))
ctl__syntax_error(37,TRUE);
if (dbox->icons==NULL) /* first icon */
{
dbox->icons=(ctl__icon *)ctl__malloc(sizeof(ctl__icon));
an_icon=dbox->icons;
}
else
{
an_icon=dbox->icons;
if (an_icon->num==inum)
{
if (an_icon->action->action.name!=NULL) ctl__syntax_error(38,TRUE);
else return an_icon->action;
}
while (an_icon->next != NULL)
{
an_icon=an_icon->next;
if (an_icon->num==inum)
{
if (an_icon->action->action.name!=NULL) ctl__syntax_error(38,TRUE);
else return an_icon->action;
}
}
an_icon->next=(ctl__icon *)ctl__malloc(sizeof(ctl__icon));
an_icon=an_icon->next;
}
an_icon->num=inum;
an_icon->action=(ctl__action *)ctl__malloc(sizeof(ctl__action));
an_icon->action->action.name=NULL;
an_icon->disabled=0;
an_icon->ticked=FALSE;
an_icon->help_action=NULL;
an_icon->next=NULL;
return an_icon->action;
}
static ctl__action *ctl__add_icon_help(ctl__dbox *dbox)
{
ctl__tokenstr tokenval;
ctl__icon *an_icon;
#ifdef LOG
fprintf(logfile,"New Icon Help:\n");
#endif
if (ctl__read_next_token(&tokenval)!=ctl_TOK_NUMBER)
ctl__syntax_error(36,TRUE);
if ((an_icon=ctl__find_icon(tokenval.num,dbox))==NULL)
{
ctl__new_icon(dbox,tokenval.num);
an_icon=ctl__find_icon(tokenval.num,dbox);
}
if (an_icon->help_action==NULL)
{
an_icon->help_action=(ctl__action *) ctl__malloc(sizeof(ctl__action));
an_icon->help_action->action.name=NULL;
return an_icon->help_action;
}
else ctl__syntax_error(71,TRUE);
/* Should never get here. */
return NULL;
}
/*
* ctl__add_new_icon_from_file
*
* add new icon to given dbox. icon number is next token in file.
*
*/
static ctl__action *ctl__add_new_icon_from_file(ctl__dbox *dbox)
{
ctl__tokenstr tokenval;
ctl__token token;
/* get icon number */
if ((token=ctl__read_next_token(&tokenval))==ctl_TOK_HELP)
return ctl__add_icon_help(dbox);
if (token!=ctl_TOK_NUMBER)
ctl__syntax_error(36,TRUE);
return ctl__new_icon(dbox,tokenval.num);
}
/*
* ctl__new_key
*
* add new entry to given ctl.
*
*/
static ctl__action *ctl__new_key(ctl *cctl)
{
ctl__tokenstr tokenval;
ctl__key *a_key;
int keynum;
ctl__token token;
#ifdef LOG
fprintf(logfile,"New Hot Key:\n");
#endif
/* get entry number */
keynum=-1;
if ((token=ctl__read_next_token(&tokenval))==ctl_TOK_NUMBER)
keynum=tokenval.num;
else if (token==ctl_TOK_STRING) keynum=ctl__keynum(tokenval.string);
if (keynum==-1) ctl__syntax_error(40,TRUE);
if (cctl->keys==NULL) /* first entry */
{
cctl->keys=(ctl__key *)ctl__malloc(sizeof(ctl__key));
a_key=cctl->keys;
}
else
{
a_key=cctl->keys;
if (a_key->keycode==keynum) ctl__syntax_error(41,TRUE);
while (a_key->next != NULL)
{
a_key=a_key->next;
if (a_key->keycode==keynum) ctl__syntax_error(41,TRUE);
}
a_key->next=(ctl__key *)ctl__malloc(sizeof(ctl__key));
a_key=a_key->next;
}
a_key->keycode=keynum;
a_key->action=(ctl__action *)ctl__malloc(sizeof(ctl__action));
a_key->action->action.name=NULL;
a_key->action->next=NULL;
a_key->disabled=FALSE;
a_key->next=NULL;
return a_key->action;
}
/*
* ctl__submenu
*
* attach submenu to given menu.
*
*/
static ctl__action *ctl__submenu(ctl *cctl,ctl__menu *a_menu)
{
ctl__token token;
ctl__tokenstr tokenval;
ctl__action *actionlist;
ctl__actionstr act;
int entry;
ctl__menu *submenu;
ctl__dbox *a_dbox;
/* get entry number */
if (ctl__read_next_token(&tokenval)!=ctl_TOK_NUMBER)
ctl__syntax_error(25,TRUE);
if (
(tokenval.num!=-1) &&
(!a_menu->external) &&
((tokenval.num<1) || (tokenval.num>a_menu->entrycount))
)
ctl__syntax_error(26,TRUE);
if (ctl__find_entry(tokenval.num,a_menu)!=NULL)
ctl__syntax_error(27,TRUE);
entry=tokenval.num;
if ((token=ctl__read_next_token(&tokenval))==ctl_TOK_MENU)
{
if (ctl__read_next_token(&tokenval)!=ctl_TOK_STRING)
ctl__syntax_error(13,TRUE);
submenu=ctl__find_menu(tokenval.string,cctl);
if (!a_menu->external)
{
int en;
for (en=((entry==-1)?1:entry);
en<=((entry==-1)?a_menu->entrycount:entry);
en++)
{
ctl__menu_item(a_menu->menu_body,en)->flags|=wimp_MSUBLINKMSG;
ctl__menu_item(a_menu->menu_body,en)->submenu=
(submenu->external ? (wimp_menustr *)1 :
menu_syshandle(submenu->menu_body));
if (submenu->external)
submenu->parent=ctl__menu_item(a_menu->menu_body,en);
menu_setflags(a_menu->menu_body,en,0,0);
}
}
actionlist=ctl__new_entry(a_menu,entry);
actionlist->type=ctl_ACT_FUNCTION;
act.name="<submenu>";
actionlist->action.address=
ctl__find_action(&act,ctls->actions,FALSE,TRUE);
actionlist->args=(char *)submenu;
actionlist->line=ctls->line;
actionlist->nest=ctls->nest;
actionlist->next=NULL;
return actionlist;
}
else if (token==ctl_TOK_DBOX)
{
if (ctl__read_next_token(&tokenval)!=ctl_TOK_STRING)
ctl__syntax_error(31,TRUE);
a_dbox=ctl__find_dbox(tokenval.string,cctl);
if (!a_menu->external)
{
int en;
for (en=((entry==-1)?1:entry);
en<=((entry==-1)?a_menu->entrycount:entry);
en++)
{
ctl__menu_item(a_menu->menu_body,en)->submenu=(wimp_menustr *) a_dbox;
ctl__menu_item(a_menu->menu_body,en)->flags|=wimp_MSUBLINKMSG;
menu_setflags(a_menu->menu_body,en,0,0);
}
}
actionlist=ctl__new_entry(a_menu,entry);
actionlist->type=ctl_ACT_FUNCTION;
act.name="<subdbox>";
actionlist->action.address=
ctl__find_action(&act,ctls->actions,FALSE,TRUE);
actionlist->args=(char *)a_dbox;
actionlist->line=ctls->line;
actionlist->nest=ctls->nest;
actionlist->next=NULL;
return actionlist;
}
else if (token==ctl_TOK_WARNING)
{
if (!a_menu->external)
{
int en;
for (en=((entry==-1)?1:entry);
en<=((entry==-1)?a_menu->entrycount:entry);
en++)
{
ctl__menu_item(a_menu->menu_body,en)->flags|=wimp_MSUBLINKMSG;
menu_setflags(a_menu->menu_body,en,0,0);
ctl__menu_item(a_menu->menu_body,en)->submenu=(wimp_menustr *)1;
}
}
return ctl__new_entry(a_menu,entry);
} else ctl__syntax_error(43,TRUE);
/*NEVER */
return NULL;
}
/*
* ctl__subdboxmenu
*
* attach submenu to given dbox.
*
*/
static ctl__action *ctl__subdboxmenu(ctl *cctl,ctl__dbox *dbx)
{
ctl__token token;
ctl__tokenstr tokenval;
ctl__action *actionlist;
ctl__actionstr act;
int icon;
ctl__dbox *a_dbox;
#ifdef DBOXSUBMENUS
ctl__menu *submenu;
#endif
/* get icon number */
if (ctl__read_next_token(&tokenval)!=ctl_TOK_NUMBER)
ctl__syntax_error(25,TRUE);
if ((tokenval.num!=-1) &&
((tokenval.num<0) || (tokenval.num>=dbx->iconcount)))
ctl__syntax_error(26,TRUE);
if (ctl__find_icon(tokenval.num,dbx)!=NULL)
ctl__syntax_error(27,TRUE);
icon=tokenval.num;
if ((token=ctl__read_next_token(&tokenval))==ctl_TOK_MENU)
{
#ifndef DBOXMENUS
ctl__syntax_error(47,TRUE);
#else
if (ctl__read_next_token(&tokenval)!=ctl_TOK_STRING)
ctl__syntax_error(13,TRUE);
submenu=ctl__find_menu(tokenval.string,cctl);
actionlist=ctl__new_icon(dbx,icon);
actionlist->type=ctl_ACT_FUNCTION;
act.name="<dsubmenu>";
actionlist->action.address=
ctl__find_action(&act,ctls->actions,FALSE,TRUE);
actionlist->args=(char *)submenu;
actionlist->line=ctls->line;
actionlist->nest=ctls->nest;
actionlist->next=NULL;
return actionlist;
#endif /* DBOXMENUS */
}
else if (token==ctl_TOK_DBOX)
{
if (ctl__read_next_token(&tokenval)!=ctl_TOK_STRING)
ctl__syntax_error(31,TRUE);
a_dbox=ctl__find_dbox(tokenval.string,cctl);
actionlist=ctl__new_icon(dbx,icon);
actionlist->type=ctl_ACT_FUNCTION;
act.name="<dsubdbox>";
actionlist->action.address=
ctl__find_action(&act,ctls->actions,FALSE,TRUE);
actionlist->args=(char *)a_dbox;
actionlist->line=ctls->line;
actionlist->nest=ctls->nest;
actionlist->next=NULL;
return actionlist;
}
else ctl__syntax_error(43,TRUE);
/*NEVER */
return NULL;
}
static int ctl__exec(ctl__action *action)
{
ctl__argbuf argbuf;
if (action->type==ctl_ACT_FUNCTION)
{
if (action->action.address->syntax==NULL)
return (int) (action->action.address->function.function(
ctls->current_handle->user_handle,
action->action.address->function.handle,
action->args,
ctls->return_code));
else
{
ctl__read_args(action->action.address->syntax,action->args,&argbuf);
return (int)(action->action.address->function.function(
ctls->current_handle->user_handle,
action->action.address->function.handle,
(char *) &argbuf,
ctls->return_code));
}
}
else
{
ctl__actionstr act,*actpos;
act.name=action->action.name;
actpos=ctl__find_action(&act,ctls->actions,FALSE,FALSE);
if (actpos==NULL)
{
if (action->type==ctl_ACT_LABEL) return 0;
ctls->line=action->line;
ctl__error(44,act.name,FALSE);
return 0;
}
else
{
if (actpos->syntax==NULL)
return (int)(actpos->function.function(
ctls->current_handle->user_handle,
actpos->function.handle,
action->args,
ctls->return_code));
else
{
ctl__read_args(actpos->syntax,action->args,&argbuf);
return (int)(actpos->function.function(
ctls->current_handle->user_handle,
actpos->function.handle,
(char *) &argbuf,
ctls->return_code));
}
}
}
return 0;
}
static void ctl__run(ctl__action *action)
{
BOOL submenu=(wimpt_last_event()->e!=wimp_EMENU);
BOOL skipflag=FALSE;
ctl__action *an_action=action;
int tmp_skip=ctls->skip;
#ifdef LOG
if (logfile!=NULL)
{
fclose(logfile);
logfile=NULL;
}
#endif
if ((action==NULL) || (action==(ctl__action *)-1)) return;
ctls->skip=-1;
for (an_action=action;an_action!=NULL;an_action=an_action->next)
{
if (skipflag)
{
skipflag=FALSE;
continue;
}
if ((ctls->skip<0) || (ctls->skip>=an_action->nest))
{
ctls->return_code=ctl__exec(an_action);
if (ctls->skip==-2)
{
ctls->skip=an_action->nest;
skipflag=TRUE;
} else if (ctls->skip!=-3) ctls->skip=-1;
if ((an_action->type==ctl_ACT_FUNCTION) &&
(an_action->action.address->function.function==ctl__submenu_request) &&
(submenu)
) break;
}
}
ctls->skip=tmp_skip;
}
static void ctl__get_template(ctl__dbox *a_dbox)
{
ctl__tokenstr token;
if (ctl__read_next_token(&token)!=ctl_TOK_STRING)
ctl__syntax_error(54,TRUE);
if (template_find(token.string)==NULL)
ctl__error(53,token.string,TRUE);
a_dbox->template=token.string;
a_dbox->dbox_body=dbox_new(token.string);
if (a_dbox->dbox_body==NULL) ctl__error(32,a_dbox->name,TRUE);
a_dbox->iconcount=ctl__iconcount(&a_dbox->dbox_body);
dbox_dispose(&a_dbox->dbox_body);
}
static void ctl__get_dbox_help(ctl__dbox *a_dbox)
{
ctl__tokenstr token;
ctl__token type;
type=ctl__read_next_token(&token);
if (type==ctl_TOK_HELPACTION) werr(1,"Action help not implemented.");
if (type!=ctl_TOK_TOKEN) ctl__syntax_error(62,TRUE);
if (a_dbox->mih_token!=NULL) ctl__syntax_error(60,TRUE);
if (ctl__read_next_token(&token)!=ctl_TOK_STRING)
ctl__syntax_error(61,TRUE);
a_dbox->mih_token=token.string;
}
static void ctl__get_menu_help(ctl__menu *a_menu)
{
ctl__tokenstr token;
ctl__token type;
type=ctl__read_next_token(&token);
if (type==ctl_TOK_HELPACTION) werr(1,"Action help not implemented.");
if (type!=ctl_TOK_TOKEN) ctl__syntax_error(62,TRUE);
if (a_menu->mih_token!=NULL) ctl__syntax_error(60,TRUE);
if (ctl__read_next_token(&token)!=ctl_TOK_STRING)
ctl__syntax_error(61,TRUE);
a_menu->mih_token=token.string;
}
/* ctl__load :
* open and load the control file.
* if errors is TRUE generate errors for non exsistant actions.
*/
static void ctl__load(BOOL errors)
{
FILE *control;
ctl__token token;
ctl__tokenstr value;
ctl *current_ctl=NULL;
ctl__menu *current_menu=NULL;
ctl__dbox *current_dbox=NULL;
ctl__action *action_list=NULL;
ctl__state saved_state=ctl_ST_LOADING;
if (control=res_openfile("Control","r"),control==NULL)
{
ctl__error(5,NULL,TRUE);
return;
}
ctls->file=control;
ctls->state=ctl_ST_LOADING;
ctls->nest=0;
do
{
token=ctl__read_next_token(&value);
switch(token)
{
case ctl_TOK_EOF:
fclose(ctls->file);
if (ctls->state!=ctl_ST_LOADING) ctl__error(9,NULL,TRUE);
if (ctls->nest!=0) ctl__syntax_error(29,TRUE);
break;
case ctl_TOK_CTL:
if (ctls->state!=ctl_ST_LOADING) ctl__syntax_error(10,TRUE);
if (ctls->nest!=0) ctl__syntax_error(29,TRUE);
current_ctl=ctl__new_ctl();
ctls->state=ctl_ST_CTLDEF;
break;
case ctl_TOK_MENU:
if (ctls->state!=ctl_ST_CTLDEF) ctl__syntax_error(10,TRUE);
if (ctls->nest!=0) ctl__syntax_error(29,TRUE);
current_menu=ctl__new_menu(current_ctl);
ctls->state=ctl_ST_MENUDEF;
break;
case ctl_TOK_DBOX:
if (ctls->state!=ctl_ST_CTLDEF) ctl__syntax_error(30,TRUE);
if (ctls->nest!=0) ctl__syntax_error(29,TRUE);
current_dbox=ctl__new_dbox(current_ctl);
ctls->state=ctl_ST_DBOXDEF;
break;
case ctl_TOK_ONOPEN:
if (ctls->nest!=0) ctl__syntax_error(29,TRUE);
if ((ctls->state!=ctl_ST_MENUDEF) &&
(ctls->state!=ctl_ST_DBOXDEF)) ctl__syntax_error(14,TRUE);
if (((ctls->state==ctl_ST_MENUDEF) && (current_menu->onopen!=NULL))
||((ctls->state==ctl_ST_DBOXDEF) && (current_dbox->onopen!=NULL)))
ctl__error(15,(ctls->state==ctl_ST_MENUDEF)?
current_menu->name:current_dbox->name,TRUE);
#ifdef LOG
fprintf(logfile,"Onopen action:\n");
#endif
action_list=(ctl__action *)ctl__malloc(sizeof(ctl__action));
action_list->action.name=NULL;
if (ctls->state==ctl_ST_MENUDEF) current_menu->onopen=action_list;
else current_dbox->onopen=action_list;
saved_state=ctls->state;
ctls->state=ctl_ST_GETACTION;
break;
case ctl_TOK_ONREOPEN:
if (ctls->nest!=0) ctl__syntax_error(29,TRUE);
if ((ctls->state!=ctl_ST_MENUDEF) &&
(ctls->state!=ctl_ST_DBOXDEF)) ctl__syntax_error(14,TRUE);
if (((ctls->state==ctl_ST_MENUDEF) && (current_menu->onreopen!=NULL))
||((ctls->state==ctl_ST_DBOXDEF) && (current_dbox->onreopen!=NULL)))
ctl__error(15,(ctls->state==ctl_ST_MENUDEF)?
current_menu->name:current_dbox->name,TRUE);
#ifdef LOG
fprintf(logfile,"Onreopen action:\n");
#endif
action_list=(ctl__action *)ctl__malloc(sizeof(ctl__action));
action_list->action.name=NULL;
if (ctls->state==ctl_ST_MENUDEF) current_menu->onreopen=action_list;
else current_dbox->onreopen=action_list;
saved_state=ctls->state;
ctls->state=ctl_ST_GETACTION;
break;
case ctl_TOK_NOREOPEN:
if (ctls->nest!=0) ctl__syntax_error(29,TRUE);
if (ctls->state!=ctl_ST_DBOXDEF) ctl__syntax_error(14,TRUE);
if (current_dbox->onreopen!=NULL)
ctl__error(15,current_dbox->name,TRUE);
current_dbox->onreopen=(ctl__action *)-1;
break;
case ctl_TOK_ONCLOSE:
if (ctls->nest!=0) ctl__syntax_error(29,TRUE);
if (ctls->state!=ctl_ST_DBOXDEF) ctl__syntax_error(33,TRUE);
if (current_dbox->onclose!=NULL)
ctl__error(34,current_dbox->name,TRUE);
#ifdef LOG
fprintf(logfile,"Onclose action:\n");
#endif
action_list=(ctl__action *)ctl__malloc(sizeof(ctl__action));
action_list->action.name=NULL;
current_dbox->onclose=action_list;
saved_state=ctls->state;
ctls->state=ctl_ST_GETACTION;
break;
case ctl_TOK_ENDDBOX:
if (ctls->nest!=0) ctl__syntax_error(29,TRUE);
if (ctls->state!=ctl_ST_DBOXDEF) ctl__syntax_error(17,TRUE);
ctls->state=ctl_ST_CTLDEF;
break;
case ctl_TOK_ENDMENU:
if (ctls->nest!=0) ctl__syntax_error(29,TRUE);
if ((ctls->state!=ctl_ST_MENUDEF) && (ctls->state!=ctl_ST_GETACTION))
ctl__syntax_error(18,TRUE);
ctls->state=ctl_ST_CTLDEF;
break;
case ctl_TOK_ENDCTL:
if (ctls->nest!=0) ctl__syntax_error(29,TRUE);
if (ctls->state!=ctl_ST_CTLDEF) ctl__syntax_error(19,TRUE);
ctls->state=ctl_ST_LOADING;
break;
case ctl_TOK_OPENBLOCK:
if ((ctls->state!=ctl_ST_GETACTION) &&
(ctls->state!=ctl_ST_GETACTIONBLOCK)) ctl__syntax_error(16,TRUE);
ctls->nest++;
ctls->state=ctl_ST_GETACTIONBLOCK;
break;
case ctl_TOK_CLOSEBLOCK:
if (ctls->state!=ctl_ST_GETACTIONBLOCK) ctl__syntax_error(20,TRUE);
if (--ctls->nest<0) ctl__syntax_error(28,TRUE);
if (ctls->nest==0) ctls->state=saved_state;
break;
case ctl_TOK_ENTRY:
if (ctls->state==ctl_ST_GETACTION) ctls->state=saved_state;
if (ctls->nest!=0) ctl__syntax_error(29,TRUE);
if (ctls->state!=ctl_ST_MENUDEF) ctl__syntax_error(24,TRUE);
action_list=ctl__add_new_entry_from_file(current_menu);
saved_state=ctls->state;
ctls->state=ctl_ST_GETACTION;
break;
case ctl_TOK_SUBMENU:
if (ctls->state==ctl_ST_GETACTION) ctls->state=saved_state;
if (ctls->nest!=0) ctl__syntax_error(29,TRUE);
else if (ctls->state==ctl_ST_MENUDEF)
action_list=ctl__submenu(current_ctl,current_menu);
else if (ctls->state==ctl_ST_DBOXDEF)
action_list=ctl__subdboxmenu(current_ctl,current_dbox);
else ctl__syntax_error(24,TRUE);
if (action_list!=NULL)
{
saved_state=ctls->state;
ctls->state=ctl_ST_GETACTION;
}
break;
case ctl_TOK_ONKEY:
if (ctls->nest!=0) ctl__syntax_error(29,TRUE);
if (ctls->state!=ctl_ST_CTLDEF) ctl__syntax_error(39,TRUE);
action_list=ctl__new_key(current_ctl);
saved_state=ctls->state;
ctls->state=ctl_ST_GETACTION;
break;
case ctl_TOK_ONCLICK:
if (ctls->nest!=0) ctl__syntax_error(29,TRUE);
if (ctls->state!=ctl_ST_CTLDEF) ctl__syntax_error(68,TRUE);
if (current_ctl->onclick!=NULL) ctl__syntax_error(69,TRUE);
#ifdef LOG
fprintf(logfile,"Onclick action list:\n");
#endif
action_list=(current_ctl->onclick=
(ctl__action *)ctl__malloc(sizeof(ctl__action)));
action_list->action.name=NULL;
action_list->next=NULL;
saved_state=ctls->state;
ctls->state=ctl_ST_GETACTION;
break;
case ctl_TOK_ICON:
if (ctls->nest!=0) ctl__syntax_error(29,TRUE);
if (ctls->state!=ctl_ST_DBOXDEF) ctl__syntax_error(35,TRUE);
if (current_dbox->template==NULL)
ctl__error(55,current_dbox->name,TRUE);
action_list=ctl__add_new_icon_from_file(current_dbox);
saved_state=ctls->state;
ctls->state=ctl_ST_GETACTION;
break;
case ctl_TOK_ACTION:
if (ctls->state==ctl_ST_GETACTION) ctls->nest++;
if ((ctls->state!=ctl_ST_GETACTION) &&
(ctls->state!=ctl_ST_GETACTIONBLOCK)) ctl__syntax_error(21,TRUE);
action_list=ctl__add_to_actionlist(action_list,&value);
if (ctls->state==ctl_ST_GETACTION)
{
ctls->state=saved_state;
ctls->nest--;
}
break;
case ctl_TOK_STRING:
if ((ctls->state!=ctl_ST_GETACTION) &&
(ctls->state!=ctl_ST_GETACTIONBLOCK)) ctl__syntax_error(22,TRUE);
if ((errors) &&
((value.string[0] != '(') ||
(value.string[strlen(value.string)-1] != ')')
)
) ctl__syntax_error(23,TRUE);
if (ctls->state==ctl_ST_GETACTION) ctls->nest++;
action_list=ctl__add_string_to_actionlist(action_list,&value);
if (ctls->state==ctl_ST_GETACTION)
{
ctls->state=saved_state;
ctls->nest--;
}
break;
case ctl_TOK_TEMPLATE:
if (ctls->nest!=0) ctl__syntax_error(29,TRUE);
if (ctls->state!=ctl_ST_DBOXDEF) ctl__syntax_error(52,TRUE);
if (current_dbox->template!=NULL)
ctl__error(56,current_dbox->name,TRUE);
ctl__get_template(current_dbox);
break;
case ctl_TOK_HELP:
if (ctls->nest!=0) ctl__syntax_error(29,TRUE);
if ((ctls->state!=ctl_ST_DBOXDEF) && (ctls->state!=ctl_ST_MENUDEF))
ctl__syntax_error(59,TRUE);
switch(ctls->state)
{
case ctl_ST_DBOXDEF:
ctl__get_dbox_help(current_dbox);
break;
case ctl_ST_MENUDEF:
ctl__get_menu_help(current_menu);
break;
}
break;
case ctl_TOK_COMMENT:
ctl__skip_toeol();
break;
case ctl_TOK_EOL:
ctls->line++;
if (ctls->current_char=='#') ctl__skip_toeol();
break;
}
} while (token!=ctl_TOK_EOF);
ctls->state=ctl_ST_LOADED;
ctls->line=0;
}
static menu ctl__menu_maker(ctl__handlestr *handle)
{
ctls->current_handle=handle;
ctls->current_menu=handle->mnu;
ctls->top_menu=handle->mnu;
ctls->return_code=(wimpt_last_event()->data.but.m.i);
if (!event_is_menu_being_recreated()) ctl__run(handle->mnu->onopen);
return handle->mnu->menu_body;
}
static void ctl__menu_select(ctl__handlestr *handle,char *hit)
{
ctl__menu *mnu;
ctl__menu_entry *entry;
char *c;
BOOL recreate=event_is_menu_being_recreated();
if (wimpt_last_event()->e!=wimp_EMENU) recreate=FALSE;
else
{
wimp_mousestr m;
wimp_get_point_info(&m);
recreate=((m.bbits & wimp_BRIGHT) != 0);
}
ctls->current_menu=handle->mnu;
for (c=hit;*(c+1);c++)
{
if (ctls->current_menu->external)
{
if ((wimpt_last_event()->e==wimp_ESEND) && !*(c+2)) *(c+1)='\0';
strcpy(ctls->external_hit,c);
}
if ((wimpt_last_event()->e==wimp_ESEND) && !*(c+2))
{
*(c+1)='\0';
break;
}
entry=ctl__find_entry(*c,ctls->current_menu);
if (entry==NULL) entry=ctl__find_entry(-1,ctls->current_menu);
if (entry==NULL) break;
if (entry->action->action.address->function.function!=
ctl__submenu_request) break;
ctls->current_menu=(ctl__menu *) entry->action->args;
}
strcpy(ctls->last_menu_hit,hit);
entry=ctl__find_entry(*c,ctls->current_menu);
ctls->return_code=*c;
if (entry!=NULL) ctl__run(entry->action);
else if (entry=ctl__find_entry(-1,ctls->current_menu),entry!=NULL)
ctl__run(entry->action);
if (recreate)
{
mnu=handle->mnu;
for (c=ctls->last_menu_hit;*(c+1);c++)
{
entry=ctl__find_entry(*c,mnu);
if (entry==NULL) entry=ctl__find_entry(-1,ctls->current_menu);
if (entry==NULL) break;
if (mnu->external) break;
ctl__run(mnu->onreopen);
mnu=(ctl__menu *) entry->action->args;
}
ctl__run(mnu->onreopen);
wimp_create_menu(menu_syshandle(handle->mnu->menu_body),0,0);
}
}
/* ctl__find_action_in_list.
*
* given an action name and an action list returns
* TRUE if action is in the list, FALSE if not.
*
*
*/
static BOOL ctl__find_action_in_list(char *name,ctl__action *list)
{
ctl__action *act;
static ctl__actionstr the_action,*the_action_address;
if (the_action.name!=name)
{
the_action.name=name;
the_action_address=
ctl__find_action(&the_action,ctls->actions,FALSE,FALSE);
}
if (list==NULL) return FALSE;
else if (list==(ctl__action *)-1) return FALSE;
for (act=list;act!=NULL;act=act->next)
{
if ((act->type==ctl_ACT_LABEL) &&
(strcmp(act->action.name,the_action.name)==0)) return TRUE;
if ((act->type==ctl_ACT_STRING) &&
(strcmp(act->action.name,the_action.name)==0))
{
act->type=ctl_ACT_LABEL;
return TRUE;
}
if (act->type!=ctl_ACT_FUNCTION) continue;
if (act->action.address==the_action_address) return TRUE;
if (act->action.address->function.function!=ctl__submenu_request)
continue;
if ( ( (act->action.address->function.handle==(void *) 1) ||
(act->action.address->function.handle==(void *) 3)
) &&
(
(ctl__find_action_in_list(name,((ctl__menu *)act->args)->onopen)) ||
(ctl__find_action_in_list(name,((ctl__menu *)act->args)->onreopen))
)
)
return TRUE;
if ( ( (act->action.address->function.handle==(void *) 2) ||
(act->action.address->function.handle==(void *) 4)
) &&
(
(ctl__find_action_in_list(name,((ctl__dbox *)act->args)->onopen)) ||
(ctl__find_action_in_list(name,((ctl__dbox *)act->args)->onreopen)) ||
(ctl__find_action_in_list(name,((ctl__dbox *)act->args)->onclose))
)
)
return TRUE;
}
return FALSE;
}
/*
* ctl__find action.
*
* Find all places in given ctl where the action given is executed
* for every place call func with arg arg, pointer to entry/icon,
* entry/icon flag.
*
*/
static void ctl__find_action_in_ctl(ctl *a_ctl,char *name,void (func()),void *arg)
{
ctl__menu_entry *entry;
ctl__menu *a_menu;
ctl__dbox *a_dbox;
ctl__icon *icon;
/*Must do dboxes first because of writeable icons */
for (a_dbox=a_ctl->dboxes;a_dbox!=NULL;a_dbox=a_dbox->next)
for (icon=a_dbox->icons;icon!=NULL;icon=icon->next)
{
if ((icon->action!=NULL) && (ctl__find_action_in_list(name,icon->action)))
{
func(arg,a_dbox,icon,ctl_ENTRY_ICON,a_dbox->displayed);
}
}
for (a_menu=a_ctl->menus;a_menu!=NULL;a_menu=a_menu->next)
for (entry=a_menu->entries;entry!=NULL;entry=entry->next)
{
if ((entry->action!=NULL)&&(ctl__find_action_in_list(name,entry->action)))
{
func(arg,a_menu,entry,ctl_ENTRY_MENUENTRY,FALSE);
}
}
}
/* ctl__tick_entry
*
* Tick the given entry / select icons if in a displayed dbox.
*
*/
static void ctl__tick_entry(void *arg,void *parent,
void *entry,ctl_entrytype type,BOOL displayed)
{
switch(type)
{
case ctl_ENTRY_MENUENTRY:
if ((BOOL)arg)
ctl__menu_item(((ctl__menu *)parent)->menu_body,
((ctl__menu_entry *)entry)->num)->flags|=wimp_MTICK;
else ctl__menu_item(((ctl__menu *)parent)->menu_body,
((ctl__menu_entry *)entry)->num)->flags&=~wimp_MTICK;
break;
case ctl_ENTRY_ICON:
if (displayed)
{
if ((BOOL)arg) wimp_set_icon_state(
dbox_syshandle(((ctl__dbox *)parent)->dbox_body),
((ctl__icon *)entry)->num,wimp_ISELECTED,wimp_ISELECTED);
else wimp_set_icon_state(
dbox_syshandle(((ctl__dbox *)parent)->dbox_body),
((ctl__icon *)entry)->num,0,wimp_ISELECTED);
}
((ctl__icon *)entry)->ticked=(BOOL)arg;
break;
}
}
/* ctl__apply_function
*
* Apply the given function on the given action entries / icons.
*
*/
static void ctl__apply_function(void (arg()),void *parent,
void *entry,ctl_entrytype type,BOOL displayed)
{
ctl_parentstr the_parent;
switch(type)
{
case ctl_ENTRY_MENUENTRY:
the_parent.parent_menu=
menu_syshandle(((ctl__menu *)parent)->menu_body);
arg(the_parent,
((ctl__menu_entry *)entry)->num,ctl_ENTRY_MENUENTRY);
break;
case ctl_ENTRY_ICON:
the_parent.parent_window=
dbox_syshandle(((ctl__dbox *)parent)->dbox_body);
if (displayed)
arg(the_parent,
((ctl__icon *)entry)->num,ctl_ENTRY_ICON);
break;
}
}
/* ctl__make_entry_writeable
*
* Make the given entry /icon writeable.
*
*/
static void ctl__make_entry_writeable(void *arg,void *parent,
void *entry,ctl_entrytype type,BOOL displayed)
{
ctl__indirectstr *data=(ctl__indirectstr *)arg;
switch(type)
{
case ctl_ENTRY_MENUENTRY:
if (data->flag) /* already created buffer */
menu_make_writeable(((ctl__menu *)parent)->menu_body,
((ctl__menu_entry *)entry)->num,data->buffer,data->len,data->valid);
else /* This is the first menu entry and there were no icons !
We know this because we know the order find_action_in_ctl
works which is very important !! */
{
data->buffer=ctl__malloc(data->len+5);
*data->buffer='\0';
menu_make_writeable(((ctl__menu *)parent)->menu_body,
((ctl__menu_entry *)entry)->num,data->buffer,data->len,data->valid);
data->flag=TRUE;
}
break;
case ctl_ENTRY_ICON:
((ctl__icon *)entry)->writeable=TRUE;
if (data->flag)
werr(TRUE,
msgs_lookup(
"ctdupind:Duplicate writeable action icon (Icon %i in dbox %s)"),
((ctl__icon *)entry)->num,((ctl__dbox *)parent)->name);
if (displayed)
{
wimp_icon icon;
wimp_get_icon_info(dbox_syshandle(((ctl__dbox *)parent)->dbox_body),
((ctl__icon *)entry)->num,&icon);
if
(((icon.flags & wimp_ITEXT)==0) || ((icon.flags & wimp_INDIRECT)==0))
werr(TRUE,
msgs_lookup(
"ctindicn:Icon %i in dbox %s should be an indirected text icon"),
((ctl__icon *)entry)->num,((ctl__dbox *)parent)->name);
if ((icon.flags & (wimp_BWRITABLE<<12))!=(wimp_BWRITABLE<<12))
werr(TRUE,
msgs_lookup(
"ctwrticn:Icon %i in dbox %s should be a writeable icon"),
((ctl__icon *)entry)->num,((ctl__dbox *)parent)->name);
if (icon.data.indirecttext.bufflen<data->len)
werr(TRUE,
msgs_lookup(
"cticnbuf:Icon %i in dbox %s should have a buffer of at least %i positions."),
((ctl__icon *)entry)->num,((ctl__dbox *)parent)->name,data->len);
if ( ((int)icon.data.indirecttext.validstring>0) &&
(strncmp(icon.data.indirecttext.validstring,data->valid,
strlen(data->valid))!=0))
werr(TRUE,
msgs_lookup(
"cticnval:Icon %i in dbox %s should have a validation string of %s"),
((ctl__icon *)entry)->num,((ctl__dbox *)parent)->name,data->valid);
data->buffer=icon.data.indirecttext.buffer;
data->flag=TRUE;
}
else
{
wimp_wind *the_template=
template_syshandle(((ctl__dbox *)parent)->template);
wimp_icon *iconptr=(wimp_icon *)((int)the_template+sizeof(wimp_wind));
iconptr+=((ctl__icon *)entry)->num;
ctl__error(67,((ctl__dbox *)parent)->name,TRUE);
if
(((iconptr->flags & wimp_ITEXT)==0) ||
((iconptr->flags & wimp_INDIRECT)==0))
werr(TRUE,
msgs_lookup(
"ctindicn:Icon %i in dbox %s should be an indirected text icon"),
((ctl__icon *)entry)->num,((ctl__dbox *)parent)->name);
if ((iconptr->flags & (wimp_BWRITABLE<<12))!=(wimp_BWRITABLE<<12))
werr(TRUE,
msgs_lookup(
"ctwrticn:Icon %i in dbox %s should be a writeable icon"),
((ctl__icon *)entry)->num,((ctl__dbox *)parent)->name);
if (iconptr->data.indirecttext.bufflen<data->len)
werr(TRUE,
msgs_lookup(
"cticnbuf:Icon %i in dbox %s should have a buffer of at least %i positions."),
((ctl__icon *)entry)->num,((ctl__dbox *)parent)->name,data->len);
if ( ((int)(iconptr->data.indirecttext.validstring)>0) &&
(strncmp(iconptr->data.indirecttext.validstring,data->valid,
strlen(data->valid))!=0))
werr(TRUE,
msgs_lookup(
"cticnval:Icon %i in dbox %s should have a validation string of %s"),
((ctl__icon *)entry)->num,((ctl__dbox *)parent)->name,data->valid);
data->buffer=iconptr->data.indirecttext.buffer;
data->flag=TRUE;
}
break;
}
}
/* ctl__set_entry_text
*
* Set the given entry /icon text.
*
*/
static void ctl__set_entry_text(void *arg,void *parent,
void *entry,ctl_entrytype type,BOOL displayed)
{
switch(type)
{
case ctl_ENTRY_MENUENTRY:
{
wimp_menuitem *item;
item=ctl__menu_item(((ctl__menu *)parent)->menu_body,
((ctl__menu_entry *)entry)->num);
item->iconflags|=wimp_INDIRECT | wimp_ITEXT;
item->data.indirecttext.buffer=(char *)arg;
item->data.indirecttext.bufflen=strlen((char *)arg+1);
item->data.indirecttext.validstring="";
}
break;
case ctl_ENTRY_ICON:
if (displayed)
{
wimp_icon icon;
wimp_get_icon_info(dbox_syshandle(((ctl__dbox *)parent)->dbox_body),
((ctl__icon *)entry)->num,&icon);
if
(((icon.flags & wimp_ITEXT)==0) || ((icon.flags & wimp_INDIRECT)==0))
werr(TRUE,
msgs_lookup(
"ctindicn:Icon %i in dbox %s should be an indirected text icon"),
((ctl__icon *)entry)->num,((ctl__dbox *)parent)->name);
dbox_setfield(((ctl__dbox *)parent)->dbox_body,
((ctl__icon *)entry)->num,
(char *)arg);
} else
{
wimp_wind *the_template=
template_syshandle(((ctl__dbox *)parent)->template);
wimp_icon *iconptr=(wimp_icon *)((int)the_template+sizeof(wimp_wind));
iconptr+=((ctl__icon *)entry)->num;
if
(((iconptr->flags & wimp_ITEXT)==0) ||
((iconptr->flags & wimp_INDIRECT)==0))
werr(TRUE,
msgs_lookup(
"ctindicn:Icon %i in dbox %s should be an indirected text icon"),
((ctl__icon *)entry)->num,((ctl__dbox *)parent)->name);
strncpy(iconptr->data.indirecttext.buffer,
(char *)arg,
iconptr->data.indirecttext.bufflen);
}
break;
}
}
/* ctl__set_caret_in_entry
*
* Set the caret in the given entry /icon.
*
*/
static void ctl__set_caret_in_entry(void *arg,void *parent,
void *entry,ctl_entrytype type,BOOL displayed)
{
if ((*(int *)arg)++) return;
if ((type==ctl_ENTRY_ICON) && (displayed))
{
wimp_caretstr c;
c.w=dbox_syshandle(((ctl__dbox *)parent)->dbox_body);
c.i=((ctl__icon *)entry)->num;
c.height=-1;
c.index=0;
wimp_set_caret_pos(&c);
}
}
/*
*
* BOOL ctl__chk_disabled(ctl__action *list)
*
* Return true if any of the actions on the list are disabled.
*
*/
static BOOL ctl__chk_disabled(ctl__action *list)
{
ctl__actionstr act,*actadr;
if (list==NULL) return FALSE;
if ((list->type==ctl_ACT_FUNCTION) &&
((list->action.address)->disabled)) return TRUE;
else if ((list->type==ctl_ACT_STRING) || (list->type==ctl_ACT_LABEL))
{
act.name=list->action.name;
actadr=ctl__find_action(&act,ctls->actions,FALSE,FALSE);
if ((actadr!=NULL) && (actadr->disabled)) return TRUE;
}
return ctl__chk_disabled(list->next);
}
/* ctl__enable_entry
*
* Fade the given entry / icon if in a displayed dbox.
*
*/
static void ctl__enable_entry(void *arg,void *parent,
void *entry,ctl_entrytype type,BOOL displayed)
{
switch(type)
{
case ctl_ENTRY_MENUENTRY:
if (!(BOOL)arg)
{
ctl__menu_item(((ctl__menu *)parent)->menu_body,
((ctl__menu_entry *)entry)->num)->iconflags|=wimp_INOSELECT;
}
else if (!ctl__chk_disabled(((ctl__menu_entry *)entry)->action))
ctl__menu_item(((ctl__menu *)parent)->menu_body,
((ctl__menu_entry *)entry)->num)->iconflags&=~wimp_INOSELECT;
break;
case ctl_ENTRY_ICON:
if (!(BOOL)arg)
if (displayed)
{
if ((BOOL)arg) wimp_set_icon_state(
dbox_syshandle(((ctl__dbox *)parent)->dbox_body),
((ctl__icon *)entry)->num,wimp_INOSELECT,wimp_INOSELECT);
else if (!ctl__chk_disabled(((ctl__icon *)entry)->action))
wimp_set_icon_state(
dbox_syshandle(((ctl__dbox *)parent)->dbox_body),
((ctl__icon *)entry)->num,0,wimp_INOSELECT);
}
((ctl__icon *)entry)->disabled=(BOOL)arg;
break;
}
}
static BOOL ctl__process_help_event(wimp_eventstr *e)
{
ctl__handlestr *handle=ctl__find_handle(e->data.msg.data.helprequest.m.w);
if (e->data.msg.data.helprequest.m.w<0) return FALSE;
if (handle==NULL) /* Not in a window is it in our menu ? */
{
_kernel_swi_regs r;
wimp_msgstr m;
char token[50];
int buf[30],i;
ctl__menu *a_menu;
ctl__menu_entry *an_entry;
r.r[0]=1;
r.r[1]=(int)buf;
r.r[2]=e->data.msg.data.helprequest.m.w;
r.r[3]=e->data.msg.data.helprequest.m.i;
_kernel_swi(XOS_Bit | Wimp_GetMenuState,&r,&r);
if (buf[0]==-1) return FALSE; /* No Menu Open */
a_menu=ctls->top_menu;
for (i=0;buf[i+1]!=-1;i++)
a_menu=(ctl__menu *)(ctl__find_entry(buf[i]+1,a_menu)->action->args);
an_entry=ctl__find_entry(buf[i]+1,a_menu);
if (an_entry==NULL) an_entry=ctl__find_entry(-1,a_menu);
if ((an_entry!=NULL) && (an_entry->help_action!=NULL))
{
ctl__run(an_entry->help_action);
return TRUE;
}
if (a_menu->mih_token==NULL) return FALSE;
sprintf(token,"%s%i\0",a_menu->mih_token,1+buf[i]);
strcpy(m.data.helpreply.text,msgs_lookup(token));
m.hdr.action=wimp_MHELPREPLY;
m.hdr.your_ref=e->data.msg.hdr.my_ref;
m.hdr.my_ref=0;
m.hdr.size=220;
wimp_sendmessage(wimp_ESEND,&m,e->data.msg.hdr.task);
return TRUE;
}
else if (handle->help_token==NULL) return FALSE;
else
{
wimp_msgstr m;
char token[50];
int inum;
if ((inum=e->data.msg.data.helprequest.m.i)>=0)
{
if (handle->the_dbox!=NULL)
{
ctl__icon *an_icon=ctl__find_icon(inum,handle->the_dbox);
if (an_icon==NULL) an_icon=ctl__find_icon(-1,handle->the_dbox);
if ((an_icon!=NULL) && (an_icon->help_action!=NULL))
{
ctl__run(an_icon->help_action);
return TRUE;
}
}
sprintf(token,"%s%i\0",handle->help_token,inum);
strcpy(m.data.helpreply.text,msgs_lookup(token));
} else strcpy(m.data.helpreply.text,msgs_lookup(handle->help_token));
m.hdr.action=wimp_MHELPREPLY;
m.hdr.your_ref=e->data.msg.hdr.my_ref;
m.hdr.my_ref=0;
m.hdr.size=220;
wimp_sendmessage(wimp_ESEND,&m,e->data.msg.hdr.task);
}
return TRUE;
}
static BOOL ctl__process_key_event(wimp_eventstr *e)
{
ctl__handlestr *handle;
ctl__key *key;
if (handle=ctl__find_handle(e->data.key.c.w),handle==NULL) return FALSE;
ctls->current_handle=handle;
if (ctls->current_handle->the_ctl==NULL) return FALSE;
for (key=ctls->current_handle->the_ctl->keys;key!=NULL;key=key->next)
if (key->keycode==e->data.key.chcode)
{
ctls->return_code=e->data.key.chcode;
if (!key->disabled) ctl__run(key->action);
return TRUE;
} else
if (key->keycode==-1)
{
ctls->return_code=e->data.key.chcode;
if (!key->disabled) ctl__run(key->action);
return TRUE;
}
return FALSE;
}
static BOOL ctl__process_mouse_event(wimp_eventstr *e)
{
ctl__handlestr *handle;
if (e->data.but.m.bbits & 2) return FALSE;
handle=ctl__find_handle((e->data.but.m.w<0)?win_ICONBAR:e->data.but.m.w);
if (handle==NULL) return FALSE;
ctls->current_handle=handle;
if (ctls->current_handle->the_ctl==NULL) return FALSE;
if (ctls->current_handle->the_ctl->onclick==NULL) return FALSE;
if (!ctl__chk_disabled(ctls->current_handle->the_ctl->onclick))
{
ctls->return_code=e->data.but.m.bbits;
ctl__run(ctls->current_handle->the_ctl->onclick);
return TRUE;
}
return FALSE;
}
static BOOL ctl__process_event(wimp_eventstr *e)
{
switch (e->e)
{
default:
return FALSE;
case wimp_EKEY:
return ctl__process_key_event(e);
case wimp_EBUT:
return ctl__process_mouse_event(e);
case wimp_ESEND:
case wimp_ESENDWANTACK:
if (e->data.msg.hdr.action==wimp_MHELPREQUEST)
return ctl__process_help_event(e); else return FALSE;
}
}
/************************* External functions ****************************/
/* ctl_init():
* BOOL load - if true load control file and ignore any
* undefined actions.
*
*/
void ctl_init(BOOL load)
{
ctl__init();
if (load) ctl__load(FALSE);
}
/* ctl_load()
* Load control file (Can only be called if ctl_init was
* called with FALSE. Generate FATAL error if undefined action
* in control file.
*/
void ctl_load()
{
if (ctls->state!=ctl_ST_PRELOAD) ctl__error(4,NULL,TRUE);
ctl__load(TRUE);
}
/*
* BOOL ctl_attach_menu(event_w,char ctlname,char menuname);
*
*
*
*/
BOOL ctl_attach_menu(event_w w,char *ctlname,char *menuname,void *userhandle)
{
ctl *the_ctl;
ctl__menu *the_menu;
ctl__handlestr *handle;
the_ctl=ctl__find_ctl(ctlname);
the_menu=ctl__find_menu(menuname,the_ctl);
if (the_menu->external)
ctl__error(66,menuname,TRUE);
handle=ctl__add_handle(w,userhandle,the_ctl,the_menu);
return event_attachmenumaker(w,
(event_menu_maker) ctl__menu_maker,
(event_menu_proc) ctl__menu_select,
handle);
}
void ctl_add_action(char *name,char *syntax,ctl_action_proc func,void *arg)
{
ctl__add_action(name,syntax,func,arg,FALSE);
}
void ctl_tick_action(char *ctlname,char *actname)
{
ctl *a_ctl;
a_ctl=ctl__find_ctl(ctlname);
ctl__find_action_in_ctl(a_ctl,actname,ctl__tick_entry,(void *)TRUE);
}
void ctl_untick_action(char *ctlname,char *actname)
{
ctl *a_ctl;
a_ctl=ctl__find_ctl(ctlname);
ctl__find_action_in_ctl(a_ctl,actname,ctl__tick_entry,(void *)FALSE);
}
void ctl_set_action_text(char *ctlname,char *actname,char *text)
{
ctl *a_ctl;
a_ctl=ctl__find_ctl(ctlname);
ctl__find_action_in_ctl(a_ctl,actname,ctl__set_entry_text,(void *)text);
}
void ctl_set_caret_in_action(char *ctlname,char *actname)
{
int f=0;
ctl *a_ctl;
a_ctl=ctl__find_ctl(ctlname);
ctl__find_action_in_ctl(a_ctl,actname,ctl__set_caret_in_entry,(void *)&f);
if (f>1) ctl__error(63,actname,TRUE);
}
void ctl_enable_action(char *ctlname,char *actname)
{
ctl *a_ctl;
ctl__key *key;
ctl__actionstr the_action,*the_address;
a_ctl=ctl__find_ctl(ctlname);
the_action.name=actname;
the_address=ctl__find_action(&the_action,ctls->actions,FALSE,FALSE);
if (the_address==NULL) ctl__error(50,actname,TRUE);
the_address->disabled=FALSE;
ctl__find_action_in_ctl(a_ctl,actname,ctl__enable_entry,(void *)TRUE);
for (key=a_ctl->keys;key!=NULL;key=key->next)
key->disabled=ctl__chk_disabled(key->action);
}
void ctl_disable_action(char *ctlname,char *actname)
{
ctl *a_ctl;
ctl__actionstr the_action,*the_address;
ctl__key *key;
a_ctl=ctl__find_ctl(ctlname);
the_action.name=actname;
the_address=ctl__find_action(&the_action,ctls->actions,FALSE,FALSE);
if (the_address==NULL) ctl__error(50,actname,TRUE);
the_address->disabled=TRUE;
ctl__find_action_in_ctl(a_ctl,actname,ctl__enable_entry,(void *)FALSE);
for (key=a_ctl->keys;key!=NULL;key=key->next)
if (ctl__find_action_in_list(actname,key->action)) key->disabled=TRUE;
}
char *ctl_make_action_writeable(
char *ctlname,
char *actname,
int len,
char *valid)
{
ctl *a_ctl;
ctl__actionstr the_action /*,*the_address*/;
ctl__indirectstr data;
data.len=len;
data.valid=valid;
data.buffer=NULL;
data.flag=FALSE;
a_ctl=ctl__find_ctl(ctlname);
the_action.name=actname;
/* the_address=ctl__find_action(&the_action,ctls->actions,FALSE,FALSE);
if (the_address==NULL) ctl__error(51,actname,TRUE); */
ctl__find_action_in_ctl(a_ctl,actname,ctl__make_entry_writeable,
(void *)&data);
return data.buffer;
}
void ctl_find_entries(char *ctlname,char *actname,void ((*func)()))
{
ctl *a_ctl;
a_ctl=ctl__find_ctl(ctlname);
ctl__find_action_in_ctl(a_ctl,actname,ctl__apply_function,(void *)func);
}
void ctl_process(void)
{
wimp_eventstr e;
wimpt_poll(event_getmask(),&e);
if (!ctl__process_event(&e))
{
wimpt_fake_event(&e);
event_process();
}
}
void ctl_attach_external_menu(char *ctlname,char *menuname,wimp_menustr *m)
{
ctl *a_ctl;
ctl__menu *a_menu;
ctl__menu_entry *an_entry;
wimp_menuitem *item;
a_ctl=ctl__find_ctl(ctlname);
a_menu=ctl__find_menu(menuname,a_ctl);
if (!a_menu->external) ctl__error(65,menuname,TRUE);
a_menu->menu_body=(menu)m;
a_menu->entrycount=ctl__count_menu_entries(m);
an_entry=ctl__find_entry(-1,a_menu);
item=(wimp_menuitem *)(m+1);
do
{
if (an_entry==NULL) item->iconflags|=wimp_INOSELECT;
else
{
/* item->iconflags&=~wimp_INOSELECT; */
if ((an_entry->action != NULL) &&
(an_entry->action->type==ctl_ACT_FUNCTION) &&
(an_entry->action->action.address->function.function==
ctl__submenu_request)
)
{
item->flags|=wimp_MSUBLINKMSG;
if ((an_entry->action->action.address->function.handle==(void *)1) ||
(an_entry->action->action.address->function.handle==(void *)3)
)
item->submenu=
menu_syshandle(((ctl__menu *)an_entry->action->args)->menu_body);
else item->submenu=(wimp_menustr *)1;
}
}
if ((item->flags & wimp_MLAST)!=0) break;
item++;
}
while (TRUE);
item=(wimp_menuitem *)(m+1);
for (an_entry=a_menu->entries;an_entry!=NULL;an_entry=an_entry->next)
{
if ((an_entry->num!=-1) &&
((an_entry->num<0) || (an_entry->num>a_menu->entrycount)))
werr(TRUE,
msgs_lookup("inveent:Invalid entry number (%i) in external menu %s.")
,an_entry->num,menuname);
if (an_entry->num>0)
{
(item+an_entry->num-1)->iconflags&=~wimp_INOSELECT;
if ((an_entry->action != NULL) &&
(an_entry->action->action.name!=NULL) &&
(an_entry->action->type==ctl_ACT_FUNCTION) &&
(an_entry->action->action.address->function.function==
ctl__submenu_request) &&
((an_entry->action->action.address->function.handle==(void *)1) ||
(an_entry->action->action.address->function.handle==(void *)3)
)
)
{
ctl__menu *submenu=(ctl__menu *) an_entry->action->args;
if ((submenu->external) && (submenu->menu_body==NULL))
{
submenu->parent=(item+an_entry->num-1);
}
else
{
(item+an_entry->num-1)->submenu=menu_syshandle(submenu->menu_body);
}
}
}
}
}
char * ctl_return_external_hit(void)
{
return ctls->external_hit;
}
void ctl_help_reply(char *text)
{
wimp_msgstr m;
strcpy(m.data.helpreply.text,text);
m.hdr.action=wimp_MHELPREPLY;
m.hdr.your_ref=wimpt_last_event()->data.msg.hdr.my_ref;
m.hdr.my_ref=0;
m.hdr.size=220;
wimp_sendmessage(wimp_ESEND,&m,wimpt_last_event()->data.msg.hdr.task);
}
/* Copyright 1996 Acorn Computers Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/****************************************************************************
* This source file was written by Acorn Computers Limited. It is part of *
* the RISCOS library for writing applications in C for RISC OS. It may be *
* used freely in the creation of programs for Archimedes. It should be *
* used with Acorn's C Compiler Release 3 or later. *
* *
***************************************************************************/
/*
* Title: ctl.h
* Purpose: Provide support for Control resource file, for the
* specification of an applications user interface.
*/
#ifndef __ctl
#define __ctl
#ifndef BOOL
#define BOOL int
#define TRUE 1
#define FALSE 0
#endif
#include "wimp.h"
#include "event.h"
typedef union { /* Describes the parent of an entry / icon */
wimp_menustr *parent_menu; /* If entry in a menu */
wimp_w parent_window; /* If an icon in an open dbox. */
}ctl_parentstr;
/* ------------------------ ctl_action_proc -----------------------------
*
* Description: This is the type for action handlers.
*
* Parameters: void *ctlhandle -- The handle given when the
* ctl was attached to the window.
* void *acthandle -- The handle given to
* ctl_add_action when this action
* was defined.
* void *args -- The arguments for the action,
* if the action syntax given to
* ctl_add_action was NULL this is
* a pointer to the text following
* the action in the Control file,
* otherwise it is a pointer to an
* argument buffer as returned from
* OS_ReadArgs.
* int return_code -- The return code returned by the
* previous action executed.
*
* Returns: The return code to be passed to the next action.
*
*/
typedef int (*ctl_action_proc)(void *ctlhandle,
void *acthandle,
void *args,
int return_code);
typedef enum { /* The entry type passed to entry processors, see below */
ctl_ENTRY_ICON = 1, /* An icon in an open dbox. */
ctl_ENTRY_MENUENTRY = 2 /* A menu entry. */
} ctl_entrytype;
/* ---------------------------- ctl_entry_proc --------------------------
*
* Description: This is the type for functions passed to ctl_find_entries.
*
* Parameters: parent -- If type is ctl_ENTRY_ICON parent.parent_window
* is a wimp window number of an open dbox.
* If type is ctl_ENTRY_MENUENTRY
* parent.parent_menu is a pointer to a
* wimp_menustr.
*
* entry -- For menu entries this is the entry number
* (starting from 1), for icons this is the icon
* number (starting from 0).
*
* type -- ctl_ENTRY_ICON when this is an icon.
* ctl_ENTRY_MENUENTRY when this is an entry in
* a menu.
* Returns: void.
*
*/
typedef void (*ctl_entry_proc)
(ctl_parentstr parent,int entry,ctl_entrytype type);
/* -------------------------------- ctl_init -------------------------
*
* Description: Initialises the ctl module, and optionally loads
* the Control file.
*
* Parameters: load -- If true, loads the control file and ignores any
* undefined actions.
*
* Returns: void.
*
*
* Other Info: This function should be called once before any other
* function in this module.
*
* It should be called with TRUE for development work,
* as it allows you to have undefined actions in the Control
* file. For a working program, this should be called with
* FALSE, then all actions should be defined, and then the
* Control file should be loaded using ctl_load(),
* this enables the ctl module to do syntax checking when the
* application starts and produce errors if there are
* undefined actions in the Control file.
*
* You must call:
* wimpt_init(),
* res_init(),
* resspr_init(),
* template_init(),
* msgs_init(),
* and dbox_init()
* before calling this function.
*
*/
void ctl_init(BOOL load);
/* -------------------------------- ctl_load ---------------------------
*
* Description: Load the Control file.
*
* Parameters: None.
*
* Returns: void.
*
* Other Info: If ctl_init() was called with FALSE, this function should
* be called after all actions have been defined. This will
* load the Control file, and produce FATAL errors if there
* are any undefined actions in the file.
*
* It should be called ONCE after all actions have been
* defined but before any other function in this module.
* (i.e. only a call to ctl_init(FALSE), followed by calls to
* ctl_add_action() can come before this call)
*
*/
void ctl_load(void);
/* -------------------------- ctl_attach_menu --------------------------
*
* Description: Attach the given ctl structure and a menu from it to a
* window.
*
* Parameters: w -- The window handle.
*
* *ctlname -- The name of a ctl defined in the Control file.
*
* *menuname -- The name of a menu in the ctl.
*
* oid *handle -- A handle to be passed to any action function
* executed from the ctl as a result of user
* actions in this window.
*
* Returns: TRUE if able to attach menu.
*
*
* Other Info: To attach a ctl for icons on the iconbar attach the ctl to
* win_ICONBAR.
*
*
*/
#ifndef win_ICONBAR
#define win_ICONBAR -3
#endif
BOOL ctl_attach_menu(event_w w,char *ctlname,char *menuname,void *handle);
/* -------------------------- ctl_add_action ---------------------------
*
* Description: Add an action to the known actions list.
*
* Parameters: *name -- The action name.
* *syntax -- If NULL, the action_handler function will be passed
* a pointer to the action's argument string when the
* function is called.
*
* If not NULL this should point to a syntax string
* in the form passed to OS_ReadArgs, on entry the
* action handler function will be passed a result
* buffer in the format returned from OS_ReadArgs,
* after the arguments have been evaluated.
*
* ctl_action_proc -- The action handler.
*
* void *hndl -- A handle to be passed to the action handler
* when this action is executed, this enables you to
* implement more than one action using a single
* function.
*
* Returns: void.
*
* Other Info: 1. Actions are global to the application.
* 2. Pointers are kept to the action name and syntax string,
* so their life span should be long enough.
*/
void
ctl_add_action(char *name,char *syntax,ctl_action_proc func,void *hndl);
/* -------------------------- ctl_tick_action ---------------------------
*
* Description: Puts a tick next to any menu entry, and selects any icon
* leading to the execution of the given action (even if it is
* not the only action executed by the menu entry or icon).
*
*
* Parameters: *ctlname -- A ctl name.
* *action -- The action name.
*
* Returns: void.
*
* Other Info:
* Non leaf menu entries which lead to a menu or dbox which has
* the action on its onopen,onreopen or onclose action list will
* also be ticked.
*/
void ctl_tick_action(char *ctlname,char *actname);
/* ------------------------ ctl_untick_action -----------------------------
*
* Description: Unticks any menu entry, and deselects any icon,
* leading to the execution of the given action (even if it is
* not the only action executed by the menu entry or icon).
*
* Parameters: *ctlname -- A ctl name.
* *action -- The action name.
*
* Returns: void.
*
* Other Info:
* Non leaf menu entries which lead to a menu or dbox which has
* the action on its onopen, onreopen or onclose action list will
* also be unticked.
*
*/
void ctl_untick_action(char *ctlname,char *actname);
/* ------------------- ctl_set_action_text --------------------------------
*
* Description: Sets the text of any menu entry, and any icon,
* leading to the execution of the given action (even if it
* is not the only action executed by the menu entry or
* icon).
*
* Parameters: *ctlname -- A ctl name.
* *action -- The action name.
* *text -- The text to set the action to.
*
* Returns: void.
*
* Other Info: The text of any non leaf menu entries which lead to a
* menu or dbox which has the action on its onopen, onreopen
* or onclose action list will also be set.
*
* If any icon leading to the execution of the action is
* not an indirected text icon, an error is produced.
* If an icon's buffer is too small to contain the text, the
* text is truncated.
*/
void ctl_set_action_text(char *ctlname,char *actname,char *text);
/* ---------------------- ctl_set_caret_in_action -------------------------
*
* Description: Sets the caret in the icon which leads to the execution
* of the given action. (even if it is not the only action
* executed by the icon).
*
* Parameters: *ctlname -- A ctl name.
* *action -- The action name.
*
* Returns: void.
*
* Other Info: A FATAL error is produced if more than one icon leads to
* the execution of the action or if the icon is not an
* indirected text icon.
*
*/
void ctl_set_caret_in_action(char *ctlname,char *actname);
/* ---------------------------- ctl_disable_action ------------------------
*
* Description: Disables (greys out) any menu entry and any icon,
* leading to the execution of the given action (even if it
* is not the only action executed by the menu entry or
* icon).
*
* Parameters: *ctlname -- A ctl name.
* *action -- The action name.
*
* Returns: void.
*
* Other Info: This will also disable any defined hot keys which lead
* to the action and non leaf menu entries which lead to a
* menu or dbox which has the action on its onopen, onreopen
* or onclose action list.
*
*/
void ctl_disable_action(char *ctlname,char *actname);
/* ------------------------- ctl_enable_action -----------------------------
*
* Description: Enables (ungreys) any menu entry, and any icon,
* leading to the execution of the given action.
*
* Parameters: *ctlname -- A ctl name.
* *action -- The action name.
*
* Returns: void.
*
* Other Info: This will only ungrey the entry or icon if there are
* no other disabled actions executed by the entry or icon.
*
* It also enables any hot keys leading to this action,
* again only if there are no other disabled actions on
* their action list.
*
*/
void ctl_enable_action(char *ctlname,char *actname);
/* --------------------- ctl_make_action_writeable -------------------------
*
* Description: Makes any menu entry, and any icon leading to the
* execution of the given action writeable.
*
* Parameters: *ctlname -- A ctl name.
* *action -- The action name.
* len -- Length of indirected data.
* *valid -- Pointer to validation string.
*
* Returns: Pointer to indirected text buffer.
*
* Other Info: If the action is executed by an icon, a check is made that
* the icon is a writeable indirected text icon with a
* buffer length of at least len characters, and that its
* validation string matches the required one, if not a FATAL
* error results.
*
* The ctl module keeps a pointer to the validation string,
* so its life span should be long enough.
*
*/
char *
ctl_make_action_writeable(char *ctlname,char *actname,int len,char *valid);
/* ----------------------------- ctl_find_entries --------------------------
*
* Description: Calls an entry handler function for every menu entry and
* every icon which leads to the execution of the given
* action.
*
* Parameters: *ctlname -- A ctl name.
* *action -- The action name.
* ctl_entry_proc func -- A function to process the entries.
* see ctl_entry_proc above.
* Returns: void.
*
* Other Info: This can be used for special processing of entries and
* icons leading to the action, for example making them
* a sprite.
*
*/
void ctl_find_entries(char *ctlname,char *actname,ctl_entry_proc func);
/* --------------------------- ctl_process -------------------------------
*
* Description: Should be used in place of event_process(), for
* applications which use this module.
*
* The ctl module tries to process the event, if it can't
* the event is passed to event_process().
*
* Parameters: None.
*
* Returns: Void.
*
*
*/
void ctl_process(void);
/* ----------------------- ctl_attach_external_menu -----------------------
*
* Description: Attaches a wimp menu structure to a menu which is defined
* as external in the Control file.
*
* Parameters: *ctlname -- A ctl name.
* *menuname -- The name of an external menu.
* *m -- The wimp menu structure.
*
* Returns: void.
*
* Other Info: A FATAL error is produced if the menu is not defined
* or is not an external menu.
*
*/
void ctl_attach_external_menu(char *ctlname,char *menuname,wimp_menustr *m);
/* ----------------------- ctl_return_external_hit -----------------------
*
* Description: Return a menu hit for a submenu of an external menu.
*
* Parameters: None.
*
* Returns: The hit array as for a menu_selectproc
* Starting from the external menu.
*
* Other Info: Ctl will treat hits on submenus of an external menu
* (Real submenus, not ones attached using ctl).
* As hits on the external menu, this function enables you
* to get the complete hit list.
*
*
*/
char * ctl_return_external_hit(void);
#endif /* __ctl */
......@@ -548,21 +548,6 @@
Entry print_drawpage, imported, , , ,
Entry print_getrectangle, imported, , , ,
; Entry print_screendump, imported, , , ,
; Entry ctl_init,imported, , , ,
; Entry ctl_load,imported, , , ,
; Entry ctl_add_action,imported, , , ,
; Entry ctl_tick_action,imported, , , ,
; Entry ctl_untick_action,imported, , , ,
; Entry ctl_disable_action,imported, , , ,
; Entry ctl_enable_action,imported, , , ,
; Entry ctl_set_action_text,imported, , , ,
; Entry ctl_set_caret_in_action,imported, , , ,
; Entry ctl_make_action_writeable,imported, , , ,
; Entry ctl_find_entries,imported, , , ,
; Entry ctl_attach_external_menu,imported, , , ,
; Entry ctl_attach_menu,imported, , , ,
; Entry ctl_process,imported, , , ,
; Entry ctl_return_external_hit,imported, , , ,
; Entry dbox_read,imported, , , ,
Entry dbox_fillin_fixedcaret, imported, , , ,
Entry xfersend_clear_unknowns, imported, , , ,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment