home *** CD-ROM | disk | FTP | other *** search
- {----------------------------------------------------------------------------}
- { }
- { Menu System - by Marcos Della 12/15/89 }
- { }
- { D&M Enterprises }
- { c/o Marcos R. Della }
- { PO Box 4251 }
- { Santa Rosa, CA 95402 }
- { }
- { -------------------------------------------------------------------------- }
- { }
- { (c) Copyright D&M Enterprises, a general parternership, This program }
- { is CONFIDENTIAL, unpublished work of authorship created in 1989. }
- { IT IS A TRADE SECRET WHICH IS THE PROPERTY OF D&M ENTERPRISES, a general }
- { partnership. ALL USE, DISCLOSURE, AND/OR REPRODUCTION NOT SPECIFICALLY }
- { AUTHORIZED BY D&M ENTERPRISES IS PROHIBITED. This program may also be }
- { protected under copyright and similar laws of other countries. }
- { All rights reserved. }
- { }
- { -------------------------------------------------------------------------- }
- { }
- { You have two different styles of menus available with this unit. They }
- { are a standard selection box (like you see under the F in File when }
- { in the turbo editor) and a bar system with attached selection boxes. }
- { }
- { These routines were designed to be VERY easy to use and implement in }
- { your own programs. To use them, you can define your menus as static }
- { variables or dynamic for usage throughout your program... }
- { }
- { VAR m_menu : menuptr; }
- { BEGIN }
- { NEW(m_menu,init(15,10,'Test menu'); }
- { m_menu^.add_option('/Load/Pick/Save/Write to/Directory'); }
- { m_menu^.add_option('/Change Dir/OS shell/Quit'); }
- { }
- { ch := m_menu^.menuselect(TRUE); }
- { DISPOSE(m_menu,done); }
- { }
- { Thats the basics... There are a bunch of things that you can do to }
- { make life easier on you... Just check out the demo }
- { }
- { -------------------------------------------------------------------------- }
-
- {$V-}
-
- Unit Menu;
-
- Interface
-
- Uses Dos, Crt, Windows;
-
-
- TYPE colorset = ARRAY[1..6] OF BYTE;
- barset = ARRAY[1..9] OF BYTE;
- c_set = SET OF CHAR;
-
- CONST max_items = 20;
-
- {-------------------------------------------------------------------}
- { The following defaults are set for the standard menu and for the }
- { drop down menu system... These can be changed by the user program }
- { just by specifying new values! }
-
- def_color_set : colorset = ($0B,$0A,$0C,$6F,$78,$0B);
- def_bar_set : barset = ($07,$1F,$1B,$70,$07,$00,$1F,$1B,$70);
- toggle_char : CHAR = '/';
-
- {- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
-
- cskip = ^@;
- chome = ^A;
- cright = ^D;
- cprev = ^E;
- cend = ^F;
- cdel = ^G;
- cback = ^H;
- csave = ^J;
- center = ^M;
- cundo = ^R;
- cleft = ^S;
- cins = ^V;
- cnext = ^X;
- cesc = ^[;
-
- TYPE itemptr = ^menuitem;
- menuitem = OBJECT(node)
- keyrtn : CHAR;
- active : BOOLEAN;
- option : ^STRING;
- END;
-
- menuptr = ^menuobj;
- menuobj = OBJECT(nodelist)
- xpos : BYTE;
- ypos : BYTE;
- width : BYTE;
- barposn : itemptr;
- clrset : colorset;
- visible : BOOLEAN;
- titleptr : ^STRING;
- { menulist : nodelist;}
- termchar : c_set;
- CONSTRUCTOR initmenu(x,y : BYTE; title : line);
- DESTRUCTOR done; VIRTUAL;
- PROCEDURE add_option(option : STRING);
- PROCEDURE changecolorset(clrs : colorset);
- PROCEDURE changetermchar(s_ch : c_set);
- PROCEDURE changeposn(x,y : BYTE);
- PROCEDURE option_flag(option : bstr; o_active : BOOLEAN); VIRTUAL;
- FUNCTION menuselect(clearmenu : BOOLEAN) : CHAR; VIRTUAL;
- PROCEDURE closemenu;
- END;
-
- barmenuptr= ^barmenu;
- barmenu = OBJECT(node)
- xpos : BYTE;
- keyrtn : CHAR;
- header : ^STRING;
- menu : ^menuobj;
- END;
-
- barptr = ^barobj;
- barobj = OBJECT(nodelist)
- ypos : BYTE;
- barposn : barmenuptr;
- bclrset : barset;
- menus : BOOLEAN;
- visible : BOOLEAN;
- clrset : barset;
- CONSTRUCTOR initbar(y : BYTE; topline : line);
- DESTRUCTOR done; VIRTUAL;
- PROCEDURE display_bar; VIRTUAL;
- PROCEDURE add_option(option : STRING);
- PROCEDURE option_flag(option : bstr; o_active : BOOLEAN); VIRTUAL;
- FUNCTION barselect : WORD; VIRTUAL;
- END;
-
- FUNCTION readchar : CHAR;
-
- VAR extendkey : BOOLEAN;
-
- Implementation
-
- VAR reg : REGISTERS;
-
- { -------------------------------------------------------------------------- }
-
- FUNCTION readchar : CHAR;
- VAR ch : CHAR;
- BEGIN
- extendkey := FALSE;
- ch := READKEY;
- IF ch = #0 THEN
- BEGIN
- extendkey := TRUE;
- CASE READKEY OF
- #15, #72 : ch := cprev; { Shift-Tab, Up }
- #68 : ch := csave; { F10 }
- #71 : ch := chome; { Home }
- #75 : ch := cleft; { Left }
- #77 : ch := cright; { Right }
- #79 : ch := cend; { End }
- #80 : ch := cnext; { Down }
- #82 : ch := cins; { Ins }
- #83 : ch := cdel; { Del }
- ELSE ch := #0
- END
- END
- ELSE
- IF ch = #9 THEN { Tab }
- ch := cnext;
- readchar := ch
- END;
-
- { -------------------------------------------------------------------------- }
-
- PROCEDURE display_menu(VAR mnu : menuobj);
- VAR p : itemptr;
- i : BYTE;
- BEGIN
- hidecursor;
- p := itemptr(mnu.first);
- i := 0;
- WHILE p <> NIL DO BEGIN
- INC(i);
- p := itemptr(mnu.next(p))
- END;
- IF NOT mnu.visible THEN
- WITH mnu DO
- openwindow(xpos,ypos,xpos + width + 3,ypos + i + 1,clrset[2],TRUE,
- std_border,clrset[1],titleptr^,clrset[6]);
- mnu.visible := TRUE;
-
- p := itemptr(mnu.first);
- i := 0;
- WHILE p <> NIL DO BEGIN
- INC(i);
- IF NOT p^.active THEN
- setfieldatrstr(1,i,mnu.width + 2,mnu.clrset[5],' ' + p^.option^)
- ELSE
- IF p = mnu.barposn THEN
- setfieldatrstr(1,i,mnu.width + 2,mnu.clrset[4],' ' + p^.option^)
- ELSE
- WITH mnu DO BEGIN
- setfieldatrstr(1,i,mnu.width + 2,clrset[2], ' ' + p^.option^);
- writech(xpos + 2,ypos + i,p^.option^[1],clrset[3])
- END;
- p := itemptr(mnu.next(p))
- END
- END;
-
- { -------------------------------------------------------------------------- }
-
- FUNCTION nextitem(VAR option : STRING) : line;
- VAR tstr : line;
- BEGIN
- IF POS(toggle_char,option) > 0 THEN
- BEGIN
- tstr := COPY(option,POS(toggle_char,option) + 1,255);
- IF POS(toggle_char,tstr) > 0 THEN
- option := COPY(tstr,POS(toggle_char,tstr),255)
- ELSE
- option := '';
- tstr := tstr + toggle_char;
- tstr := COPY(tstr,1,POS(toggle_char,tstr + toggle_char) - 1)
- END
- ELSE
- BEGIN
- tstr := option;
- option := ''
- END;
- nextitem := tstr
- END;
-
- { -------------------------------------------------------------------------- }
-
- CONSTRUCTOR menuobj.initmenu;
- BEGIN
- xpos := x;
- ypos := y;
- width := LENGTH(title);
- barposn := NIL;
- visible := FALSE;
- clrset := def_color_set;
- GETMEM(titleptr,LENGTH(title) + 1);
- titleptr^ := title;
- initlist;
- termchar := [center,cesc];
- END;
-
- { -------------------------------------------------------------------------- }
-
- DESTRUCTOR menuobj.done;
- VAR p : itemptr;
- BEGIN
- p := itemptr(first);
- WHILE p <> NIL DO BEGIN
- FREEMEM(p^.option,LENGTH(p^.option^) + 1);
- DISPOSE(p);
- p := itemptr(next(p))
- END;
- FREEMEM(titleptr,LENGTH(titleptr^) + 1);
- IF visible THEN
- closewindow
- END;
-
- { -------------------------------------------------------------------------- }
-
- PROCEDURE menuobj.add_option;
- VAR tstr : STRING;
- p : itemptr;
- i : BYTE;
- BEGIN
- p := itemptr(first);
- i := 0;
- WHILE p <> NIL DO BEGIN
- INC(i);
- p := itemptr(next(p))
- END;
-
- WHILE (i < max_items) AND (POS(toggle_char,option) > 0) DO BEGIN
- INC(i);
- tstr := nextitem(option);
- NEW(p);
- inserttail(p);
- p^.keyrtn := tstr[1];
- p^.active := TRUE;
- IF tstr[2] = '|' THEN
- DELETE(tstr,1,2);
- GETMEM(p^.option,LENGTH(tstr) + 1);
- p^.option^ := tstr;
- IF LENGTH(tstr) > width THEN
- width := LENGTH(tstr);
- IF barposn = NIL THEN
- barposn := p
- END
- END;
-
- { -------------------------------------------------------------------------- }
-
- PROCEDURE menuobj.changecolorset;
- BEGIN
- clrset := clrs;
- IF visible THEN
- BEGIN
- closewindow;
- display_menu(self)
- END
- END;
-
- { -------------------------------------------------------------------------- }
-
- PROCEDURE menuobj.option_flag;
- VAR p : itemptr;
- i : BYTE;
- BEGIN
- IF (LENGTH(option) > 0) AND NOT empty THEN
- FOR i := 1 TO LENGTH(option) DO BEGIN
- p := itemptr(first);
- WHILE p <> NIL DO BEGIN
- IF option[i] = p^.keyrtn THEN
- p^.active := o_active;
- p := itemptr(next(p))
- END
- END
- END;
-
- { -------------------------------------------------------------------------- }
-
- PROCEDURE menuobj.changetermchar;
- BEGIN
- termchar := s_ch
- END;
-
- { -------------------------------------------------------------------------- }
-
- PROCEDURE menuobj.changeposn;
- BEGIN
- xpos := x;
- ypos := y
- END;
-
- { -------------------------------------------------------------------------- }
-
- FUNCTION menuobj.menuselect;
- VAR i : BYTE;
- p : itemptr;
- ch : CHAR;
- hotstr : STRING[max_items];
- BEGIN
- menuselect := #255;
- p := barposn;
- WHILE NOT barposn^.active DO BEGIN {Insure there is a active}
- barposn := itemptr(next_wrap(barposn)); {option in the menu! }
- IF barposn = p THEN {Return #$FF if any error}
- EXIT
- END;
-
- hotstr := '';
- p := itemptr(first); {Create a list of hotkeys}
- WHILE p <> NIL DO BEGIN
- IF p^.active THEN
- hotstr := hotstr + UPCASE(p^.option^[1]);
- p := itemptr(next(p))
- END;
- (*
- IF menuitem + ypos + HI(windmin) + 2 > 25 THEN {Make sure the menu isn't}
- EXIT; {bigger than the screen! }
- menuselect := #0;
- *)
- display_menu(self);
- REPEAT
- p := itemptr(first);
- i := 0;
- WHILE p <> NIL DO BEGIN
- INC(i);
- IF p^.active THEN
- IF p = barposn THEN
- setfieldatrstr(1,i,width + 2,clrset[4],' ' + p^.option^)
- ELSE
- BEGIN
- setfieldatrstr(1,i,width + 2,clrset[2], ' ' + p^.option^);
- writech(xpos + 2,ypos + i,p^.option^[1],clrset[3])
- END;
- p := itemptr(next(p))
- END;
- ch := UPCASE(readchar);
- CASE ch OF
- cnext : REPEAT
- barposn := itemptr(next_wrap(barposn))
- UNTIL barposn^.active;
- cprev : REPEAT
- barposn := itemptr(prev_wrap(barposn))
- UNTIL barposn^.active;
- chome : BEGIN
- barposn := itemptr(first);
- WHILE NOT barposn^.active DO
- barposn := itemptr(next(barposn))
- END;
- cend : BEGIN
- barposn := itemptr(tail);
- WHILE NOT barposn^.active DO
- barposn := itemptr(prev(barposn))
- END
- END;
- i := POS(ch,hotstr);
- UNTIL (ch IN termchar) OR (i > 0);
- IF i > 0 THEN
- REPEAT
- barposn := itemptr(next_wrap(barposn))
- UNTIL UPCASE(barposn^.option^[1]) = ch;
- display_menu(self);
- IF ch = cesc THEN
- menuselect := #0
- ELSE
- IF (ch = center) OR (i > 0) THEN
- menuselect := barposn^.keyrtn
- ELSE
- menuselect := ch;
- IF clearmenu THEN
- BEGIN
- visible := FALSE;
- closewindow
- END
- END;
-
- { -------------------------------------------------------------------------- }
-
- PROCEDURE menuobj.closemenu;
- BEGIN
- IF visible THEN
- closewindow;
- visible := FALSE
- END;
-
- { -------------------------------------------------------------------------- }
-
- PROCEDURE barobj.display_bar;
- VAR p : barmenuptr;
- i : BYTE;
- BEGIN
- IF visible THEN
- setfieldatrstr(barposn^.xpos - 1,ypos,LENGTH(barposn^.header^) + 2,
- bclrset[9],' ' + barposn^.header^ + ' ')
- ELSE
- BEGIN
- visible := TRUE;
- FOR i := LO(windmin) TO LO(windmax) DO
- writech(i + 1,HI(windmin) + 1,' ',bclrset[7]);
- p := barmenuptr(first);
- WHILE p <> NIL DO BEGIN
- setfieldatrstr(p^.xpos,ypos,LENGTH(p^.header^),bclrset[7],p^.header^);
- writech(p^.xpos + LO(windmin),ypos + HI(windmin),p^.header^[1],bclrset[8]);
- p := barmenuptr(next(p))
- END;
- display_bar
- END
- END;
-
- { -------------------------------------------------------------------------- }
-
- CONSTRUCTOR barobj.initbar;
- VAR p : barmenuptr;
- tstr : line;
- posn : BYTE;
- BEGIN
- ypos := y;
- posn := 4;
- barposn := NIL;
- bclrset := def_bar_set;
- visible := FALSE;
- menus := FALSE;
- initlist;
- WHILE LENGTH(topline) > 0 DO BEGIN
- tstr := nextitem(topline);
- NEW(p);
- inserttail(p);
- IF (tstr[2] = '|') AND (LENGTH(tstr) > 2) THEN
- BEGIN
- p^.keyrtn := tstr[1];
- DELETE(tstr,1,2)
- END
- ELSE
- p^.keyrtn := UPCASE(tstr[1]);
- GETMEM(p^.header,LENGTH(tstr) + 1);
- p^.header^ := tstr;
- p^.menu := NIL;
- p^.xpos := posn;
- INC(posn,4 + LENGTH(tstr));
- IF barposn = NIL THEN
- barposn := p
- END
- END;
-
- { -------------------------------------------------------------------------- }
-
- DESTRUCTOR barobj.done;
- VAR p : barmenuptr;
- BEGIN
- p := barmenuptr(first);
- WHILE p <> NIL DO BEGIN
- IF p^.menu <> NIL THEN
- DISPOSE(p^.menu,done);
- FREEMEM(p^.header,LENGTH(p^.header^) + 1);
- DISPOSE(p);
- p := barmenuptr(next(p))
- END;
- IF visible THEN
- closewindow
- END;
-
- { -------------------------------------------------------------------------- }
-
- PROCEDURE barobj.add_option;
- VAR s,p : barmenuptr;
- fchr : line;
- clrs : colorset;
- BEGIN
- IF LENGTH(option) < 4 THEN
- EXIT;
- fchr := nextitem(option);
- p := barmenuptr(first);
- s := barmenuptr(prev_wrap(p));
- WHILE (p^.keyrtn <> fchr[1]) AND (s <> p) DO
- p := barmenuptr(next_wrap(p));
- IF p^.keyrtn <> fchr[1] THEN
- EXIT;
- IF p^.menu = NIL THEN
- BEGIN
- MOVE(bclrset,clrs,SIZEOF(clrs));
- NEW(p^.menu,initmenu(p^.xpos - 2 + LO(windmin),ypos + 1 + HI(windmin),''));
- p^.menu^.changetermchar([center,cesc,cleft,cright]);
- p^.menu^.changecolorset(clrs);
- END;
- p^.menu^.add_option(option)
- END;
-
- { -------------------------------------------------------------------------- }
-
- PROCEDURE barobj.option_flag;
- VAR fstr : bstr;
- p : barmenuptr;
- BEGIN
- fstr := nextitem(option);
- IF (LENGTH(fstr) = 1) AND (LENGTH(option) > 1) THEN
- BEGIN
- DELETE(option,1,1);
- p := barmenuptr(first);
- WHILE (p <> NIL) AND (p^.keyrtn <> fstr[1]) DO
- p := barmenuptr(next(p));
- IF p^.keyrtn = fstr[1] THEN
- p^.menu^.option_flag(option,o_active)
- END
- END;
-
- { -------------------------------------------------------------------------- }
-
- FUNCTION barobj.barselect;
- LABEL proc_done;
- VAR p : barmenuptr;
- ch : CHAR;
- chsub : CHAR;
- hotkey : bstr;
- BEGIN
- hidecursor;
- p := barmenuptr(first);
- hotkey := '';
- barselect := $FFFF;
- WHILE p <> NIL DO BEGIN
- hotkey := hotkey + UPCASE(p^.header^[1]);
- p^.menu^.changeposn(p^.xpos - 2 + LO(windmin),ypos + 1 + HI(windmin));
- p := barmenuptr(next(p))
- END;
- IF LENGTH(hotkey) = 0 THEN
- EXIT;
- barselect := $0000;
- display_bar;
- REPEAT
- ch := #0;
- chsub := #0;
- IF menus AND (barposn^.menu <> NIL) THEN
- BEGIN
- chsub := barposn^.menu^.menuselect(TRUE);
- CASE chsub OF
- cleft,
- cright : ch := chsub;
- #0 : ch := cesc;
- #$FF : {?-?-?-?-?-?-?};
- ELSE ch := center
- END
- END
- ELSE
- BEGIN
- ch := UPCASE(readchar);
- IF POS(ch,hotkey) > 0 THEN
- BEGIN
- REPEAT
- barposn := barmenuptr(next_wrap(barposn))
- UNTIL barposn^.header^[1] = ch;
- ch := center
- END
- ELSE
- IF NOT (ch IN [center,cleft,cright,cnext,cesc]) THEN
- ch := #0
- END;
- IF (ch IN [cleft,cright]) OR
- ((ch = center) AND (menus OR (barposn^.menu = NIL))) THEN
- BEGIN
- setfieldatrstr(barposn^.xpos - 1,ypos,LENGTH(barposn^.header^) + 2,
- bclrset[7],' ' + barposn^.header^ + ' ');
- writech(barposn^.xpos + LO(windmin),ypos + HI(windmin),barposn^.header^[1],bclrset[8])
- END;
- CASE ch OF
- cleft : barposn := barmenuptr(prev_wrap(barposn));
- cright : barposn := barmenuptr(next_wrap(barposn));
- cnext : IF barposn^.menu <> NIL THEN
- menus := TRUE;
- center : IF NOT menus AND (barposn^.menu <> NIL) THEN
- BEGIN
- menus := TRUE;
- ch := #0
- END;
- cesc : ;
- END;
- IF (ch <> center) AND (ch <> cesc) THEN
- display_bar
- UNTIL (ch IN [center,cesc]);
-
- IF ch <> cesc THEN
- barselect := ORD(barposn^.keyrtn) * 256 + ORD(chsub);
- menus := FALSE;
- visible := FALSE
- END;
-
- { -------------------------------------------------------------------------- }
-
- END.