DEFINITION MODULE Selector;
(*******************************************************************
Module Selector (Version 1.0)
Copyright (c) 1995-2006 by Andreas Fischlin and ETH Zurich.
Purpose Modal dialog to select items from a scrollable
list of items.
Remarks --
Programming
o Design
Andreas Fischlin 28/10/1995
o Implementation
Andreas Fischlin 28/10/1995
ETH Zurich
Systems Ecology
CHN E 35.1
Universitaetstrasse 16
8092 Zurich
SWITZERLAND
URLs:
<mailto:RAMSES@env.ethz.ch>
<http://www.sysecol.ethz.ch>
<http://www.sysecol.ethz.ch/SimSoftware/RAMSES>
Last revision of definition: 19/06/1998 AF
*******************************************************************)
FROM SYSTEM IMPORT ADDRESS;
FROM Lists IMPORT SelectionMode;
(*******************************)
(*##### Selector Type #####*)
(*******************************)
TYPE
Item = ADDRESS;
FirstItemProc = PROCEDURE (): Item;
NextItemProc = PROCEDURE (Item): Item;
ItemExistsProc = PROCEDURE (Item): BOOLEAN;
GetItemIdentProc = PROCEDURE (Item, VAR ARRAY OF CHAR);
MarkItemProc = PROCEDURE (Item, BOOLEAN);
SelectorSetup = RECORD
selectorTitle,
checkBoxText: ARRAY [0..127] OF CHAR;
firstItem: FirstItemProc;
nextItem: NextItemProc;
itemExists: ItemExistsProc;
getItemIdent: GetItemIdentProc;
markItem: MarkItemProc;
selMode: SelectionMode;
END(*RECORD*);
(**********************************************)
(*##### Explanations and Sample Code #####*)
(**********************************************)
(*====================================================================
For your convenience a typical setup might look as follows:
TYPE
MyItem = POINTER TO ItemDescr;
ItemDescr = RECORD
next: MyItem;
ident: ARRAY [0..63] OF CHAR;
mark: BOOLEAN;
(*.
...
your other fields
.*)
END(*RECORD*);
VAR
myRoot: MyItem;
PROCEDURE MyFirstItem (): Item;
BEGIN
RETURN myRoot
END MyFirstItem;
PROCEDURE MyNextItem (i: Item): Item;
VAR myi: MyItem;
BEGIN
myi := i;
RETURN myi^.next
END MyNextItem;
PROCEDURE MyItemExists (i: Item): BOOLEAN;
BEGIN
RETURN i<>NIL
END MyItemExists;
PROCEDURE MyGetItemIdent (i: Item; VAR ident: ARRAY OF CHAR);
VAR myi: MyItem;
BEGIN
myi := i;
AssignString(myi^.ident, ident);
END MyGetItemIdent;
PROCEDURE MyMarkItem (i: Item; mark: BOOLEAN);
VAR myi: MyItem;
BEGIN
myi := i;
myi^.mark := mark;
END MyMarkItem;
Note, above routines all assume as a warranted precondition the
existence or otherwise proper value settings of the actual item
arguments of type ItemPtr at all times. These preconditions are
warranted as long as you don't change the list of items while
executing the selector and that you don't use above procedures
for anything else than the selector. This is because the selector
can't pass you non-existing items. However, if you use above
procedures also for other purposes, e.g. MyItemExists, you ought
to write them more sophisticated, e.g. such as testing for the
existence of the item at the beginning of the routine etc.
And to actually ask the user for making a selection use a procedure
similar to the following:
PROCEDURE AskUserToSelect;
VAR setup: SelectorSetup; myChkBox,ok: BOOLEAN;
BEGIN (* AskUserToSelect *)
WITH setup DO
selectorTitle := "Selector";
checkBoxText := "Checking";
firstItem := MyFirstItem;
nextItem := MyNextItem;
itemExists := MyItemExists;
getItemIdent := MyGetItemIdent;
markItem := MyMarkItem;
selMode := multipleDisconnected;
END(*WITH*);
ExecuteSelector(setup,myChkBox,ok);
IF ok THEN
(*.
... e.g. call OperateOnSelected (see below)
.*)
END(*IF*);
END AskUserToSelect;
Finally, to learn about the selection the user made and to perform some
operation with these operands use a procedure similar to this one:
PROCEDURE OperateOnSelected;
VAR myi: MyItem;
BEGIN (* OperateOnSelected *)
myi:= myRoot;
WHILE (myi<>NIL) DO
IF (myi^.mark) THEN
(*.
... do whatever is appropriate if it was selected
.*)
END(*IF*);
myi := myi^.next;
END(*WHILE*);
END OperateOnSelected;
====================================================================*)
(**********************************)
(*##### Selector Dialogs #####*)
(**********************************)
PROCEDURE ExecuteSelector (ssu: SelectorSetup;
VAR checkBoxVar, okButtonPressed: BOOLEAN );
(*
Displays a modal dialog window which allows the user to
select any items (including multiple selection) from a list
of items as defined by the routines specified in ssu. Upon
returning from this routine, find the selected items by
searching in your list for marked items if okButtonPressed.
Note that ExecuteSelector always clears first all marks.
checkBoxVar use is optional (i.e. will only be displayed if
ssu.checkBoxText is not the empty string).
*)
(**************************************)
(*##### Easy-to-use Selector #####*)
(**************************************)
PROCEDURE ChooseFromList (selectorTitle: ARRAY OF CHAR;
VAR(*speed-up*) strList: ARRAY OF CHAR;
VAR selection: ARRAY OF CHAR;
delim: CHAR; selMode: SelectionMode);
(*
Easy selection routine based on ExecuteSelector. It
features the selector with the title 'selectorTitle' and
lets you select according to mode 'selMode' any of the
items you pass as actual argument in 'strList'. It then
returns the result of the selection in 'selection'.
Items are expected to be separated by the delimiter
'delim', typically '|'; this of course also true for the
result in 'selection' in case 'selMode' is either
'multipleAdjacent' or 'multipleDisconnected'. It setups
internally a list as described above and nothing else
than just a call to this routine is required to make a
selection. Ex.:
title = "Please select one goddess:";
listOfGods := "Isis|Diana|Athena";
ChooseFromList(title,listOfGods,selection,"|",single);
returns in selection "Isis" if the user selected it. If
the user cancelled the dialog or refused to choose a
goddess, the empty string is returned in 'selection'. If
'selMode' = multipleDisconnected, ChooseFromList may return
in 'selection' "Isis|Athena" if the user selected the first
and the last goddesses.
*)
END Selector.